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 }