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.xdbm.search.evaluator; 021 022 023import java.util.Iterator; 024 025import org.apache.directory.api.ldap.model.entry.Attribute; 026import org.apache.directory.api.ldap.model.entry.Entry; 027import org.apache.directory.api.ldap.model.entry.Value; 028import org.apache.directory.api.ldap.model.exception.LdapException; 029import org.apache.directory.api.ldap.model.exception.LdapOtherException; 030import org.apache.directory.api.ldap.model.filter.ApproximateNode; 031import org.apache.directory.api.ldap.model.schema.AttributeType; 032import org.apache.directory.api.ldap.model.schema.MatchingRule; 033import org.apache.directory.api.ldap.model.schema.SchemaManager; 034import org.apache.directory.server.core.api.partition.PartitionTxn; 035import org.apache.directory.server.i18n.I18n; 036import org.apache.directory.server.xdbm.Index; 037import org.apache.directory.server.xdbm.IndexEntry; 038import org.apache.directory.server.xdbm.IndexNotFoundException; 039import org.apache.directory.server.xdbm.Store; 040 041 042/** 043 * An Evaluator which determines if candidates are matched by ApproximateNode 044 * assertions. Same as equality for now. 045 * 046 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 047 */ 048public class ApproximateEvaluator<T> extends LeafEvaluator<T> 049{ 050 /** 051 * Creates a new ApproximateEvaluator 052 * 053 * @param node The ApproximateNode 054 * @param db The Store 055 * @param schemaManager The SchemaManager 056 * @throws LdapException If the creation failed 057 */ 058 public ApproximateEvaluator( ApproximateNode<T> node, Store db, SchemaManager schemaManager ) 059 throws LdapException 060 { 061 super( node, db, schemaManager ); 062 063 if ( db.hasIndexOn( attributeType ) ) 064 { 065 try 066 { 067 idx = ( Index<T, String> ) db.getIndex( attributeType ); 068 } 069 catch ( IndexNotFoundException infe ) 070 { 071 throw new LdapOtherException( infe.getMessage(), infe ); 072 } 073 normalizer = null; 074 ldapComparator = null; 075 } 076 else 077 { 078 idx = null; 079 080 MatchingRule mr = attributeType.getEquality(); 081 082 if ( mr == null ) 083 { 084 throw new IllegalStateException( I18n.err( I18n.ERR_709, node ) ); 085 } 086 087 normalizer = mr.getNormalizer(); 088 ldapComparator = mr.getLdapComparator(); 089 } 090 } 091 092 093 /** 094 * {@inheritDoc} 095 */ 096 @Override 097 public ApproximateNode<T> getExpression() 098 { 099 return ( ApproximateNode<T> ) node; 100 } 101 102 103 /** 104 * {@inheritDoc} 105 */ 106 @Override 107 public boolean evaluate( Entry entry ) throws LdapException 108 { 109 // get the attribute 110 Attribute attr = entry.get( attributeType ); 111 112 // if the attribute does not exist just return false 113 if ( ( attr != null ) && evaluate( attr ) ) 114 { 115 return true; 116 } 117 118 // If we do not have the attribute, loop through the sub classes of 119 // the attributeType. Perhaps the entry has an attribute value of a 120 // subtype (descendant) that will produce a match 121 if ( schemaManager.getAttributeTypeRegistry().hasDescendants( attributeType ) ) 122 { 123 // TODO check to see if descendant handling is necessary for the 124 // index so we can match properly even when for example a name 125 // attribute is used instead of more specific commonName 126 Iterator<AttributeType> descendants = schemaManager.getAttributeTypeRegistry().descendants( attributeType ); 127 128 while ( descendants.hasNext() ) 129 { 130 AttributeType descendant = descendants.next(); 131 132 attr = entry.get( descendant ); 133 134 if ( attr != null && evaluate( attr ) ) 135 { 136 return true; 137 } 138 } 139 } 140 141 // we fell through so a match was not found - assertion was false. 142 return false; 143 } 144 145 146 /** 147 * {@inheritDoc} 148 */ 149 @Override 150 public boolean evaluate( PartitionTxn partitionTxn, IndexEntry<?, String> indexEntry ) throws LdapException 151 { 152 Entry entry = indexEntry.getEntry(); 153 154 // resuscitate the entry if it has not been and set entry in IndexEntry 155 if ( null == entry ) 156 { 157 entry = db.fetch( partitionTxn, indexEntry.getId() ); 158 159 if ( null == entry ) 160 { 161 // The entry is not anymore present : get out 162 return false; 163 } 164 165 indexEntry.setEntry( entry ); 166 } 167 168 return evaluate( entry ); 169 } 170 171 172 // TODO - determine if comparator and index entry should have the Value 173 // wrapper or the raw normalized value 174 private boolean evaluate( Attribute attribute ) 175 { 176 /* 177 * Cycle through the attribute values testing normalized version 178 * obtained from using the ordering or equality matching rule's 179 * normalizer. The test uses the comparator obtained from the 180 * appropriate matching rule to perform the check. 181 */ 182 183 for ( Value value : attribute ) 184 { 185 if ( value.compareTo( node.getValue() ) == 0 ) 186 { 187 return true; 188 } 189 } 190 191 return false; 192 } 193 194 195 /** 196 * @see Object#toString() 197 */ 198 @Override 199 public String toString( String tabs ) 200 { 201 StringBuilder sb = new StringBuilder(); 202 203 sb.append( tabs ).append( "ApproximateEvaluator : " ).append( super.toString() ).append( "\n" ); 204 205 return sb.toString(); 206 } 207 208 209 /** 210 * @see Object#toString() 211 */ 212 @Override 213 public String toString() 214 { 215 return toString( "" ); 216 } 217}