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.core.schema;
21  
22  
23  import jdbm.helper.IntegerComparator;
24  import org.apache.directory.server.core.DirectoryService;
25  import org.apache.directory.server.core.entry.ServerEntry;
26  import org.apache.directory.server.core.entry.ServerEntryUtils;
27  import org.apache.directory.server.core.integ.CiRunner;
28  import static org.apache.directory.server.core.integ.IntegrationUtils.getSchemaContext;
29  import static org.apache.directory.server.core.integ.IntegrationUtils.getRootContext;
30  import static org.apache.directory.server.core.integ.IntegrationUtils.getSystemContext;
31  import org.apache.directory.shared.ldap.exception.LdapNameAlreadyBoundException;
32  import org.apache.directory.shared.ldap.exception.LdapOperationNotSupportedException;
33  import org.apache.directory.shared.ldap.message.ResultCodeEnum;
34  import org.apache.directory.shared.ldap.name.LdapDN;
35  import org.apache.directory.shared.ldap.schema.AttributeType;
36  import org.apache.directory.shared.ldap.schema.DeepTrimNormalizer;
37  import org.apache.directory.shared.ldap.schema.syntax.AcceptAllSyntaxChecker;
38  import org.apache.directory.shared.ldap.schema.syntax.AttributeTypeDescription;
39  import org.apache.directory.shared.ldap.schema.syntax.ComparatorDescription;
40  import org.apache.directory.shared.ldap.schema.syntax.LdapSyntaxDescription;
41  import org.apache.directory.shared.ldap.schema.syntax.MatchingRuleDescription;
42  import org.apache.directory.shared.ldap.schema.syntax.NormalizerDescription;
43  import org.apache.directory.shared.ldap.schema.syntax.ObjectClassDescription;
44  import org.apache.directory.shared.ldap.schema.syntax.SyntaxChecker;
45  import org.apache.directory.shared.ldap.schema.syntax.SyntaxCheckerDescription;
46  import org.apache.directory.shared.ldap.schema.syntax.parser.AttributeTypeDescriptionSchemaParser;
47  import org.apache.directory.shared.ldap.schema.syntax.parser.ComparatorDescriptionSchemaParser;
48  import org.apache.directory.shared.ldap.schema.syntax.parser.LdapSyntaxDescriptionSchemaParser;
49  import org.apache.directory.shared.ldap.schema.syntax.parser.MatchingRuleDescriptionSchemaParser;
50  import org.apache.directory.shared.ldap.schema.syntax.parser.NormalizerDescriptionSchemaParser;
51  import org.apache.directory.shared.ldap.schema.syntax.parser.ObjectClassDescriptionSchemaParser;
52  import org.apache.directory.shared.ldap.schema.syntax.parser.SyntaxCheckerDescriptionSchemaParser;
53  import org.apache.directory.shared.ldap.util.Base64;
54  import org.apache.directory.shared.ldap.util.DateUtils;
55  import static org.junit.Assert.assertEquals;
56  import static org.junit.Assert.fail;
57  import static org.junit.Assert.assertNull;
58  import static org.junit.Assert.assertTrue;
59  import static org.junit.Assert.assertFalse;
60  import static org.junit.Assert.assertNotNull;
61  import org.junit.Ignore;
62  import org.junit.Test;
63  import org.junit.runner.RunWith;
64  
65  import javax.naming.Context;
66  import javax.naming.NamingEnumeration;
67  import javax.naming.NamingException;
68  import javax.naming.directory.Attribute;
69  import javax.naming.directory.Attributes;
70  import javax.naming.directory.BasicAttribute;
71  import javax.naming.directory.BasicAttributes;
72  import javax.naming.directory.DirContext;
73  import javax.naming.directory.InitialDirContext;
74  import javax.naming.directory.ModificationItem;
75  import javax.naming.directory.SearchControls;
76  import javax.naming.directory.SearchResult;
77  import javax.naming.ldap.LdapContext;
78  import java.io.ByteArrayOutputStream;
79  import java.io.IOException;
80  import java.io.InputStream;
81  import java.util.ArrayList;
82  import java.util.Calendar;
83  import java.util.Date;
84  import java.util.Hashtable;
85  import java.util.List;
86  import java.util.TimeZone;
87  
88  
89  /**
90   * An integration test class for performing various operations on the 
91   * subschemaSubentry as listed in the rootDSE.
92   *
93   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
94   * @version $Rev$
95   */
96  @RunWith ( CiRunner.class )
97  public class SubschemaSubentryIT 
98  {
99      private static final String GLOBAL_SUBSCHEMA_DN = "cn=schema";
100     private static final String SUBSCHEMA_SUBENTRY = "subschemaSubentry";
101     
102     private static final SyntaxCheckerDescriptionSchemaParser SYNTAX_CHECKER_DESCRIPTION_SCHEMA_PARSER =
103         new SyntaxCheckerDescriptionSchemaParser();
104     private static final AttributeTypeDescriptionSchemaParser ATTRIBUTE_TYPE_DESCRIPTION_SCHEMA_PARSER =
105         new AttributeTypeDescriptionSchemaParser();
106     private ComparatorDescriptionSchemaParser comparatorDescriptionSchemaParser =
107         new ComparatorDescriptionSchemaParser();
108     private NormalizerDescriptionSchemaParser normalizerDescriptionSchemaParser =
109         new NormalizerDescriptionSchemaParser();
110     private LdapSyntaxDescriptionSchemaParser ldapSyntaxDescriptionSchemaParser =
111         new LdapSyntaxDescriptionSchemaParser();
112     private MatchingRuleDescriptionSchemaParser matchingRuleDescriptionSchemaParser =
113         new MatchingRuleDescriptionSchemaParser();
114     private ObjectClassDescriptionSchemaParser objectClassDescriptionSchemaParser =
115         new ObjectClassDescriptionSchemaParser();
116 
117 
118     public static DirectoryService service;
119 
120     
121     /**
122      * Make sure the global subschemaSubentry is where it is expected to be.
123      *
124      * @throws NamingException on error
125      */
126     @Test
127     public void testRootDSEsSubschemaSubentry() throws Exception
128     {
129         assertEquals( GLOBAL_SUBSCHEMA_DN, getSubschemaSubentryDN() );
130         Attributes subschemaSubentryAttrs = getSubschemaSubentryAttributes();
131         assertNotNull( subschemaSubentryAttrs );
132     }
133     
134     
135     /**
136      * Tests the rejection of a delete operation on the SubschemaSubentry (SSSE).
137      *
138      * @throws NamingException on error
139      */
140     @Test
141     public void testSSSEDeleteRejection() throws Exception
142     {
143         try
144         {
145             getRootContext( service ).destroySubcontext( getSubschemaSubentryDN() );
146             fail( "You are not allowed to delete the global schema subentry" );
147         }
148         catch( LdapOperationNotSupportedException e )
149         {
150             assertEquals( ResultCodeEnum.UNWILLING_TO_PERFORM, e.getResultCode() );
151         }
152     }
153 
154 
155     /**
156      * Tests the rejection of an add operation for the SubschemaSubentry (SSSE).
157      *
158      * @throws NamingException on error
159      */
160     @Test
161     public void testSSSEAddRejection() throws Exception
162     {
163         try
164         {
165             getRootContext( service ).createSubcontext( getSubschemaSubentryDN(), getSubschemaSubentryAttributes() );
166             fail( "You are not allowed to add the global schema subentry which exists by default" );
167         }
168         catch( LdapNameAlreadyBoundException e )
169         {
170             assertEquals( ResultCodeEnum.ENTRY_ALREADY_EXISTS, e.getResultCode() );
171         }
172     }
173 
174 
175     /**
176      * Tests the rejection of rename (modifyDn) operation for the SubschemaSubentry (SSSE).
177      *
178      * @throws NamingException on error
179      */
180     @Test
181     public void testSSSERenameRejection() throws Exception
182     {
183         try
184         {
185             getRootContext( service ).rename( getSubschemaSubentryDN(), "cn=schema,ou=system" );
186             fail( "You are not allowed to rename the global schema subentry which is fixed" );
187         }
188         catch( LdapOperationNotSupportedException e )
189         {
190             assertEquals( ResultCodeEnum.UNWILLING_TO_PERFORM, e.getResultCode() );
191         }
192     }
193 
194 
195     /**
196      * Tests the rejection of move operation for the SubschemaSubentry (SSSE).
197      *
198      * @throws NamingException on error
199      */
200     @Test
201     public void testSSSEMoveRejection() throws Exception
202     {
203         try
204         {
205             getRootContext( service ).rename( getSubschemaSubentryDN(), "cn=blah,ou=schema" );
206             fail( "You are not allowed to move the global schema subentry which is fixed" );
207         }
208         catch( LdapOperationNotSupportedException e )
209         {
210             assertEquals( ResultCodeEnum.UNWILLING_TO_PERFORM, e.getResultCode() );
211         }
212 
213         try
214         {
215             getRootContext( service ).rename( getSubschemaSubentryDN(), "cn=schema,ou=schema" );
216             fail( "You are not allowed to move the global schema subentry which is fixed" );
217         }
218         catch( LdapOperationNotSupportedException e )
219         {
220             assertEquals( ResultCodeEnum.UNWILLING_TO_PERFORM, e.getResultCode() );
221         }
222     }
223     
224     
225     // -----------------------------------------------------------------------
226     // SyntaxChecker Tests
227     // -----------------------------------------------------------------------
228 
229     
230     private void checkSyntaxCheckerPresent( String oid, String schemaName, boolean isPresent ) throws Exception
231     {
232         // -------------------------------------------------------------------
233         // check first to see if it is present in the subschemaSubentry
234         // -------------------------------------------------------------------
235         
236         Attributes attrs = getSubschemaSubentryAttributes();
237         Attribute attrTypes = attrs.get( "syntaxCheckers" );
238         SyntaxCheckerDescription syntaxCheckerDescription = null; 
239         for ( int ii = 0; ii < attrTypes.size(); ii++ )
240         {
241             String desc = ( String ) attrTypes.get( ii );
242             if ( desc.indexOf( oid ) != -1 )
243             {
244                 syntaxCheckerDescription = SYNTAX_CHECKER_DESCRIPTION_SCHEMA_PARSER.parseSyntaxCheckerDescription( desc );
245                 break;
246             }
247         }
248      
249         if ( isPresent )
250         {
251             assertNotNull( syntaxCheckerDescription );
252             assertEquals( oid, syntaxCheckerDescription.getNumericOid() );
253         }
254         else
255         {
256             assertNull( syntaxCheckerDescription );
257         }
258 
259         // -------------------------------------------------------------------
260         // check next to see if it is present in the schema partition
261         // -------------------------------------------------------------------
262         
263         attrs = null;
264         
265         if ( isPresent )
266         {
267             attrs = getSchemaContext( service ).getAttributes( "m-oid=" + oid + ",ou=syntaxCheckers,cn=" + schemaName );
268             assertNotNull( attrs );
269             SchemaEntityFactory factory = new SchemaEntityFactory( service.getRegistries() );
270             
271             ServerEntry serverEntry = ServerEntryUtils.toServerEntry( attrs, LdapDN.EMPTY_LDAPDN, service.getRegistries() );
272 
273             SyntaxChecker syntaxChecker = factory.getSyntaxChecker( serverEntry, service.getRegistries() );
274             assertEquals( oid, syntaxChecker.getSyntaxOid() );
275         }
276         else
277         {
278             //noinspection EmptyCatchBlock
279             try
280             {
281                 attrs = getSchemaContext( service ).getAttributes( "m-oid=" + oid + ",ou=syntaxCheckers,cn=" + schemaName );
282                 fail( "should never get here" );
283             }
284             catch( NamingException e )
285             {
286             }
287             
288             assertNull( attrs );
289         }
290         
291         // -------------------------------------------------------------------
292         // check to see if it is present in the syntaxCheckerRegistry
293         // -------------------------------------------------------------------
294 
295         if ( isPresent )
296         {
297             assertTrue( service.getRegistries().getSyntaxCheckerRegistry().hasSyntaxChecker( oid ) );
298         }
299         else
300         {
301             assertFalse( service.getRegistries().getSyntaxCheckerRegistry().hasSyntaxChecker( oid ) );
302         }
303     }
304 
305 
306     /**
307      * Tests a number of modify add, remove and replace operation combinations for
308      * a syntaxChecker on the schema subentry.
309      *
310      * @throws Exception on error
311      */
312     @Test
313     public void testAddRemoveReplaceSyntaxCheckers() throws Exception
314     {
315         // 1st change
316         enableSchema( "nis" );
317         List<String> descriptions = new ArrayList<String>();
318         
319         // ( 1.3.6.1.4.1.18060.0.4.0.2.10000 DESC 'bogus desc' FQCN org.foo.Bar BYTECODE 14561234 )
320         descriptions.add( "( 1.3.6.1.4.1.18060.0.4.1.0.10000 DESC 'bogus desc' FQCN " 
321             + AcceptAllSyntaxChecker.class.getName() + " X-SCHEMA 'nis' )" );
322         descriptions.add( "( 1.3.6.1.4.1.18060.0.4.1.0.10001 DESC 'bogus desc' FQCN " 
323             + AcceptAllSyntaxChecker.class.getName() + " X-SCHEMA 'nis' )" );
324 
325         // -------------------------------------------------------------------
326         // add and check
327         // -------------------------------------------------------------------
328         
329         // 2nd change
330         modify( DirContext.ADD_ATTRIBUTE, descriptions, "syntaxCheckers" );
331         checkSyntaxCheckerPresent( "1.3.6.1.4.1.18060.0.4.1.0.10000", "nis", true );
332         checkSyntaxCheckerPresent( "1.3.6.1.4.1.18060.0.4.1.0.10001", "nis", true );
333 
334         // -------------------------------------------------------------------
335         // remove and check
336         // -------------------------------------------------------------------
337 
338         // 3rd change
339         modify( DirContext.REMOVE_ATTRIBUTE, descriptions, "syntaxCheckers" );
340         checkSyntaxCheckerPresent( "1.3.6.1.4.1.18060.0.4.1.0.10000", "nis", false );
341         checkSyntaxCheckerPresent( "1.3.6.1.4.1.18060.0.4.1.0.10001", "nis", false );
342         
343         // -------------------------------------------------------------------
344         // test failure to replace
345         // -------------------------------------------------------------------
346         
347         try
348         {
349             modify( DirContext.REPLACE_ATTRIBUTE, descriptions, "syntaxCheckers" );
350             fail( "modify REPLACE operations should not be allowed" );
351         }
352         catch ( LdapOperationNotSupportedException e )
353         {
354             assertEquals( ResultCodeEnum.UNWILLING_TO_PERFORM, e.getResultCode() );
355         }
356 
357         // -------------------------------------------------------------------
358         // check add with valid bytecode
359         // -------------------------------------------------------------------
360         
361         descriptions.clear();
362         descriptions.add( "( 1.3.6.1.4.1.18060.0.4.1.0.10002 DESC 'bogus desc' FQCN DummySyntaxChecker BYTECODE " 
363             +  getByteCode( "DummySyntaxChecker.bytecode" ) + " X-SCHEMA 'nis' )" );
364 
365         // 4th change
366         modify( DirContext.ADD_ATTRIBUTE, descriptions, "syntaxCheckers" );
367         checkSyntaxCheckerPresent( "1.3.6.1.4.1.18060.0.4.1.0.10002", "nis", true );
368 
369         // -------------------------------------------------------------------
370         // check remove
371         // -------------------------------------------------------------------
372 
373         // 5th change
374         modify( DirContext.REMOVE_ATTRIBUTE, descriptions, "syntaxCheckers" );
375         checkSyntaxCheckerPresent( "1.3.6.1.4.1.18060.0.4.1.0.10002", "nis", false );
376 
377         // -------------------------------------------------------------------
378         // check add no schema info
379         // -------------------------------------------------------------------
380         
381         descriptions.clear();
382         descriptions.add( "( 1.3.6.1.4.1.18060.0.4.1.0.10002 DESC 'bogus desc' FQCN DummySyntaxChecker BYTECODE " 
383             +  getByteCode( "DummySyntaxChecker.bytecode" ) + " )" );
384 
385         // 6th change
386         modify( DirContext.ADD_ATTRIBUTE, descriptions, "syntaxCheckers" );
387         checkSyntaxCheckerPresent( "1.3.6.1.4.1.18060.0.4.1.0.10002", "other", true );
388 
389         // after a total of 6 changes 
390         if ( service.getChangeLog().getLatest() != null )
391         {
392             assertEquals( service.getChangeLog().getLatest().getRevision() + 6,
393                     service.getChangeLog().getCurrentRevision() );
394         }
395     }
396     
397     
398     // -----------------------------------------------------------------------
399     // Comparator Tests
400     // -----------------------------------------------------------------------
401     
402     
403     private void checkComparatorPresent( String oid, String schemaName, boolean isPresent ) throws Exception
404     {
405         // -------------------------------------------------------------------
406         // check first to see if it is present in the subschemaSubentry
407         // -------------------------------------------------------------------
408         
409         Attributes attrs = getSubschemaSubentryAttributes();
410         Attribute attrTypes = attrs.get( "comparators" );
411         ComparatorDescription comparatorDescription = null; 
412         for ( int ii = 0; ii < attrTypes.size(); ii++ )
413         {
414             String desc = ( String ) attrTypes.get( ii );
415             if ( desc.indexOf( oid ) != -1 )
416             {
417                 comparatorDescription = comparatorDescriptionSchemaParser.parseComparatorDescription( desc );
418                 break;
419             }
420         }
421      
422         if ( isPresent )
423         {
424             assertNotNull( comparatorDescription );
425             assertEquals( oid, comparatorDescription.getNumericOid() );
426         }
427         else
428         {
429             assertNull( comparatorDescription );
430         }
431 
432         // -------------------------------------------------------------------
433         // check next to see if it is present in the schema partition
434         // -------------------------------------------------------------------
435         
436         attrs = null;
437 
438         LdapContext schemaRoot = getSchemaContext( service );
439         if ( isPresent )
440         {
441             attrs = schemaRoot.getAttributes( "m-oid=" + oid + ",ou=comparators,cn=" + schemaName );
442             assertNotNull( attrs );
443         }
444         else
445         {
446             //noinspection EmptyCatchBlock
447             try
448             {
449                 attrs = schemaRoot.getAttributes( "m-oid=" + oid + ",ou=comparators,cn=" + schemaName );
450                 fail( "should never get here" );
451             }
452             catch( NamingException e )
453             {
454             }
455             assertNull( attrs );
456         }
457         
458         // -------------------------------------------------------------------
459         // check to see if it is present in the comparatorRegistry
460         // -------------------------------------------------------------------
461 
462         if ( isPresent )
463         {
464             assertTrue( service.getRegistries().getComparatorRegistry().hasComparator( oid ) );
465         }
466         else
467         {
468             assertFalse( service.getRegistries().getComparatorRegistry().hasComparator( oid ) );
469         }
470     }
471     
472     
473     /**
474      * Tests a number of modify add, remove and replace operation combinations for
475      * comparators on the schema subentry.
476      *
477      * @throws Exception on error
478      */
479     @Test
480     public void testAddRemoveReplaceComparators() throws Exception
481     {
482         enableSchema( "nis" );
483         List<String> descriptions = new ArrayList<String>();
484         
485         descriptions.add( "( 1.3.6.1.4.1.18060.0.4.1.0.10000 DESC 'bogus desc' FQCN " 
486             + IntegerComparator.class.getName() + " X-SCHEMA 'nis' )" );
487         descriptions.add( "( 1.3.6.1.4.1.18060.0.4.1.0.10001 DESC 'bogus desc' FQCN " 
488             + IntegerComparator.class.getName() + " X-SCHEMA 'nis' )" );
489 
490         // -------------------------------------------------------------------
491         // add and check
492         // -------------------------------------------------------------------
493         
494         modify( DirContext.ADD_ATTRIBUTE, descriptions, "comparators" );
495         checkComparatorPresent( "1.3.6.1.4.1.18060.0.4.1.0.10000", "nis", true );
496         checkComparatorPresent( "1.3.6.1.4.1.18060.0.4.1.0.10001", "nis", true );
497 
498         // -------------------------------------------------------------------
499         // remove and check
500         // -------------------------------------------------------------------
501         
502         modify( DirContext.REMOVE_ATTRIBUTE, descriptions, "comparators" );
503         checkComparatorPresent( "1.3.6.1.4.1.18060.0.4.1.0.10000", "nis", false );
504         checkComparatorPresent( "1.3.6.1.4.1.18060.0.4.1.0.10001", "nis", false );
505         
506         // -------------------------------------------------------------------
507         // test failure to replace
508         // -------------------------------------------------------------------
509         
510         try
511         {
512             modify( DirContext.REPLACE_ATTRIBUTE, descriptions, "comparators" );
513             fail( "modify REPLACE operations should not be allowed" );
514         }
515         catch ( LdapOperationNotSupportedException e )
516         {
517             assertEquals( ResultCodeEnum.UNWILLING_TO_PERFORM, e.getResultCode() );
518         }
519 
520         // -------------------------------------------------------------------
521         // check add with valid bytecode
522         // -------------------------------------------------------------------
523         
524         descriptions.clear();
525         descriptions.add( "( 1.3.6.1.4.1.18060.0.4.1.0.10002 DESC 'bogus desc' FQCN DummyComparator BYTECODE " 
526             +  getByteCode( "DummyComparator.bytecode" ) + " X-SCHEMA 'nis' )" );
527 
528         modify( DirContext.ADD_ATTRIBUTE, descriptions, "comparators" );
529         checkComparatorPresent( "1.3.6.1.4.1.18060.0.4.1.0.10002", "nis", true );
530 
531         // -------------------------------------------------------------------
532         // check remove with valid bytecode
533         // -------------------------------------------------------------------
534         
535         modify( DirContext.REMOVE_ATTRIBUTE, descriptions, "comparators" );
536         checkComparatorPresent( "1.3.6.1.4.1.18060.0.4.1.0.10002", "nis", false );
537 
538         // -------------------------------------------------------------------
539         // check add no schema info
540         // -------------------------------------------------------------------
541         
542         descriptions.clear();
543         descriptions.add( "( 1.3.6.1.4.1.18060.0.4.1.0.10002 DESC 'bogus desc' FQCN DummyComparator BYTECODE " 
544             +  getByteCode( "DummyComparator.bytecode" ) + " )" );
545 
546         modify( DirContext.ADD_ATTRIBUTE, descriptions, "comparators" );
547         checkComparatorPresent( "1.3.6.1.4.1.18060.0.4.1.0.10002", "other", true );
548     }
549 
550     
551     // -----------------------------------------------------------------------
552     // Normalizer Tests
553     // -----------------------------------------------------------------------
554     
555     
556     private void checkNormalizerPresent( String oid, String schemaName, boolean isPresent ) throws Exception
557     {
558         // -------------------------------------------------------------------
559         // check first to see if it is present in the subschemaSubentry
560         // -------------------------------------------------------------------
561         
562         Attributes attrs = getSubschemaSubentryAttributes();
563         Attribute attrTypes = attrs.get( "normalizers" );
564         NormalizerDescription normalizerDescription = null; 
565         for ( int ii = 0; ii < attrTypes.size(); ii++ )
566         {
567             String desc = ( String ) attrTypes.get( ii );
568             if ( desc.indexOf( oid ) != -1 )
569             {
570                 normalizerDescription = normalizerDescriptionSchemaParser.parseNormalizerDescription( desc );
571                 break;
572             }
573         }
574      
575         if ( isPresent )
576         {
577             assertNotNull( normalizerDescription );
578             assertEquals( oid, normalizerDescription.getNumericOid() );
579         }
580         else
581         {
582             assertNull( normalizerDescription );
583         }
584 
585         // -------------------------------------------------------------------
586         // check next to see if it is present in the schema partition
587         // -------------------------------------------------------------------
588         
589         attrs = null;
590 
591         LdapContext schemaRoot = getSchemaContext( service );
592         if ( isPresent )
593         {
594             attrs = schemaRoot.getAttributes( "m-oid=" + oid + ",ou=normalizers,cn=" + schemaName );
595             assertNotNull( attrs );
596         }
597         else
598         {
599             //noinspection EmptyCatchBlock
600             try
601             {
602                 attrs = schemaRoot.getAttributes( "m-oid=" + oid + ",ou=normalizers,cn=" + schemaName );
603                 fail( "should never get here" );
604             }
605             catch( NamingException e )
606             {
607             }
608             assertNull( attrs );
609         }
610         
611         // -------------------------------------------------------------------
612         // check to see if it is present in the normalizerRegistry
613         // -------------------------------------------------------------------
614         
615         if ( isPresent ) 
616         { 
617             assertTrue( service.getRegistries().getNormalizerRegistry().hasNormalizer( oid ) );
618         }
619         else
620         {
621             assertFalse( service.getRegistries().getNormalizerRegistry().hasNormalizer( oid ) );
622         }
623     }
624     
625     
626     /**
627      * Tests a number of modify add, remove and replace operation combinations for
628      * normalizers on the schema subentry.
629      *
630      * @throws Exception on error
631      */
632     @Test
633     public void testAddRemoveReplaceNormalizers() throws Exception
634     {
635         enableSchema( "nis" );
636         List<String> descriptions = new ArrayList<String>();
637         
638         descriptions.add( "( 1.3.6.1.4.1.18060.0.4.1.0.10000 DESC 'bogus desc' FQCN " 
639             + DeepTrimNormalizer.class.getName() + " X-SCHEMA 'nis' )" );
640         descriptions.add( "( 1.3.6.1.4.1.18060.0.4.1.0.10001 DESC 'bogus desc' FQCN " 
641             + DeepTrimNormalizer.class.getName() + " X-SCHEMA 'nis' )" );
642 
643         // -------------------------------------------------------------------
644         // add and check
645         // -------------------------------------------------------------------
646         
647         modify( DirContext.ADD_ATTRIBUTE, descriptions, "normalizers" );
648         checkNormalizerPresent( "1.3.6.1.4.1.18060.0.4.1.0.10000", "nis", true );
649         checkNormalizerPresent( "1.3.6.1.4.1.18060.0.4.1.0.10001", "nis", true );
650 
651         // -------------------------------------------------------------------
652         // remove and check
653         // -------------------------------------------------------------------
654         
655         modify( DirContext.REMOVE_ATTRIBUTE, descriptions, "normalizers" );
656         checkNormalizerPresent( "1.3.6.1.4.1.18060.0.4.1.0.10000", "nis", false );
657         checkNormalizerPresent( "1.3.6.1.4.1.18060.0.4.1.0.10001", "nis", false );
658         
659         // -------------------------------------------------------------------
660         // test failure to replace
661         // -------------------------------------------------------------------
662         
663         try
664         {
665             modify( DirContext.REPLACE_ATTRIBUTE, descriptions, "normalizers" );
666             fail( "modify REPLACE operations should not be allowed" );
667         }
668         catch ( LdapOperationNotSupportedException e )
669         {
670             assertEquals( ResultCodeEnum.UNWILLING_TO_PERFORM, e.getResultCode() );
671         }
672 
673         // -------------------------------------------------------------------
674         // check add with valid bytecode
675         // -------------------------------------------------------------------
676         
677         descriptions.clear();
678         descriptions.add( "( 1.3.6.1.4.1.18060.0.4.1.0.10002 DESC 'bogus desc' FQCN DummyNormalizer BYTECODE " 
679             +  getByteCode( "DummyNormalizer.bytecode" ) + " X-SCHEMA 'nis' )" );
680 
681         modify( DirContext.ADD_ATTRIBUTE, descriptions, "normalizers" );
682         checkNormalizerPresent( "1.3.6.1.4.1.18060.0.4.1.0.10002", "nis", true );
683 
684         // -------------------------------------------------------------------
685         // check remove with valid bytecode
686         // -------------------------------------------------------------------
687         
688         modify( DirContext.REMOVE_ATTRIBUTE, descriptions, "normalizers" );
689         checkNormalizerPresent( "1.3.6.1.4.1.18060.0.4.1.0.10002", "nis", false );
690 
691         // -------------------------------------------------------------------
692         // check add no schema info
693         // -------------------------------------------------------------------
694         
695         descriptions.clear();
696         descriptions.add( "( 1.3.6.1.4.1.18060.0.4.1.0.10002 DESC 'bogus desc' FQCN DummyNormalizer BYTECODE " 
697             +  getByteCode( "DummyNormalizer.bytecode" ) + " )" );
698 
699         modify( DirContext.ADD_ATTRIBUTE, descriptions, "normalizers" );
700         checkNormalizerPresent( "1.3.6.1.4.1.18060.0.4.1.0.10002", "other", true );
701     }
702 
703     
704     // -----------------------------------------------------------------------
705     // Syntax Tests
706     // -----------------------------------------------------------------------
707     
708     
709     private void checkSyntaxPresent( String oid, String schemaName, boolean isPresent ) throws Exception
710     {
711         // -------------------------------------------------------------------
712         // check first to see if it is present in the subschemaSubentry
713         // -------------------------------------------------------------------
714         
715         Attributes attrs = getSubschemaSubentryAttributes();
716         Attribute attrTypes = attrs.get( "ldapSyntaxes" );
717         LdapSyntaxDescription syntaxDescription = null; 
718         for ( int ii = 0; ii < attrTypes.size(); ii++ )
719         {
720             String desc = ( String ) attrTypes.get( ii );
721             if ( desc.indexOf( oid ) != -1 )
722             {
723                 syntaxDescription = ldapSyntaxDescriptionSchemaParser.parseLdapSyntaxDescription( desc );
724                 break;
725             }
726         }
727      
728         if ( isPresent )
729         {
730             assertNotNull( syntaxDescription );
731             assertEquals( oid, syntaxDescription.getNumericOid() );
732         }
733         else
734         {
735             assertNull( syntaxDescription );
736         }
737 
738         // -------------------------------------------------------------------
739         // check next to see if it is present in the schema partition
740         // -------------------------------------------------------------------
741         
742         attrs = null;
743 
744         LdapContext schemaRoot = getSchemaContext( service );
745         if ( isPresent )
746         {
747             attrs = schemaRoot.getAttributes( "m-oid=" + oid + ",ou=syntaxes,cn=" + schemaName );
748             assertNotNull( attrs );
749         }
750         else
751         {
752             //noinspection EmptyCatchBlock
753             try
754             {
755                 attrs = schemaRoot.getAttributes( "m-oid=" + oid + ",ou=syntaxes,cn=" + schemaName );
756                 fail( "should never get here" );
757             }
758             catch( NamingException e )
759             {
760             }
761             assertNull( attrs );
762         }
763         
764         // -------------------------------------------------------------------
765         // check to see if it is present in the syntaxRegistry
766         // -------------------------------------------------------------------
767         
768         if ( isPresent ) 
769         { 
770             assertTrue( service.getRegistries().getSyntaxRegistry().hasSyntax( oid ) );
771         }
772         else
773         {
774             assertFalse( service.getRegistries().getSyntaxRegistry().hasSyntax( oid ) );
775         }
776     }
777     
778     
779     /**
780      * Tests a number of modify add, remove and replace operation combinations for
781      * syntaxes on the schema subentry.
782      *
783      * @throws Exception on error
784      */
785     @Test
786     public void testAddRemoveReplaceSyntaxes() throws Exception
787     {
788         enableSchema( "nis" );
789         List<String> descriptions = new ArrayList<String>();
790         
791         // -------------------------------------------------------------------
792         // add of syntaxes without their syntax checkers should fail
793         // -------------------------------------------------------------------
794         
795         descriptions.add( "( 1.3.6.1.4.1.18060.0.4.1.0.10000 DESC 'bogus desc' X-SCHEMA 'nis' )" );
796         descriptions.add( "( 1.3.6.1.4.1.18060.0.4.1.0.10001 DESC 'bogus desc' X-SCHEMA 'nis' )" );
797         
798         try
799         {
800             modify( DirContext.ADD_ATTRIBUTE, descriptions, "ldapSyntaxes" );
801             fail( "should not be able to add syntaxes without their syntaxCheckers" );
802         }
803         catch( LdapOperationNotSupportedException e )
804         {
805             assertEquals( ResultCodeEnum.UNWILLING_TO_PERFORM, e.getResultCode() );
806         }
807         
808         // none of the syntaxes should be present
809         checkSyntaxPresent( "1.3.6.1.4.1.18060.0.4.1.0.10000", "nis", false );
810         checkSyntaxPresent( "1.3.6.1.4.1.18060.0.4.1.0.10001", "nis", false );
811 
812         // -------------------------------------------------------------------
813         // first in order to add syntaxes we need their syntax checkers 
814         // -------------------------------------------------------------------
815 
816         descriptions.clear();
817         descriptions.add( "( 1.3.6.1.4.1.18060.0.4.1.0.10000 DESC 'bogus desc' FQCN " 
818             + AcceptAllSyntaxChecker.class.getName() + " X-SCHEMA 'nis' )" );
819         descriptions.add( "( 1.3.6.1.4.1.18060.0.4.1.0.10001 DESC 'bogus desc' FQCN " 
820             + AcceptAllSyntaxChecker.class.getName() + " X-SCHEMA 'nis' )" );
821         descriptions.add( "( 1.3.6.1.4.1.18060.0.4.1.0.10002 DESC 'bogus desc' FQCN " 
822             + AcceptAllSyntaxChecker.class.getName() + " X-SCHEMA 'nis' )" );
823 
824         modify( DirContext.ADD_ATTRIBUTE, descriptions, "syntaxCheckers" );
825         checkSyntaxCheckerPresent( "1.3.6.1.4.1.18060.0.4.1.0.10000", "nis", true );
826         checkSyntaxCheckerPresent( "1.3.6.1.4.1.18060.0.4.1.0.10001", "nis", true );
827         checkSyntaxCheckerPresent( "1.3.6.1.4.1.18060.0.4.1.0.10002", "nis", true );
828 
829         // -------------------------------------------------------------------
830         // add and check
831         // -------------------------------------------------------------------
832         
833         descriptions.clear();
834         descriptions.add( "( 1.3.6.1.4.1.18060.0.4.1.0.10000 DESC 'bogus desc' X-SCHEMA 'nis' )" );
835         descriptions.add( "( 1.3.6.1.4.1.18060.0.4.1.0.10001 DESC 'bogus desc' X-SCHEMA 'nis' )" );
836 
837         modify( DirContext.ADD_ATTRIBUTE, descriptions, "ldapSyntaxes" );
838         checkSyntaxPresent( "1.3.6.1.4.1.18060.0.4.1.0.10000", "nis", true );
839         checkSyntaxPresent( "1.3.6.1.4.1.18060.0.4.1.0.10001", "nis", true );
840 
841         // -------------------------------------------------------------------
842         // remove and check
843         // -------------------------------------------------------------------
844         
845         modify( DirContext.REMOVE_ATTRIBUTE, descriptions, "ldapSyntaxes" );
846         checkSyntaxPresent( "1.3.6.1.4.1.18060.0.4.1.0.10000", "nis", false );
847         checkSyntaxPresent( "1.3.6.1.4.1.18060.0.4.1.0.10001", "nis", false );
848         
849         // -------------------------------------------------------------------
850         // test failure to replace
851         // -------------------------------------------------------------------
852         
853         try
854         {
855             modify( DirContext.REPLACE_ATTRIBUTE, descriptions, "ldapSyntaxes" );
856             fail( "modify REPLACE operations should not be allowed" );
857         }
858         catch ( LdapOperationNotSupportedException e )
859         {
860             assertEquals( ResultCodeEnum.UNWILLING_TO_PERFORM, e.getResultCode() );
861         }
862 
863         // -------------------------------------------------------------------
864         // check add no schema info
865         // -------------------------------------------------------------------
866         
867         descriptions.clear();
868         descriptions.add( "( 1.3.6.1.4.1.18060.0.4.1.0.10002 DESC 'bogus desc' )" );
869         modify( DirContext.ADD_ATTRIBUTE, descriptions, "ldapSyntaxes" );
870         checkSyntaxPresent( "1.3.6.1.4.1.18060.0.4.1.0.10002", "other", true );
871     }
872     
873     
874     // -----------------------------------------------------------------------
875     // MatchingRule Tests
876     // -----------------------------------------------------------------------
877     
878     
879     private void checkMatchingRulePresent( String oid, String schemaName, boolean isPresent ) throws Exception
880     {
881         // -------------------------------------------------------------------
882         // check first to see if it is present in the subschemaSubentry
883         // -------------------------------------------------------------------
884         
885         Attributes attrs = getSubschemaSubentryAttributes();
886         Attribute attrTypes = attrs.get( "matchingRules" );
887         MatchingRuleDescription matchingRuleDescription = null; 
888         for ( int ii = 0; ii < attrTypes.size(); ii++ )
889         {
890             String desc = ( String ) attrTypes.get( ii );
891             if ( desc.indexOf( oid ) != -1 )
892             {
893                 matchingRuleDescription = matchingRuleDescriptionSchemaParser.parseMatchingRuleDescription( desc );
894                 break;
895             }
896         }
897      
898         if ( isPresent )
899         {
900             assertNotNull( matchingRuleDescription );
901             assertEquals( oid, matchingRuleDescription.getNumericOid() );
902         }
903         else
904         {
905             assertNull( matchingRuleDescription );
906         }
907 
908         // -------------------------------------------------------------------
909         // check next to see if it is present in the schema partition
910         // -------------------------------------------------------------------
911         
912         attrs = null;
913 
914         LdapContext schemaRoot = getSchemaContext( service );
915         if ( isPresent )
916         {
917             attrs = schemaRoot.getAttributes( "m-oid=" + oid + ",ou=matchingRules,cn=" + schemaName );
918             assertNotNull( attrs );
919         }
920         else
921         {
922             //noinspection EmptyCatchBlock
923             try
924             {
925                 attrs = schemaRoot.getAttributes( "m-oid=" + oid + ",ou=matchingRules,cn=" + schemaName );
926                 fail( "should never get here" );
927             }
928             catch( NamingException e )
929             {
930             }
931             assertNull( attrs );
932         }
933         
934         // -------------------------------------------------------------------
935         // check to see if it is present in the matchingRuleRegistry
936         // -------------------------------------------------------------------
937         
938         if ( isPresent ) 
939         { 
940             assertTrue( service.getRegistries().getMatchingRuleRegistry().hasMatchingRule( oid ) );
941         }
942         else
943         {
944             assertFalse( service.getRegistries().getMatchingRuleRegistry().hasMatchingRule( oid ) );
945         }
946     }
947     
948     
949     /**
950      * Tests a number of modify add, remove and replace operation combinations for
951      * matchingRules on the schema subentry.
952      *
953      * @throws Exception on error
954      */
955     @Test
956     public void testAddRemoveReplaceMatchingRules() throws Exception
957     {
958         enableSchema( "nis" );
959         List<String> descriptions = new ArrayList<String>();
960 
961         // -------------------------------------------------------------------
962         // test rejection with non-existant syntax
963         // -------------------------------------------------------------------
964         
965         descriptions.add( "( 1.3.6.1.4.1.18060.0.4.1.1.10000 DESC 'bogus desc' SYNTAX 1.2.3.4 X-SCHEMA 'nis' )" );
966         descriptions.add( "( 1.3.6.1.4.1.18060.0.4.1.1.10001 DESC 'bogus desc' SYNTAX 1.2.3.4 X-SCHEMA 'nis' )" );
967 
968         try
969         {
970             modify( DirContext.ADD_ATTRIBUTE, descriptions, "matchingRules" );
971             fail( "Cannot add matchingRule with bogus non-existant syntax" );
972         }
973         catch( LdapOperationNotSupportedException e )
974         {
975             assertEquals( ResultCodeEnum.UNWILLING_TO_PERFORM, e.getResultCode() );
976         }
977         
978         checkMatchingRulePresent( "1.3.6.1.4.1.18060.0.4.1.1.10000", "nis", false );
979         checkMatchingRulePresent( "1.3.6.1.4.1.18060.0.4.1.1.10001", "nis", false );
980 
981         // -------------------------------------------------------------------
982         // test add with existant syntax but no name and no desc
983         // -------------------------------------------------------------------
984 
985         descriptions.clear();
986         descriptions.add( "( 1.3.6.1.4.1.18060.0.4.1.1.10000 " +
987                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-SCHEMA 'nis' )" );
988         descriptions.add( "( 1.3.6.1.4.1.18060.0.4.1.1.10001 " +
989                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-SCHEMA 'nis' )" );
990         
991         modify( DirContext.ADD_ATTRIBUTE, descriptions, "matchingRules" );
992         
993         checkMatchingRulePresent( "1.3.6.1.4.1.18060.0.4.1.1.10000", "nis", true );
994         checkMatchingRulePresent( "1.3.6.1.4.1.18060.0.4.1.1.10001", "nis", true );
995 
996         // -------------------------------------------------------------------
997         // test add with existant syntax but no name 
998         // -------------------------------------------------------------------
999         
1000         // clear the matchingRules out now
1001         modify( DirContext.REMOVE_ATTRIBUTE, descriptions, "matchingRules" );
1002         checkMatchingRulePresent( "1.3.6.1.4.1.18060.0.4.1.1.10000", "nis", false );
1003         checkMatchingRulePresent( "1.3.6.1.4.1.18060.0.4.1.1.10001", "nis", false );
1004 
1005         descriptions.clear();
1006         descriptions.add( "( 1.3.6.1.4.1.18060.0.4.1.1.10000 DESC 'bogus desc' " +
1007                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-SCHEMA 'nis' )" );
1008         descriptions.add( "( 1.3.6.1.4.1.18060.0.4.1.1.10001 DESC 'bogus desc' " +
1009                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-SCHEMA 'nis' )" );
1010         
1011         modify( DirContext.ADD_ATTRIBUTE, descriptions, "matchingRules" );
1012         
1013         checkMatchingRulePresent( "1.3.6.1.4.1.18060.0.4.1.1.10000", "nis", true );
1014         checkMatchingRulePresent( "1.3.6.1.4.1.18060.0.4.1.1.10001", "nis", true );
1015 
1016         // -------------------------------------------------------------------
1017         // test add success with name
1018         // -------------------------------------------------------------------
1019         
1020         modify( DirContext.REMOVE_ATTRIBUTE, descriptions, "matchingRules" );
1021         checkMatchingRulePresent( "1.3.6.1.4.1.18060.0.4.1.1.10000", "nis", false );
1022         checkMatchingRulePresent( "1.3.6.1.4.1.18060.0.4.1.1.10001", "nis", false );
1023         
1024         descriptions.clear();
1025         descriptions.add( "( 1.3.6.1.4.1.18060.0.4.1.1.10000 NAME 'blah0' DESC 'bogus desc' " +
1026                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-SCHEMA 'nis' )" );
1027         descriptions.add( "( 1.3.6.1.4.1.18060.0.4.1.1.10001 NAME ( 'blah1' 'othername1' ) DESC 'bogus desc' " +
1028                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-SCHEMA 'nis' )" );
1029         
1030         modify( DirContext.ADD_ATTRIBUTE, descriptions, "matchingRules" );
1031         
1032         checkMatchingRulePresent( "1.3.6.1.4.1.18060.0.4.1.1.10000", "nis", true );
1033         checkMatchingRulePresent( "1.3.6.1.4.1.18060.0.4.1.1.10001", "nis", true );
1034 
1035         // -------------------------------------------------------------------
1036         // test add success full (with obsolete)
1037         // -------------------------------------------------------------------
1038         
1039         modify( DirContext.REMOVE_ATTRIBUTE, descriptions, "matchingRules" );
1040         checkMatchingRulePresent( "1.3.6.1.4.1.18060.0.4.1.1.10000", "nis", false );
1041         checkMatchingRulePresent( "1.3.6.1.4.1.18060.0.4.1.1.10001", "nis", false );
1042         
1043         descriptions.clear();
1044         descriptions.add( "( 1.3.6.1.4.1.18060.0.4.1.1.10000 NAME 'blah0' DESC 'bogus desc' " +
1045                 "OBSOLETE SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-SCHEMA 'nis' )" );
1046         descriptions.add( "( 1.3.6.1.4.1.18060.0.4.1.1.10001 NAME ( 'blah1' 'othername1' ) DESC 'bogus desc' " +
1047                 "OBSOLETE SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-SCHEMA 'nis' )" );
1048         
1049         modify( DirContext.ADD_ATTRIBUTE, descriptions, "matchingRules" );
1050         
1051         checkMatchingRulePresent( "1.3.6.1.4.1.18060.0.4.1.1.10000", "nis", true );
1052         checkMatchingRulePresent( "1.3.6.1.4.1.18060.0.4.1.1.10001", "nis", true );
1053 
1054         // -------------------------------------------------------------------
1055         // test failure to replace
1056         // -------------------------------------------------------------------
1057         
1058         modify( DirContext.REMOVE_ATTRIBUTE, descriptions, "matchingRules" );
1059         checkMatchingRulePresent( "1.3.6.1.4.1.18060.0.4.1.1.10000", "nis", false );
1060         checkMatchingRulePresent( "1.3.6.1.4.1.18060.0.4.1.1.10001", "nis", false );
1061         
1062         try
1063         {
1064             modify( DirContext.REPLACE_ATTRIBUTE, descriptions, "matchingRules" );
1065             fail( "modify REPLACE operations should not be allowed" );
1066         }
1067         catch ( LdapOperationNotSupportedException e )
1068         {
1069             assertEquals( ResultCodeEnum.UNWILLING_TO_PERFORM, e.getResultCode() );
1070         }
1071 
1072         // -------------------------------------------------------------------
1073         // check add no schema info
1074         // -------------------------------------------------------------------
1075         
1076         descriptions.clear();
1077         descriptions.add( "( 1.3.6.1.4.1.18060.0.4.1.1.10002 DESC 'bogus desc' " +
1078         "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )" );
1079         modify( DirContext.ADD_ATTRIBUTE, descriptions, "matchingRules" );
1080         checkMatchingRulePresent( "1.3.6.1.4.1.18060.0.4.1.1.10002", "other", true );
1081     }
1082 
1083     
1084     // -----------------------------------------------------------------------
1085     // AttributeType Tests
1086     // -----------------------------------------------------------------------
1087 
1088     
1089     private void checkAttributeTypePresent( String oid, String schemaName, boolean isPresent ) throws Exception
1090     {
1091         // -------------------------------------------------------------------
1092         // check first to see if it is present in the subschemaSubentry
1093         // -------------------------------------------------------------------
1094         
1095         Attributes attrs = getSubschemaSubentryAttributes();
1096         Attribute attrTypes = attrs.get( "attributeTypes" );
1097         AttributeTypeDescription attributeTypeDescription = null; 
1098         
1099         for ( int ii = 0; ii < attrTypes.size(); ii++ )
1100         {
1101             String desc = ( String ) attrTypes.get( ii );
1102             
1103             if ( desc.indexOf( oid ) != -1 )
1104             {
1105                 attributeTypeDescription = ATTRIBUTE_TYPE_DESCRIPTION_SCHEMA_PARSER.parseAttributeTypeDescription( desc );
1106                 break;
1107             }
1108         }
1109      
1110         if ( isPresent )
1111         {
1112             assertNotNull( attributeTypeDescription );
1113             assertEquals( oid, attributeTypeDescription.getNumericOid() );
1114         }
1115         else
1116         {
1117             assertNull( attributeTypeDescription );
1118         }
1119 
1120         // -------------------------------------------------------------------
1121         // check next to see if it is present in the schema partition
1122         // -------------------------------------------------------------------
1123 
1124         //noinspection UnusedAssignment
1125         attrs = null;
1126 
1127         LdapContext schemaRoot = getSchemaContext( service );
1128         if ( isPresent )
1129         {
1130             attrs = schemaRoot.getAttributes( "m-oid=" + oid + ",ou=attributeTypes,cn=" + schemaName );
1131             assertNotNull( attrs );
1132         }
1133         else
1134         {
1135             //noinspection EmptyCatchBlock
1136             try
1137             {
1138                 attrs = schemaRoot.getAttributes( "m-oid=" + oid + ",ou=attributeTypes,cn=" + schemaName );
1139                 fail( "should never get here" );
1140             }
1141             catch( NamingException e )
1142             {
1143             }
1144             assertNull( attrs );
1145         }
1146         
1147         // -------------------------------------------------------------------
1148         // check to see if it is present in the attributeTypeRegistry
1149         // -------------------------------------------------------------------
1150         
1151         if ( isPresent ) 
1152         { 
1153             assertTrue( service.getRegistries().getAttributeTypeRegistry().hasAttributeType( oid ) );
1154         }
1155         else
1156         {
1157             assertFalse( service.getRegistries().getAttributeTypeRegistry().hasAttributeType( oid ) );
1158         }
1159     }
1160     
1161     
1162     /**
1163      * Tests a number of modify add, remove and replace operation combinations for
1164      * attributeTypes on the schema subentry.
1165      *
1166      * @throws Exception on error
1167      */
1168     @Test
1169     public void testAddRemoveReplaceAttributeTypes() throws Exception
1170     {
1171         enableSchema( "nis" );
1172         List<String> descriptions = new ArrayList<String>();
1173 
1174         // -------------------------------------------------------------------
1175         // test rejection with non-existant syntax
1176         // -------------------------------------------------------------------
1177         
1178         descriptions.add( "( 1.3.6.1.4.1.18060.0.4.1.2.10000 DESC 'bogus desc' " +
1179                 "SYNTAX 1.2.3.4 X-SCHEMA 'nis' )" );
1180         descriptions.add( "( 1.3.6.1.4.1.18060.0.4.1.2.10001 DESC 'bogus desc' " +
1181                 "SYNTAX 1.2.3.4 X-SCHEMA 'nis' )" );
1182 
1183         try
1184         {
1185             modify( DirContext.ADD_ATTRIBUTE, descriptions, "attributeTypes" );
1186             fail( "Cannot add attributeType with bogus non-existant syntax" );
1187         }
1188         catch( LdapOperationNotSupportedException e )
1189         {
1190             assertEquals( ResultCodeEnum.UNWILLING_TO_PERFORM, e.getResultCode() );
1191         }
1192         
1193         checkAttributeTypePresent( "1.3.6.1.4.1.18060.0.4.1.2.10000", "nis", false );
1194         checkAttributeTypePresent( "1.3.6.1.4.1.18060.0.4.1.2.10001", "nis", false );
1195 
1196         // -------------------------------------------------------------------
1197         // test reject with non-existant super type
1198         // -------------------------------------------------------------------
1199 
1200         descriptions.clear();
1201         descriptions.add( "( 1.3.6.1.4.1.18060.0.4.1.2.10000 " +
1202                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SUP 1.2.3.4 X-SCHEMA 'nis' )" );
1203         descriptions.add( "( 1.3.6.1.4.1.18060.0.4.1.2.10001 " +
1204                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SUP 1.2.3.4 X-SCHEMA 'nis' )" );
1205         
1206         try
1207         {
1208             modify( DirContext.ADD_ATTRIBUTE, descriptions, "attributeTypes" );
1209             fail( "Cannot add attributeType with bogus non-existant syntax" );
1210         }
1211         catch( LdapOperationNotSupportedException e )
1212         {
1213             assertEquals( ResultCodeEnum.UNWILLING_TO_PERFORM, e.getResultCode() );
1214         }
1215         
1216         checkAttributeTypePresent( "1.3.6.1.4.1.18060.0.4.1.2.10000", "nis", false );
1217         checkAttributeTypePresent( "1.3.6.1.4.1.18060.0.4.1.2.10001", "nis", false );
1218 
1219         // -------------------------------------------------------------------
1220         // test reject with non-existant equality matchingRule
1221         // -------------------------------------------------------------------
1222 
1223         descriptions.clear();
1224         descriptions.add( "( 1.3.6.1.4.1.18060.0.4.1.2.10000 " +
1225                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 EQUALITY 1.2.3.4 X-SCHEMA 'nis' )" );
1226         descriptions.add( "( 1.3.6.1.4.1.18060.0.4.1.2.10001 " +
1227                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 EQUALITY 1.2.3.4 X-SCHEMA 'nis' )" );
1228         
1229         try
1230         {
1231             modify( DirContext.ADD_ATTRIBUTE, descriptions, "attributeTypes" );
1232             fail( "Cannot add attributeType with bogus non-existant equality MatchingRule" );
1233         }
1234         catch( LdapOperationNotSupportedException e )
1235         {
1236             assertEquals( ResultCodeEnum.UNWILLING_TO_PERFORM, e.getResultCode() );
1237         }
1238         
1239         checkAttributeTypePresent( "1.3.6.1.4.1.18060.0.4.1.2.10000", "nis", false );
1240         checkAttributeTypePresent( "1.3.6.1.4.1.18060.0.4.1.2.10001", "nis", false );
1241 
1242         // -------------------------------------------------------------------
1243         // test reject with non-existant ordering matchingRule
1244         // -------------------------------------------------------------------
1245 
1246         descriptions.clear();
1247         descriptions.add( "( 1.3.6.1.4.1.18060.0.4.1.2.10000 " +
1248                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 ORDERING 1.2.3.4 X-SCHEMA 'nis' )" );
1249         descriptions.add( "( 1.3.6.1.4.1.18060.0.4.1.2.10001 " +
1250                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 ORDERING 1.2.3.4 X-SCHEMA 'nis' )" );
1251         
1252         try
1253         {
1254             modify( DirContext.ADD_ATTRIBUTE, descriptions, "attributeTypes" );
1255             fail( "Cannot add attributeType with bogus non-existant ordering MatchingRule" );
1256         }
1257         catch( LdapOperationNotSupportedException e )
1258         {
1259             assertEquals( ResultCodeEnum.UNWILLING_TO_PERFORM, e.getResultCode() );
1260         }
1261         
1262         checkAttributeTypePresent( "1.3.6.1.4.1.18060.0.4.1.2.10000", "nis", false );
1263         checkAttributeTypePresent( "1.3.6.1.4.1.18060.0.4.1.2.10001", "nis", false );
1264 
1265         // -------------------------------------------------------------------
1266         // test reject with non-existant substring matchingRule
1267         // -------------------------------------------------------------------
1268 
1269         descriptions.clear();
1270         descriptions.add( "( 1.3.6.1.4.1.18060.0.4.1.2.10000 " +
1271                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SUBSTR 1.2.3.4 X-SCHEMA 'nis' )" );
1272         descriptions.add( "( 1.3.6.1.4.1.18060.0.4.1.2.10001 " +
1273                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SUBSTR 1.2.3.4 X-SCHEMA 'nis' )" );
1274         
1275         try
1276         {
1277             modify( DirContext.ADD_ATTRIBUTE, descriptions, "attributeTypes" );
1278             fail( "Cannot add attributeType with bogus non-existant substrings MatchingRule" );
1279         }
1280         catch( LdapOperationNotSupportedException e )
1281         {
1282             assertEquals( ResultCodeEnum.UNWILLING_TO_PERFORM, e.getResultCode() );
1283         }
1284         
1285         checkAttributeTypePresent( "1.3.6.1.4.1.18060.0.4.1.2.10000", "nis", false );
1286         checkAttributeTypePresent( "1.3.6.1.4.1.18060.0.4.1.2.10001", "nis", false );
1287 
1288         // -------------------------------------------------------------------
1289         // test success with valid superior, valid syntax but no name
1290         // -------------------------------------------------------------------
1291 
1292         descriptions.clear();
1293         descriptions.add( "( 1.3.6.1.4.1.18060.0.4.1.2.10000 " +
1294                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SUP 2.5.4.41 X-SCHEMA 'nis' )" );
1295         descriptions.add( "( 1.3.6.1.4.1.18060.0.4.1.2.10001 " +
1296                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SUP 2.5.4.41 X-SCHEMA 'nis' )" );
1297         
1298         modify( DirContext.ADD_ATTRIBUTE, descriptions, "attributeTypes" );
1299         
1300         checkAttributeTypePresent( "1.3.6.1.4.1.18060.0.4.1.2.10000", "nis", true );
1301         checkAttributeTypePresent( "1.3.6.1.4.1.18060.0.4.1.2.10001", "nis", true );
1302 
1303         // -------------------------------------------------------------------
1304         // test success with valid superior, valid syntax and names
1305         // -------------------------------------------------------------------
1306 
1307         modify( DirContext.REMOVE_ATTRIBUTE, descriptions, "attributeTypes" );
1308         
1309         descriptions.clear();
1310         descriptions.add( "( 1.3.6.1.4.1.18060.0.4.1.2.10000 NAME 'type0' " +
1311                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SUP 2.5.4.41 X-SCHEMA 'nis' )" );
1312         descriptions.add( "( 1.3.6.1.4.1.18060.0.4.1.2.10001 NAME ( 'type1' 'altName' ) " +
1313                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SUP 2.5.4.41 X-SCHEMA 'nis' )" );
1314         
1315         modify( DirContext.ADD_ATTRIBUTE, descriptions, "attributeTypes" );
1316         
1317         checkAttributeTypePresent( "1.3.6.1.4.1.18060.0.4.1.2.10000", "nis", true );
1318         checkAttributeTypePresent( "1.3.6.1.4.1.18060.0.4.1.2.10001", "nis", true );
1319 
1320         // -------------------------------------------------------------------
1321         // test success with everything
1322         // -------------------------------------------------------------------
1323 
1324         modify( DirContext.REMOVE_ATTRIBUTE, descriptions, "attributeTypes" );
1325         
1326         descriptions.clear();
1327         descriptions.add( "( 1.3.6.1.4.1.18060.0.4.1.2.10000 NAME 'type0' " +
1328                 "OBSOLETE SUP 2.5.4.41 " +
1329                 "EQUALITY caseExactIA5Match " +
1330                 "ORDERING octetStringOrderingMatch " +
1331                 "SUBSTR caseExactIA5SubstringsMatch COLLECTIVE " +
1332                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 " +
1333                 "SINGLE-VALUE USAGE userApplications X-SCHEMA 'nis' )" );
1334         descriptions.add( "( 1.3.6.1.4.1.18060.0.4.1.2.10001 NAME ( 'type1' 'altName' ) " +
1335                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SUP 2.5.4.41 " +
1336                 "NO-USER-MODIFICATION USAGE directoryOperation X-SCHEMA 'nis' )" );
1337         
1338         modify( DirContext.ADD_ATTRIBUTE, descriptions, "attributeTypes" );
1339         
1340         checkAttributeTypePresent( "1.3.6.1.4.1.18060.0.4.1.2.10000", "nis", true );
1341         checkAttributeTypePresent( "1.3.6.1.4.1.18060.0.4.1.2.10001", "nis", true );
1342 
1343         // -------------------------------------------------------------------
1344         // test failure to replace
1345         // -------------------------------------------------------------------
1346         
1347         modify( DirContext.REMOVE_ATTRIBUTE, descriptions, "attributeTypes" );
1348         checkMatchingRulePresent( "1.3.6.1.4.1.18060.0.4.1.2.10000", "nis", false );
1349         checkMatchingRulePresent( "1.3.6.1.4.1.18060.0.4.1.2.10001", "nis", false );
1350         
1351         try
1352         {
1353             modify( DirContext.REPLACE_ATTRIBUTE, descriptions, "attributeTypes" );
1354             fail( "modify REPLACE operations should not be allowed" );
1355         }
1356         catch ( LdapOperationNotSupportedException e )
1357         {
1358             assertEquals( ResultCodeEnum.UNWILLING_TO_PERFORM, e.getResultCode() );
1359         }
1360 
1361         // -------------------------------------------------------------------
1362         // check add no schema info
1363         // -------------------------------------------------------------------
1364         
1365         descriptions.clear();
1366         descriptions.add( "( 1.3.6.1.4.1.18060.0.4.1.2.10000 NAME 'type0' " +
1367                 "OBSOLETE SUP 2.5.4.41 " +
1368                 "EQUALITY caseExactIA5Match " +
1369                 "ORDERING octetStringOrderingMatch " +
1370                 "SUBSTR caseExactIA5SubstringsMatch COLLECTIVE " +
1371                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 " +
1372                 "SINGLE-VALUE USAGE userApplications )" );
1373         descriptions.add( "( 1.3.6.1.4.1.18060.0.4.1.2.10001 NAME ( 'type1' 'altName' ) " +
1374                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SUP 2.5.4.41 " +
1375                 "NO-USER-MODIFICATION USAGE directoryOperation )" );
1376         
1377         modify( DirContext.ADD_ATTRIBUTE, descriptions, "attributeTypes" );
1378         
1379         checkAttributeTypePresent( "1.3.6.1.4.1.18060.0.4.1.2.10000", "other", true );
1380         checkAttributeTypePresent( "1.3.6.1.4.1.18060.0.4.1.2.10001", "other", true );
1381     }
1382 
1383     
1384     /**
1385      * Tests the addition of a new attributeType via a modify ADD on the SSSE to disabled schema.
1386      *
1387      * @throws Exception on error
1388      */
1389     @Test
1390     public void testAddAttributeTypeOnDisabledSchema() throws Exception
1391     {
1392         disableSchema( "nis" );
1393         LdapDN dn = new LdapDN( getSubschemaSubentryDN() );
1394         String substrate = "( 1.3.6.1.4.1.18060.0.4.0.2.10000 NAME ( 'bogus' 'bogusName' ) " +
1395             "DESC 'bogus description' SUP name SINGLE-VALUE X-SCHEMA 'nis' )";
1396         ModificationItem[] mods = new ModificationItem[1];
1397         mods[0] = new ModificationItem( DirContext.ADD_ATTRIBUTE, 
1398             new BasicAttribute( "attributeTypes", substrate ) );
1399         
1400         getRootContext( service ).modifyAttributes( dn, mods );
1401         
1402         Attributes attrs = getSubschemaSubentryAttributes();
1403         Attribute attrTypes = attrs.get( "attributeTypes" );
1404         AttributeTypeDescription attributeTypeDescription = null;
1405         
1406         for ( int ii = 0; ii < attrTypes.size(); ii++ )
1407         {
1408             String desc = ( String ) attrTypes.get( ii );
1409             
1410             if ( desc.indexOf( "1.3.6.1.4.1.18060.0.4.0.2.10000" ) != -1 )
1411             {
1412                 attributeTypeDescription = ATTRIBUTE_TYPE_DESCRIPTION_SCHEMA_PARSER.parseAttributeTypeDescription( desc );
1413                 break;
1414             }
1415         }
1416         
1417         assertNull( attributeTypeDescription );
1418 
1419         attrs = getSchemaContext( service ).getAttributes( "m-oid=1.3.6.1.4.1.18060.0.4.0.2.10000,ou=attributeTypes,cn=nis" );
1420         assertNotNull( attrs );
1421         SchemaEntityFactory factory = new SchemaEntityFactory( service.getRegistries() );
1422         
1423         ServerEntry serverEntry = ServerEntryUtils.toServerEntry( attrs, LdapDN.EMPTY_LDAPDN, service.getRegistries() );
1424         
1425         AttributeType at = factory.getAttributeType( serverEntry, service.getRegistries(), "nis" );
1426         assertEquals( "1.3.6.1.4.1.18060.0.4.0.2.10000", at.getOid() );
1427         assertEquals( "name", at.getSuperior().getName() );
1428         assertEquals( "bogus description", at.getDescription() );
1429         assertEquals( "bogus", at.getName() );
1430         assertEquals( "bogusName", at.getNamesRef()[1] );
1431         assertEquals( true, at.isCanUserModify() );
1432         assertEquals( false, at.isCollective() );
1433         assertEquals( false, at.isObsolete() );
1434         assertEquals( true, at.isSingleValue() );
1435     }
1436 
1437     
1438     /**
1439      * Tests the addition of a new attributeType via a modify ADD on the SSSE to enabled schema.
1440      *
1441      * @throws Exception on error
1442      */
1443     @Test
1444     public void testAddAttributeTypeOnEnabledSchema() throws Exception
1445     {
1446         enableSchema( "nis" );
1447         LdapDN dn = new LdapDN( getSubschemaSubentryDN() );
1448         String substrate = "( 1.3.6.1.4.1.18060.0.4.0.2.10000 NAME ( 'bogus' 'bogusName' ) " +
1449             "DESC 'bogus description' SUP name SINGLE-VALUE X-SCHEMA 'nis' )";
1450         ModificationItem[] mods = new ModificationItem[1];
1451         mods[0] = new ModificationItem( DirContext.ADD_ATTRIBUTE, 
1452             new BasicAttribute( "attributeTypes", substrate ) );
1453         
1454         getRootContext( service ).modifyAttributes( dn, mods );
1455         
1456         Attributes attrs = getSubschemaSubentryAttributes();
1457         Attribute attrTypes = attrs.get( "attributeTypes" );
1458         AttributeTypeDescription attributeTypeDescription = null; 
1459         
1460         for ( int ii = 0; ii < attrTypes.size(); ii++ )
1461         {
1462             String desc = ( String ) attrTypes.get( ii );
1463             if ( desc.indexOf( "1.3.6.1.4.1.18060.0.4.0.2.10000" ) != -1 )
1464             {
1465                 attributeTypeDescription = ATTRIBUTE_TYPE_DESCRIPTION_SCHEMA_PARSER.parseAttributeTypeDescription( desc );
1466                 break;
1467             }
1468         }
1469         
1470         assertNotNull( attributeTypeDescription );
1471         assertEquals( true, attributeTypeDescription.isSingleValued() );
1472         assertEquals( false, attributeTypeDescription.isCollective() );
1473         assertEquals( false, attributeTypeDescription.isObsolete() );
1474         assertEquals( true, attributeTypeDescription.isUserModifiable() );
1475         assertEquals( "bogus description", attributeTypeDescription.getDescription() );
1476         assertEquals( "bogus", attributeTypeDescription.getNames().get( 0 ) );
1477         assertEquals( "bogusName", attributeTypeDescription.getNames().get( 1 ) );
1478         assertEquals( "name", attributeTypeDescription.getSuperType() );
1479         
1480         attrs = getSchemaContext( service ).getAttributes(
1481                 "m-oid=1.3.6.1.4.1.18060.0.4.0.2.10000,ou=attributeTypes,cn=nis" );
1482         assertNotNull( attrs );
1483         SchemaEntityFactory factory = new SchemaEntityFactory( service.getRegistries() );
1484         
1485         ServerEntry serverEntry = ServerEntryUtils.toServerEntry( attrs, LdapDN.EMPTY_LDAPDN, service.getRegistries() );
1486 
1487         AttributeType at = factory.getAttributeType( serverEntry, service.getRegistries(), "nis" );
1488         assertEquals( "1.3.6.1.4.1.18060.0.4.0.2.10000", at.getOid() );
1489         assertEquals( "name", at.getSuperior().getName() );
1490         assertEquals( "bogus description", at.getDescription() );
1491         assertEquals( "bogus", at.getNamesRef()[0] );
1492         assertEquals( "bogusName", at.getNamesRef()[1] );
1493         assertEquals( true, at.isCanUserModify() );
1494         assertEquals( false, at.isCollective() );
1495         assertEquals( false, at.isObsolete() );
1496         assertEquals( true, at.isSingleValue() );
1497     }
1498 
1499 
1500     // -----------------------------------------------------------------------
1501     // ObjectClass Tests
1502     // -----------------------------------------------------------------------
1503     
1504     
1505     private void checkObjectClassPresent( String oid, String schemaName, boolean isPresent ) throws Exception
1506     {
1507         // -------------------------------------------------------------------
1508         // check first to see if it is present in the subschemaSubentry
1509         // -------------------------------------------------------------------
1510         
1511         Attributes attrs = getSubschemaSubentryAttributes();
1512         Attribute attrTypes = attrs.get( "objectClasses" );
1513         ObjectClassDescription objectClassDescription = null; 
1514         for ( int ii = 0; ii < attrTypes.size(); ii++ )
1515         {
1516             String desc = ( String ) attrTypes.get( ii );
1517             if ( desc.indexOf( oid ) != -1 )
1518             {
1519                 objectClassDescription = objectClassDescriptionSchemaParser.parseObjectClassDescription( desc );
1520                 break;
1521             }
1522         }
1523      
1524         if ( isPresent )
1525         {
1526             assertNotNull( objectClassDescription );
1527             assertEquals( oid, objectClassDescription.getNumericOid() );
1528         }
1529         else
1530         {
1531             assertNull( objectClassDescription );
1532         }
1533 
1534         // -------------------------------------------------------------------
1535         // check next to see if it is present in the schema partition
1536         // -------------------------------------------------------------------
1537 
1538         //noinspection UnusedAssignment
1539         attrs = null;
1540         
1541         if ( isPresent )
1542         {
1543             attrs = getSchemaContext( service ).getAttributes( "m-oid=" + oid
1544                     + ",ou=objectClasses,cn=" + schemaName );
1545             assertNotNull( attrs );
1546         }
1547         else
1548         {
1549             //noinspection EmptyCatchBlock
1550             try
1551             {
1552                 attrs = getSchemaContext( service ).getAttributes( "m-oid=" +
1553                         oid + ",ou=objectClasses,cn=" + schemaName );
1554                 fail( "should never get here" );
1555             }
1556             catch( NamingException e )
1557             {
1558             }
1559             assertNull( attrs );
1560         }
1561         
1562         // -------------------------------------------------------------------
1563         // check to see if it is present in the matchingRuleRegistry
1564         // -------------------------------------------------------------------
1565         
1566         if ( isPresent ) 
1567         { 
1568             assertTrue( service.getRegistries().getObjectClassRegistry().hasObjectClass( oid ) );
1569         }
1570         else
1571         {
1572             assertFalse( service.getRegistries().getObjectClassRegistry().hasObjectClass( oid ) );
1573         }
1574     }
1575     
1576     
1577     /**
1578      * Tests a number of modify add, remove and replace operation combinations for
1579      * objectClasses on the schema subentry.
1580      *
1581      * @throws Exception on error
1582      */
1583     @Test
1584     public void testAddRemoveReplaceObjectClasses() throws Exception
1585     {
1586         enableSchema( "nis" );
1587         List<String> descriptions = new ArrayList<String>();
1588 
1589         // -------------------------------------------------------------------
1590         // test rejection with non-existant superclass
1591         // -------------------------------------------------------------------
1592         
1593         descriptions.add( "( 1.3.6.1.4.1.18060.0.4.1.3.10000 SUP 1.2.3 X-SCHEMA 'nis' )" );
1594         descriptions.add( "( 1.3.6.1.4.1.18060.0.4.1.3.10001 SUP ( 1.2.3 $ 4.5.6 ) X-SCHEMA 'nis' )" );
1595 
1596         try
1597         {
1598             modify( DirContext.ADD_ATTRIBUTE, descriptions, "objectClasses" );
1599             fail( "Cannot add objectClass with bogus non-existant super" );
1600         }
1601         catch( LdapOperationNotSupportedException e )
1602         {
1603             assertEquals( ResultCodeEnum.UNWILLING_TO_PERFORM, e.getResultCode() );
1604         }
1605         
1606         checkObjectClassPresent( "1.3.6.1.4.1.18060.0.4.1.3.10000", "nis", false );
1607         checkObjectClassPresent( "1.3.6.1.4.1.18060.0.4.1.3.10001", "nis", false );
1608 
1609         // -------------------------------------------------------------------
1610         // test add with existant superiors but no name and no desc
1611         // -------------------------------------------------------------------
1612 
1613         descriptions.clear();
1614         descriptions.add( "( 1.3.6.1.4.1.18060.0.4.1.3.10000 " +
1615                 "SUP 2.5.6.0 X-SCHEMA 'nis' )" );
1616         descriptions.add( "( 1.3.6.1.4.1.18060.0.4.1.3.10001 " +
1617                 "SUP 2.5.6.0 X-SCHEMA 'nis' )" );
1618         
1619         modify( DirContext.ADD_ATTRIBUTE, descriptions, "objectClasses" );
1620         
1621         checkObjectClassPresent( "1.3.6.1.4.1.18060.0.4.1.3.10000", "nis", true );
1622         checkObjectClassPresent( "1.3.6.1.4.1.18060.0.4.1.3.10001", "nis", true );
1623 
1624         // -------------------------------------------------------------------
1625         // test add with existant superiors with names and no desc
1626         // -------------------------------------------------------------------
1627 
1628         modify( DirContext.REMOVE_ATTRIBUTE, descriptions, "objectClasses" );
1629         checkObjectClassPresent( "1.3.6.1.4.1.18060.0.4.1.3.10000", "nis", false );
1630         checkObjectClassPresent( "1.3.6.1.4.1.18060.0.4.1.3.10001", "nis", false );
1631         
1632         descriptions.clear();
1633         descriptions.add( "( 1.3.6.1.4.1.18060.0.4.1.3.10000 " +
1634                 "NAME ( 'blah0' 'altname0' ) SUP 2.5.6.0 X-SCHEMA 'nis' )" );
1635         descriptions.add( "( 1.3.6.1.4.1.18060.0.4.1.3.10001 " +
1636                 "NAME ( 'blah1' 'altname1' ) SUP 2.5.6.0 X-SCHEMA 'nis' )" );
1637         
1638         modify( DirContext.ADD_ATTRIBUTE, descriptions, "objectClasses" );
1639         
1640         checkObjectClassPresent( "1.3.6.1.4.1.18060.0.4.1.3.10000", "nis", true );
1641         checkObjectClassPresent( "1.3.6.1.4.1.18060.0.4.1.3.10001", "nis", true );
1642 
1643         // -------------------------------------------------------------------
1644         // test add with existant superiors with names and desc
1645         // -------------------------------------------------------------------
1646 
1647         modify( DirContext.REMOVE_ATTRIBUTE, descriptions, "objectClasses" );
1648         checkObjectClassPresent( "1.3.6.1.4.1.18060.0.4.1.3.10000", "nis", false );
1649         checkObjectClassPresent( "1.3.6.1.4.1.18060.0.4.1.3.10001", "nis", false );
1650         
1651         descriptions.clear();
1652         descriptions.add( "( 1.3.6.1.4.1.18060.0.4.1.3.10000 " +
1653                 "NAME ( 'blah0' 'altname0' ) DESC 'bogus' SUP 2.5.6.0 X-SCHEMA 'nis' )" );
1654         descriptions.add( "( 1.3.6.1.4.1.18060.0.4.1.3.10001 " +
1655                 "NAME ( 'blah1' 'altname1' ) DESC 'bogus' SUP 2.5.6.0 X-SCHEMA 'nis' )" );
1656         
1657         modify( DirContext.ADD_ATTRIBUTE, descriptions, "objectClasses" );
1658         
1659         checkObjectClassPresent( "1.3.6.1.4.1.18060.0.4.1.3.10000", "nis", true );
1660         checkObjectClassPresent( "1.3.6.1.4.1.18060.0.4.1.3.10001", "nis", true );
1661 
1662         // -------------------------------------------------------------------
1663         // test add with many existant superiors with names and desc
1664         // -------------------------------------------------------------------
1665 
1666         modify( DirContext.REMOVE_ATTRIBUTE, descriptions, "objectClasses" );
1667         checkObjectClassPresent( "1.3.6.1.4.1.18060.0.4.1.3.10000", "nis", false );
1668         checkObjectClassPresent( "1.3.6.1.4.1.18060.0.4.1.3.10001", "nis", false );
1669         
1670         descriptions.clear();
1671         descriptions.add( "( 1.3.6.1.4.1.18060.0.4.1.3.10000 " +
1672                 "NAME ( 'blah0' 'altname0' ) DESC 'bogus' SUP ( 2.5.6.0 $ dynamicObject ) X-SCHEMA 'nis' )" );
1673         descriptions.add( "( 1.3.6.1.4.1.18060.0.4.1.3.10001 " +
1674                 "NAME ( 'blah1' 'altname1' ) DESC 'bogus' SUP ( 2.5.6.0 $ domain ) X-SCHEMA 'nis' )" );
1675         
1676         modify( DirContext.ADD_ATTRIBUTE, descriptions, "objectClasses" );
1677         
1678         checkObjectClassPresent( "1.3.6.1.4.1.18060.0.4.1.3.10000", "nis", true );
1679         checkObjectClassPresent( "1.3.6.1.4.1.18060.0.4.1.3.10001", "nis", true );
1680 
1681         // -------------------------------------------------------------------
1682         // test reject with non-existant attributeType in may list
1683         // -------------------------------------------------------------------
1684 
1685         modify( DirContext.REMOVE_ATTRIBUTE, descriptions, "objectClasses" );
1686         checkObjectClassPresent( "1.3.6.1.4.1.18060.0.4.1.3.10000", "nis", false );
1687         checkObjectClassPresent( "1.3.6.1.4.1.18060.0.4.1.3.10001", "nis", false );
1688         
1689         descriptions.clear();
1690         descriptions.add( "( 1.3.6.1.4.1.18060.0.4.1.3.10000 " +
1691                 "NAME ( 'blah0' 'altname0' ) DESC 'bogus' SUP ( 2.5.6.0 $ dynamicObject ) " +
1692                 "MAY ( blah0 $ cn ) X-SCHEMA 'nis' )" );
1693         descriptions.add( "( 1.3.6.1.4.1.18060.0.4.1.3.10001 " +
1694                 "NAME ( 'blah1' 'altname1' ) DESC 'bogus' SUP ( 2.5.6.0 $ domain ) " +
1695                 "MAY ( sn $ blah1 ) X-SCHEMA 'nis' )" );
1696         
1697         try
1698         {
1699             modify( DirContext.ADD_ATTRIBUTE, descriptions, "objectClasses" );
1700             fail( "Cannot add objectClass with bogus non-existant attributeTypes" );
1701         }
1702         catch( LdapOperationNotSupportedException e )
1703         {
1704             assertEquals( ResultCodeEnum.UNWILLING_TO_PERFORM, e.getResultCode() );
1705         }
1706         
1707         checkObjectClassPresent( "1.3.6.1.4.1.18060.0.4.1.3.10000", "nis", false );
1708         checkObjectClassPresent( "1.3.6.1.4.1.18060.0.4.1.3.10001", "nis", false );
1709 
1710         // -------------------------------------------------------------------
1711         // test reject with non-existant attributeType in must list
1712         // -------------------------------------------------------------------
1713 
1714         descriptions.clear();
1715         descriptions.add( "( 1.3.6.1.4.1.18060.0.4.1.3.10000 " +
1716                 "NAME ( 'blah0' 'altname0' ) DESC 'bogus' SUP ( 2.5.6.0 $ dynamicObject ) " +
1717                 "MUST ( blah0 $ cn ) X-SCHEMA 'nis' )" );
1718         descriptions.add( "( 1.3.6.1.4.1.18060.0.4.1.3.10001 " +
1719                 "NAME ( 'blah1' 'altname1' ) DESC 'bogus' SUP ( 2.5.6.0 $ domain ) " +
1720                 "MUST ( sn $ blah1 ) X-SCHEMA 'nis' )" );
1721         
1722         try
1723         {
1724             modify( DirContext.ADD_ATTRIBUTE, descriptions, "objectClasses" );
1725             fail( "Cannot add objectClass with bogus non-existant attributeTypes" );
1726         }
1727         catch( LdapOperationNotSupportedException e )
1728         {
1729             assertEquals( ResultCodeEnum.UNWILLING_TO_PERFORM, e.getResultCode() );
1730         }
1731         
1732         checkObjectClassPresent( "1.3.6.1.4.1.18060.0.4.1.3.10000", "nis", false );
1733         checkObjectClassPresent( "1.3.6.1.4.1.18060.0.4.1.3.10001", "nis", false );
1734 
1735         // -------------------------------------------------------------------
1736         // test add with valid attributeTypes in may list
1737         // -------------------------------------------------------------------
1738 
1739         descriptions.clear();
1740         descriptions.add( "( 1.3.6.1.4.1.18060.0.4.1.3.10000 " +
1741                 "NAME ( 'blah0' 'altname0' ) DESC 'bogus' SUP ( 2.5.6.0 $ dynamicObject ) " +
1742                 "MAY ( sn $ cn ) X-SCHEMA 'nis' )" );
1743         descriptions.add( "( 1.3.6.1.4.1.18060.0.4.1.3.10001 " +
1744                 "NAME ( 'blah1' 'altname1' ) DESC 'bogus' SUP ( 2.5.6.0 $ domain ) " +
1745                 "MAY ( sn $ ou ) X-SCHEMA 'nis' )" );
1746         
1747         modify( DirContext.ADD_ATTRIBUTE, descriptions, "objectClasses" );
1748         
1749         checkObjectClassPresent( "1.3.6.1.4.1.18060.0.4.1.3.10000", "nis", true );
1750         checkObjectClassPresent( "1.3.6.1.4.1.18060.0.4.1.3.10001", "nis", true );
1751 
1752         // -------------------------------------------------------------------
1753         // test add with valid attributeTypes in must list
1754         // -------------------------------------------------------------------
1755 
1756         modify( DirContext.REMOVE_ATTRIBUTE, descriptions, "objectClasses" );
1757         checkObjectClassPresent( "1.3.6.1.4.1.18060.0.4.1.3.10000", "nis", false );
1758         checkObjectClassPresent( "1.3.6.1.4.1.18060.0.4.1.3.10001", "nis", false );
1759         
1760         descriptions.clear();
1761         descriptions.add( "( 1.3.6.1.4.1.18060.0.4.1.3.10000 " +
1762                 "NAME ( 'blah0' 'altname0' ) DESC 'bogus' SUP ( 2.5.6.0 $ dynamicObject ) " +
1763                 "MUST ( sn $ cn ) X-SCHEMA 'nis' )" );
1764         descriptions.add( "( 1.3.6.1.4.1.18060.0.4.1.3.10001 " +
1765                 "NAME ( 'blah1' 'altname1' ) DESC 'bogus' SUP ( 2.5.6.0 $ domain ) " +
1766                 "MUST ( sn $ ou ) X-SCHEMA 'nis' )" );
1767         
1768         modify( DirContext.ADD_ATTRIBUTE, descriptions, "objectClasses" );
1769         
1770         checkObjectClassPresent( "1.3.6.1.4.1.18060.0.4.1.3.10000", "nis", true );
1771         checkObjectClassPresent( "1.3.6.1.4.1.18060.0.4.1.3.10001", "nis", true );
1772 
1773         // -------------------------------------------------------------------
1774         // test add success full (with obsolete)
1775         // -------------------------------------------------------------------
1776         
1777         modify( DirContext.REMOVE_ATTRIBUTE, descriptions, "objectClasses" );
1778         checkObjectClassPresent( "1.3.6.1.4.1.18060.0.4.1.3.10000", "nis", false );
1779         checkObjectClassPresent( "1.3.6.1.4.1.18060.0.4.1.3.10001", "nis", false );
1780         
1781         descriptions.clear();
1782         descriptions.add( "( 1.3.6.1.4.1.18060.0.4.1.3.10000 " +
1783                 "NAME ( 'blah0' 'altname0' ) DESC 'bogus' OBSOLETE SUP ( 2.5.6.0 $ dynamicObject ) STRUCTURAL " +
1784                 "MUST ( sn $ cn ) " +
1785                 "MAY ( sn $ ou ) " +
1786                 "X-SCHEMA 'nis' ) " );
1787         descriptions.add( "( 1.3.6.1.4.1.18060.0.4.1.3.10001 " +
1788                 "NAME ( 'blah1' 'altname1' ) DESC 'bogus' OBSOLETE SUP ( 2.5.6.0 $ domain ) STRUCTURAL " +
1789                 "MUST ( sn $ ou ) " +
1790                 "MAY ( sn $ ou ) " +
1791                 "X-SCHEMA 'nis' )" );
1792         
1793         modify( DirContext.ADD_ATTRIBUTE, descriptions, "objectClasses" );
1794         
1795         checkObjectClassPresent( "1.3.6.1.4.1.18060.0.4.1.3.10000", "nis", true );
1796         checkObjectClassPresent( "1.3.6.1.4.1.18060.0.4.1.3.10001", "nis", true );
1797 
1798         // -------------------------------------------------------------------
1799         // test failure to replace
1800         // -------------------------------------------------------------------
1801         
1802         modify( DirContext.REMOVE_ATTRIBUTE, descriptions, "objectClasses" );
1803         checkMatchingRulePresent( "1.3.6.1.4.1.18060.0.4.1.3.10000", "nis", false );
1804         checkMatchingRulePresent( "1.3.6.1.4.1.18060.0.4.1.3.10001", "nis", false );
1805         
1806         try
1807         {
1808             modify( DirContext.REPLACE_ATTRIBUTE, descriptions, "objectClasses" );
1809             fail( "modify REPLACE operations should not be allowed" );
1810         }
1811         catch ( LdapOperationNotSupportedException e )
1812         {
1813             assertEquals( ResultCodeEnum.UNWILLING_TO_PERFORM, e.getResultCode() );
1814         }
1815 
1816         // -------------------------------------------------------------------
1817         // check add no schema info
1818         // -------------------------------------------------------------------
1819         
1820         descriptions.clear();
1821         descriptions.add( "( 1.3.6.1.4.1.18060.0.4.1.3.10000 " +
1822             "NAME ( 'blah0' 'altname0' ) DESC 'bogus' OBSOLETE SUP ( 2.5.6.0 $ dynamicObject ) STRUCTURAL " +
1823             "MUST ( sn $ cn ) " +
1824             "MAY ( sn $ ou ) )" );
1825         descriptions.add( "( 1.3.6.1.4.1.18060.0.4.1.3.10001 " +
1826             "NAME ( 'blah1' 'altname1' ) DESC 'bogus' OBSOLETE SUP ( 2.5.6.0 $ domain ) STRUCTURAL " +
1827             "MUST ( sn $ ou ) " +
1828             "MAY ( sn $ ou ) )" );
1829 
1830         modify( DirContext.ADD_ATTRIBUTE, descriptions, "objectClasses" );
1831         checkObjectClassPresent( "1.3.6.1.4.1.18060.0.4.1.3.10000", "other", true );
1832         checkObjectClassPresent( "1.3.6.1.4.1.18060.0.4.1.3.10001", "other", true );
1833     }
1834 
1835     
1836     // -----------------------------------------------------------------------
1837     // Test Modifier and Timestamp Updates 
1838     // -----------------------------------------------------------------------
1839     
1840     
1841     /**
1842      * This method checks the modifiersName, and the modifyTimestamp on the schema
1843      * subentry then modifies a schema.  It then checks it again to make sure these
1844      * values have been updated properly to reflect the modification time and the
1845      * modifier.
1846      *
1847      * @throws InterruptedException on error
1848      * @throws NamingException on error
1849      */
1850     @Test
1851     @Ignore ( "Don't know why but this is causing intermittant failures in assertions" )
1852     public void testTimestampAndModifierUpdates() throws Exception, InterruptedException
1853     {
1854         TimeZone tz = TimeZone.getTimeZone( "GMT" );
1855         
1856         Attributes subentry = this.getSubschemaSubentryAttributes();
1857         
1858         // check first that everything that is required is present
1859         
1860         Attribute creatorsNameAttr = subentry.get( "creatorsName" );
1861         Attribute createTimestampAttr = subentry.get( "createTimestamp" );
1862         assertNotNull( creatorsNameAttr );
1863         assertNotNull( createTimestampAttr );
1864 
1865         Attribute modifiersNameAttr = subentry.get( "modifiersName" );
1866         Attribute modifyTimestampAttr = subentry.get( "modifyTimestamp" );
1867         assertNotNull( modifiersNameAttr );
1868         LdapDN expectedDN = new LdapDN( "uid=admin,ou=system" );
1869         expectedDN.normalize( service.getRegistries().getAttributeTypeRegistry().getNormalizerMapping() );
1870         assertEquals( expectedDN.getNormName(), modifiersNameAttr.get() );
1871         assertNotNull( modifyTimestampAttr );
1872 
1873         Calendar cal = Calendar.getInstance( tz );
1874         String modifyTimestampStr = ( String ) modifyTimestampAttr.get();
1875         Date modifyTimestamp = DateUtils.getDate( modifyTimestampStr );
1876         Date currentTimestamp = cal.getTime();
1877 
1878         assertFalse( modifyTimestamp.after( currentTimestamp ) );
1879         
1880         // now update the schema information: add a new attribute type
1881         
1882         enableSchema( "nis" );
1883         LdapDN dn = new LdapDN( getSubschemaSubentryDN() );
1884         String substrate = "( 1.3.6.1.4.1.18060.0.4.0.2.10000 NAME ( 'bogus' 'bogusName' ) " +
1885             "DESC 'bogus description' SUP name SINGLE-VALUE X-SCHEMA 'nis' )";
1886         ModificationItem[] mods = new ModificationItem[1];
1887         mods[0] = new ModificationItem( DirContext.ADD_ATTRIBUTE, 
1888             new BasicAttribute( "attributeTypes", substrate ) );
1889         
1890         getRootContext( service ).modifyAttributes( dn, mods );
1891 
1892         // now check the modification timestamp and the modifiers name
1893 
1894         subentry = this.getSubschemaSubentryAttributes();
1895         
1896         // check first that everything that is required is present
1897         
1898         Attribute creatorsNameAttrAfter = subentry.get( "creatorsName" );
1899         Attribute createTimestampAttrAfter = subentry.get( "createTimestamp" );
1900         assertNotNull( creatorsNameAttrAfter );
1901         assertNotNull( createTimestampAttrAfter );
1902 
1903         Attribute modifiersNameAttrAfter = subentry.get( "modifiersName" );
1904         Attribute modifiersTimestampAttrAfter = subentry.get( "modifyTimestamp" );
1905         assertNotNull( modifiersNameAttrAfter );
1906         expectedDN = new LdapDN( "uid=admin,ou=system" );
1907         expectedDN.normalize( service.getRegistries().getAttributeTypeRegistry().getNormalizerMapping() );
1908         assertEquals( expectedDN.getNormName(), modifiersNameAttrAfter.get() );
1909         assertNotNull( modifiersTimestampAttrAfter );
1910         
1911         cal = Calendar.getInstance( tz );
1912         Date modifyTimestampAfter = DateUtils.getDate( ( String ) modifiersTimestampAttrAfter.get() );
1913         assertTrue( modifyTimestampAfter.getTime() <= cal.getTime().getTime() );
1914 
1915 
1916         assertTrue( modifyTimestampAfter.getTime() >= modifyTimestamp.getTime() );
1917 
1918         // now let's test the modifiersName update with another user besides
1919         // the administrator - we'll create a dummy user for that ...
1920         
1921         Attributes user = new BasicAttributes( "objectClass", "person", true );
1922         user.put( "sn", "bogus" );
1923         user.put( "cn", "bogus user" );
1924         user.put( "userPassword", "secret" );
1925         getSystemContext( service ).createSubcontext( "cn=bogus user", user );
1926         
1927         // now let's get a context for this user
1928         
1929         Hashtable<String,Object> env = new Hashtable<String,Object>();
1930         env.put( Context.INITIAL_CONTEXT_FACTORY, "org.apache.directory.server.core.jndi.CoreContextFactory" );
1931         env.put( Context.PROVIDER_URL, "" );
1932         env.put( Context.SECURITY_AUTHENTICATION, "simple" );
1933         env.put( Context.SECURITY_CREDENTIALS, "secret" );
1934         env.put( Context.SECURITY_PRINCIPAL, "cn=bogus user,ou=system" );
1935         env.put( DirectoryService.JNDI_KEY, service );
1936         InitialDirContext ctx = new InitialDirContext( env );
1937         
1938         // now let's add another attribute type definition to the schema but 
1939         // with this newly created user and check that the modifiers name is his
1940 
1941         substrate = "( 1.3.6.1.4.1.18060.0.4.0.2.10001 NAME ( 'bogus2' 'bogusName2' ) " +
1942             "DESC 'bogus description' SUP name SINGLE-VALUE X-SCHEMA 'nis' )";
1943         mods[0] = new ModificationItem( DirContext.ADD_ATTRIBUTE, 
1944             new BasicAttribute( "attributeTypes", substrate ) );
1945         ctx.modifyAttributes( dn, mods );
1946         
1947         // now let's verify the new values for the modification attributes
1948 
1949         subentry = this.getSubschemaSubentryAttributes();
1950 
1951         creatorsNameAttrAfter = subentry.get( "creatorsName" );
1952         createTimestampAttrAfter = subentry.get( "createTimestamp" );
1953         assertNotNull( creatorsNameAttrAfter );
1954         assertNotNull( createTimestampAttrAfter );
1955 
1956         modifiersNameAttrAfter = subentry.get( "modifiersName" );
1957         modifiersTimestampAttrAfter = subentry.get( "modifyTimestamp" );
1958         assertNotNull( modifiersNameAttrAfter );
1959         expectedDN = new LdapDN( "cn=bogus user,ou=system" );
1960         expectedDN.normalize( service.getRegistries().getAttributeTypeRegistry().getNormalizerMapping() );
1961         assertEquals( expectedDN.getNormName(), modifiersNameAttrAfter.get() );
1962         assertNotNull( modifiersTimestampAttrAfter );
1963         
1964         cal = Calendar.getInstance( tz );
1965         modifyTimestamp = DateUtils.getDate( ( String ) modifyTimestampAttr.get() );
1966         modifyTimestampAfter = DateUtils.getDate( ( String ) modifiersTimestampAttrAfter.get() );
1967         assertTrue( modifyTimestampAfter.getTime() <= cal.getTime().getTime() );
1968         assertTrue( modifyTimestampAfter.getTime() >= modifyTimestamp.getTime() );
1969     }
1970 
1971 
1972     // -----------------------------------------------------------------------
1973     // Private Utility Methods 
1974     // -----------------------------------------------------------------------
1975     
1976 
1977     private void modify( int op, List<String> descriptions, String opAttr ) throws Exception
1978     {
1979         LdapDN dn = new LdapDN( getSubschemaSubentryDN() );
1980         Attribute attr = new BasicAttribute( opAttr );
1981         for ( String description : descriptions )
1982         {
1983             attr.add( description );
1984         }
1985         
1986         Attributes mods = new BasicAttributes( true );
1987         mods.put( attr );
1988         
1989         getRootContext( service ).modifyAttributes( dn, op, mods );
1990     }
1991     
1992     
1993     private void enableSchema( String schemaName ) throws Exception
1994     {
1995         // now enable the test schema
1996         ModificationItem[] mods = new ModificationItem[1];
1997         Attribute attr = new BasicAttribute( "m-disabled", "FALSE" );
1998         mods[0] = new ModificationItem( DirContext.REPLACE_ATTRIBUTE, attr );
1999         getSchemaContext( service ).modifyAttributes( "cn=" + schemaName, mods );
2000     }
2001     
2002     
2003     private void disableSchema( String schemaName ) throws Exception
2004     {
2005         // now enable the test schema
2006         ModificationItem[] mods = new ModificationItem[1];
2007         Attribute attr = new BasicAttribute( "m-disabled", "TRUE" );
2008         mods[0] = new ModificationItem( DirContext.REPLACE_ATTRIBUTE, attr );
2009         getSchemaContext( service ).modifyAttributes( "cn=" + schemaName, mods );
2010     }
2011     
2012     
2013     private String getByteCode( String resource ) throws IOException
2014     {
2015         InputStream in = getClass().getResourceAsStream( resource );
2016         ByteArrayOutputStream out = new ByteArrayOutputStream();
2017         while ( in.available() > 0 )
2018         {
2019             out.write( in.read() );
2020         }
2021         
2022         return new String( Base64.encode( out.toByteArray() ) );
2023     }
2024 
2025 
2026     /**
2027      * Get's the subschemaSubentry attribute value from the rootDSE.
2028      * 
2029      * @return the subschemaSubentry distinguished name
2030      * @throws NamingException if there are problems accessing the RootDSE
2031      */
2032     private String getSubschemaSubentryDN() throws Exception
2033     {
2034         SearchControls controls = new SearchControls();
2035         controls.setSearchScope( SearchControls.OBJECT_SCOPE );
2036         controls.setReturningAttributes( new String[]{ SUBSCHEMA_SUBENTRY } );
2037         
2038         NamingEnumeration<SearchResult> results = getRootContext( service )
2039                 .search( "", "(objectClass=*)", controls );
2040         SearchResult result = results.next();
2041         results.close();
2042         Attribute subschemaSubentry = result.getAttributes().get( SUBSCHEMA_SUBENTRY );
2043         return ( String ) subschemaSubentry.get();
2044     }
2045 
2046     
2047     /**
2048      * Gets the subschemaSubentry attributes for the global schema.
2049      *
2050      * @return all operational attributes of the subschemaSubentry
2051      * @throws NamingException if there are problems accessing this entry
2052      */
2053     private Attributes getSubschemaSubentryAttributes() throws Exception
2054     {
2055         SearchControls controls = new SearchControls();
2056         controls.setSearchScope( SearchControls.OBJECT_SCOPE );
2057         controls.setReturningAttributes( new String[]{ "+", "*" } );
2058 
2059         NamingEnumeration<SearchResult> results = getRootContext( service )
2060                 .search( getSubschemaSubentryDN(), "(objectClass=*)", controls );
2061         SearchResult result = results.next();
2062         results.close();
2063         return result.getAttributes();
2064     }
2065 }