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.LessEqNode; 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 LessEqNode 044 * assertions. 045 * 046 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 047 */ 048public class LessEqEvaluator<T> extends LeafEvaluator<T> 049{ 050 /** 051 * Creates a new LessEqEvaluator 052 * 053 * @param node The LessEqNode 054 * @param db The Store 055 * @param schemaManager The SchemaManager 056 * @throws LdapException If the creation failed 057 */ 058 @SuppressWarnings("unchecked") 059 public LessEqEvaluator( LessEqNode<T> node, Store db, SchemaManager schemaManager ) 060 throws LdapException 061 { 062 super( node, db, schemaManager ); 063 064 if ( db.hasIndexOn( attributeType ) ) 065 { 066 try 067 { 068 idx = ( Index<T, String> ) db.getIndex( attributeType ); 069 } 070 catch ( IndexNotFoundException infe ) 071 { 072 throw new LdapOtherException( infe.getMessage(), infe ); 073 } 074 } 075 else 076 { 077 idx = null; 078 } 079 080 /* 081 * We prefer matching using the Normalizer and Comparator pair from 082 * the ordering matchingRule if one is available. It may very well 083 * not be. If so then we resort to using the Normalizer and 084 * Comparator from the equality matchingRule as a last resort. 085 */ 086 MatchingRule mr = attributeType.getOrdering(); 087 088 if ( mr == null ) 089 { 090 mr = attributeType.getEquality(); 091 } 092 093 if ( mr == null ) 094 { 095 throw new IllegalStateException( I18n.err( I18n.ERR_717, node ) ); 096 } 097 098 normalizer = mr.getNormalizer(); 099 ldapComparator = mr.getLdapComparator(); 100 } 101 102 103 /** 104 * {@inheritDoc} 105 */ 106 @Override 107 public LessEqNode<T> getExpression() 108 { 109 return ( LessEqNode<T> ) node; 110 } 111 112 113 /** 114 * {@inheritDoc} 115 */ 116 @Override 117 public boolean evaluate( PartitionTxn partitionTxn, IndexEntry<?, String> indexEntry ) throws LdapException 118 { 119 Entry entry = indexEntry.getEntry(); 120 121 // resuscitate the entry if it has not been and set entry in IndexEntry 122 if ( null == entry ) 123 { 124 entry = db.fetch( partitionTxn, indexEntry.getId() ); 125 126 if ( null == entry ) 127 { 128 // The entry is not anymore present : get out 129 return false; 130 } 131 132 indexEntry.setEntry( entry ); 133 } 134 135 // get the attribute 136 Attribute attr = entry.get( attributeType ); 137 138 // if the attribute does not exist just return false 139 //noinspection unchecked 140 if ( attr != null && evaluate( ( IndexEntry<Object, String> ) indexEntry, 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( attributeType ) ) 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( attributeType ); 154 155 while ( descendants.hasNext() ) 156 { 157 AttributeType descendant = descendants.next(); 158 159 attr = entry.get( descendant ); 160 161 //noinspection unchecked 162 if ( attr != null && evaluate( ( IndexEntry<Object, String> ) indexEntry, 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 /** 175 * {@inheritDoc} 176 */ 177 @Override 178 public boolean evaluate( Entry entry ) throws LdapException 179 { 180 // get the attribute 181 Attribute attr = entry.get( attributeType ); 182 183 // if the attribute does not exist just return false 184 if ( ( attr != null ) && evaluate( null, attr ) ) 185 { 186 return true; 187 } 188 189 // If we do not have the attribute, loop through the sub classes of 190 // the attributeType. Perhaps the entry has an attribute value of a 191 // subtype (descendant) that will produce a match 192 if ( schemaManager.getAttributeTypeRegistry().hasDescendants( attributeType ) ) 193 { 194 // TODO check to see if descendant handling is necessary for the 195 // index so we can match properly even when for example a name 196 // attribute is used instead of more specific commonName 197 Iterator<AttributeType> descendants = schemaManager.getAttributeTypeRegistry().descendants( attributeType ); 198 199 while ( descendants.hasNext() ) 200 { 201 AttributeType descendant = descendants.next(); 202 203 attr = entry.get( descendant ); 204 205 if ( attr != null && evaluate( null, attr ) ) 206 { 207 return true; 208 } 209 } 210 } 211 212 // we fell through so a match was not found - assertion was false. 213 return false; 214 } 215 216 217 // TODO - determine if comparator and index entry should have the Value 218 // wrapper or the raw normalized value 219 private boolean evaluate( IndexEntry<Object, String> indexEntry, Attribute attribute ) 220 { 221 /* 222 * Cycle through the attribute values testing normalized version 223 * obtained from using the ordering or equality matching rule's 224 * normalizer. The test uses the comparator obtained from the 225 * appropriate matching rule to perform the check. 226 */ 227 for ( Value value : attribute ) 228 { 229 if ( ldapComparator.compare( value.getNormalized(), node.getValue().getNormalized() ) <= 0 ) 230 { 231 if ( indexEntry != null ) 232 { 233 indexEntry.setKey( value.getString() ); 234 } 235 236 return true; 237 } 238 } 239 240 return false; 241 } 242 243 244 /** 245 * @see Object#toString() 246 */ 247 @Override 248 public String toString( String tabs ) 249 { 250 StringBuilder sb = new StringBuilder(); 251 252 sb.append( tabs ).append( "LessEqEvaluator : " ).append( super.toString() ).append( "\n" ); 253 254 return sb.toString(); 255 } 256 257 258 /** 259 * @see Object#toString() 260 */ 261 @Override 262 public String toString() 263 { 264 return toString( "" ); 265 } 266}