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.evaluator;
21  
22  
23  import org.apache.directory.api.ldap.model.entry.Entry;
24  import org.apache.directory.api.ldap.model.exception.LdapException;
25  import org.apache.directory.api.ldap.model.filter.ScopeNode;
26  import org.apache.directory.api.ldap.model.message.SearchScope;
27  import org.apache.directory.server.core.api.partition.PartitionTxn;
28  import org.apache.directory.server.i18n.I18n;
29  import org.apache.directory.server.xdbm.IndexEntry;
30  import org.apache.directory.server.xdbm.ParentIdAndRdn;
31  import org.apache.directory.server.xdbm.Store;
32  import org.apache.directory.server.xdbm.search.Evaluator;
33  
34  
35  /**
36   * Evaluates one level scope assertions on candidates using an entry database.
37   * 
38   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
39   */
40  public class OneLevelScopeEvaluator<E> implements Evaluator<ScopeNode>
41  {
42      /** The ScopeNode containing initial search scope constraints */
43      private final ScopeNode node;
44  
45      /** The entry identifier of the scope base */
46      private final String baseId;
47  
48      /** True if the scope requires alias dereferencing while searching */
49      private final boolean dereferencing;
50  
51      /** the entry db storing entries */
52      private final Store db;
53  
54  
55      /**
56       * Creates a one level scope node Evaluator for search expressions.
57       *
58       * @param node the scope node
59       * @param db the database used to evaluate scope node
60       */
61      public OneLevelScopeEvaluator( Store db, ScopeNode node )
62      {
63          this.node = node;
64  
65          if ( node.getScope() != SearchScope.ONELEVEL )
66          {
67              throw new IllegalStateException( I18n.err( I18n.ERR_720 ) );
68          }
69  
70          this.db = db;
71          baseId = node.getBaseId();
72          dereferencing = node.getDerefAliases().isDerefInSearching() || node.getDerefAliases().isDerefAlways();
73      }
74  
75  
76      /**
77       * Asserts whether or not a candidate has one level scope while taking
78       * alias dereferencing into account.
79       *
80       * TODO - terribly inefficient - would benefit from exposing the id of an
81       * entry within the Entry
82       *
83       * {@inheritDoc}
84       */
85      public boolean evaluate( Entry candidate ) throws LdapException
86      {
87          throw new UnsupportedOperationException( I18n.err( I18n.ERR_721 ) );
88      }
89  
90  
91      /**
92       * {@inheritDoc}
93       */
94      @Override
95      public boolean evaluate( PartitionTxn partitionTxn, IndexEntry<?, String> indexEntry ) throws LdapException
96      {
97          ParentIdAndRdn parent = db.getRdnIndex().reverseLookup( partitionTxn, indexEntry.getId() );
98          boolean isChild = parent.getParentId().equals( baseId );
99          Entry entry = indexEntry.getEntry();
100 
101         // Fetch the entry
102         if ( null == entry )
103         {
104             entry = db.fetch( partitionTxn, indexEntry.getId() );
105 
106             if ( null == entry )
107             {
108                 // The entry is not anymore present : get out
109                 return false;
110             }
111 
112             indexEntry.setEntry( entry );
113         }
114 
115         /*
116          * The candidate id could be any entry in the db.  If search
117          * dereferencing is not enabled then we return the results of the child
118          * test.
119          */
120         if ( !dereferencing )
121         {
122             return isChild;
123         }
124 
125         /*
126          * From here down alias dereferencing is enabled.  We determine if the
127          * candidate id is an alias, if so we reject it since aliases should
128          * not be returned.
129          */
130         if ( null != db.getAliasIndex().reverseLookup( partitionTxn, indexEntry.getId() ) )
131         {
132             return false;
133         }
134 
135         /*
136          * The candidate is NOT an alias at this point.  So if it is a child we
137          * just return true since it is in normal one level scope.
138          */
139         if ( isChild )
140         {
141             return true;
142         }
143 
144         /*
145          * At this point the candidate is not a child and it is not an alias.
146          * We need to check if the candidate is in extended one level scope by
147          * performing a lookup on the one level alias index.  This index stores
148          * a tuple mapping the baseId to the id of objects brought into the
149          * one level scope of the base by an alias: ( baseId, aliasedObjId )
150          * If the candidate id is an object brought into one level scope then
151          * the lookup returns true accepting the candidate.  Otherwise the
152          * candidate is rejected with a false return because it is not in scope.
153          */
154         return db.getOneAliasIndex().forward( partitionTxn, baseId, indexEntry.getId() );
155     }
156 
157 
158     public ScopeNode getExpression()
159     {
160         return node;
161     }
162 
163 
164     /**
165      * Gets the id of the search base associated with the ScopeNode expression.
166      *
167      * @return identifier of the search base
168      */
169     public String getBaseId()
170     {
171         return baseId;
172     }
173 
174 
175     /**
176      * Gets whether or not dereferencing is enabled for this evaluator.
177      *
178      * @return true if dereferencing is enabled, false otherwise
179      */
180     public boolean isDereferencing()
181     {
182         return dereferencing;
183     }
184 
185 
186     /**
187      * @see Object#toString()
188      */
189     public String toString( String tabs )
190     {
191         StringBuilder sb = new StringBuilder();
192 
193         sb.append( tabs ).append( "OneLevelScopEvaluator : " ).append( node ).append( "\n" );
194 
195         return sb.toString();
196     }
197 
198 
199     /**
200      * @see Object#toString()
201      */
202     public String toString()
203     {
204         return toString( "" );
205     }
206 }