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 */
020package org.apache.directory.api.ldap.model.filter;
021
022
023import java.util.ArrayList;
024import java.util.List;
025
026import 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 */
035public class BranchNode extends AbstractExprNode
036{
037    /** child node list for this branch node */
038    protected List<ExprNode> children = null;
039
040
041    /**
042     * Creates a BranchNode using a logical operator and a list of children.
043     * @param assertionType the node's type
044     * @param childList the child nodes under this branch node.
045     */
046    protected BranchNode( AssertionType assertionType, List<ExprNode> childList )
047    {
048        super( assertionType );
049
050        if ( null == childList )
051        {
052            this.children = new ArrayList<ExprNode>( 2 );
053        }
054        else
055        {
056            this.children = childList;
057        }
058
059        isSchemaAware = true;
060    }
061
062
063    /**
064     * Creates a BranchNode using a logical operator and a list of children.
065     * 
066     * @param assertionType the node's type
067     * @param childList the child nodes under this branch node.
068     */
069    protected BranchNode( AssertionType assertionType, ExprNode... childList )
070    {
071        super( assertionType );
072
073        if ( null == children )
074        {
075            this.children = new ArrayList<ExprNode>( childList.length );
076        }
077
078        CollectionUtils.addAll( children, childList );
079    }
080
081
082    /**
083     * Creates a BranchNode using a logical operator.
084     * 
085     * @param assertionType the node's type
086     */
087    protected BranchNode( AssertionType assertionType )
088    {
089        super( assertionType );
090
091        this.children = new ArrayList<ExprNode>( 2 );
092        isSchemaAware = true;
093    }
094
095
096    /**
097     * @see ExprNode#isLeaf()
098     * @return false all the time.
099     */
100    public final boolean isLeaf()
101    {
102        return false;
103    }
104
105
106    /**
107     * Makes a full clone in new memory space of the current node and children
108     * 
109     * @return the clone
110     */
111    @Override
112    public ExprNode clone()
113    {
114        ExprNode clone = ( ExprNode ) super.clone();
115
116        // Clone the children
117        if ( children != null )
118        {
119            ( ( BranchNode ) clone ).children = new ArrayList<ExprNode>();
120
121            for ( ExprNode child : children )
122            {
123                ( ( BranchNode ) clone ).children.add( ( ExprNode ) child.clone() );
124            }
125        }
126
127        return clone;
128    }
129
130
131    /**
132     * Adds a child node to this branch node node
133     * 
134     * @param node the child expression to add to this branch node
135     */
136    public void addNode( ExprNode node )
137    {
138        children.add( node );
139    }
140
141
142    /**
143     * Adds a child node to this branch node at the head rather than the tail. 
144     * 
145     * @param node the child expression to add to this branch node
146     */
147    public void addNodeToHead( ExprNode node )
148    {
149        children.add( 0, node );
150    }
151
152
153    /**
154     * Gets the children below this BranchNode. We purposefully do not clone the
155     * array list so that backends can sort the order of children using their
156     * own search optimization algorithms. We want backends and other parts of
157     * the system to be able to induce side effects on the tree structure.
158     * 
159     * @return the list of child nodes under this branch node.
160     */
161    public List<ExprNode> getChildren()
162    {
163        return children;
164    }
165
166
167    /**
168     * Sets the list of children under this node.
169     * 
170     * @param list the list of children to set.
171     */
172    public void setChildren( List<ExprNode> list )
173    {
174        children = list;
175    }
176
177
178    /**
179     * Convenience method that gets the first child in the children array. Its
180     * very useful for NOT nodes since they only have one child by avoiding code
181     * that looks like: <code> ( ExprNode ) m_children.get( 0 ) </code>
182     * 
183     * @return the first child
184     */
185    public ExprNode getFirstChild()
186    {
187        if ( children.size() > 0 )
188        {
189            return children.get( 0 );
190        }
191
192        return null;
193    }
194
195
196    /**
197     * @see ExprNode#accept(
198     *FilterVisitor)
199     *      
200     * @return The modified element
201     */
202    public final Object accept( FilterVisitor visitor )
203    {
204        if ( visitor.isPrefix() )
205        {
206            List<ExprNode> childrenList = visitor.getOrder( this, this.children );
207            ExprNode result = null;
208
209            if ( visitor.canVisit( this ) )
210            {
211                result = ( ExprNode ) visitor.visit( this );
212            }
213
214            for ( ExprNode node : childrenList )
215            {
216                node.accept( visitor );
217            }
218
219            return result;
220        }
221        else
222        {
223            if ( visitor.canVisit( this ) )
224            {
225                return visitor.visit( this );
226            }
227            else
228            {
229                return null;
230            }
231        }
232    }
233
234
235    /**
236     * @see Object#hashCode()
237     * @return the instance's hash code 
238     */
239    public int hashCode()
240    {
241        int h = 37;
242
243        h = h * 17 + super.hashCode();
244
245        if ( children != null )
246        {
247            for ( ExprNode child : children )
248            {
249                h = h * 17 + child.hashCode();
250            }
251        }
252
253        return h;
254    }
255
256
257    /**
258     * @see java.lang.Object#equals(java.lang.Object)
259     */
260    public boolean equals( Object other )
261    {
262        if ( this == other )
263        {
264            return true;
265        }
266
267        if ( !( other instanceof BranchNode ) )
268        {
269            return false;
270        }
271
272        if ( other.getClass() != this.getClass() )
273        {
274            return false;
275        }
276
277        BranchNode otherExprNode = ( BranchNode ) other;
278
279        List<ExprNode> otherChildren = otherExprNode.getChildren();
280
281        if ( otherChildren == children )
282        {
283            return true;
284        }
285
286        if ( children.size() != otherChildren.size() )
287        {
288            return false;
289        }
290
291        for ( int i = 0; i < children.size(); i++ )
292        {
293            ExprNode child = children.get( i );
294            ExprNode otherChild = children.get( i );
295
296            if ( !child.equals( otherChild ) )
297            {
298                return false;
299            }
300        }
301
302        return true;
303    }
304}