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  import static org.junit.Assert.*;
23  
24  import java.io.File;
25  import java.util.ArrayList;
26  import java.util.HashSet;
27  import java.util.List;
28  import java.util.Set;
29  
30  import org.apache.commons.io.FileUtils;
31  import org.apache.directory.server.core.cursor.Cursor;
32  import org.apache.directory.server.core.cursor.InvalidCursorPositionException;
33  import org.apache.directory.server.core.partition.impl.btree.jdbm.JdbmIndex;
34  import org.apache.directory.server.core.partition.impl.btree.jdbm.JdbmStore;
35  import org.apache.directory.server.core.entry.ServerEntry;
36  import org.apache.directory.server.schema.SerializableComparator;
37  import org.apache.directory.server.schema.bootstrap.ApacheSchema;
38  import org.apache.directory.server.schema.bootstrap.ApachemetaSchema;
39  import org.apache.directory.server.schema.bootstrap.BootstrapSchemaLoader;
40  import org.apache.directory.server.schema.bootstrap.CollectiveSchema;
41  import org.apache.directory.server.schema.bootstrap.CoreSchema;
42  import org.apache.directory.server.schema.bootstrap.Schema;
43  import org.apache.directory.server.schema.bootstrap.SystemSchema;
44  import org.apache.directory.server.schema.registries.AttributeTypeRegistry;
45  import org.apache.directory.server.schema.registries.DefaultOidRegistry;
46  import org.apache.directory.server.schema.registries.DefaultRegistries;
47  import org.apache.directory.server.schema.registries.OidRegistry;
48  import org.apache.directory.server.schema.registries.Registries;
49  import org.apache.directory.server.xdbm.ForwardIndexEntry;
50  import org.apache.directory.server.xdbm.IndexEntry;
51  import org.apache.directory.server.xdbm.Store;
52  import org.apache.directory.server.xdbm.IndexCursor;
53  import org.apache.directory.server.xdbm.search.Evaluator;
54  import org.apache.directory.server.xdbm.tools.StoreUtils;
55  import org.apache.directory.shared.ldap.constants.SchemaConstants;
56  import org.apache.directory.shared.ldap.filter.ExprNode;
57  import org.apache.directory.shared.ldap.filter.FilterParser;
58  import org.apache.directory.shared.ldap.filter.OrNode;
59  import org.apache.directory.shared.ldap.filter.SubstringNode;
60  import org.junit.*;
61  
62  import org.slf4j.Logger;
63  import org.slf4j.LoggerFactory;
64  
65  
66  /**
67   * 
68   * Test class for OrCursor.
69   * 
70   * Note: The results of OrCursor need not be symmetric, in the sense that the results obtained<br>
71   * in a particular order (say first to last ) need not be same as the results obtained in the<br> 
72   * order last to first, cause each underlying cursor of OrCursor will have elements in their own order.<br>
73   *
74   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
75   * @version $Rev$, $Date$
76   */
77  public class OrCursorTest
78  {
79      private static final Logger LOG = LoggerFactory.getLogger( OrCursorTest.class.getSimpleName() );
80  
81      File wkdir;
82      Store<ServerEntry> store;
83      Registries registries = null;
84      AttributeTypeRegistry attributeRegistry;
85      EvaluatorBuilder evaluatorBuilder;
86      CursorBuilder cursorBuilder;
87  
88      public OrCursorTest() throws Exception
89      {
90          // setup the standard registries
91          BootstrapSchemaLoader loader = new BootstrapSchemaLoader();
92          OidRegistry oidRegistry = new DefaultOidRegistry();
93          registries = new DefaultRegistries( "bootstrap", loader, oidRegistry );
94          SerializableComparator.setRegistry( registries.getComparatorRegistry() );
95  
96          // load essential bootstrap schemas
97          Set<Schema> bootstrapSchemas = new HashSet<Schema>();
98          bootstrapSchemas.add( new ApachemetaSchema() );
99          bootstrapSchemas.add( new ApacheSchema() );
100         bootstrapSchemas.add( new CoreSchema() );
101         bootstrapSchemas.add( new SystemSchema() );
102         bootstrapSchemas.add( new CollectiveSchema() );
103         loader.loadWithDependencies( bootstrapSchemas, registries );
104         attributeRegistry = registries.getAttributeTypeRegistry();
105     }
106 
107 
108     @Before
109     public void createStore() throws Exception
110     {
111         destryStore();
112 
113         // setup the working directory for the store
114         wkdir = File.createTempFile( getClass().getSimpleName(), "db" );
115         wkdir.delete();
116         wkdir = new File( wkdir.getParentFile(), getClass().getSimpleName() );
117         wkdir.mkdirs();
118 
119         // initialize the store
120         store = new JdbmStore<ServerEntry>();
121         store.setName( "example" );
122         store.setCacheSize( 10 );
123         store.setWorkingDirectory( wkdir );
124         store.setSyncOnWrite( false );
125 
126         store.addIndex( new JdbmIndex( SchemaConstants.OU_AT_OID ) );
127         store.addIndex( new JdbmIndex( SchemaConstants.CN_AT_OID ) );
128         StoreUtils.loadExampleData( store, registries );
129         
130         evaluatorBuilder = new EvaluatorBuilder( store, registries );
131         cursorBuilder = new CursorBuilder( store, evaluatorBuilder );
132         
133         LOG.debug( "Created new store" );
134     }
135 
136     
137     @After
138     public void destryStore() throws Exception
139     {
140         if ( store != null )
141         {
142             store.destroy();
143         }
144 
145         store = null;
146         if ( wkdir != null )
147         {
148             FileUtils.deleteDirectory( wkdir );
149         }
150 
151         wkdir = null;
152     }
153 
154     
155     @Test
156     @SuppressWarnings( "unchecked" )
157     public void testOrCursorUsingCursorBuilder() throws Exception
158     {
159         String filter = "(|(cn=J*)(sn=W*))";
160 
161         ExprNode exprNode = FilterParser.parse( filter );
162         
163         IndexCursor<?,ServerEntry> cursor = cursorBuilder.build( exprNode );
164 
165         cursor.afterLast();
166 
167         assertTrue( cursor.previous() );
168         assertTrue( cursor.available() );
169         assertEquals( 5, ( long ) cursor.get().getId() );
170         assertEquals( "walker", cursor.get().getValue() );
171         
172         assertTrue( cursor.previous() );
173         assertTrue( cursor.available() );
174         assertEquals( 11, ( long ) cursor.get().getId() );
175         assertEquals( "johnny walker", cursor.get().getValue() );
176         
177         assertTrue( cursor.previous() );
178         assertTrue( cursor.available() );
179         assertEquals( 10, ( long ) cursor.get().getId() );
180         assertEquals( "jim bean", cursor.get().getValue() );
181         
182         assertTrue( cursor.previous() );
183         assertTrue( cursor.available() );
184         assertEquals( 9, ( long ) cursor.get().getId() );
185         assertEquals( "jim bean", cursor.get().getValue() );
186         
187         assertTrue( cursor.previous() );
188         assertTrue( cursor.available() );
189         assertEquals( 6, ( long ) cursor.get().getId() );
190         assertEquals( "jim bean", cursor.get().getValue() );
191         
192         assertTrue( cursor.previous() );
193         assertTrue( cursor.available() );
194         assertEquals( 8, ( long ) cursor.get().getId() );
195         assertEquals( "jack daniels", cursor.get().getValue() );
196         
197         assertFalse( cursor.previous() );
198         assertFalse( cursor.available() );
199         
200         cursor.beforeFirst();
201         
202         assertTrue( cursor.next() );
203         assertTrue( cursor.available() );
204         assertEquals( 8, ( long ) cursor.get().getId() );
205         assertEquals( "jack daniels", cursor.get().getValue() );
206         
207         assertTrue( cursor.next() );
208         assertTrue( cursor.available() );
209         assertEquals( 6, ( long ) cursor.get().getId() );
210         assertEquals( "jim bean", cursor.get().getValue() );
211         
212         assertTrue( cursor.next() );
213         assertTrue( cursor.available() );
214         assertEquals( 9, ( long ) cursor.get().getId() );
215         assertEquals( "jim bean", cursor.get().getValue() );
216         
217         assertTrue( cursor.next() );
218         assertTrue( cursor.available() );
219         assertEquals( 10, ( long ) cursor.get().getId() );
220         assertEquals( "jim bean", cursor.get().getValue() );
221         
222         assertTrue( cursor.next() );
223         assertTrue( cursor.available() );
224         assertEquals( 11, ( long ) cursor.get().getId() );
225         assertEquals( "johnny walker", cursor.get().getValue() );
226         
227         assertTrue( cursor.next() );
228         assertTrue( cursor.available() );
229         assertEquals( 5, ( long ) cursor.get().getId() );
230         assertEquals( "walker", cursor.get().getValue() );
231         
232         assertFalse( cursor.next() );
233         assertFalse( cursor.available() );
234         
235         cursor.close();
236         assertTrue( cursor.isClosed() );
237     }
238     
239     
240     @Test( expected = InvalidCursorPositionException.class )
241     @SuppressWarnings( "unchecked" )
242     public void testOrCursor() throws Exception
243     {
244         List<Evaluator<? extends ExprNode,ServerEntry>> evaluators = new ArrayList<Evaluator<? extends ExprNode,ServerEntry>>();
245         List<Cursor<IndexEntry<?,ServerEntry>>> cursors = new ArrayList<Cursor<IndexEntry<?,ServerEntry>>>();
246         Evaluator<? extends ExprNode, ServerEntry> eval;
247         Cursor<IndexEntry<?,ServerEntry>> cursor;
248         
249         OrNode orNode = new OrNode();
250 
251         ExprNode exprNode = new SubstringNode( "cn", "J", null );
252         eval = new SubstringEvaluator( ( SubstringNode ) exprNode, store, registries );
253         Cursor subStrCursor1 = new SubstringCursor( store, ( SubstringEvaluator ) eval );
254         cursors.add( subStrCursor1 );
255         evaluators.add( eval );  
256         orNode.addNode( exprNode );
257         
258         try
259         {
260             new OrCursor( cursors, evaluators );
261             fail( "should throw IllegalArgumentException" );
262         }
263         catch( IllegalArgumentException ie ){ }
264         
265         exprNode = new SubstringNode( "sn", "W", null );
266         eval = new SubstringEvaluator( ( SubstringNode ) exprNode, store, registries );
267         evaluators.add( eval );
268         Cursor subStrCursor2 = new SubstringCursor( store, ( SubstringEvaluator ) eval );
269         cursors.add( subStrCursor2 );
270         
271         orNode.addNode( exprNode );
272         
273         cursor =  new OrCursor( cursors, evaluators );
274         
275         cursor.beforeFirst();
276         assertFalse( cursor.available() );
277         
278         // from first
279         assertTrue( cursor.first() );
280         assertTrue( cursor.available() );
281         assertEquals( 8, ( long ) cursor.get().getId() );
282         assertEquals( "jack daniels", cursor.get().getValue() );
283         
284         assertTrue( cursor.next() );
285         assertTrue( cursor.available() );
286         assertEquals( 6, ( long ) cursor.get().getId() );
287         assertEquals( "jim bean", cursor.get().getValue() );
288         
289         assertTrue( cursor.next() );
290         assertTrue( cursor.available() );
291         assertEquals( 9, ( long ) cursor.get().getId() );
292         assertEquals( "jim bean", cursor.get().getValue() );
293         
294         assertTrue( cursor.next() );
295         assertTrue( cursor.available() );
296         assertEquals( 10, ( long ) cursor.get().getId() );
297         assertEquals( "jim bean", cursor.get().getValue() );
298         
299         assertTrue( cursor.next() );
300         assertTrue( cursor.available() );
301         assertEquals( 5, ( long ) cursor.get().getId() );
302         assertEquals( "walker", cursor.get().getValue() );
303         
304         assertTrue( cursor.next() );
305         assertTrue( cursor.available() );
306         assertEquals( 11, ( long ) cursor.get().getId() );
307         assertEquals( "johnny walker", cursor.get().getValue() );
308 
309         assertFalse( cursor.next() );
310         assertFalse( cursor.available() );
311 
312         // from last        
313         cursor.afterLast();
314         assertFalse( cursor.available() );
315         
316         assertTrue( cursor.last() );
317         assertTrue( cursor.available() );
318         assertEquals( 11, ( long ) cursor.get().getId() );
319         assertEquals( "johnny walker", cursor.get().getValue() );
320         
321         assertTrue( cursor.previous() );
322         assertTrue( cursor.available() );
323         assertEquals( 5, ( long ) cursor.get().getId() );
324         assertEquals( "walker", cursor.get().getValue() );
325         
326         assertTrue( cursor.previous() );
327         assertTrue( cursor.available() );
328         assertEquals( 10, ( long ) cursor.get().getId() );
329         assertEquals( "jim bean", cursor.get().getValue() );
330         
331         assertTrue( cursor.previous() );
332         assertTrue( cursor.available() );
333         assertEquals( 9, ( long ) cursor.get().getId() );
334         assertEquals( "jim bean", cursor.get().getValue() );
335         
336         assertTrue( cursor.previous() );
337         assertTrue( cursor.available() );
338         assertEquals( 6, ( long ) cursor.get().getId() );
339         assertEquals( "jim bean", cursor.get().getValue() );
340         
341         assertTrue( cursor.previous() );
342         assertTrue( cursor.available() );
343         assertEquals( 8, ( long ) cursor.get().getId() );
344         assertEquals( "jack daniels", cursor.get().getValue() );
345         
346         assertFalse( cursor.previous() );
347         assertFalse( cursor.available() );
348         
349         assertTrue( cursor.isElementReused() );
350         
351         try
352         {
353             cursor.after( new ForwardIndexEntry() );
354             fail( "should fail with UnsupportedOperationException " );
355         }
356         catch( UnsupportedOperationException uoe ) {}
357         
358         try
359         {
360             cursor.before( new ForwardIndexEntry() );
361             fail( "should fail with UnsupportedOperationException " );
362         }
363         catch( UnsupportedOperationException uoe ) {}
364         
365         cursor.get();
366     }
367 
368 }