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.GreaterEqNode; 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 GreaterEqNode 044 * assertions. 045 * 046 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 047 */ 048public class GreaterEqEvaluator<T> extends LeafEvaluator<T> 049{ 050 /** 051 * Creates a new GreaterEqEvaluator 052 * 053 * @param node The GreaterEqNode 054 * @param db The Store 055 * @param schemaManager The SchemaManager 056 * @throws LdapException If the creation failed 057 */ 058 @SuppressWarnings("unchecked") 059 public GreaterEqEvaluator( GreaterEqNode<T> node, Store db, SchemaManager schemaManager ) 060 throws LdapException 061 { 062 super( node, db, schemaManager ); 063 064 if ( db.hasIndexOn( node.getAttributeType() ) ) 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_715, node ) ); 096 } 097 098 normalizer = mr.getNormalizer(); 099 ldapComparator = mr.getLdapComparator(); 100 } 101 102 103 /** 104 * {@inheritDoc} 105 */ 106 @Override 107 public GreaterEqNode getExpression() 108 { 109 return ( GreaterEqNode ) 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 /* 136 * The code below could have been replaced by a call to 137 * evaluate( Entry ) but it was not because we wanted to make 138 * sure the call to evaluate with the attribute was made using a 139 * non-null IndexEntry parameter. This is to make sure the call to 140 * evaluate with the attribute will set the value on the IndexEntry. 141 */ 142 143 // get the attribute 144 Attribute attr = entry.get( attributeType ); 145 146 // if the attribute exists and has a greater than or equal value return true 147 //noinspection unchecked 148 if ( attr != null && evaluate( ( IndexEntry<Object, String> ) indexEntry, attr ) ) 149 { 150 return true; 151 } 152 153 // If we do not have the attribute, loop through the sub classes of 154 // the attributeType. Perhaps the entry has an attribute value of a 155 // subtype (descendant) that will produce a match 156 if ( schemaManager.getAttributeTypeRegistry().hasDescendants( attributeType ) ) 157 { 158 // TODO check to see if descendant handling is necessary for the 159 // index so we can match properly even when for example a name 160 // attribute is used instead of more specific commonName 161 Iterator<AttributeType> descendants = schemaManager.getAttributeTypeRegistry().descendants( attributeType ); 162 163 while ( descendants.hasNext() ) 164 { 165 AttributeType descendant = descendants.next(); 166 167 attr = entry.get( descendant ); 168 169 //noinspection unchecked 170 if ( attr != null && evaluate( ( IndexEntry<Object, String> ) indexEntry, attr ) ) 171 { 172 return true; 173 } 174 } 175 } 176 177 // we fell through so a match was not found - assertion was false. 178 return false; 179 } 180 181 182 /** 183 * {@inheritDoc} 184 */ 185 @Override 186 public boolean evaluate( Entry entry ) throws LdapException 187 { 188 // get the attribute 189 Attribute attr = entry.get( attributeType ); 190 191 // if the attribute exists and has a greater than or equal value return true 192 if ( ( attr != null ) && evaluate( null, attr ) ) 193 { 194 return true; 195 } 196 197 // If we do not have the attribute, loop through the sub classes of 198 // the attributeType. Perhaps the entry has an attribute value of a 199 // subtype (descendant) that will produce a match 200 if ( schemaManager.getAttributeTypeRegistry().hasDescendants( attributeType ) ) 201 { 202 // TODO check to see if descendant handling is necessary for the 203 // index so we can match properly even when for example a name 204 // attribute is used instead of more specific commonName 205 Iterator<AttributeType> descendants = schemaManager.getAttributeTypeRegistry().descendants( attributeType ); 206 207 while ( descendants.hasNext() ) 208 { 209 AttributeType descendant = descendants.next(); 210 211 attr = entry.get( descendant ); 212 213 if ( ( attr != null ) && evaluate( null, attr ) ) 214 { 215 return true; 216 } 217 } 218 } 219 220 // we fell through so a match was not found - assertion was false. 221 return false; 222 } 223 224 225 // TODO - determine if comaparator and index entry should have the Value 226 // wrapper or the raw normalized value 227 private boolean evaluate( IndexEntry<Object, String> indexEntry, Attribute attribute ) 228 throws LdapException 229 { 230 /* 231 * Cycle through the attribute values testing normalized version 232 * obtained from using the ordering or equality matching rule's 233 * normalizer. The test uses the comparator obtained from the 234 * appropriate matching rule to perform the check. 235 */ 236 for ( Value value : attribute ) 237 { 238 if ( ldapComparator.compare( value.getNormalized(), node.getValue().getNormalized() ) >= 0 ) 239 { 240 if ( indexEntry != null ) 241 { 242 indexEntry.setKey( value.getString() ); 243 } 244 245 return true; 246 } 247 } 248 249 return false; 250 } 251 252 253 /** 254 * @see Object#toString() 255 */ 256 @Override 257 public String toString( String tabs ) 258 { 259 StringBuilder sb = new StringBuilder(); 260 261 sb.append( tabs ).append( "GreaterEqEvaluator : " ).append( super.toString() ).append( "\n" ); 262 263 return sb.toString(); 264 } 265 266 267 /** 268 * @see Object#toString() 269 */ 270 @Override 271 public String toString() 272 { 273 return toString( "" ); 274 } 275}