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.server.core.normalization;
021
022
023import java.util.Iterator;
024import java.util.List;
025
026import org.apache.directory.api.ldap.model.exception.LdapException;
027import org.apache.directory.api.ldap.model.filter.ApproximateNode;
028import org.apache.directory.api.ldap.model.filter.BranchNode;
029import org.apache.directory.api.ldap.model.filter.EqualityNode;
030import org.apache.directory.api.ldap.model.filter.ExprNode;
031import org.apache.directory.api.ldap.model.filter.ExtensibleNode;
032import org.apache.directory.api.ldap.model.filter.FilterVisitor;
033import org.apache.directory.api.ldap.model.filter.GreaterEqNode;
034import org.apache.directory.api.ldap.model.filter.LeafNode;
035import org.apache.directory.api.ldap.model.filter.LessEqNode;
036import org.apache.directory.api.ldap.model.filter.OrNode;
037import org.apache.directory.api.ldap.model.filter.PresenceNode;
038import org.apache.directory.api.ldap.model.filter.SubstringNode;
039import org.apache.directory.api.ldap.model.schema.AttributeType;
040import org.apache.directory.api.ldap.model.schema.SchemaManager;
041import org.apache.directory.server.i18n.I18n;
042
043
044/**
045 *
046 *
047 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
048 */
049public class ExpandingVisitor implements FilterVisitor
050{
051    /** The schemaManager */
052    private SchemaManager schemaManager;
053
054
055    /**
056     * 
057     * Creates a new instance of ExpandingVisitor.
058     *
059     * @param schemaManager The server schemaManager
060     */
061    public ExpandingVisitor( SchemaManager schemaManager )
062    {
063        this.schemaManager = schemaManager;
064    }
065
066
067    /**
068     * {@inheritDoc}
069     */
070    @Override
071    public boolean canVisit( ExprNode node )
072    {
073        return node instanceof BranchNode;
074    }
075
076
077    /**
078     * {@inheritDoc}
079     */
080    @Override
081    public List<ExprNode> getOrder( BranchNode node, List<ExprNode> children )
082    {
083        return children;
084    }
085
086
087    /**
088     * {@inheritDoc}
089     */
090    @Override
091    public boolean isPrefix()
092    {
093        return false;
094    }
095
096
097    /**
098     * {@inheritDoc}
099     */
100    @Override
101    public Object visit( ExprNode node )
102    {
103        BranchNode bnode = ( BranchNode ) node;
104
105        // --------------------------------------------------------------------
106        // we want to check each child leaf node to see if it must be expanded
107        // children that are branch nodes are recursively visited
108        // --------------------------------------------------------------------
109
110        final List<ExprNode> children = bnode.getChildren();
111        int childNumber = 0;
112
113        for ( ExprNode child : children )
114        {
115            if ( child instanceof LeafNode )
116            {
117                LeafNode leaf = ( LeafNode ) child;
118
119                try
120                {
121                    if ( schemaManager.getAttributeTypeRegistry().hasDescendants( leaf.getAttributeType() ) )
122                    {
123                        // create a new OR node to hold all descendent forms
124                        // add to this node the generalized leaf node and 
125                        // replace the old leaf with the new OR branch node
126                        BranchNode orNode = new OrNode();
127                        orNode.getChildren().add( leaf );
128                        children.set( childNumber++, orNode );
129
130                        // iterate through descendants adding them to the orNode
131                        Iterator<AttributeType> descendants = schemaManager.getAttributeTypeRegistry().descendants(
132                            leaf.getAttributeType() );
133
134                        while ( descendants.hasNext() )
135                        {
136                            LeafNode newLeaf;
137                            AttributeType descendant = descendants.next();
138
139                            if ( leaf instanceof PresenceNode )
140                            {
141                                newLeaf = new PresenceNode( descendant );
142                            }
143                            else if ( leaf instanceof ApproximateNode )
144                            {
145                                ApproximateNode approximateNode = ( ApproximateNode ) leaf;
146
147                                newLeaf = new ApproximateNode( descendant, approximateNode.getValue() );
148                            }
149                            else if ( leaf instanceof EqualityNode )
150                            {
151                                EqualityNode equalityNode = ( EqualityNode ) leaf;
152
153                                newLeaf = new EqualityNode( descendant, equalityNode.getValue() );
154                            }
155                            else if ( leaf instanceof GreaterEqNode )
156                            {
157                                GreaterEqNode greaterEqNode = ( GreaterEqNode ) leaf;
158
159                                newLeaf = new GreaterEqNode( descendant, greaterEqNode.getValue() );
160                            }
161                            else if ( leaf instanceof LessEqNode )
162                            {
163                                LessEqNode lessEqNode = ( LessEqNode ) leaf;
164
165                                newLeaf = new LessEqNode( descendant, lessEqNode.getValue() );
166                            }
167                            else if ( leaf instanceof ExtensibleNode )
168                            {
169                                ExtensibleNode extensibleNode = ( ExtensibleNode ) leaf;
170                                newLeaf = new ExtensibleNode( descendant, extensibleNode.getValue(),
171                                    extensibleNode.getMatchingRuleId(), extensibleNode.hasDnAttributes() );
172                            }
173                            else if ( leaf instanceof SubstringNode )
174                            {
175                                SubstringNode substringNode = ( SubstringNode ) leaf;
176                                newLeaf = new SubstringNode( descendant, substringNode.getInitial(),
177                                    substringNode.getFinal() );
178                            }
179                            else
180                            {
181                                throw new IllegalStateException( I18n.err( I18n.ERR_260, leaf ) );
182                            }
183
184                            orNode.addNode( newLeaf );
185                        }
186                    }
187                }
188                catch ( LdapException e )
189                {
190                    // log something here and throw a runtime excpetion
191                    throw new RuntimeException( I18n.err( I18n.ERR_261 ) );
192                }
193            }
194            else
195            {
196                visit( child );
197            }
198        } // end for loop
199
200        return null;
201    }
202}