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.event;
21  
22  
23  import java.util.Comparator;
24  
25  import javax.naming.NamingException;
26  
27  import org.apache.directory.server.core.entry.ServerEntry;
28  import org.apache.directory.server.schema.registries.AttributeTypeRegistry;
29  import org.apache.directory.server.schema.registries.OidRegistry;
30  import org.apache.directory.shared.ldap.NotImplementedException;
31  import org.apache.directory.shared.ldap.entry.EntryAttribute;
32  import org.apache.directory.shared.ldap.entry.Value;
33  import org.apache.directory.shared.ldap.filter.ApproximateNode;
34  import org.apache.directory.shared.ldap.filter.EqualityNode;
35  import org.apache.directory.shared.ldap.filter.ExprNode;
36  import org.apache.directory.shared.ldap.filter.ExtensibleNode;
37  import org.apache.directory.shared.ldap.filter.GreaterEqNode;
38  import org.apache.directory.shared.ldap.filter.LessEqNode;
39  import org.apache.directory.shared.ldap.filter.PresenceNode;
40  import org.apache.directory.shared.ldap.filter.ScopeNode;
41  import org.apache.directory.shared.ldap.filter.SimpleNode;
42  import org.apache.directory.shared.ldap.filter.SubstringNode;
43  import org.apache.directory.shared.ldap.schema.AttributeType;
44  import org.apache.directory.shared.ldap.schema.MatchingRule;
45  import org.apache.directory.shared.ldap.schema.Normalizer;
46  
47  
48  /**
49   * Evaluates LeafNode assertions on candidates using a database.
50   * 
51   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
52   * @version $Rev: 666516 $
53   */
54  public class LeafEvaluator implements Evaluator
55  {
56      /** equality matching type constant */
57      private static final int EQUALITY_MATCH = 0;
58      /** ordering matching type constant */
59      private static final int ORDERING_MATCH = 1;
60      /** substring matching type constant */
61      private static final int SUBSTRING_MATCH = 3;
62  
63      /** Oid Registry used to translate attributeIds to OIDs */
64      private OidRegistry oidRegistry;
65      /** AttributeType registry needed for normalizing and comparing values */
66      private AttributeTypeRegistry attributeTypeRegistry;
67      /** Substring node evaluator we depend on */
68      private SubstringEvaluator substringEvaluator;
69      /** ScopeNode evaluator we depend on */
70      private ScopeEvaluator scopeEvaluator;
71  
72      /** Constants used for comparisons */
73      private static final boolean COMPARE_GREATER = true;
74      private static final boolean COMPARE_LESSER = false;
75  
76  
77      /**
78       * Creates a leaf expression node evaluator.
79       *
80       * @param substringEvaluator
81       */
82      public LeafEvaluator( OidRegistry oidRegistry, AttributeTypeRegistry attributeTypeRegistry,
83          SubstringEvaluator substringEvaluator )
84      {
85          this.oidRegistry = oidRegistry;
86          this.attributeTypeRegistry = attributeTypeRegistry;
87          this.scopeEvaluator = new ScopeEvaluator();
88          this.substringEvaluator = substringEvaluator;
89      }
90  
91  
92      public ScopeEvaluator getScopeEvaluator()
93      {
94          return scopeEvaluator;
95      }
96  
97  
98      public SubstringEvaluator getSubstringEvaluator()
99      {
100         return substringEvaluator;
101     }
102 
103 
104     /**
105      * @see Evaluator#evaluate(ExprNode, String, ServerEntry)
106      */
107     public boolean evaluate( ExprNode node, String dn, ServerEntry entry ) throws NamingException
108     {
109         if ( node instanceof ScopeNode )
110         {
111             return scopeEvaluator.evaluate( node, dn, entry );
112         }
113 
114         if ( node instanceof PresenceNode )
115         {
116             String attrId = ( ( PresenceNode ) node ).getAttribute();
117             return evalPresence( attrId, entry );
118         }
119         else if ( ( node instanceof EqualityNode ) || ( node instanceof ApproximateNode ) )
120         {
121             return evalEquality( ( EqualityNode<?> ) node, entry );
122         }
123         else if ( node instanceof GreaterEqNode )
124         {
125             return evalGreaterOrLesser( ( GreaterEqNode<?> ) node, entry, COMPARE_GREATER );
126         }
127         else if ( node instanceof LessEqNode )
128         {
129             return evalGreaterOrLesser( ( LessEqNode<?> ) node, entry, COMPARE_LESSER );
130         }
131         else if ( node instanceof SubstringNode )
132         {
133             return substringEvaluator.evaluate( node, dn, entry );
134         }
135         else if ( node instanceof ExtensibleNode )
136         {
137             throw new NotImplementedException();
138         }
139         else
140         {
141             throw new NamingException( "Unrecognized leaf node type: " + node );
142         }
143     }
144 
145 
146     /**
147      * Evaluates a simple greater than or less than attribute value assertion on
148      * a perspective candidate.
149      * 
150      * @param node the greater than or less than node to evaluate
151      * @param entry the perspective candidate
152      * @param isGreater true if it is a greater than or equal to comparison,
153      *      false if it is a less than or equal to comparison.
154      * @return the ava evaluation on the perspective candidate
155      * @throws javax.naming.NamingException if there is a database access failure
156      */
157     @SuppressWarnings("unchecked")
158     private boolean evalGreaterOrLesser( SimpleNode<?> node, ServerEntry entry, boolean isGreaterOrLesser )
159         throws NamingException
160     {
161         String attrId = node.getAttribute();
162 
163         // get the attribute associated with the node
164         AttributeType type = attributeTypeRegistry.lookup( oidRegistry.getOid( attrId ) );
165         EntryAttribute attr = entry.get( type );
166 
167         // If we do not have the attribute just return false
168         if ( null == attr )
169         {
170             return false;
171         }
172 
173         /*
174          * We need to iterate through all values and for each value we normalize
175          * and use the comparator to determine if a match exists.
176          */
177         Normalizer normalizer = getNormalizer( attrId );
178         Comparator comparator = getComparator( attrId );
179         Object filterValue = normalizer.normalize( node.getValue() );
180 
181         /*
182          * Cheaper to not check isGreater in one loop - better to separate
183          * out into two loops which you choose to execute based on isGreater
184          */
185         if ( isGreaterOrLesser == COMPARE_GREATER )
186         {
187             for ( Value<?> value : attr )
188             {
189                 Object normValue = normalizer.normalize( value );
190 
191                 // Found a value that is greater than or equal to the ava value
192                 if ( 0 >= comparator.compare( normValue, filterValue ) )
193                 {
194                     return true;
195                 }
196             }
197         }
198         else
199         {
200             for ( Value<?> value : attr )
201             {
202                 Object normValue = normalizer.normalize( value );
203 
204                 // Found a value that is less than or equal to the ava value
205                 if ( 0 <= comparator.compare( normValue, filterValue ) )
206                 {
207                     return true;
208                 }
209             }
210         }
211 
212         // no match so return false
213         return false;
214     }
215 
216 
217     /**
218      * Evaluates a simple presence attribute value assertion on a perspective
219      * candidate.
220      * 
221      * @param attrId the name of the attribute tested for presence 
222      * @param entry the perspective candidate
223      * @return the ava evaluation on the perspective candidate
224      */
225     private boolean evalPresence( String attrId, ServerEntry entry ) throws NamingException
226     {
227         if ( entry == null )
228         {
229             return false;
230         }
231 
232         return null != entry.get( attrId );
233     }
234 
235 
236     /**
237      * Evaluates a simple equality attribute value assertion on a perspective
238      * candidate.
239      *
240      * @param node the equality node to evaluate
241      * @param entry the perspective candidate
242      * @return the ava evaluation on the perspective candidate
243      * @throws javax.naming.NamingException if there is a database access failure
244      */
245     @SuppressWarnings("unchecked")
246     private boolean evalEquality( EqualityNode<?> node, ServerEntry entry ) throws NamingException
247     {
248         Normalizer normalizer = getNormalizer( node.getAttribute() );
249         Comparator comparator = getComparator( node.getAttribute() );
250 
251         // get the attribute associated with the node
252         EntryAttribute attr = entry.get( node.getAttribute() );
253 
254         // If we do not have the attribute just return false
255         if ( null == attr )
256         {
257             return false;
258         }
259 
260         // check if AVA value exists in attribute
261         if ( attr.contains( node.getValue() ) )
262         {
263             return true;
264         }
265 
266         // get the normalized AVA filter value
267         Object filterValue = normalizer.normalize( node.getValue().get() );
268 
269         // check if the normalized value is present
270         if ( filterValue instanceof String )
271         {
272             if ( attr.contains( ( String ) filterValue ) )
273             {
274                 return true;
275             }
276         }
277         else if ( attr.contains( ( byte[] ) filterValue ) )
278         {
279             return true;
280         }
281 
282         /*
283          * We need to now iterate through all values because we could not get
284          * a lookup to work.  For each value we normalize and use the comparator
285          * to determine if a match exists.
286          */
287         for ( Value<?> value : attr )
288         {
289             Object normValue = normalizer.normalize( value.get() );
290 
291             if ( 0 == comparator.compare( normValue, filterValue ) )
292             {
293                 return true;
294             }
295         }
296 
297         // no match so return false
298         return false;
299     }
300 
301 
302     /**
303      * Gets the comparator for equality matching.
304      *
305      * @param attrId the attribute identifier
306      * @return the comparator for equality matching
307      * @throws javax.naming.NamingException if there is a failure
308      */
309     private Comparator<?> getComparator( String attrId ) throws NamingException
310     {
311         MatchingRule mrule = getMatchingRule( attrId, EQUALITY_MATCH );
312         return mrule.getComparator();
313     }
314 
315 
316     /**
317      * Gets the normalizer for equality matching.
318      *
319      * @param attrId the attribute identifier
320      * @return the normalizer for equality matching
321      * @throws javax.naming.NamingException if there is a failure
322      */
323     private Normalizer getNormalizer( String attrId ) throws NamingException
324     {
325         MatchingRule mrule = getMatchingRule( attrId, EQUALITY_MATCH );
326         return mrule.getNormalizer();
327     }
328 
329 
330     /**
331      * Gets the matching rule for an attributeType.
332      *
333      * @param attrId the attribute identifier
334      * @return the matching rule
335      * @throws javax.naming.NamingException if there is a failure
336      */
337     private MatchingRule getMatchingRule( String attrId, int matchType ) throws NamingException
338     {
339         MatchingRule mrule = null;
340         String oid = oidRegistry.getOid( attrId );
341         AttributeType type = attributeTypeRegistry.lookup( oid );
342 
343         switch ( matchType )
344         {
345             case ( EQUALITY_MATCH ):
346                 mrule = type.getEquality();
347                 break;
348 
349             case ( SUBSTRING_MATCH ):
350                 mrule = type.getSubstr();
351                 break;
352 
353             case ( ORDERING_MATCH ):
354                 mrule = type.getOrdering();
355                 break;
356 
357             default:
358                 throw new NamingException( "Unknown match type: " + matchType );
359         }
360 
361         if ( ( mrule == null ) && ( matchType != EQUALITY_MATCH ) )
362         {
363             mrule = type.getEquality();
364         }
365 
366         return mrule;
367     }
368 }