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