View Javadoc

1   /*
2    *  Licensed to the Apache Software Foundation (ASF) under one
3    *  or more contributor license agreements.  See the NOTICE file
4    *  distributed with this work for additional information
5    *  regarding copyright ownership.  The ASF licenses this file
6    *  to you under the Apache License, Version 2.0 (the
7    *  "License"); you may not use this file except in compliance
8    *  with the License.  You may obtain a copy of the License at
9    *  
10   *    http://www.apache.org/licenses/LICENSE-2.0
11   *  
12   *  Unless required by applicable law or agreed to in writing,
13   *  software distributed under the License is distributed on an
14   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *  KIND, either express or implied.  See the License for the
16   *  specific language governing permissions and limitations
17   *  under the License. 
18   *  
19   */
20  package org.apache.directory.server.xdbm.search.impl;
21  
22  
23  import org.apache.directory.shared.ldap.filter.ScopeNode;
24  import org.apache.directory.shared.ldap.filter.SearchScope;
25  import org.apache.directory.server.xdbm.IndexEntry;
26  import org.apache.directory.server.xdbm.Store;
27  import org.apache.directory.server.xdbm.search.Evaluator;
28  
29  
30  /**
31   * Evaluates one level scope assertions on candidates using an entry database.
32   * 
33   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
34   * @version $Rev: 659774 $
35   */
36  public class OneLevelScopeEvaluator<E> implements Evaluator<ScopeNode,E>
37  {
38      /** The ScopeNode containing initial search scope constraints */
39      private final ScopeNode node;
40  
41      /** The entry identifier of the scope base */
42      private final Long baseId;
43  
44      /** True if the scope requires alias dereferencing while searching */
45      private final boolean dereferencing;
46  
47      /** the entry db storing entries */
48      private final Store<E> db;
49  
50  
51      /**
52       * Creates a one level scope node Evaluator for search expressions.
53       *
54       * @param node the scope node
55       * @param db the database used to evaluate scope node
56       * @throws Exception on db access failure
57       */
58      public OneLevelScopeEvaluator( Store<E> db, ScopeNode node ) throws Exception
59      {
60          this.node = node;
61  
62          if ( node.getScope() != SearchScope.ONELEVEL )
63          {
64              throw new IllegalStateException( "ScopeNode is not of onelevel scope." );
65          }
66  
67          this.db = db;
68          baseId = db.getEntryId( node.getBaseDn() );
69          dereferencing = node.getDerefAliases().isDerefInSearching() ||
70              node.getDerefAliases().isDerefAlways();
71      }
72  
73  
74      /**
75       * Asserts whether or not a candidate has one level scope while taking
76       * alias dereferencing into account.
77       *
78       * @param candidate the candidate to assert
79       * @return true if the candidate is within one level scope
80       * @throws Exception if db lookups fail
81       * @see org.apache.directory.server.xdbm.search.Evaluator#evaluate(IndexEntry)
82       */
83      public boolean evaluate( Long candidate ) throws Exception
84      {
85          boolean isChild = db.getOneLevelIndex().forward( baseId, candidate );
86  
87          /*
88           * The candidate id could be any entry in the db.  If search
89           * dereferencing is not enabled then we return the results of the child
90           * test.
91           */
92          if ( ! dereferencing )
93          {
94              return isChild;
95          }
96  
97          /*
98           * From here down alias dereferencing is enabled.  We determine if the
99           * candidate id is an alias, if so we reject it since aliases should
100          * not be returned.
101          */
102         if ( null != db.getAliasIndex().reverseLookup( candidate ) )
103         {
104             return false;
105         }
106 
107         /*
108          * The candidate is NOT an alias at this point.  So if it is a child we
109          * just return true since it is in normal one level scope.
110          */
111         if ( isChild )
112         {
113             return true;
114         }
115 
116         /*
117          * At this point the candidate is not a child and it is not an alias.
118          * We need to check if the candidate is in extended one level scope by
119          * performing a lookup on the one level alias index.  This index stores
120          * a tuple mapping the baseId to the id of objects brought into the
121          * one level scope of the base by an alias: ( baseId, aliasedObjId )
122          * If the candidate id is an object brought into one level scope then
123          * the lookup returns true accepting the candidate.  Otherwise the
124          * candidate is rejected with a false return because it is not in scope.
125          */
126         return db.getOneAliasIndex().forward( baseId, candidate );
127     }
128 
129 
130     /**
131      * Asserts whether or not a candidate has one level scope while taking
132      * alias dereferencing into account.
133      *
134      * TODO - terribly inefficient - would benefit from exposing the id of an
135      * entry within the ServerEntry
136      *
137      * @see Evaluator#evaluate(Object)
138      */
139     public boolean evaluate( E candidate ) throws Exception
140     {
141         throw new UnsupportedOperationException( "This is too inefficient without getId() on ServerEntry" );
142     }
143 
144 
145     /**
146      * Asserts whether or not a candidate has one level scope while taking
147      * alias dereferencing into account.
148      *
149      * @param candidate the candidate to assert
150      * @return true if the candidate is within one level scope
151      * @throws Exception if db lookups fail
152      * @see org.apache.directory.server.xdbm.search.Evaluator#evaluate(IndexEntry)
153      */
154     public boolean evaluate( IndexEntry<?,E> candidate ) throws Exception
155     {
156         boolean isChild = db.getOneLevelIndex().forward( baseId, candidate.getId() );
157 
158         /*
159          * The candidate id could be any entry in the db.  If search
160          * dereferencing is not enabled then we return the results of the child
161          * test.
162          */
163         if ( ! dereferencing )
164         {
165             return isChild;
166         }
167 
168         /*
169          * From here down alias dereferencing is enabled.  We determine if the
170          * candidate id is an alias, if so we reject it since aliases should
171          * not be returned.
172          */
173         if ( null != db.getAliasIndex().reverseLookup( candidate.getId() ) )
174         {
175             return false;
176         }
177 
178         /*
179          * The candidate is NOT an alias at this point.  So if it is a child we
180          * just return true since it is in normal one level scope.
181          */
182         if ( isChild )
183         {
184             return true;
185         }
186 
187         /*
188          * At this point the candidate is not a child and it is not an alias.
189          * We need to check if the candidate is in extended one level scope by
190          * performing a lookup on the one level alias index.  This index stores
191          * a tuple mapping the baseId to the id of objects brought into the
192          * one level scope of the base by an alias: ( baseId, aliasedObjId )
193          * If the candidate id is an object brought into one level scope then
194          * the lookup returns true accepting the candidate.  Otherwise the
195          * candidate is rejected with a false return because it is not in scope.
196          */
197         return db.getOneAliasIndex().forward( baseId, candidate.getId() );
198     }
199 
200 
201     public ScopeNode getExpression()
202     {
203         return node;
204     }
205 
206 
207     /**
208      * Gets the id of the search base associated with the ScopeNode expression.
209      *
210      * @return identifier of the search base
211      */
212     public Long getBaseId()
213     {
214         return baseId;
215     }
216 
217 
218     /**
219      * Gets whether or not dereferencing is enabled for this evaluator.
220      *
221      * @return true if dereferencing is enabled, false otherwise
222      */
223     public boolean isDereferencing()
224     {
225         return dereferencing;
226     }
227 }