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