View Javadoc

1   /*
2    *   Copyright 2004 The Apache Software Foundation
3    *
4    *   Licensed under the Apache License, Version 2.0 (the "License");
5    *   you may not use this file except in compliance with the License.
6    *   You may obtain a copy of the License at
7    *
8    *       http://www.apache.org/licenses/LICENSE-2.0
9    *
10   *   Unless required by applicable law or agreed to in writing, software
11   *   distributed under the License is distributed on an "AS IS" BASIS,
12   *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   *   See the License for the specific language governing permissions and
14   *   limitations under the License.
15   *
16   */
17  package org.apache.ldap.server.event;
18  
19  
20  import java.util.Comparator;
21  
22  import javax.naming.NamingEnumeration;
23  import javax.naming.NamingException;
24  import javax.naming.directory.Attribute;
25  import javax.naming.directory.Attributes;
26  
27  import org.apache.ldap.common.NotImplementedException;
28  import org.apache.ldap.common.filter.ExprNode;
29  import org.apache.ldap.common.filter.LeafNode;
30  import org.apache.ldap.common.filter.PresenceNode;
31  import org.apache.ldap.common.filter.ScopeNode;
32  import org.apache.ldap.common.filter.SimpleNode;
33  import org.apache.ldap.common.schema.AttributeType;
34  import org.apache.ldap.common.schema.MatchingRule;
35  import org.apache.ldap.common.schema.Normalizer;
36  import org.apache.ldap.server.schema.AttributeTypeRegistry;
37  import org.apache.ldap.server.schema.OidRegistry;
38  
39  
40  /***
41   * Evaluates LeafNode assertions on candidates using a database.
42   * 
43   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
44   * @version $Rev$
45   */
46  public class LeafEvaluator implements Evaluator
47  {
48      /*** equality matching type constant */
49      private static final int EQUALITY_MATCH = 0;
50      /*** ordering matching type constant */
51      private static final int ORDERING_MATCH = 1;
52      /*** substring matching type constant */
53      private static final int SUBSTRING_MATCH = 3;
54  
55  
56      /*** Oid Registry used to translate attributeIds to OIDs */
57      private OidRegistry oidRegistry;
58      /*** AttributeType registry needed for normalizing and comparing values */
59      private AttributeTypeRegistry attributeTypeRegistry;
60      /*** Substring node evaluator we depend on */
61      private SubstringEvaluator substringEvaluator;
62      /*** ScopeNode evaluator we depend on */
63      private ScopeEvaluator scopeEvaluator;
64  
65  
66      /***
67       * Creates a leaf expression node evaluator.
68       *
69       * @param substringEvaluator
70       */
71      public LeafEvaluator( OidRegistry oidRegistry,
72                            AttributeTypeRegistry attributeTypeRegistry,
73                            SubstringEvaluator substringEvaluator ) throws NamingException
74      {
75          this.oidRegistry = oidRegistry;
76          this.attributeTypeRegistry = attributeTypeRegistry;
77          this.scopeEvaluator = new ScopeEvaluator();
78          this.substringEvaluator = substringEvaluator;
79      }
80  
81  
82      public ScopeEvaluator getScopeEvaluator()
83      {
84          return scopeEvaluator;
85      }
86  
87  
88      public SubstringEvaluator getSubstringEvaluator()
89      {
90          return substringEvaluator;
91      }
92  
93  
94      /***
95       * @see Evaluator#evaluate(ExprNode, String, Attributes)
96       */
97      public boolean evaluate( ExprNode node, String dn, Attributes entry ) throws NamingException
98      {
99          if ( node instanceof ScopeNode )
100         {
101             return scopeEvaluator.evaluate( node, dn, entry );
102         }
103         
104         switch( ( ( LeafNode ) node ).getAssertionType() ) 
105         {
106         case( LeafNode.APPROXIMATE ):
107             return evalEquality( ( SimpleNode ) node, entry );
108         case( LeafNode.EQUALITY ):
109             return evalEquality( ( SimpleNode ) node, entry );
110         case( LeafNode.EXTENSIBLE ):
111             throw new NotImplementedException();
112         case( LeafNode.GREATEREQ ):
113             return evalGreater( ( SimpleNode ) node, entry, true );
114         case( LeafNode.LESSEQ ):
115             return evalGreater( ( SimpleNode ) node, entry, false );
116         case( LeafNode.PRESENCE ):
117             String attrId = ( ( PresenceNode ) node ).getAttribute();
118             return evalPresence( attrId, entry );
119         case( LeafNode.SUBSTRING ):
120             return substringEvaluator.evaluate( node, dn, entry );
121         default:
122             throw new NamingException( "Unrecognized leaf node type: "
123                 + ( ( LeafNode ) node ).getAssertionType() );
124         }
125     }
126     
127     
128     /***
129      * Evaluates a simple greater than or less than attribute value assertion on
130      * a perspective candidate.
131      * 
132      * @param node the greater than or less than node to evaluate
133      * @param entry the perspective candidate
134      * @param isGreater true if it is a greater than or equal to comparison,
135      *      false if it is a less than or equal to comparison.
136      * @return the ava evaluation on the perspective candidate
137      * @throws javax.naming.NamingException if there is a database access failure
138      */
139     private boolean evalGreater( SimpleNode node, Attributes entry,
140         boolean isGreater ) throws NamingException
141     {
142         String attrId = node.getAttribute();
143 
144         // get the attribute associated with the node
145         Attribute attr = entry.get( attrId );
146 
147         // If we do not have the attribute just return false
148         if ( null == attr )
149         {
150             return false;
151         }
152         
153         /*
154          * We need to iterate through all values and for each value we normalize
155          * and use the comparator to determine if a match exists.
156          */
157         Normalizer normalizer = getNormalizer( attrId );
158         Comparator comparator = getComparator( attrId );
159         Object filterValue = normalizer.normalize( node.getValue() );
160         NamingEnumeration list = attr.getAll();
161         
162         /*
163          * Cheaper to not check isGreater in one loop - better to separate
164          * out into two loops which you choose to execute based on isGreater
165          */
166         if ( isGreater )
167         {
168             while ( list.hasMore() )
169             {
170                 Object value = normalizer.normalize( list.next() );
171             
172                 // Found a value that is greater than or equal to the ava value
173                 if ( 0 >= comparator.compare( value, filterValue ) )
174                 {
175                     return true;
176                 }
177             }
178         }
179         else 
180         {    
181             while ( list.hasMore() )
182             {
183                 Object value = normalizer.normalize( list.next() );
184             
185                 // Found a value that is less than or equal to the ava value
186                 if ( 0 <= comparator.compare( value, filterValue ) )
187                 {
188                     return true;
189                 }
190             }
191         }
192         
193         // no match so return false
194         return false;
195     }
196 
197     
198     /***
199      * Evaluates a simple presence attribute value assertion on a perspective
200      * candidate.
201      * 
202      * @param attrId the name of the attribute tested for presence 
203      * @param entry the perspective candidate
204      * @return the ava evaluation on the perspective candidate
205      */
206     private boolean evalPresence( String attrId, Attributes entry )
207     {
208         if ( entry == null )
209         {
210             return false;
211         }
212         
213         return null != entry.get( attrId );
214     }
215 
216 
217     /***
218      * Evaluates a simple equality attribute value assertion on a perspective
219      * candidate.
220      *
221      * @param node the equality node to evaluate
222      * @param entry the perspective candidate
223      * @return the ava evaluation on the perspective candidate
224      * @throws javax.naming.NamingException if there is a database access failure
225      */
226     private boolean evalEquality( SimpleNode node, Attributes entry )
227         throws NamingException
228     {
229         Normalizer normalizer = getNormalizer( node.getAttribute() );
230         Comparator comparator = getComparator( node.getAttribute() );
231 
232         // get the attribute associated with the node
233         Attribute attr = entry.get( node.getAttribute() );
234 
235         // If we do not have the attribute just return false
236         if ( null == attr )
237         {
238             return false;
239         }
240         
241         // check if AVA value exists in attribute
242         if ( attr.contains( node.getValue() ) )
243         {
244             return true;
245         }
246 
247         // get the normalized AVA filter value
248         Object filterValue = normalizer.normalize( node.getValue() );
249 
250         // check if the normalized value is present
251         if ( attr.contains( filterValue ) )
252         {
253             return true;
254         }
255         
256         /*
257          * We need to now iterate through all values because we could not get
258          * a lookup to work.  For each value we normalize and use the comparator
259          * to determine if a match exists.
260          */
261         NamingEnumeration list = attr.getAll();
262         while ( list.hasMore() )
263         {
264             Object value = normalizer.normalize( list.next() );
265             
266             if ( 0 == comparator.compare( value, filterValue ) )
267             {
268                 return true;
269             }
270         }
271         
272         // no match so return false
273         return false;
274     }
275 
276 
277     /***
278      * Gets the comparator for equality matching.
279      *
280      * @param attrId the attribute identifier
281      * @return the comparator for equality matching
282      * @throws javax.naming.NamingException if there is a failure
283      */
284     private Comparator getComparator( String attrId ) throws NamingException
285     {
286         MatchingRule mrule = getMatchingRule( attrId, EQUALITY_MATCH );
287         return mrule.getComparator();
288     }
289 
290 
291     /***
292      * Gets the normalizer for equality matching.
293      *
294      * @param attrId the attribute identifier
295      * @return the normalizer for equality matching
296      * @throws javax.naming.NamingException if there is a failure
297      */
298     private Normalizer getNormalizer( String attrId ) throws NamingException
299     {
300         MatchingRule mrule = getMatchingRule( attrId, EQUALITY_MATCH );
301         return mrule.getNormalizer();
302     }
303 
304 
305     /***
306      * Gets the matching rule for an attributeType.
307      *
308      * @param attrId the attribute identifier
309      * @return the matching rule
310      * @throws javax.naming.NamingException if there is a failure
311      */
312     private MatchingRule getMatchingRule( String attrId, int matchType )
313         throws NamingException
314     {
315         MatchingRule mrule = null;
316         String oid = oidRegistry.getOid( attrId );
317         AttributeType type = attributeTypeRegistry.lookup( oid );
318 
319         switch( matchType )
320         {
321             case( EQUALITY_MATCH ):
322                 mrule = type.getEquality();
323                 break;
324             case( SUBSTRING_MATCH ):
325                 mrule = type.getSubstr();
326                 break;
327             case( ORDERING_MATCH ):
328                 mrule = type.getOrdering();
329                 break;
330             default:
331                 throw new NamingException( "Unknown match type: " + matchType );
332         }
333 
334         return mrule;
335     }
336 }