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 org.apache.directory.shared.ldap.filter.ScopeNode; 024 import org.apache.directory.shared.ldap.filter.SearchScope; 025 import org.apache.directory.server.i18n.I18n; 026 import org.apache.directory.server.xdbm.IndexEntry; 027 import org.apache.directory.server.xdbm.Store; 028 import org.apache.directory.server.xdbm.search.Evaluator; 029 030 031 /** 032 * Evaluates one level scope assertions on candidates using an entry database. 033 * 034 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 035 * @version $Rev: 917312 $ 036 */ 037 public class OneLevelScopeEvaluator<E, ID> implements Evaluator<ScopeNode, E, ID> 038 { 039 /** The ScopeNode containing initial search scope constraints */ 040 private final ScopeNode node; 041 042 /** The entry identifier of the scope base */ 043 private final ID baseId; 044 045 /** True if the scope requires alias dereferencing while searching */ 046 private final boolean dereferencing; 047 048 /** the entry db storing entries */ 049 private final Store<E, ID> db; 050 051 052 /** 053 * Creates a one level scope node Evaluator for search expressions. 054 * 055 * @param node the scope node 056 * @param db the database used to evaluate scope node 057 * @throws Exception on db access failure 058 */ 059 public OneLevelScopeEvaluator( Store<E, ID> db, ScopeNode node ) throws Exception 060 { 061 this.node = node; 062 063 if ( node.getScope() != SearchScope.ONELEVEL ) 064 { 065 throw new IllegalStateException( I18n.err( I18n.ERR_720 ) ); 066 } 067 068 this.db = db; 069 baseId = db.getEntryId( node.getBaseDn() ); 070 dereferencing = node.getDerefAliases().isDerefInSearching() || node.getDerefAliases().isDerefAlways(); 071 } 072 073 074 /** 075 * Asserts whether or not a candidate has one level scope while taking 076 * alias dereferencing into account. 077 * 078 * @param candidate the candidate to assert 079 * @return true if the candidate is within one level scope 080 * @throws Exception if db lookups fail 081 * @see org.apache.directory.server.xdbm.search.Evaluator#evaluate(IndexEntry) 082 */ 083 public boolean evaluateId( ID candidate ) throws Exception 084 { 085 boolean isChild = db.getOneLevelIndex().forward( baseId, candidate ); 086 087 /* 088 * The candidate id could be any entry in the db. If search 089 * dereferencing is not enabled then we return the results of the child 090 * test. 091 */ 092 if ( !dereferencing ) 093 { 094 return isChild; 095 } 096 097 /* 098 * From here down alias dereferencing is enabled. We determine if the 099 * candidate id is an alias, if so we reject it since aliases should 100 * not be returned. 101 */ 102 if ( null != db.getAliasIndex().reverseLookup( candidate ) ) 103 { 104 return false; 105 } 106 107 /* 108 * The candidate is NOT an alias at this point. So if it is a child we 109 * just return true since it is in normal one level scope. 110 */ 111 if ( isChild ) 112 { 113 return true; 114 } 115 116 /* 117 * At this point the candidate is not a child and it is not an alias. 118 * We need to check if the candidate is in extended one level scope by 119 * performing a lookup on the one level alias index. This index stores 120 * a tuple mapping the baseId to the id of objects brought into the 121 * one level scope of the base by an alias: ( baseId, aliasedObjId ) 122 * If the candidate id is an object brought into one level scope then 123 * the lookup returns true accepting the candidate. Otherwise the 124 * candidate is rejected with a false return because it is not in scope. 125 */ 126 return db.getOneAliasIndex().forward( baseId, candidate ); 127 } 128 129 130 /** 131 * Asserts whether or not a candidate has one level scope while taking 132 * alias dereferencing into account. 133 * 134 * TODO - terribly inefficient - would benefit from exposing the id of an 135 * entry within the ServerEntry 136 * 137 * @see Evaluator#evaluate(Object) 138 */ 139 public boolean evaluateEntry( E candidate ) throws Exception 140 { 141 throw new UnsupportedOperationException( I18n.err( I18n.ERR_721 ) ); 142 } 143 144 145 /** 146 * Asserts whether or not a candidate has one level scope while taking 147 * alias dereferencing into account. 148 * 149 * @param candidate the candidate to assert 150 * @return true if the candidate is within one level scope 151 * @throws Exception if db lookups fail 152 * @see org.apache.directory.server.xdbm.search.Evaluator#evaluate(IndexEntry) 153 */ 154 public boolean evaluate( IndexEntry<?, E, ID> candidate ) throws Exception 155 { 156 boolean isChild = db.getOneLevelIndex().forward( baseId, candidate.getId() ); 157 158 /* 159 * The candidate id could be any entry in the db. If search 160 * dereferencing is not enabled then we return the results of the child 161 * test. 162 */ 163 if ( !dereferencing ) 164 { 165 return isChild; 166 } 167 168 /* 169 * From here down alias dereferencing is enabled. We determine if the 170 * candidate id is an alias, if so we reject it since aliases should 171 * not be returned. 172 */ 173 if ( null != db.getAliasIndex().reverseLookup( candidate.getId() ) ) 174 { 175 return false; 176 } 177 178 /* 179 * The candidate is NOT an alias at this point. So if it is a child we 180 * just return true since it is in normal one level scope. 181 */ 182 if ( isChild ) 183 { 184 return true; 185 } 186 187 /* 188 * At this point the candidate is not a child and it is not an alias. 189 * We need to check if the candidate is in extended one level scope by 190 * performing a lookup on the one level alias index. This index stores 191 * a tuple mapping the baseId to the id of objects brought into the 192 * one level scope of the base by an alias: ( baseId, aliasedObjId ) 193 * If the candidate id is an object brought into one level scope then 194 * the lookup returns true accepting the candidate. Otherwise the 195 * candidate is rejected with a false return because it is not in scope. 196 */ 197 return db.getOneAliasIndex().forward( baseId, candidate.getId() ); 198 } 199 200 201 public ScopeNode getExpression() 202 { 203 return node; 204 } 205 206 207 /** 208 * Gets the id of the search base associated with the ScopeNode expression. 209 * 210 * @return identifier of the search base 211 */ 212 public ID getBaseId() 213 { 214 return baseId; 215 } 216 217 218 /** 219 * Gets whether or not dereferencing is enabled for this evaluator. 220 * 221 * @return true if dereferencing is enabled, false otherwise 222 */ 223 public boolean isDereferencing() 224 { 225 return dereferencing; 226 } 227 }