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 org.apache.directory.api.ldap.model.entry.Attribute;
24  import org.apache.directory.api.ldap.model.entry.Entry;
25  import org.apache.directory.api.ldap.model.entry.Value;
26  import org.apache.directory.api.ldap.model.exception.LdapException;
27  import org.apache.directory.api.ldap.model.exception.LdapInvalidSearchFilterException;
28  import org.apache.directory.api.ldap.model.filter.ApproximateNode;
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.GreaterEqNode;
33  import org.apache.directory.api.ldap.model.filter.LessEqNode;
34  import org.apache.directory.api.ldap.model.filter.PresenceNode;
35  import org.apache.directory.api.ldap.model.filter.ScopeNode;
36  import org.apache.directory.api.ldap.model.filter.SimpleNode;
37  import org.apache.directory.api.ldap.model.filter.SubstringNode;
38  import org.apache.directory.api.ldap.model.name.Dn;
39  import org.apache.directory.api.ldap.model.schema.AttributeType;
40  import org.apache.directory.api.ldap.model.schema.MatchingRule;
41  import org.apache.directory.api.util.exception.NotImplementedException;
42  import org.apache.directory.server.i18n.I18n;
43  
44  
45  /**
46   * Evaluates LeafNode assertions on candidates using a database.
47   * 
48   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
49   */
50  public class LeafEvaluator implements Evaluator
51  {
52      /** equality matching type constant */
53      private static final int EQUALITY_MATCH = 0;
54  
55      /** ordering matching type constant */
56      private static final int ORDERING_MATCH = 1;
57  
58      /** substring matching type constant */
59      private static final int SUBSTRING_MATCH = 3;
60  
61      /** Substring node evaluator we depend on */
62      private SubstringEvaluator substringEvaluator;
63  
64      /** ScopeNode evaluator we depend on */
65      private ScopeEvaluator scopeEvaluator;
66  
67      /** Constants used for comparisons */
68      private static final boolean COMPARE_GREATER = true;
69      private static final boolean COMPARE_LESSER = false;
70  
71  
72      /**
73       * Creates a leaf expression node evaluator.
74       *
75       * @param substringEvaluator The evaluator to use
76       */
77      public LeafEvaluator( SubstringEvaluator substringEvaluator )
78      {
79          this.scopeEvaluator = new ScopeEvaluator();
80          this.substringEvaluator = substringEvaluator;
81      }
82  
83  
84      public ScopeEvaluator getScopeEvaluator()
85      {
86          return scopeEvaluator;
87      }
88  
89  
90      public SubstringEvaluator getSubstringEvaluator()
91      {
92          return substringEvaluator;
93      }
94  
95  
96      /**
97       * {@inheritDoc}
98       */
99      public boolean evaluate( ExprNode node, Dn dn, Entry entry ) throws LdapException
100     {
101         if ( node instanceof ScopeNode )
102         {
103             return scopeEvaluator.evaluate( node, dn, entry );
104         }
105 
106         if ( node instanceof PresenceNode )
107         {
108             return evalPresence( ( ( PresenceNode ) node ).getAttributeType(), entry );
109         }
110         else if ( ( node instanceof EqualityNode ) || ( node instanceof ApproximateNode ) )
111         {
112             return evalEquality( ( EqualityNode<?> ) node, entry );
113         }
114         else if ( node instanceof GreaterEqNode )
115         {
116             return evalGreaterOrLesser( ( GreaterEqNode<?> ) node, entry, COMPARE_GREATER );
117         }
118         else if ( node instanceof LessEqNode )
119         {
120             return evalGreaterOrLesser( ( LessEqNode<?> ) node, entry, COMPARE_LESSER );
121         }
122         else if ( node instanceof SubstringNode )
123         {
124             return substringEvaluator.evaluate( node, dn, entry );
125         }
126         else if ( node instanceof ExtensibleNode )
127         {
128             throw new NotImplementedException();
129         }
130         else
131         {
132             throw new LdapInvalidSearchFilterException( I18n.err( I18n.ERR_245, node ) );
133         }
134     }
135 
136 
137     /**
138      * Evaluates a simple greater than or less than attribute value assertion on
139      * a perspective candidate.
140      * 
141      * @param node the greater than or less than node to evaluate
142      * @param entry the perspective candidate
143      * @param isGreater true if it is a greater than or equal to comparison,
144      *      false if it is a less than or equal to comparison.
145      * @return the ava evaluation on the perspective candidate
146      * @throws LdapException if there is a database access failure
147      */
148     private boolean evalGreaterOrLesser( SimpleNode<?> node, Entry entry, boolean isGreaterOrLesser )
149         throws LdapException
150     {
151         // get the attribute associated with the node
152         Attribute attr = entry.get( node.getAttribute() );
153 
154         // If we do not have the attribute just return false
155         if ( null == attr )
156         {
157             return false;
158         }
159 
160         /*
161          * We need to iterate through all values and for each value we normalize
162          * and use the comparator to determine if a match exists.
163          */
164         Value filterValue = node.getValue();
165 
166         /*
167          * Cheaper to not check isGreater in one loop - better to separate
168          * out into two loops which you choose to execute based on isGreater
169          */
170         if ( isGreaterOrLesser == COMPARE_GREATER )
171         {
172             for ( Value value : attr )
173             {
174                 // Found a value that is greater than or equal to the ava value
175                 if ( value.compareTo( filterValue ) >= 0 )
176                 {
177                     return true;
178                 }
179             }
180         }
181         else
182         {
183             for ( Value value : attr )
184             {
185                 // Found a value that is less than or equal to the ava value
186                 if ( value.compareTo( filterValue ) <= 0 )
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( AttributeType attributeType, Entry entry )
207     {
208         if ( entry == null )
209         {
210             return false;
211         }
212 
213         return null != entry.get( attributeType );
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 org.apache.directory.api.ldap.model.exception.LdapException if there is a database access failure
225      */
226     private boolean evalEquality( EqualityNode<?> node, Entry entry ) throws LdapException
227     {
228         // get the attribute associated with the node
229         Attribute attr = entry.get( node.getAttribute() );
230 
231         // If we do not have the attribute just return false
232         if ( null == attr )
233         {
234             return false;
235         }
236 
237         // check if Ava value exists in attribute
238         Value value = node.getValue();
239 
240         // check if the normalized value is present
241         if ( attr.contains( value ) )
242         {
243             return true;
244         }
245 
246         /*
247          * We need to now iterate through all values because we could not get
248          * a lookup to work.  For each value we normalize and use the comparator
249          * to determine if a match exists.
250          */
251         for ( Value val : attr )
252         {
253             if ( 0 == val.compareTo( value ) )
254             {
255                 return true;
256             }
257         }
258 
259         // no match so return false
260         return false;
261     }
262 
263 
264     /**
265      * Gets the matching rule for an attributeType.
266      *
267      * @param attributeType the attributeType
268      * @return the matching rule
269      * @throws LdapException if there is a failure
270      */
271     private MatchingRule getMatchingRule( AttributeType attributeType, int matchType ) throws LdapException
272     {
273         MatchingRule mrule = null;
274 
275         switch ( matchType )
276         {
277             case ( EQUALITY_MATCH ):
278                 mrule = attributeType.getEquality();
279                 break;
280 
281             case ( SUBSTRING_MATCH ):
282                 mrule = attributeType.getSubstring();
283                 break;
284 
285             case ( ORDERING_MATCH ):
286                 mrule = attributeType.getOrdering();
287                 break;
288 
289             default:
290                 throw new LdapException( I18n.err( I18n.ERR_246, matchType ) );
291         }
292 
293         if ( ( mrule == null ) && ( matchType != EQUALITY_MATCH ) )
294         {
295             mrule = attributeType.getEquality();
296         }
297 
298         return mrule;
299     }
300 }