001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 * 019 */ 020package org.apache.directory.server.core.api.event; 021 022 023import org.apache.directory.api.ldap.model.entry.Attribute; 024import org.apache.directory.api.ldap.model.entry.Entry; 025import org.apache.directory.api.ldap.model.entry.Value; 026import org.apache.directory.api.ldap.model.exception.LdapException; 027import org.apache.directory.api.ldap.model.exception.LdapInvalidSearchFilterException; 028import org.apache.directory.api.ldap.model.filter.ApproximateNode; 029import org.apache.directory.api.ldap.model.filter.EqualityNode; 030import org.apache.directory.api.ldap.model.filter.ExprNode; 031import org.apache.directory.api.ldap.model.filter.ExtensibleNode; 032import org.apache.directory.api.ldap.model.filter.GreaterEqNode; 033import org.apache.directory.api.ldap.model.filter.LessEqNode; 034import org.apache.directory.api.ldap.model.filter.PresenceNode; 035import org.apache.directory.api.ldap.model.filter.ScopeNode; 036import org.apache.directory.api.ldap.model.filter.SimpleNode; 037import org.apache.directory.api.ldap.model.filter.SubstringNode; 038import org.apache.directory.api.ldap.model.name.Dn; 039import org.apache.directory.api.ldap.model.schema.AttributeType; 040import org.apache.directory.api.ldap.model.schema.MatchingRule; 041import org.apache.directory.api.util.exception.NotImplementedException; 042import org.apache.directory.server.i18n.I18n; 043 044 045/** 046 * Evaluates LeafNode assertions on candidates using a database. 047 * 048 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 049 */ 050public class LeafEvaluator implements Evaluator 051{ 052 /** equality matching type constant */ 053 private static final int EQUALITY_MATCH = 0; 054 055 /** ordering matching type constant */ 056 private static final int ORDERING_MATCH = 1; 057 058 /** substring matching type constant */ 059 private static final int SUBSTRING_MATCH = 3; 060 061 /** Substring node evaluator we depend on */ 062 private SubstringEvaluator substringEvaluator; 063 064 /** ScopeNode evaluator we depend on */ 065 private ScopeEvaluator scopeEvaluator; 066 067 /** Constants used for comparisons */ 068 private static final boolean COMPARE_GREATER = true; 069 private static final boolean COMPARE_LESSER = false; 070 071 072 /** 073 * Creates a leaf expression node evaluator. 074 * 075 * @param substringEvaluator The evaluator to use 076 */ 077 public LeafEvaluator( SubstringEvaluator substringEvaluator ) 078 { 079 this.scopeEvaluator = new ScopeEvaluator(); 080 this.substringEvaluator = substringEvaluator; 081 } 082 083 084 public ScopeEvaluator getScopeEvaluator() 085 { 086 return scopeEvaluator; 087 } 088 089 090 public SubstringEvaluator getSubstringEvaluator() 091 { 092 return substringEvaluator; 093 } 094 095 096 /** 097 * {@inheritDoc} 098 */ 099 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}