1 /*
2 * Copyright 2004 The Apache Software Foundation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 */
17
18 /*
19 * $Id: ScopeEvaluator.java,v 1.3 2003/10/15 01:59:46 akarasulu Exp $
20 *
21 * -- (c) LDAPd Group --
22 * -- Please refer to the LICENSE.txt file in the root directory of --
23 * -- any LDAPd project for copyright and distribution information. --
24 *
25 * Created on Oct 9, 2003
26 */
27 package org.apache.ldap.server.db;
28
29
30 import org.apache.ldap.common.filter.ExprNode;
31 import org.apache.ldap.common.filter.ScopeNode;
32 import org.apache.ldap.common.message.DerefAliasesEnum;
33
34 import javax.naming.NamingException;
35 import javax.naming.directory.SearchControls;
36 import java.math.BigInteger;
37
38
39 /***
40 * Evaluates ScopeNode assertions on candidates using a database.
41 *
42 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
43 * @version $Rev: 164288 $
44 */
45 public class ScopeEvaluator implements Evaluator
46 {
47 /*** Database used to evaluate scope with */
48 private Database db;
49
50
51 /***
52 * Creates a scope node evaluator for search expressions.
53 *
54 * @param db the database used to evaluate scope node
55 */
56 public ScopeEvaluator( Database db )
57 {
58 this.db = db;
59 }
60
61
62 /***
63 * @see org.apache.ldap.server.db.Evaluator#evaluate(ExprNode, org.apache.ldap.server.db.IndexRecord)
64 */
65 public boolean evaluate( ExprNode node, IndexRecord record )
66 throws NamingException
67 {
68 ScopeNode snode = ( ScopeNode ) node;
69
70 switch( snode.getScope() )
71 {
72 case( SearchControls.OBJECT_SCOPE ):
73 String dn = db.getEntryDn( record.getEntryId() );
74 return dn.equals( snode.getBaseDn() );
75 case( SearchControls.ONELEVEL_SCOPE ):
76 return assertOneLevelScope( snode, record.getEntryId() );
77 case( SearchControls.SUBTREE_SCOPE ):
78 return assertSubtreeScope( snode, record.getEntryId() );
79 default:
80 throw new NamingException( "Unrecognized search scope!" );
81 }
82 }
83
84
85 /***
86 * Asserts whether or not a candidate has one level scope while taking
87 * alias dereferencing into account.
88 *
89 * @param node the scope node containing the base and alias handling mode
90 * @param id the candidate to assert which can be any db entry's id
91 * @return true if the candidate is within one level scope whether or not
92 * alias dereferencing is enabled.
93 * @throws NamingException if the index lookups fail.
94 */
95 public boolean assertSubtreeScope( final ScopeNode node,
96 final BigInteger id ) throws NamingException
97 {
98 String dn = db.getEntryDn( id );
99 DerefAliasesEnum mode = node.getDerefAliases();
100 Object baseId = db.getEntryId( node.getBaseDn() );
101 boolean isDescendant = dn.endsWith( node.getBaseDn() );
102
103 /*
104 * The candidate id could be any entry in the db. If search
105 * dereferencing is not enabled then we return the results of the
106 * descendant test.
107 */
108 if ( ! mode.derefInSearching() )
109 {
110 return isDescendant;
111 }
112
113 /*
114 * From here down alias dereferencing is enabled. We determine if the
115 * candidate id is an alias, if so we reject it since aliases should
116 * not be returned.
117 */
118 Index idx = db.getAliasIndex();
119 if ( null != idx.reverseLookup( id ) )
120 {
121 return false;
122 }
123
124 /*
125 * The candidate is NOT an alias at this point. So if it is a
126 * descendant we just return it since it is in normal subtree scope.
127 */
128 if ( isDescendant )
129 {
130 return true;
131 }
132
133 /*
134 * At this point the candidate is not a descendant and it is not an
135 * alias. We need to check if the candidate is in extended subtree
136 * scope by performing a lookup on the subtree alias index. This index
137 * stores a tuple mapping the baseId to the ids of objects brought
138 * into subtree scope of the base by an alias:
139 *
140 * ( baseId, aliasedObjId )
141 *
142 * If the candidate id is an object brought into subtree scope then
143 * the lookup returns true accepting the candidate. Otherwise the
144 * candidate is rejected with a false return because it is not in scope.
145 */
146 idx = db.getSubAliasIndex();
147 return idx.hasValue( baseId, id );
148 }
149
150
151 /***
152 * Asserts whether or not a candidate has one level scope while taking
153 * alias dereferencing into account.
154 *
155 * @param node the scope node containing the base and alias handling mode
156 * @param id the candidate to assert which can be any db entry's id
157 * @return true if the candidate is within one level scope whether or not
158 * alias dereferencing is enabled.
159 * @throws NamingException if the index lookups fail.
160 */
161 public boolean assertOneLevelScope( final ScopeNode node,
162 final BigInteger id ) throws NamingException
163 {
164 DerefAliasesEnum mode = node.getDerefAliases();
165 Object baseId = db.getEntryId( node.getBaseDn() );
166 Index idx = db.getHierarchyIndex();
167 boolean isChild = idx.hasValue( baseId, id );
168
169 /*
170 * The candidate id could be any entry in the db. If search
171 * dereferencing is not enabled then we return the results of the child
172 * test.
173 */
174 if ( ! mode.derefInSearching() )
175 {
176 return isChild;
177 }
178
179 /*
180 * From here down alias dereferencing is enabled. We determine if the
181 * candidate id is an alias, if so we reject it since aliases should
182 * not be returned.
183 */
184 idx = db.getAliasIndex();
185 if ( null != idx.reverseLookup( id ) )
186 {
187 return false;
188 }
189
190 /*
191 * The candidate is NOT an alias at this point. So if it is a child we
192 * just return it since it is in normal one level scope.
193 */
194 if ( isChild )
195 {
196 return true;
197 }
198
199 /*
200 * At this point the candidate is not a child and it is not an alias.
201 * We need to check if the candidate is in extended one level scope by
202 * performing a lookup on the one level alias index. This index stores
203 * a tuple mapping the baseId to the id of objects brought into the
204 * one level scope of the base by an alias: ( baseId, aliasedObjId )
205 * If the candidate id is an object brought into one level scope then
206 * the lookup returns true accepting the candidate. Otherwise the
207 * candidate is rejected with a false return because it is not in scope.
208 */
209 idx = db.getOneAliasIndex();
210 return idx.hasValue( baseId, id );
211 }
212 }