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,v 1.3 2003/10/15 01:59:46 akarasulu Exp $
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.db;
28  
29  
30  import org.apache.ldap.common.filter.ExprNode;
31  import org.apache.ldap.common.filter.ScopeNode;
32  import org.apache.ldap.common.message.DerefAliasesEnum;
33  
34  import javax.naming.NamingException;
35  import javax.naming.directory.SearchControls;
36  import java.math.BigInteger;
37  
38  
39  /***
40   * Evaluates ScopeNode assertions on candidates using a database.
41   * 
42   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
43   * @version $Rev: 164288 $
44   */
45  public class ScopeEvaluator implements Evaluator
46  {
47      /*** Database used to evaluate scope with */
48      private Database db;
49  
50  
51      /***
52       * Creates a scope node evaluator for search expressions.
53       *
54       * @param db the database used to evaluate scope node
55       */
56      public ScopeEvaluator( Database db )
57      {
58          this.db = db;
59      }
60  
61  
62      /***
63       * @see org.apache.ldap.server.db.Evaluator#evaluate(ExprNode, org.apache.ldap.server.db.IndexRecord)
64       */
65      public boolean evaluate( ExprNode node, IndexRecord record )
66          throws NamingException
67      {
68          ScopeNode snode = ( ScopeNode ) node;
69          
70          switch( snode.getScope() )
71          {
72          case( SearchControls.OBJECT_SCOPE ):
73              String dn = db.getEntryDn( record.getEntryId() );
74              return dn.equals( snode.getBaseDn() );
75          case( SearchControls.ONELEVEL_SCOPE ):
76              return assertOneLevelScope( snode, record.getEntryId() );
77          case( SearchControls.SUBTREE_SCOPE ):
78              return assertSubtreeScope( snode, record.getEntryId() );
79          default:
80              throw new NamingException( "Unrecognized search scope!" );
81          }
82      }
83      
84      
85      /***
86       * Asserts whether or not a candidate has one level scope while taking
87       * alias dereferencing into account.
88       * 
89       * @param node the scope node containing the base and alias handling mode
90       * @param id the candidate to assert which can be any db entry's id
91       * @return true if the candidate is within one level scope whether or not
92       * alias dereferencing is enabled.
93       * @throws NamingException if the index lookups fail.
94       */
95      public boolean assertSubtreeScope( final ScopeNode node, 
96          final BigInteger id ) throws NamingException
97      {
98          String dn = db.getEntryDn( id );
99          DerefAliasesEnum mode = node.getDerefAliases();
100         Object baseId = db.getEntryId( node.getBaseDn() );
101         boolean isDescendant = dn.endsWith( node.getBaseDn() );
102         
103         /*
104          * The candidate id could be any entry in the db.  If search 
105          * dereferencing is not enabled then we return the results of the 
106          * descendant test.
107          */
108         if ( ! mode.derefInSearching() )
109         {
110             return isDescendant;
111         }
112 
113         /*
114          * From here down alias dereferencing is enabled.  We determine if the
115          * candidate id is an alias, if so we reject it since aliases should
116          * not be returned.
117          */
118         Index idx = db.getAliasIndex();
119         if ( null != idx.reverseLookup( id ) )
120         {
121             return false;
122         }
123         
124         /*
125          * The candidate is NOT an alias at this point.  So if it is a 
126          * descendant we just return it since it is in normal subtree scope.
127          */
128         if ( isDescendant )
129         {
130             return true;
131         }
132         
133         /*
134          * At this point the candidate is not a descendant and it is not an 
135          * alias.  We need to check if the candidate is in extended subtree 
136          * scope by performing a lookup on the subtree alias index.  This index 
137          * stores a tuple mapping the baseId to the ids of objects brought 
138          * into subtree scope of the base by an alias: 
139          * 
140          * ( baseId, aliasedObjId )
141          * 
142          * If the candidate id is an object brought into subtree scope then 
143          * the lookup returns true accepting the candidate.  Otherwise the 
144          * candidate is rejected with a false return because it is not in scope.
145          */
146         idx = db.getSubAliasIndex();
147         return idx.hasValue( baseId, id );
148     }
149     
150     
151     /***
152      * Asserts whether or not a candidate has one level scope while taking
153      * alias dereferencing into account.
154      * 
155      * @param node the scope node containing the base and alias handling mode
156      * @param id the candidate to assert which can be any db entry's id 
157      * @return true if the candidate is within one level scope whether or not
158      * alias dereferencing is enabled.
159      * @throws NamingException if the index lookups fail.
160      */
161     public boolean assertOneLevelScope( final ScopeNode node, 
162         final BigInteger id ) throws NamingException
163     {
164         DerefAliasesEnum mode = node.getDerefAliases();
165         Object baseId = db.getEntryId( node.getBaseDn() );
166         Index idx = db.getHierarchyIndex();
167         boolean isChild = idx.hasValue( baseId, id );
168 
169         /*
170          * The candidate id could be any entry in the db.  If search 
171          * dereferencing is not enabled then we return the results of the child 
172          * test. 
173          */
174         if ( ! mode.derefInSearching() )
175         {
176             return isChild;
177         }
178 
179         /*
180          * From here down alias dereferencing is enabled.  We determine if the
181          * candidate id is an alias, if so we reject it since aliases should
182          * not be returned.
183          */
184         idx = db.getAliasIndex();
185         if ( null != idx.reverseLookup( id ) )
186         {
187             return false;
188         }
189         
190         /*
191          * The candidate is NOT an alias at this point.  So if it is a child we
192          * just return it since it is in normal one level scope.
193          */
194         if ( isChild )
195         {
196             return true;
197         }
198         
199         /*
200          * At this point the candidate is not a child and it is not an alias.
201          * We need to check if the candidate is in extended one level scope by 
202          * performing a lookup on the one level alias index.  This index stores
203          * a tuple mapping the baseId to the id of objects brought into the 
204          * one level scope of the base by an alias: ( baseId, aliasedObjId )
205          * If the candidate id is an object brought into one level scope then 
206          * the lookup returns true accepting the candidate.  Otherwise the 
207          * candidate is rejected with a false return because it is not in scope.
208          */
209         idx = db.getOneAliasIndex();
210         return idx.hasValue( baseId, id );
211     }
212 }