View Javadoc
1   /*
2    *  Licensed to the Apache Software Foundation (ASF) under one
3    *  or more contributor license agreements.  See the NOTICE file
4    *  distributed with this work for additional information
5    *  regarding copyright ownership.  The ASF licenses this file
6    *  to you under the Apache License, Version 2.0 (the
7    *  "License"); you may not use this file except in compliance
8    *  with the License.  You may obtain a copy of the License at
9    *  
10   *    http://www.apache.org/licenses/LICENSE-2.0
11   *  
12   *  Unless required by applicable law or agreed to in writing,
13   *  software distributed under the License is distributed on an
14   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *  KIND, either express or implied.  See the License for the
16   *  specific language governing permissions and limitations
17   *  under the License. 
18   *  
19   */
20  package org.apache.directory.server.core.normalization;
21  
22  
23  import java.util.Iterator;
24  import java.util.List;
25  
26  import org.apache.directory.api.ldap.model.exception.LdapException;
27  import org.apache.directory.api.ldap.model.filter.ApproximateNode;
28  import org.apache.directory.api.ldap.model.filter.BranchNode;
29  import org.apache.directory.api.ldap.model.filter.EqualityNode;
30  import org.apache.directory.api.ldap.model.filter.ExprNode;
31  import org.apache.directory.api.ldap.model.filter.ExtensibleNode;
32  import org.apache.directory.api.ldap.model.filter.FilterVisitor;
33  import org.apache.directory.api.ldap.model.filter.GreaterEqNode;
34  import org.apache.directory.api.ldap.model.filter.LeafNode;
35  import org.apache.directory.api.ldap.model.filter.LessEqNode;
36  import org.apache.directory.api.ldap.model.filter.OrNode;
37  import org.apache.directory.api.ldap.model.filter.PresenceNode;
38  import org.apache.directory.api.ldap.model.filter.SubstringNode;
39  import org.apache.directory.api.ldap.model.schema.AttributeType;
40  import org.apache.directory.api.ldap.model.schema.SchemaManager;
41  import org.apache.directory.server.i18n.I18n;
42  
43  
44  /**
45   *
46   *
47   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
48   */
49  public class ExpandingVisitor implements FilterVisitor
50  {
51      /** The schemaManager */
52      private SchemaManager schemaManager;
53  
54  
55      /**
56       * 
57       * Creates a new instance of ExpandingVisitor.
58       *
59       * @param schemaManager The server schemaManager
60       */
61      public ExpandingVisitor( SchemaManager schemaManager )
62      {
63          this.schemaManager = schemaManager;
64      }
65  
66  
67      /**
68       * {@inheritDoc}
69       */
70      @Override
71      public boolean canVisit( ExprNode node )
72      {
73          return node instanceof BranchNode;
74      }
75  
76  
77      /**
78       * {@inheritDoc}
79       */
80      @Override
81      public List<ExprNode> getOrder( BranchNode node, List<ExprNode> children )
82      {
83          return children;
84      }
85  
86  
87      /**
88       * {@inheritDoc}
89       */
90      @Override
91      public boolean isPrefix()
92      {
93          return false;
94      }
95  
96  
97      /**
98       * {@inheritDoc}
99       */
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 }