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.cursor;
21  
22  
23  import java.io.IOException;
24  
25  import org.apache.directory.api.ldap.model.constants.Loggers;
26  import org.apache.directory.api.ldap.model.cursor.Cursor;
27  import org.apache.directory.api.ldap.model.cursor.CursorException;
28  import org.apache.directory.api.ldap.model.exception.LdapException;
29  import org.apache.directory.server.core.api.partition.PartitionTxn;
30  import org.apache.directory.server.i18n.I18n;
31  import org.apache.directory.server.xdbm.AbstractIndexCursor;
32  import org.apache.directory.server.xdbm.IndexEntry;
33  import org.apache.directory.server.xdbm.ParentIdAndRdn;
34  import org.apache.directory.server.xdbm.Store;
35  import org.slf4j.Logger;
36  import org.slf4j.LoggerFactory;
37  
38  
39  /**
40   * A Cursor over entries satisfying one level scope constraints with alias
41   * dereferencing considerations when enabled during search.
42   *
43   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
44   */
45  public class ChildrenCursor extends AbstractIndexCursor<String>
46  {
47      /** A dedicated log for cursors */
48      private static final Logger LOG_CURSOR = LoggerFactory.getLogger( Loggers.CURSOR_LOG.getName() );
49  
50      /** Speedup for logs */
51      private static final boolean IS_DEBUG = LOG_CURSOR.isDebugEnabled();
52  
53      /** Error message for unsupported operations */
54      private static final String UNSUPPORTED_MSG = I18n.err( I18n.ERR_719 );
55  
56      /** A Cursor over the entries in the scope of the search base */
57      private final Cursor<IndexEntry<ParentIdAndRdn, String>> cursor;
58  
59      /** The Parent ID */
60      private String parentId;
61  
62      /** The prefetched element */
63      private IndexEntry<String, String> prefetched;
64  
65  
66      /**
67       * Creates a Cursor over entries satisfying one level scope criteria.
68       *
69       * @param partitionTxn The transaction to use
70       * @param db the entry store
71       * @param parentId The parent ID
72       * @param cursor The wrapped cursor
73       */
74      public ChildrenCursor( PartitionTxn partitionTxn, Store db, String parentId, 
75              Cursor<IndexEntry<ParentIdAndRdn, String>> cursor )
76      {
77          this.parentId = parentId;
78          this.cursor = cursor;
79          this.partitionTxn = partitionTxn;
80  
81          if ( IS_DEBUG )
82          {
83              LOG_CURSOR.debug( "Creating ChildrenCursor {}", this );
84          }
85      }
86  
87  
88      /**
89       * {@inheritDoc}
90       */
91      protected String getUnsupportedMessage()
92      {
93          return UNSUPPORTED_MSG;
94      }
95  
96  
97      /**
98       * {@inheritDoc}
99       */
100     public void beforeFirst() throws LdapException, CursorException
101     {
102         checkNotClosed();
103         setAvailable( false );
104     }
105 
106 
107     /**
108      * {@inheritDoc}
109      */
110     public void afterLast() throws LdapException, CursorException
111     {
112         throw new UnsupportedOperationException( getUnsupportedMessage() );
113     }
114 
115 
116     /**
117      * {@inheritDoc}
118      */
119     public boolean first() throws LdapException, CursorException
120     {
121         beforeFirst();
122 
123         return next();
124     }
125 
126 
127     /**
128      * {@inheritDoc}
129      */
130     public boolean last() throws LdapException, CursorException
131     {
132         throw new UnsupportedOperationException( getUnsupportedMessage() );
133     }
134 
135 
136     /**
137      * {@inheritDoc}
138      */
139     @Override
140     public boolean previous() throws LdapException, CursorException
141     {
142         checkNotClosed();
143 
144         boolean hasPrevious = cursor.previous();
145 
146         if ( hasPrevious )
147         {
148             IndexEntry entry = cursor.get();
149 
150             if ( ( ( ParentIdAndRdn ) entry.getTuple().getKey() ).getParentId().equals( parentId ) )
151             {
152                 prefetched = entry;
153                 return true;
154             }
155         }
156 
157         return false;
158     }
159 
160 
161     /**
162      * {@inheritDoc}
163      */
164     @Override
165     public boolean next() throws LdapException, CursorException
166     {
167         checkNotClosed();
168 
169         boolean hasNext = cursor.next();
170 
171         if ( hasNext )
172         {
173             IndexEntry cursorEntry = cursor.get();
174             IndexEntry<String, String> entry = new IndexEntry();
175             entry.setId( ( String ) cursorEntry.getId() );
176             entry.setKey( ( ( ParentIdAndRdn ) cursorEntry.getTuple().getKey() ).getParentId() );
177 
178             if ( entry.getKey().equals( parentId ) )
179             {
180                 prefetched = entry;
181                 return true;
182             }
183         }
184 
185         return false;
186     }
187 
188 
189     /**
190      * {@inheritDoc}
191      */
192     public IndexEntry<String, String> get() throws CursorException
193     {
194         checkNotClosed();
195 
196         return prefetched;
197     }
198 
199 
200     /**
201      * {@inheritDoc}
202      */
203     @Override
204     public void close() throws IOException
205     {
206         if ( IS_DEBUG )
207         {
208             LOG_CURSOR.debug( "Closing ChildrenCursor {}", this );
209         }
210 
211         cursor.close();
212 
213         super.close();
214     }
215 
216 
217     /**
218      * {@inheritDoc}
219      */
220     @Override
221     public void close( Exception cause ) throws IOException
222     {
223         if ( IS_DEBUG )
224         {
225             LOG_CURSOR.debug( "Closing ChildrenCursor {}", this );
226         }
227 
228         cursor.close( cause );
229 
230         super.close( cause );
231     }
232 
233 
234     /**
235      * @see Object#toString()
236      */
237     @Override
238     public String toString( String tabs )
239     {
240         StringBuilder sb = new StringBuilder();
241 
242         sb.append( tabs ).append( "ChildrenCursor (" );
243 
244         if ( available() )
245         {
246             sb.append( "available)" );
247         }
248         else
249         {
250             sb.append( "absent)" );
251         }
252 
253         sb.append( "#parent<" ).append( parentId ).append( "> :\n" );
254 
255         sb.append( cursor.toString( tabs + "  " ) );
256 
257         return sb.toString();
258     }
259 
260 
261     /**
262      * @see Object#toString()
263      */
264     public String toString()
265     {
266         return toString( "" );
267     }
268 }