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 javax.naming.directory.SearchControls;
024
025 import org.apache.directory.server.xdbm.EmptyIndexCursor;
026 import org.apache.directory.server.xdbm.ForwardIndexEntry;
027 import org.apache.directory.server.xdbm.IndexCursor;
028 import org.apache.directory.server.xdbm.IndexEntry;
029 import org.apache.directory.server.xdbm.SingletonIndexCursor;
030 import org.apache.directory.server.xdbm.Store;
031 import org.apache.directory.server.xdbm.search.Evaluator;
032 import org.apache.directory.server.xdbm.search.Optimizer;
033 import org.apache.directory.server.xdbm.search.SearchEngine;
034 import org.apache.directory.shared.ldap.entry.ServerEntry;
035 import org.apache.directory.shared.ldap.filter.AndNode;
036 import org.apache.directory.shared.ldap.filter.BranchNode;
037 import org.apache.directory.shared.ldap.filter.ExprNode;
038 import org.apache.directory.shared.ldap.filter.ScopeNode;
039 import org.apache.directory.shared.ldap.filter.SearchScope;
040 import org.apache.directory.shared.ldap.message.AliasDerefMode;
041 import org.apache.directory.shared.ldap.name.DN;
042
043
044 /**
045 * Given a search filter and a scope the search engine identifies valid
046 * candidate entries returning their ids.
047 *
048 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
049 * @version $Rev: 927146 $
050 */
051 public class DefaultSearchEngine<ID> implements SearchEngine<ServerEntry, ID>
052 {
053 /** the Optimizer used by this DefaultSearchEngine */
054 private final Optimizer optimizer;
055 /** the Database this DefaultSearchEngine operates on */
056 private final Store<ServerEntry, ID> db;
057 /** creates Cursors over entries satisfying filter expressions */
058 private final CursorBuilder<ID> cursorBuilder;
059 /** creates evaluators which check to see if candidates satisfy a filter expression */
060 private final EvaluatorBuilder<ID> evaluatorBuilder;
061
062
063 // ------------------------------------------------------------------------
064 // C O N S T R U C T O R S
065 // ------------------------------------------------------------------------
066
067 /**
068 * Creates a DefaultSearchEngine for searching a Database without setting
069 * up the database.
070 * @param db the btree based partition
071 * @param cursorBuilder an expression cursor builder
072 * @param evaluatorBuilder an expression evaluator builder
073 * @param optimizer an optimizer to use during search
074 */
075 public DefaultSearchEngine( Store<ServerEntry, ID> db, CursorBuilder<ID> cursorBuilder,
076 EvaluatorBuilder<ID> evaluatorBuilder, Optimizer optimizer )
077 {
078 this.db = db;
079 this.optimizer = optimizer;
080 this.cursorBuilder = cursorBuilder;
081 this.evaluatorBuilder = evaluatorBuilder;
082 }
083
084
085 /**
086 * Gets the optimizer for this DefaultSearchEngine.
087 *
088 * @return the optimizer
089 */
090 public Optimizer getOptimizer()
091 {
092 return optimizer;
093 }
094
095
096 /**
097 * @see SearchEngine#cursor(DN, AliasDerefMode, ExprNode, SearchControls)
098 */
099 public IndexCursor<ID, ServerEntry, ID> cursor( DN base, AliasDerefMode aliasDerefMode, ExprNode filter,
100 SearchControls searchCtls ) throws Exception
101 {
102 DN effectiveBase;
103 ID baseId = db.getEntryId( base.getNormName() );
104
105 // Check that we have an entry, otherwise we can immediately get out
106 if ( baseId == null )
107 {
108 // The entry is not found : ciao !
109 return new EmptyIndexCursor<ID, ServerEntry, ID>();
110 }
111
112 String aliasedBase = db.getAliasIndex().reverseLookup( baseId );
113
114 // --------------------------------------------------------------------
115 // Determine the effective base with aliases
116 // --------------------------------------------------------------------
117
118 /*
119 * If the base is not an alias or if alias dereferencing does not
120 * occur on finding the base then we set the effective base to the
121 * given base.
122 */
123 if ( ( null == aliasedBase ) || !aliasDerefMode.isDerefFindingBase() )
124 {
125 effectiveBase = base;
126 }
127
128 /*
129 * If the base is an alias and alias dereferencing does occur on
130 * finding the base then we set the effective base to the alias target
131 * got from the alias index.
132 */
133 else
134 {
135 effectiveBase = new DN( aliasedBase );
136 }
137
138 // --------------------------------------------------------------------
139 // Specifically Handle Object Level Scope
140 // --------------------------------------------------------------------
141
142 if ( searchCtls.getSearchScope() == SearchControls.OBJECT_SCOPE )
143 {
144 ID effectiveBaseId = baseId;
145 if ( effectiveBase != base )
146 {
147 effectiveBaseId = db.getEntryId( effectiveBase.getNormName() );
148 }
149
150 IndexEntry<ID, ServerEntry, ID> indexEntry = new ForwardIndexEntry<ID, ServerEntry, ID>();
151 indexEntry.setId( effectiveBaseId );
152 optimizer.annotate( filter );
153 Evaluator<? extends ExprNode, ServerEntry, ID> evaluator = evaluatorBuilder.build( filter );
154
155 if ( evaluator.evaluate( indexEntry ) )
156 {
157 return new SingletonIndexCursor<ID, ServerEntry, ID>( indexEntry );
158 }
159 else
160 {
161 return new EmptyIndexCursor<ID, ServerEntry, ID>();
162 }
163 }
164
165 // Add the scope node using the effective base to the filter
166 BranchNode root = new AndNode();
167 ExprNode node = new ScopeNode( aliasDerefMode, effectiveBase.getNormName(), SearchScope.getSearchScope( searchCtls
168 .getSearchScope() ) );
169 root.getChildren().add( node );
170 root.getChildren().add( filter );
171
172 // Annotate the node with the optimizer and return search enumeration.
173 optimizer.annotate( root );
174 return ( IndexCursor<ID, ServerEntry, ID> ) cursorBuilder.build( root );
175 }
176
177
178 /**
179 * @see SearchEngine#evaluator(ExprNode)
180 */
181 public Evaluator<? extends ExprNode, ServerEntry, ID> evaluator( ExprNode filter ) throws Exception
182 {
183 return evaluatorBuilder.build( filter );
184 }
185 }