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