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.Iterator; 024 025 import org.apache.directory.server.i18n.I18n; 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.ApproximateNode; 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 040 041 /** 042 * An Evaluator which determines if candidates are matched by ApproximateNode 043 * assertions. Same as equality for now. 044 * 045 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 046 * @version $Rev$ 047 */ 048 public class ApproximateEvaluator<T, ID> implements Evaluator<ApproximateNode<T>, ServerEntry, ID> 049 { 050 private final ApproximateNode<T> node; 051 private final Store<ServerEntry, ID> db; 052 private final SchemaManager schemaManager; 053 private final AttributeType type; 054 private final Normalizer normalizer; 055 private final LdapComparator<? super Object> ldapComparator; 056 private final Index<T, ServerEntry, ID> idx; 057 058 059 @SuppressWarnings("unchecked") 060 public ApproximateEvaluator( ApproximateNode<T> node, Store<ServerEntry, ID> db, SchemaManager schemaManager ) 061 throws Exception 062 { 063 this.db = db; 064 this.node = node; 065 this.schemaManager = schemaManager; 066 067 if ( db.hasIndexOn( node.getAttribute() ) ) 068 { 069 idx = ( Index<T, ServerEntry, ID> ) db.getIndex( node.getAttribute() ); 070 type = null; 071 normalizer = null; 072 ldapComparator = null; 073 } 074 else 075 { 076 idx = null; 077 type = schemaManager.lookupAttributeTypeRegistry( node.getAttribute() ); 078 079 MatchingRule mr = type.getEquality(); 080 081 if ( mr == null ) 082 { 083 throw new IllegalStateException( I18n.err( I18n.ERR_709, node ) ); 084 } 085 086 normalizer = mr.getNormalizer(); 087 ldapComparator = mr.getLdapComparator(); 088 } 089 } 090 091 092 public ApproximateNode<T> getExpression() 093 { 094 return node; 095 } 096 097 098 public boolean evaluateEntry( ServerEntry entry ) throws Exception 099 { 100 // get the attribute 101 EntryAttribute attr = entry.get( type ); 102 103 // if the attribute does not exist just return false 104 if ( ( attr != null ) && evaluate( attr ) ) 105 { 106 return true; 107 } 108 109 // If we do not have the attribute, loop through the sub classes of 110 // the attributeType. Perhaps the entry has an attribute value of a 111 // subtype (descendant) that will produce a match 112 if ( schemaManager.getAttributeTypeRegistry().hasDescendants( node.getAttribute() ) ) 113 { 114 // TODO check to see if descendant handling is necessary for the 115 // index so we can match properly even when for example a name 116 // attribute is used instead of more specific commonName 117 Iterator<AttributeType> descendants = schemaManager.getAttributeTypeRegistry().descendants( 118 node.getAttribute() ); 119 120 while ( descendants.hasNext() ) 121 { 122 AttributeType descendant = descendants.next(); 123 124 attr = entry.get( descendant ); 125 126 if ( attr != null && evaluate( attr ) ) 127 { 128 return true; 129 } 130 } 131 } 132 133 // we fell through so a match was not found - assertion was false. 134 return false; 135 } 136 137 138 public boolean evaluateId( ID id ) throws Exception 139 { 140 if ( idx != null ) 141 { 142 return idx.reverse( id ); 143 } 144 145 return evaluateEntry( db.lookup( id ) ); 146 } 147 148 149 public boolean evaluate( IndexEntry<?, ServerEntry, ID> indexEntry ) throws Exception 150 { 151 if ( idx != null ) 152 { 153 return idx.forward( node.getValue().get(), indexEntry.getId() ); 154 } 155 156 ServerEntry entry = indexEntry.getObject(); 157 158 // resuscitate the entry if it has not been and set entry in IndexEntry 159 if ( null == entry ) 160 { 161 entry = db.lookup( indexEntry.getId() ); 162 indexEntry.setObject( entry ); 163 } 164 165 return evaluateEntry( entry ); 166 } 167 168 169 // TODO - determine if comaparator and index entry should have the Value 170 // wrapper or the raw normalized value 171 private boolean evaluate( EntryAttribute attribute ) throws Exception 172 { 173 /* 174 * Cycle through the attribute values testing normalized version 175 * obtained from using the ordering or equality matching rule's 176 * normalizer. The test uses the comparator obtained from the 177 * appropriate matching rule to perform the check. 178 */ 179 180 for ( Value value : attribute ) 181 { 182 value.normalize( normalizer ); 183 184 //noinspection unchecked 185 if ( ldapComparator.compare( value.getNormalizedValue(), node.getValue().getNormalizedValue() ) == 0 ) 186 { 187 return true; 188 } 189 } 190 191 return false; 192 } 193 }