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 */ 020 package org.apache.directory.server.xdbm.search.impl; 021 022 023 import java.util.Comparator; 024 import java.util.Iterator; 025 026 import org.apache.directory.server.xdbm.Index; 027 import org.apache.directory.server.xdbm.IndexEntry; 028 import org.apache.directory.server.xdbm.Store; 029 import org.apache.directory.server.xdbm.search.Evaluator; 030 import org.apache.directory.shared.ldap.entry.EntryAttribute; 031 import org.apache.directory.shared.ldap.entry.ServerEntry; 032 import org.apache.directory.shared.ldap.entry.Value; 033 import org.apache.directory.shared.ldap.filter.EqualityNode; 034 import org.apache.directory.shared.ldap.schema.AttributeType; 035 import org.apache.directory.shared.ldap.schema.LdapComparator; 036 import org.apache.directory.shared.ldap.schema.MatchingRule; 037 import org.apache.directory.shared.ldap.schema.Normalizer; 038 import org.apache.directory.shared.ldap.schema.SchemaManager; 039 import org.apache.directory.shared.ldap.schema.comparators.ByteArrayComparator; 040 import org.apache.directory.shared.ldap.schema.comparators.StringComparator; 041 import org.apache.directory.shared.ldap.schema.normalizers.NoOpNormalizer; 042 import org.apache.directory.shared.ldap.util.StringTools; 043 044 045 /** 046 * An Evaluator which determines if candidates are matched by GreaterEqNode 047 * assertions. 048 * 049 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 050 * @version $Rev$ 051 */ 052 public class EqualityEvaluator<T, ID> implements Evaluator<EqualityNode<T>, ServerEntry, ID> 053 { 054 private final EqualityNode<T> node; 055 private final Store<ServerEntry, ID> db; 056 private final SchemaManager schemaManager; 057 private final AttributeType type; 058 private final Normalizer normalizer; 059 060 /** The comparator to use */ 061 private final LdapComparator<?> comparator; 062 063 /** The default byte[] comparator if no comparator has been defined */ 064 private static final Comparator<byte[]> BINARY_COMPARATOR = new ByteArrayComparator( null ); 065 066 /** The default String comparator if no comparator has been defined */ 067 private static final Comparator<String> STRING_COMPARATOR = new StringComparator( null ); 068 069 private final Index<T, ServerEntry, ID> idx; 070 071 072 @SuppressWarnings("unchecked") 073 public EqualityEvaluator( EqualityNode<T> node, Store<ServerEntry, ID> db, SchemaManager schemaManager ) 074 throws Exception 075 { 076 this.db = db; 077 this.node = node; 078 this.schemaManager = schemaManager; 079 080 if ( db.hasIndexOn( node.getAttribute() ) ) 081 { 082 idx = ( Index<T, ServerEntry, ID> ) db.getIndex( node.getAttribute() ); 083 type = null; 084 normalizer = null; 085 comparator = null; 086 } 087 else 088 { 089 idx = null; 090 type = schemaManager.lookupAttributeTypeRegistry( node.getAttribute() ); 091 092 MatchingRule mr = type.getEquality(); 093 094 if ( mr == null ) 095 { 096 normalizer = new NoOpNormalizer( type.getOid() ); 097 comparator = null; 098 } 099 else 100 { 101 normalizer = mr.getNormalizer(); 102 comparator = mr.getLdapComparator(); 103 } 104 } 105 } 106 107 108 public EqualityNode<T> getExpression() 109 { 110 return node; 111 } 112 113 114 public boolean evaluate( IndexEntry<?, ServerEntry, ID> indexEntry ) throws Exception 115 { 116 if ( idx != null ) 117 { 118 return idx.forward( node.getValue().get(), indexEntry.getId() ); 119 } 120 121 ServerEntry entry = indexEntry.getObject(); 122 123 // resuscitate the entry if it has not been and set entry in IndexEntry 124 if ( null == entry ) 125 { 126 entry = db.lookup( indexEntry.getId() ); 127 indexEntry.setObject( entry ); 128 } 129 130 return evaluateEntry( entry ); 131 } 132 133 134 public boolean evaluateEntry( ServerEntry entry ) throws Exception 135 { 136 // get the attribute 137 EntryAttribute attr = entry.get( type ); 138 139 // if the attribute does not exist just return false 140 if ( attr != null && evaluate( attr ) ) 141 { 142 return true; 143 } 144 145 // If we do not have the attribute, loop through the sub classes of 146 // the attributeType. Perhaps the entry has an attribute value of a 147 // subtype (descendant) that will produce a match 148 if ( schemaManager.getAttributeTypeRegistry().hasDescendants( node.getAttribute() ) ) 149 { 150 // TODO check to see if descendant handling is necessary for the 151 // index so we can match properly even when for example a name 152 // attribute is used instead of more specific commonName 153 Iterator<AttributeType> descendants = schemaManager.getAttributeTypeRegistry().descendants( 154 node.getAttribute() ); 155 156 while ( descendants.hasNext() ) 157 { 158 AttributeType descendant = descendants.next(); 159 160 attr = entry.get( descendant ); 161 162 if ( attr != null && evaluate( attr ) ) 163 { 164 return true; 165 } 166 } 167 } 168 169 // we fell through so a match was not found - assertion was false. 170 return false; 171 } 172 173 174 public boolean evaluateId( ID id ) throws Exception 175 { 176 if ( idx != null ) 177 { 178 return idx.reverse( id ); 179 } 180 181 return evaluateEntry( db.lookup( id ) ); 182 } 183 184 185 // TODO - determine if comparator and index entry should have the Value 186 // wrapper or the raw normalized value 187 private boolean evaluate( EntryAttribute attribute ) throws Exception 188 { 189 /* 190 * Cycle through the attribute values testing normalized version 191 * obtained from using the ordering or equality matching rule's 192 * normalizer. The test uses the comparator obtained from the 193 * appropriate matching rule to perform the check. 194 */ 195 for ( Value<?> value : attribute ) 196 { 197 value.normalize( normalizer ); 198 199 //noinspection unchecked 200 if ( value.isBinary() ) 201 { 202 // Deal with a binary value 203 byte[] serverValue = ( ( Value<byte[]> ) value ).getNormalizedValue(); 204 byte[] nodeValue = ( ( Value<byte[]> ) node.getValue() ).getNormalizedValue(); 205 206 if ( comparator != null ) 207 { 208 if ( ( ( ( LdapComparator<byte[]> ) comparator ).compare( serverValue, nodeValue ) == 0 ) ) 209 { 210 return true; 211 } 212 } 213 else 214 { 215 if ( BINARY_COMPARATOR.compare( serverValue, nodeValue ) == 0 ) 216 { 217 return true; 218 } 219 } 220 } 221 else 222 { 223 // Deal with a String value 224 String serverValue = ( ( Value<String> ) value ).getNormalizedValue(); 225 String nodeValue = null; 226 227 if ( node.getValue().isBinary() ) 228 { 229 nodeValue = StringTools.utf8ToString( ( ( Value<byte[]> ) node.getValue() ).getNormalizedValue() ); 230 } 231 else 232 { 233 nodeValue = ( ( Value<String> ) node.getValue() ).getNormalizedValue(); 234 } 235 236 if ( comparator != null ) 237 { 238 if ( ( ( LdapComparator<String> ) comparator ).compare( serverValue, nodeValue ) == 0 ) 239 { 240 return true; 241 } 242 } 243 else 244 { 245 if ( STRING_COMPARATOR.compare( serverValue, nodeValue ) == 0 ) 246 { 247 return true; 248 } 249 } 250 } 251 } 252 253 return false; 254 } 255 }