1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.directory.server.xdbm.search.impl;
21
22
23 import java.util.HashSet;
24 import java.util.Set;
25
26 import org.apache.directory.api.ldap.model.cursor.Cursor;
27 import org.apache.directory.api.ldap.model.cursor.CursorException;
28 import org.apache.directory.api.ldap.model.entry.Entry;
29 import org.apache.directory.api.ldap.model.exception.LdapException;
30 import org.apache.directory.api.ldap.model.exception.LdapNoSuchObjectException;
31 import org.apache.directory.api.ldap.model.exception.LdapOtherException;
32 import org.apache.directory.api.ldap.model.filter.AndNode;
33 import org.apache.directory.api.ldap.model.filter.ExprNode;
34 import org.apache.directory.api.ldap.model.filter.ObjectClassNode;
35 import org.apache.directory.api.ldap.model.filter.ScopeNode;
36 import org.apache.directory.api.ldap.model.message.AliasDerefMode;
37 import org.apache.directory.api.ldap.model.message.SearchScope;
38 import org.apache.directory.api.ldap.model.name.Dn;
39 import org.apache.directory.api.ldap.model.schema.SchemaManager;
40 import org.apache.directory.server.core.api.interceptor.context.SearchOperationContext;
41 import org.apache.directory.server.core.api.partition.Partition;
42 import org.apache.directory.server.core.api.partition.PartitionTxn;
43 import org.apache.directory.server.core.partition.impl.btree.IndexCursorAdaptor;
44 import org.apache.directory.server.i18n.I18n;
45 import org.apache.directory.server.xdbm.IndexEntry;
46 import org.apache.directory.server.xdbm.Store;
47 import org.apache.directory.server.xdbm.search.Evaluator;
48 import org.apache.directory.server.xdbm.search.Optimizer;
49 import org.apache.directory.server.xdbm.search.PartitionSearchResult;
50 import org.apache.directory.server.xdbm.search.SearchEngine;
51 import org.apache.directory.server.xdbm.search.evaluator.BaseLevelScopeEvaluator;
52 import org.slf4j.Logger;
53 import org.slf4j.LoggerFactory;
54
55
56
57
58
59
60
61
62 public class DefaultSearchEngine implements SearchEngine
63 {
64
65 private static final Logger LOG = LoggerFactory.getLogger( DefaultSearchEngine.class );
66
67
68 private final Optimizer optimizer;
69
70
71 private final Store db;
72
73
74 private final CursorBuilder cursorBuilder;
75
76
77 private final EvaluatorBuilder evaluatorBuilder;
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92 public DefaultSearchEngine( Store db, CursorBuilder cursorBuilder,
93 EvaluatorBuilder evaluatorBuilder, Optimizer optimizer )
94 {
95 this.db = db;
96 this.optimizer = optimizer;
97 this.cursorBuilder = cursorBuilder;
98 this.evaluatorBuilder = evaluatorBuilder;
99 }
100
101
102
103
104
105
106
107 @Override
108 public Optimizer getOptimizer()
109 {
110 return optimizer;
111 }
112
113
114
115
116
117 @Override
118 public PartitionSearchResult computeResult( PartitionTxn partitionTxn, SchemaManager schemaManager,
119 SearchOperationContext searchContext ) throws LdapException
120 {
121 SearchScope scope = searchContext.getScope();
122 Dn baseDn = searchContext.getDn();
123 AliasDerefMode aliasDerefMode = searchContext.getAliasDerefMode();
124 ExprNode filter = searchContext.getFilter();
125
126
127 String baseId = db.getEntryId( partitionTxn, baseDn );
128
129
130 PartitionSearchResultPartitionSearchResult.html#PartitionSearchResult">PartitionSearchResult searchResult = new PartitionSearchResult( schemaManager );
131 Set<IndexEntry<String, String>> resultSet = new HashSet<>();
132
133
134 if ( baseId == null )
135 {
136 if ( ( ( Partition ) db ).getSuffixDn().equals( baseDn ) )
137 {
138
139 searchResult.setResultSet( resultSet );
140
141 return searchResult;
142 }
143 else
144 {
145
146 throw new LdapNoSuchObjectException( I18n.err( I18n.ERR_648, baseDn ) );
147 }
148 }
149
150
151
152
153 Dn aliasedBase = null;
154
155
156 if ( db.getAliasCache() != null )
157 {
158 aliasedBase = db.getAliasCache().getIfPresent( baseId );
159 }
160 else
161 {
162 aliasedBase = db.getAliasIndex().reverseLookup( partitionTxn, baseId );
163 }
164
165 Dn effectiveBase = baseDn;
166 String effectiveBaseId = baseId;
167
168 if ( ( aliasedBase != null ) && aliasDerefMode.isDerefFindingBase() )
169 {
170
171
172
173
174
175 if ( !aliasedBase.isSchemaAware() )
176 {
177 effectiveBase = new Dn( schemaManager, aliasedBase );
178 }
179 else
180 {
181 effectiveBase = aliasedBase;
182 }
183
184 effectiveBaseId = db.getEntryId( partitionTxn, effectiveBase );
185 }
186
187
188
189
190 if ( scope == SearchScope.OBJECT )
191 {
192 IndexEntry<String, String> indexEntry = new IndexEntry<>();
193 indexEntry.setId( effectiveBaseId );
194
195
196 Entry entry = db.fetch( partitionTxn, indexEntry.getId(), effectiveBase );
197
198 Evaluator<? extends ExprNode> evaluator;
199
200 if ( filter instanceof ObjectClassNode )
201 {
202 ScopeNode node = new ScopeNode( aliasDerefMode, effectiveBase, effectiveBaseId, scope );
203 evaluator = new BaseLevelScopeEvaluator<>( db, node );
204 }
205 else
206 {
207 optimizer.annotate( partitionTxn, filter );
208 evaluator = evaluatorBuilder.build( partitionTxn, filter );
209
210
211 if ( evaluator == null )
212 {
213 ScopeNode node = new ScopeNode( aliasDerefMode, effectiveBase, effectiveBaseId, scope );
214 evaluator = new BaseLevelScopeEvaluator<>( db, node );
215 }
216 }
217
218 indexEntry.setEntry( entry );
219 resultSet.add( indexEntry );
220
221 searchResult.setEvaluator( evaluator );
222 searchResult.setResultSet( resultSet );
223
224 return searchResult;
225 }
226
227
228
229
230 ExprNode root;
231
232 if ( filter instanceof ObjectClassNode )
233 {
234 root = new ScopeNode( aliasDerefMode, effectiveBase, effectiveBaseId, scope );
235 }
236 else
237 {
238 root = new AndNode();
239 ( ( AndNode ) root ).getChildren().add( filter );
240 ExprNode node = new ScopeNode( aliasDerefMode, effectiveBase, effectiveBaseId, scope );
241 ( ( AndNode ) root ).getChildren().add( node );
242 }
243
244
245 optimizer.annotate( partitionTxn, root );
246 Evaluator<? extends ExprNode> evaluator = evaluatorBuilder.build( partitionTxn, root );
247
248 Set<String> uuidSet = new HashSet<>();
249 searchResult.setAliasDerefMode( aliasDerefMode );
250 searchResult.setCandidateSet( uuidSet );
251
252 long nbResults = cursorBuilder.build( partitionTxn, root, searchResult );
253
254 LOG.debug( "Nb results : {} for filter : {}", nbResults, root );
255
256 if ( nbResults < Long.MAX_VALUE )
257 {
258 for ( String uuid : uuidSet )
259 {
260 IndexEntry<String, String> indexEntry = new IndexEntry<>();
261 indexEntry.setId( uuid );
262 resultSet.add( indexEntry );
263 }
264 }
265 else
266 {
267
268 Cursor<IndexEntry<String, String>> cursor = new IndexCursorAdaptor( partitionTxn, db.getMasterTable().cursor(), true );
269
270 try
271 {
272 while ( cursor.next() )
273 {
274 IndexEntry<String, String> indexEntry = cursor.get();
275
276
277 IndexEntry<String, String> forwardIndexEntry = new IndexEntry<>();
278 forwardIndexEntry.setKey( indexEntry.getKey() );
279 forwardIndexEntry.setId( indexEntry.getKey() );
280 forwardIndexEntry.setEntry( null );
281
282 resultSet.add( forwardIndexEntry );
283 }
284 }
285 catch ( CursorException ce )
286 {
287 throw new LdapOtherException( ce.getMessage(), ce );
288 }
289 }
290
291 searchResult.setEvaluator( evaluator );
292 searchResult.setResultSet( resultSet );
293
294 return searchResult;
295 }
296
297
298
299
300
301 @Override
302 public Evaluator<? extends ExprNode> evaluator( PartitionTxn partitionTxn, ExprNode filter ) throws LdapException
303 {
304 return evaluatorBuilder.build( partitionTxn, filter );
305 }
306 }