View Javadoc

1   /*
2    *   Copyright 2004 The Apache Software Foundation
3    *
4    *   Licensed under the Apache License, Version 2.0 (the "License");
5    *   you may not use this file except in compliance with the License.
6    *   You may obtain a copy of the License at
7    *
8    *       http://www.apache.org/licenses/LICENSE-2.0
9    *
10   *   Unless required by applicable law or agreed to in writing, software
11   *   distributed under the License is distributed on an "AS IS" BASIS,
12   *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   *   See the License for the specific language governing permissions and
14   *   limitations under the License.
15   *
16   */
17  
18  /*
19   * $Id: ScopeEvaluator.java 264732 2005-08-30 08:04:51Z akarasulu $
20   *
21   * -- (c) LDAPd Group                                                    --
22   * -- Please refer to the LICENSE.txt file in the root directory of      --
23   * -- any LDAPd project for copyright and distribution information.      --
24   *
25   * Created on Oct 9, 2003
26   */
27  package org.apache.ldap.server.partition.impl.btree;
28  
29  
30  import java.math.BigInteger;
31  
32  import javax.naming.NamingException;
33  import javax.naming.directory.SearchControls;
34  
35  import org.apache.ldap.common.filter.ExprNode;
36  import org.apache.ldap.common.filter.ScopeNode;
37  import org.apache.ldap.common.message.DerefAliasesEnum;
38  
39  
40  /***
41   * Evaluates ScopeNode assertions on candidates using a database.
42   * 
43   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
44   * @version $Rev: 264732 $
45   */
46  public class ScopeEvaluator implements Evaluator
47  {
48      /*** Database used to evaluate scope with */
49      private BTreeContextPartition db;
50  
51  
52      /***
53       * Creates a scope node evaluator for search expressions.
54       *
55       * @param db the database used to evaluate scope node
56       */
57      public ScopeEvaluator( BTreeContextPartition db )
58      {
59          this.db = db;
60      }
61  
62  
63      /***
64       * @see org.apache.ldap.server.partition.impl.btree.Evaluator#evaluate(ExprNode, org.apache.ldap.server.partition.impl.btree.IndexRecord)
65       */
66      public boolean evaluate( ExprNode node, IndexRecord record )
67          throws NamingException
68      {
69          ScopeNode snode = ( ScopeNode ) node;
70          
71          switch( snode.getScope() )
72          {
73          case( SearchControls.OBJECT_SCOPE ):
74              String dn = db.getEntryDn( record.getEntryId() );
75              return dn.equals( snode.getBaseDn() );
76          case( SearchControls.ONELEVEL_SCOPE ):
77              return assertOneLevelScope( snode, record.getEntryId() );
78          case( SearchControls.SUBTREE_SCOPE ):
79              return assertSubtreeScope( snode, record.getEntryId() );
80          default:
81              throw new NamingException( "Unrecognized search scope!" );
82          }
83      }
84      
85      
86      /***
87       * Asserts whether or not a candidate has one level scope while taking
88       * alias dereferencing into account.
89       * 
90       * @param node the scope node containing the base and alias handling mode
91       * @param id the candidate to assert which can be any db entry's id
92       * @return true if the candidate is within one level scope whether or not
93       * alias dereferencing is enabled.
94       * @throws NamingException if the index lookups fail.
95       */
96      public boolean assertSubtreeScope( final ScopeNode node, 
97          final BigInteger id ) throws NamingException
98      {
99          String dn = db.getEntryDn( id );
100         DerefAliasesEnum mode = node.getDerefAliases();
101         Object baseId = db.getEntryId( node.getBaseDn() );
102         boolean isDescendant = dn.endsWith( node.getBaseDn() );
103         
104         /*
105          * The candidate id could be any entry in the db.  If search 
106          * dereferencing is not enabled then we return the results of the 
107          * descendant test.
108          */
109         if ( ! mode.derefInSearching() )
110         {
111             return isDescendant;
112         }
113 
114         /*
115          * From here down alias dereferencing is enabled.  We determine if the
116          * candidate id is an alias, if so we reject it since aliases should
117          * not be returned.
118          */
119         Index idx = db.getAliasIndex();
120         if ( null != idx.reverseLookup( id ) )
121         {
122             return false;
123         }
124         
125         /*
126          * The candidate is NOT an alias at this point.  So if it is a 
127          * descendant we just return it since it is in normal subtree scope.
128          */
129         if ( isDescendant )
130         {
131             return true;
132         }
133         
134         /*
135          * At this point the candidate is not a descendant and it is not an 
136          * alias.  We need to check if the candidate is in extended subtree 
137          * scope by performing a lookup on the subtree alias index.  This index 
138          * stores a tuple mapping the baseId to the ids of objects brought 
139          * into subtree scope of the base by an alias: 
140          * 
141          * ( baseId, aliasedObjId )
142          * 
143          * If the candidate id is an object brought into subtree scope then 
144          * the lookup returns true accepting the candidate.  Otherwise the 
145          * candidate is rejected with a false return because it is not in scope.
146          */
147         idx = db.getSubAliasIndex();
148         return idx.hasValue( baseId, id );
149     }
150     
151     
152     /***
153      * Asserts whether or not a candidate has one level scope while taking
154      * alias dereferencing into account.
155      * 
156      * @param node the scope node containing the base and alias handling mode
157      * @param id the candidate to assert which can be any db entry's id 
158      * @return true if the candidate is within one level scope whether or not
159      * alias dereferencing is enabled.
160      * @throws NamingException if the index lookups fail.
161      */
162     public boolean assertOneLevelScope( final ScopeNode node, 
163         final BigInteger id ) throws NamingException
164     {
165         DerefAliasesEnum mode = node.getDerefAliases();
166         Object baseId = db.getEntryId( node.getBaseDn() );
167         Index idx = db.getHierarchyIndex();
168         boolean isChild = idx.hasValue( baseId, id );
169 
170         /*
171          * The candidate id could be any entry in the db.  If search 
172          * dereferencing is not enabled then we return the results of the child 
173          * test. 
174          */
175         if ( ! mode.derefInSearching() )
176         {
177             return isChild;
178         }
179 
180         /*
181          * From here down alias dereferencing is enabled.  We determine if the
182          * candidate id is an alias, if so we reject it since aliases should
183          * not be returned.
184          */
185         idx = db.getAliasIndex();
186         if ( null != idx.reverseLookup( id ) )
187         {
188             return false;
189         }
190         
191         /*
192          * The candidate is NOT an alias at this point.  So if it is a child we
193          * just return it since it is in normal one level scope.
194          */
195         if ( isChild )
196         {
197             return true;
198         }
199         
200         /*
201          * At this point the candidate is not a child and it is not an alias.
202          * We need to check if the candidate is in extended one level scope by 
203          * performing a lookup on the one level alias index.  This index stores
204          * a tuple mapping the baseId to the id of objects brought into the 
205          * one level scope of the base by an alias: ( baseId, aliasedObjId )
206          * If the candidate id is an object brought into one level scope then 
207          * the lookup returns true accepting the candidate.  Otherwise the 
208          * candidate is rejected with a false return because it is not in scope.
209          */
210         idx = db.getOneAliasIndex();
211         return idx.hasValue( baseId, id );
212     }
213 }