1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.ldap.server.partition.impl.btree;
18
19
20 import java.math.BigInteger;
21
22 import javax.naming.NamingEnumeration;
23 import javax.naming.NamingException;
24 import javax.naming.directory.SearchControls;
25
26 import org.apache.ldap.common.filter.ExprNode;
27 import org.apache.ldap.common.filter.ScopeNode;
28 import org.apache.ldap.common.util.SingletonEnumeration;
29
30
31 /***
32 * Enumerates candidates based on scope.
33 *
34 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
35 * @version $Rev: 264732 $
36 */
37 public class ScopeEnumerator implements Enumerator
38 {
39 /*** Database used to enumerate based on scope */
40 private BTreeContextPartition db = null;
41 /*** Filter scope expression evaluator */
42 private ScopeEvaluator evaluator = null;
43
44
45 public ScopeEnumerator( BTreeContextPartition db, ScopeEvaluator evaluator )
46 {
47 this.db = db;
48 this.evaluator = evaluator;
49 }
50
51
52 /***
53 * Builds an enumeration over all entries that satisfy the constraints of
54 * the scope assertion node.
55 *
56 * @param node the scope node
57 * @return the candidates that are within scope
58 * @throws NamingException if any system indices fail
59 * @see org.apache.ldap.server.partition.impl.btree.Enumerator#enumerate(ExprNode)
60 */
61 public NamingEnumeration enumerate( ExprNode node ) throws NamingException
62 {
63 final ScopeNode snode = ( ScopeNode ) node;
64 final BigInteger id = db.getEntryId( snode.getBaseDn() );
65
66 switch( snode.getScope() )
67 {
68 case( SearchControls.OBJECT_SCOPE ):
69 final IndexRecord record = new IndexRecord();
70 record.setEntryId( id );
71 record.setIndexKey( snode.getBaseDn() );
72 return new SingletonEnumeration( record );
73 case( SearchControls.ONELEVEL_SCOPE ):
74 return enumerateChildren( snode.getBaseDn(),
75 snode.getDerefAliases().derefInSearching() );
76 case( SearchControls.SUBTREE_SCOPE ):
77 return enumerateDescendants( snode );
78 default:
79 throw new NamingException( "Unrecognized search scope!" );
80 }
81 }
82
83
84 /***
85 * Constructs an enumeration over all entries within one level scope even
86 * when aliases are enabled while searching.
87 *
88 * @param dn the base dn
89 * @param deref whether or not we dereference while searching
90 * @return the enumeration of all entries in direct or alias extended one
91 * level scope to the base
92 * @throws NamingException if any failures occur while accessing system
93 * indices.
94 */
95 private NamingEnumeration enumerateChildren( String dn, boolean deref )
96 throws NamingException
97 {
98 Index idx = db.getHierarchyIndex();
99 final BigInteger id = db.getEntryId( dn );
100 final NamingEnumeration children = idx.listIndices( id );
101
102
103
104
105
106 if ( ! deref )
107 {
108 return children;
109 }
110
111
112
113
114
115
116
117
118
119
120
121
122
123 idx = db.getOneAliasIndex();
124 NamingEnumeration aliasIntroduced = idx.listIndices( id );
125
126
127 NamingEnumeration nonAliasChildren = new IndexAssertionEnumeration(
128 children, new AssertNotAlias() );
129
130
131 NamingEnumeration [] all = {nonAliasChildren, aliasIntroduced};
132 return new DisjunctionEnumeration( all );
133 }
134
135
136 /***
137 * Constructs an enumeration over all entries within subtree scope even
138 * when aliases are enabled while searching.
139 *
140 * @param node the scope node
141 * @return the enumeration of all entries in direct or alias extended
142 * subtree scope to the base
143 * @throws NamingException if any failures occur while accessing system
144 * indices.
145 */
146 private NamingEnumeration enumerateDescendants( final ScopeNode node )
147 throws NamingException
148 {
149 Index idx = null;
150
151
152
153
154
155 if ( ! node.getDerefAliases().derefInSearching() )
156 {
157
158 idx = db.getNdnIndex();
159 NamingEnumeration underlying = idx.listIndices();
160 return new IndexAssertionEnumeration( underlying,
161 new AssertDescendant( node ) );
162 }
163
164
165 IndexAssertion assertion = new IndexAssertion()
166 {
167 public boolean assertCandidate( IndexRecord rec )
168 throws NamingException
169 {
170 return evaluator.evaluate( node, rec );
171 }
172 };
173
174
175 idx = db.getNdnIndex();
176 NamingEnumeration underlying = idx.listIndices();
177 return new IndexAssertionEnumeration( underlying, assertion );
178 }
179
180
181 /***
182 * Asserts an entry is a descendant.
183 */
184 class AssertDescendant implements IndexAssertion
185 {
186 /*** Scope node with base and alias info */
187 private final ScopeNode scope;
188
189
190 /***
191 * Creates a assertion using a ScopeNode to determine the search base.
192 *
193 * @param node the scope node with search base
194 */
195 AssertDescendant( final ScopeNode node )
196 {
197 scope = node;
198 }
199
200
201 /***
202 * Returns true if the candidate with id is a descendant of the base,
203 * false otherwise.
204 *
205 * @see org.apache.ldap.server.partition.impl.btree.IndexAssertion#assertCandidate(IndexRecord)
206 */
207 public boolean assertCandidate( IndexRecord record ) throws NamingException
208 {
209 String dn = db.getEntryDn( record.getEntryId() );
210 return dn.endsWith( scope.getBaseDn() );
211 }
212 }
213
214
215 /***
216 * Asserts an entry is NOT an alias.
217 */
218 class AssertNotAlias implements IndexAssertion
219 {
220 /***
221 * Returns true if the candidate is not an alias, false otherwise.
222 *
223 * @see IndexAssertion#assertCandidate(IndexRecord)
224 */
225 public boolean assertCandidate( IndexRecord record ) throws NamingException
226 {
227 Index aliasIdx = db.getAliasIndex();
228
229 if ( null == aliasIdx.reverseLookup( record.getEntryId() ) )
230 {
231 return true;
232 }
233
234 return false;
235 }
236 }
237 }