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