001    /*
002     *  Licensed to the Apache Software Foundation (ASF) under one
003     *  or more contributor license agreements.  See the NOTICE file
004     *  distributed with this work for additional information
005     *  regarding copyright ownership.  The ASF licenses this file
006     *  to you under the Apache License, Version 2.0 (the
007     *  "License"); you may not use this file except in compliance
008     *  with the License.  You may obtain a copy of the License at
009     *  
010     *    http://www.apache.org/licenses/LICENSE-2.0
011     *  
012     *  Unless required by applicable law or agreed to in writing,
013     *  software distributed under the License is distributed on an
014     *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015     *  KIND, either express or implied.  See the License for the
016     *  specific language governing permissions and limitations
017     *  under the License. 
018     *  
019     */
020    package org.apache.directory.shared.ldap.filter;
021    
022    
023    import java.util.ArrayList;
024    import java.util.List;
025    
026    import org.apache.commons.collections.CollectionUtils;
027    
028    
029    /**
030     * Node representing branches within the expression tree corresponding to
031     * logical operators within the filter expression.
032     * 
033     * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
034     * @version $Rev: 746607 $
035     */
036    public class BranchNode extends AbstractExprNode
037    {
038        /** child node list for this branch node */
039        protected List<ExprNode> children = null;
040    
041    
042        /**
043         * Creates a BranchNode using a logical operator and a list of children.
044         * @param assertionType the node's type
045         * @param childList the child nodes under this branch node.
046         */
047        protected BranchNode( AssertionType assertionType, List<ExprNode> childList )
048        {
049            super( assertionType );
050    
051            if ( null == childList )
052            {
053                this.children = new ArrayList<ExprNode>( 2 );
054            }
055            else
056            {
057                this.children = childList;
058            }
059        }
060    
061    
062        /**
063         * Creates a BranchNode using a logical operator and a list of children.
064         * 
065         * @param assertionType the node's type
066         * @param childList the child nodes under this branch node.
067         */
068        protected BranchNode( AssertionType assertionType, ExprNode... childList )
069        {
070            super( assertionType );
071    
072            if ( null == children )
073            {
074                this.children = new ArrayList<ExprNode>( childList.length );
075            }
076            
077            CollectionUtils.addAll( children, childList );
078        }
079    
080    
081        /**
082         * Creates a BranchNode using a logical operator.
083         * 
084         * @param assertionType the node's type
085         */
086        protected BranchNode( AssertionType assertionType )
087        {
088            super( assertionType );
089            
090            this.children = new ArrayList<ExprNode>( 2 );
091        }
092    
093        
094        /**
095         * @see org.apache.directory.shared.ldap.filter.ExprNode#isLeaf()
096         * @return false all the time.
097         */
098        public final boolean isLeaf()
099        {
100            return false;
101        }
102    
103        /**
104         * Makes a full clone in new memory space of the current node and children
105         * 
106         * @return the clone
107         */
108        @Override public ExprNode clone()
109        {
110            ExprNode clone = (ExprNode)super.clone();
111            
112            // Clone the children
113            if ( children != null )
114            {
115                ((BranchNode)clone).children = new ArrayList<ExprNode>();
116                
117                for ( ExprNode child : children )
118                {
119                    ((BranchNode)clone).children.add( (ExprNode)child.clone() );
120                }
121            }
122            
123            return clone;
124        }
125    
126    
127        /**
128         * Adds a child node to this branch node node
129         * 
130         * @param node the child expression to add to this branch node
131         */
132        public void addNode( ExprNode node )
133        {
134            children.add( node );
135        }
136    
137    
138        /**
139         * Adds a child node to this branch node at the head rather than the tail. 
140         * 
141         * @param node the child expression to add to this branch node
142         */
143        public void addNodeToHead( ExprNode node )
144        {
145            children.add( 0, node );
146        }
147    
148        
149        /**
150         * Gets the children below this BranchNode. We purposefully do not clone the
151         * array list so that backends can sort the order of children using their
152         * own search optimization algorithms. We want backends and other parts of
153         * the system to be able to induce side effects on the tree structure.
154         * 
155         * @return the list of child nodes under this branch node.
156         */
157        public List<ExprNode> getChildren()
158        {
159            return children;
160        }
161    
162    
163        /**
164         * Sets the list of children under this node.
165         * 
166         * @param list the list of children to set.
167         */
168        public void setChildren( List<ExprNode> list )
169        {
170            children = list;
171        }
172        
173        /**
174         * Convenience method that gets the first child in the children array. Its
175         * very useful for NOT nodes since they only have one child by avoiding code
176         * that looks like: <code> ( ExprNode ) m_children.get( 0 ) </code>
177         * 
178         * @return the first child
179         */
180        public ExprNode getFirstChild()
181        {
182            if ( children.size() > 0 )
183            {
184                return children.get( 0 );
185            }
186    
187            return null;
188        }
189    
190    
191        /**
192         * @see org.apache.directory.shared.ldap.filter.ExprNode#accept(
193         *      org.apache.directory.shared.ldap.filter.FilterVisitor)
194         *      
195         * @return The modified element
196         */
197        public final Object accept( FilterVisitor visitor )
198        {
199            if ( visitor.isPrefix() )
200            {
201                List<ExprNode> childrenList = visitor.getOrder( this, this.children );
202                ExprNode result = null;
203    
204                if ( visitor.canVisit( this ) )
205                {
206                    result = (ExprNode)visitor.visit( this );
207                }
208    
209                for ( ExprNode node:childrenList )
210                {
211                    node.accept( visitor );
212                }
213    
214                return result;
215            }
216            else
217            {
218                if ( visitor.canVisit( this ) )
219                {
220                    return visitor.visit( this );
221                }
222                else
223                {
224                    return null;
225                }
226            }
227        }
228        
229        
230        /**
231         * (non-Javadoc)
232         * 
233         * @see Object#hashCode()
234         * @return the instance's hash code 
235         */
236        public int hashCode()
237        {
238            int h = 37;
239            
240            h = h*17 + super.hashCode();
241            
242            if ( children != null )
243            {
244                for ( ExprNode child:children )
245                {
246                    h = h*17 + child.hashCode();
247                }
248            }
249            
250            return h;
251        }
252        
253        /*
254         * (non-Javadoc)
255         * 
256         * @see java.lang.Object#equals(java.lang.Object)
257         */
258        public boolean equals( Object other )
259        {
260            if ( this == other )
261            {
262                return true;
263            }
264    
265            if ( !( other instanceof BranchNode ) )
266            {
267                return false;
268            }
269            
270            if ( other.getClass() != this.getClass() )
271            {
272                return false;
273            }
274    
275            BranchNode otherExprNode = ( BranchNode ) other;
276    
277            List<ExprNode> otherChildren = otherExprNode.getChildren();
278    
279            if ( otherChildren == children )
280            {
281                return true;
282            }
283    
284            if ( children.size() != otherChildren.size() )
285            {
286                return false;
287            }
288            
289            for ( int i = 0; i < children.size(); i++ )
290            {
291                ExprNode child = children.get( i );
292                ExprNode otherChild = children.get( i );
293                
294                if ( !child.equals( otherChild ) )
295                {
296                    return false;
297                }
298            }
299            
300            return true;
301        }
302    }