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 org.apache.directory.server.constants.MetaSchemaConstants;
24  import org.apache.directory.server.core.DirectoryService;
25  import org.apache.directory.server.core.integ.CiRunner;
26  import static org.apache.directory.server.core.integ.IntegrationUtils.getSchemaContext;
27  import org.apache.directory.server.schema.registries.AttributeTypeRegistry;
28  import org.apache.directory.shared.ldap.constants.SchemaConstants;
29  import org.apache.directory.shared.ldap.exception.LdapInvalidNameException;
30  import org.apache.directory.shared.ldap.exception.LdapOperationNotSupportedException;
31  import org.apache.directory.shared.ldap.message.ResultCodeEnum;
32  import org.apache.directory.shared.ldap.name.LdapDN;
33  import org.apache.directory.shared.ldap.schema.AttributeType;
34  import static org.junit.Assert.assertEquals;
35  import static org.junit.Assert.assertTrue;
36  import static org.junit.Assert.assertFalse;
37  import static org.junit.Assert.fail;
38  import org.junit.Test;
39  import org.junit.runner.RunWith;
40  
41  import javax.naming.NamingException;
42  import javax.naming.directory.Attribute;
43  import javax.naming.directory.Attributes;
44  import javax.naming.directory.BasicAttribute;
45  import javax.naming.directory.BasicAttributes;
46  import javax.naming.directory.DirContext;
47  import javax.naming.directory.ModificationItem;
48  import javax.naming.ldap.LdapContext;
49  
50  
51  /**
52   * A test case which tests the addition of various schema elements
53   * to the ldap server.
54   *
55   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
56   * @version $Rev$
57   */
58  @RunWith ( CiRunner.class )
59  public class MetaAttributeTypeHandlerIT
60  {
61      private static final String DESCRIPTION0 = "A test attributeType";
62      private static final String DESCRIPTION1 = "An alternate description";
63  
64      private static final String INTEGER_SYNTAX_OID = "1.3.6.1.4.1.1466.115.121.1.27";
65      private static final String DIRSTR_SYNTAX_OID = "1.3.6.1.4.1.1466.115.121.1.15";
66      
67      private static final String OID = "1.3.6.1.4.1.18060.0.4.0.2.100000";
68      private static final String NEW_OID = "1.3.6.1.4.1.18060.0.4.0.2.100001";
69      private static final String DEPENDEE_OID = "1.3.6.1.4.1.18060.0.4.0.2.100002";
70  
71  
72      public static DirectoryService service;
73  
74      
75      /**
76       * Gets relative DN to ou=schema.
77       *
78       * @param schemaName the name of the schema
79       * @return the dn of the a schema's attributeType entity container
80       * @throws Exception on failure
81       */
82      private LdapDN getAttributeTypeContainer( String schemaName ) throws Exception
83      {
84          return new LdapDN( "ou=attributeTypes,cn=" + schemaName );
85      }
86  
87  
88      private static AttributeTypeRegistry getAttributeTypeRegistry()
89      {
90          return service.getRegistries().getAttributeTypeRegistry();
91      }
92      
93      
94      // ----------------------------------------------------------------------
95      // Test all core methods with normal operational pathways
96      // ----------------------------------------------------------------------
97  
98      
99      @Test
100     public void testAddAttributeType() throws Exception
101     {
102         Attributes attrs = new BasicAttributes( true );
103         Attribute oc = new BasicAttribute( SchemaConstants.OBJECT_CLASS_AT, "top" );
104         oc.add( MetaSchemaConstants.META_TOP_OC );
105         oc.add( MetaSchemaConstants.META_ATTRIBUTE_TYPE_OC );
106         attrs.put( oc );
107         attrs.put( MetaSchemaConstants.M_OID_AT, OID );
108         attrs.put( MetaSchemaConstants.M_SYNTAX_AT, INTEGER_SYNTAX_OID );
109         attrs.put( MetaSchemaConstants.M_DESCRIPTION_AT, DESCRIPTION0 );
110         attrs.put( MetaSchemaConstants.M_EQUALITY_AT, "caseIgnoreMatch" );
111         attrs.put( MetaSchemaConstants.M_SINGLE_VALUE_AT, "FALSE" );
112         attrs.put( MetaSchemaConstants.M_USAGE_AT, "directoryOperation" );
113         
114         LdapDN dn = getAttributeTypeContainer( "apachemeta" );
115         dn.add( MetaSchemaConstants.M_OID_AT + "=" + OID );
116         getSchemaContext( service ).createSubcontext( dn, attrs );
117         
118         assertTrue( service.getRegistries().getAttributeTypeRegistry().hasAttributeType( OID ) );
119         assertEquals( getAttributeTypeRegistry().getSchemaName( OID ), "apachemeta" );
120     }
121     
122     
123     @Test
124     public void testDeleteAttributeType() throws Exception
125     {
126         LdapDN dn = getAttributeTypeContainer( "apachemeta" );
127         dn.add( MetaSchemaConstants.M_OID_AT + "=" + OID );
128         testAddAttributeType();
129         
130         getSchemaContext( service ).destroySubcontext( dn );
131 
132         assertFalse( "attributeType should be removed from the registry after being deleted", 
133             getAttributeTypeRegistry().hasAttributeType( OID ) );
134         
135         try
136         {
137             getAttributeTypeRegistry().lookup( OID );
138             fail( "attributeType lookup should fail after deleting it" );
139         }
140         catch( NamingException e )
141         {
142         }
143     }
144 
145 
146     @Test
147     public void testRenameAttributeType() throws Exception
148     {
149         LdapContext schemaRoot = getSchemaContext( service );
150         LdapDN dn = getAttributeTypeContainer( "apachemeta" );
151         dn.add( MetaSchemaConstants.M_OID_AT + "=" + OID );
152         testAddAttributeType();
153         
154         LdapDN newdn = getAttributeTypeContainer( "apachemeta" );
155         newdn.add( MetaSchemaConstants.M_OID_AT + "=" + NEW_OID );
156         schemaRoot.rename( dn, newdn );
157 
158         assertFalse( "old attributeType OID should be removed from the registry after being renamed", 
159             getAttributeTypeRegistry().hasAttributeType( OID ) );
160         
161         try
162         {
163             getAttributeTypeRegistry().lookup( OID );
164             fail( "attributeType lookup should fail after renaming the attributeType" );
165         }
166         catch( NamingException e )
167         {
168         }
169 
170         assertTrue( getAttributeTypeRegistry().hasAttributeType( NEW_OID ) );
171     }
172 
173 
174     @Test
175     public void testMoveAttributeType() throws Exception
176     {
177         testAddAttributeType();
178         
179         LdapDN dn = getAttributeTypeContainer( "apachemeta" );
180         dn.add( MetaSchemaConstants.M_OID_AT + "=" + OID );
181 
182         LdapDN newdn = getAttributeTypeContainer( "apache" );
183         newdn.add( MetaSchemaConstants.M_OID_AT + "=" + OID );
184         
185         getSchemaContext( service ).rename( dn, newdn );
186 
187         assertTrue( "attributeType OID should still be present",
188                 getAttributeTypeRegistry().hasAttributeType( OID ) );
189         
190         assertEquals( "attributeType schema should be set to apache not apachemeta", 
191             getAttributeTypeRegistry().getSchemaName( OID ), "apache" );
192     }
193 
194 
195     @Test
196     public void testMoveAttributeTypeAndChangeRdn() throws Exception
197     {
198         testAddAttributeType();
199         
200         LdapDN dn = getAttributeTypeContainer( "apachemeta" );
201         dn.add( MetaSchemaConstants.M_OID_AT + "=" + OID );
202 
203         LdapDN newdn = getAttributeTypeContainer( "apache" );
204         newdn.add( MetaSchemaConstants.M_OID_AT + "=" + NEW_OID );
205         
206         getSchemaContext( service ).rename( dn, newdn );
207 
208         assertFalse( "old attributeType OID should NOT be present", 
209             getAttributeTypeRegistry().hasAttributeType( OID ) );
210         
211         assertTrue( "new attributeType OID should be present", 
212             getAttributeTypeRegistry().hasAttributeType( NEW_OID ) );
213         
214         assertEquals( "attributeType with new oid should have schema set to apache NOT apachemeta", 
215             getAttributeTypeRegistry().getSchemaName( NEW_OID ), "apache" );
216     }
217 
218     
219     @Test
220     public void testModifyAttributeTypeWithModificationItems() throws Exception
221     {
222         testAddAttributeType();
223         
224         AttributeType at = getAttributeTypeRegistry().lookup( OID );
225         assertEquals( at.getDescription(), DESCRIPTION0 );
226         assertEquals( at.getSyntax().getOid(), INTEGER_SYNTAX_OID );
227 
228         LdapDN dn = getAttributeTypeContainer( "apachemeta" );
229         dn.add( MetaSchemaConstants.M_OID_AT + "=" + OID );
230         
231         ModificationItem[] mods = new ModificationItem[2];
232         Attribute attr = new BasicAttribute( MetaSchemaConstants.M_DESCRIPTION_AT, DESCRIPTION1 );
233         mods[0] = new ModificationItem( DirContext.REPLACE_ATTRIBUTE, attr );
234         attr = new BasicAttribute( MetaSchemaConstants.M_SYNTAX_AT, DIRSTR_SYNTAX_OID );
235         mods[1] = new ModificationItem( DirContext.REPLACE_ATTRIBUTE, attr );
236         getSchemaContext( service ).modifyAttributes( dn, mods );
237 
238         assertTrue( "attributeType OID should still be present", 
239             getAttributeTypeRegistry().hasAttributeType( OID ) );
240         
241         assertEquals( "attributeType schema should be set to apachemeta", 
242             getAttributeTypeRegistry().getSchemaName( OID ), "apachemeta" );
243         
244         at = getAttributeTypeRegistry().lookup( OID );
245         assertEquals( at.getDescription(), DESCRIPTION1 );
246         assertEquals( at.getSyntax().getOid(), DIRSTR_SYNTAX_OID );
247     }
248 
249     
250     @Test
251     public void testModifyAttributeTypeWithAttributes() throws Exception
252     {
253         testAddAttributeType();
254         
255         AttributeType at = getAttributeTypeRegistry().lookup( OID );
256         assertEquals( at.getDescription(), DESCRIPTION0 );
257         assertEquals( at.getSyntax().getOid(), INTEGER_SYNTAX_OID );
258 
259         LdapDN dn = getAttributeTypeContainer( "apachemeta" );
260         dn.add( MetaSchemaConstants.M_OID_AT + "=" + OID );
261         
262         Attributes mods = new BasicAttributes( true );
263         mods.put( MetaSchemaConstants.M_DESCRIPTION_AT, DESCRIPTION1 );
264         mods.put( MetaSchemaConstants.M_SYNTAX_AT, DIRSTR_SYNTAX_OID );
265         getSchemaContext( service ).modifyAttributes( dn, DirContext.REPLACE_ATTRIBUTE, mods );
266 
267         assertTrue( "attributeType OID should still be present", 
268             getAttributeTypeRegistry().hasAttributeType( OID ) );
269         
270         assertEquals( "attributeType schema should be set to apachemeta", 
271             getAttributeTypeRegistry().getSchemaName( OID ), "apachemeta" );
272 
273         at = getAttributeTypeRegistry().lookup( OID );
274         assertEquals( at.getDescription(), DESCRIPTION1 );
275         assertEquals( at.getSyntax().getOid(), DIRSTR_SYNTAX_OID );
276     }
277     
278 
279     // ----------------------------------------------------------------------
280     // Test move, rename, and delete when a MR exists and uses the Normalizer
281     // ----------------------------------------------------------------------
282 
283     
284     private void addDependeeAttributeType() throws Exception
285     {
286         Attributes attrs = new BasicAttributes( true );
287         Attribute oc = new BasicAttribute( SchemaConstants.OBJECT_CLASS_AT, "top" );
288         oc.add( MetaSchemaConstants.META_TOP_OC );
289         oc.add( MetaSchemaConstants.META_ATTRIBUTE_TYPE_OC );
290         attrs.put( oc );
291         attrs.put( MetaSchemaConstants.M_OID_AT, DEPENDEE_OID );
292         attrs.put( MetaSchemaConstants.M_SYNTAX_AT, INTEGER_SYNTAX_OID );
293         attrs.put( MetaSchemaConstants.M_DESCRIPTION_AT, DESCRIPTION0 );
294         attrs.put( MetaSchemaConstants.M_EQUALITY_AT, "caseIgnoreMatch" );
295         attrs.put( MetaSchemaConstants.M_SINGLE_VALUE_AT, "FALSE" );
296         attrs.put( MetaSchemaConstants.M_USAGE_AT, "directoryOperation" );
297         attrs.put( MetaSchemaConstants.M_SUP_ATTRIBUTE_TYPE_AT, OID );
298         
299         LdapDN dn = getAttributeTypeContainer( "apachemeta" );
300         dn.add( MetaSchemaConstants.M_OID_AT + "=" + DEPENDEE_OID );
301         getSchemaContext( service ).createSubcontext( dn, attrs );
302         
303         assertTrue( getAttributeTypeRegistry().hasAttributeType( DEPENDEE_OID ) );
304         assertEquals( getAttributeTypeRegistry().getSchemaName( DEPENDEE_OID ), "apachemeta" );
305     }
306 
307 
308     @Test
309     public void testDeleteAttributeTypeWhenInUse() throws Exception
310     {
311         LdapDN dn = getAttributeTypeContainer( "apachemeta" );
312         dn.add( MetaSchemaConstants.M_OID_AT + "=" + OID );
313         testAddAttributeType();
314         addDependeeAttributeType();
315         
316         try
317         {
318             getSchemaContext( service ).destroySubcontext( dn );
319             fail( "should not be able to delete a attributeType in use" );
320         }
321         catch( LdapOperationNotSupportedException e ) 
322         {
323             assertEquals( e.getResultCode(), ResultCodeEnum.UNWILLING_TO_PERFORM );
324         }
325 
326         assertTrue( "attributeType should still be in the registry after delete failure", 
327             getAttributeTypeRegistry().hasAttributeType( OID ) );
328     }
329     
330     
331     @Test
332     public void testMoveAttributeTypeWhenInUse() throws Exception
333     {
334         testAddAttributeType();
335         addDependeeAttributeType();
336         
337         LdapDN dn = getAttributeTypeContainer( "apachemeta" );
338         dn.add( MetaSchemaConstants.M_OID_AT + "=" + OID );
339 
340         LdapDN newdn = getAttributeTypeContainer( "apache" );
341         newdn.add( MetaSchemaConstants.M_OID_AT + "=" + OID );
342         
343         try
344         {
345             getSchemaContext( service ).rename( dn, newdn );
346             fail( "should not be able to move a attributeType in use" );
347         }
348         catch( LdapOperationNotSupportedException e ) 
349         {
350             assertEquals( e.getResultCode(), ResultCodeEnum.UNWILLING_TO_PERFORM );
351         }
352 
353         assertTrue( "attributeType should still be in the registry after move failure", 
354             getAttributeTypeRegistry().hasAttributeType( OID ) );
355     }
356 
357 
358     @Test
359     public void testMoveAttributeTypeAndChangeRdnWhenInUse() throws Exception
360     {
361         testAddAttributeType();
362         addDependeeAttributeType();
363         
364         LdapDN dn = getAttributeTypeContainer( "apachemeta" );
365         dn.add( MetaSchemaConstants.M_OID_AT + "=" + OID );
366 
367         LdapDN newdn = getAttributeTypeContainer( "apache" );
368         newdn.add( MetaSchemaConstants.M_OID_AT + "=" + NEW_OID );
369         
370         try
371         {
372             getSchemaContext( service ).rename( dn, newdn );
373             fail( "should not be able to move a attributeType in use" );
374         }
375         catch( LdapOperationNotSupportedException e ) 
376         {
377             assertEquals( e.getResultCode(), ResultCodeEnum.UNWILLING_TO_PERFORM );
378         }
379 
380         assertTrue( "attributeType should still be in the registry after move failure", 
381             getAttributeTypeRegistry().hasAttributeType( OID ) );
382     }
383 
384     
385     @Test
386     public void testRenameAttributeTypeWhenInUse() throws Exception
387     {
388         LdapDN dn = getAttributeTypeContainer( "apachemeta" );
389         dn.add( MetaSchemaConstants.M_OID_AT + "=" + OID );
390         testAddAttributeType();
391         addDependeeAttributeType();
392         
393         LdapDN newdn = getAttributeTypeContainer( "apachemeta" );
394         newdn.add( MetaSchemaConstants.M_OID_AT + "=" + NEW_OID );
395         
396         try
397         {
398             getSchemaContext( service ).rename( dn, newdn );
399             fail( "should not be able to rename a attributeType in use" );
400         }
401         catch( LdapOperationNotSupportedException e ) 
402         {
403             assertEquals( e.getResultCode(), ResultCodeEnum.UNWILLING_TO_PERFORM );
404         }
405 
406         assertTrue( "attributeType should still be in the registry after rename failure", 
407             getAttributeTypeRegistry().hasAttributeType( OID ) );
408     }
409 
410 
411     // ----------------------------------------------------------------------
412     // Let's try some freaky stuff
413     // ----------------------------------------------------------------------
414 
415 
416     @Test
417     public void testMoveAttributeTypeToTop() throws Exception
418     {
419         testAddAttributeType();
420         
421         LdapDN dn = getAttributeTypeContainer( "apachemeta" );
422         dn.add( MetaSchemaConstants.M_OID_AT + "=" + OID );
423 
424         LdapDN top = new LdapDN();
425         top.add( MetaSchemaConstants.M_OID_AT + "=" + OID );
426         
427         try
428         {
429             getSchemaContext( service ).rename( dn, top );
430             fail( "should not be able to move a attributeType up to ou=schema" );
431         }
432         catch( LdapInvalidNameException e ) 
433         {
434             assertEquals( e.getResultCode(), ResultCodeEnum.NAMING_VIOLATION );
435         }
436 
437         assertTrue( "attributeType should still be in the registry after move failure", 
438             getAttributeTypeRegistry().hasAttributeType( OID ) );
439     }
440 
441 
442     @Test
443     public void testMoveAttributeTypeToComparatorContainer() throws Exception
444     {
445         testAddAttributeType();
446         
447         LdapDN dn = getAttributeTypeContainer( "apachemeta" );
448         dn.add( MetaSchemaConstants.M_OID_AT + "=" + OID );
449 
450         LdapDN newdn = new LdapDN( "ou=comparators,cn=apachemeta" );
451         newdn.add( MetaSchemaConstants.M_OID_AT + "=" + OID );
452         
453         try
454         {
455             getSchemaContext( service ).rename( dn, newdn );
456             fail( "should not be able to move a attributeType into comparators container" );
457         }
458         catch( LdapInvalidNameException e ) 
459         {
460             assertEquals( e.getResultCode(), ResultCodeEnum.NAMING_VIOLATION );
461         }
462 
463         assertTrue( "attributeType should still be in the registry after move failure", 
464             getAttributeTypeRegistry().hasAttributeType( OID ) );
465     }
466     
467     
468     @Test
469     public void testAddAttributeTypeToDisabledSchema() throws Exception
470     {
471         Attributes attrs = new BasicAttributes( true );
472         Attribute oc = new BasicAttribute( SchemaConstants.OBJECT_CLASS_AT, "top" );
473         oc.add( MetaSchemaConstants.META_TOP_OC );
474         oc.add( MetaSchemaConstants.META_ATTRIBUTE_TYPE_OC );
475         attrs.put( oc );
476         attrs.put( MetaSchemaConstants.M_OID_AT, OID );
477         attrs.put( MetaSchemaConstants.M_SYNTAX_AT, INTEGER_SYNTAX_OID );
478         attrs.put( MetaSchemaConstants.M_DESCRIPTION_AT, DESCRIPTION0 );
479         attrs.put( MetaSchemaConstants.M_EQUALITY_AT, "caseIgnoreMatch" );
480         attrs.put( MetaSchemaConstants.M_SINGLE_VALUE_AT, "FALSE" );
481         attrs.put( MetaSchemaConstants.M_USAGE_AT, "directoryOperation" );
482         
483         LdapDN dn = getAttributeTypeContainer( "nis" );
484         dn.add( MetaSchemaConstants.M_OID_AT + "=" + OID );
485         getSchemaContext( service ).createSubcontext( dn, attrs );
486         
487         assertFalse( "adding new attributeType to disabled schema should not register it into the registries", 
488             getAttributeTypeRegistry().hasAttributeType( OID ) );
489     }
490 
491 
492     @Test
493     public void testMoveAttributeTypeToDisabledSchema() throws Exception
494     {
495         testAddAttributeType();
496         
497         LdapDN dn = getAttributeTypeContainer( "apachemeta" );
498         dn.add( MetaSchemaConstants.M_OID_AT + "=" + OID );
499 
500         // nis is inactive by default
501         LdapDN newdn = getAttributeTypeContainer( "nis" );
502         newdn.add( MetaSchemaConstants.M_OID_AT + "=" + OID );
503         
504         getSchemaContext( service ).rename( dn, newdn );
505 
506         assertFalse( "attributeType OID should no longer be present", 
507             getAttributeTypeRegistry().hasAttributeType( OID ) );
508     }
509 
510 
511     @Test
512     public void testMoveMatchingRuleToEnabledSchema() throws Exception
513     {
514         testAddAttributeTypeToDisabledSchema();
515         
516         // nis is inactive by default
517         LdapDN dn = getAttributeTypeContainer( "nis" );
518         dn.add( MetaSchemaConstants.M_OID_AT + "=" + OID );
519 
520         assertFalse( "attributeType OID should NOT be present when added to disabled nis schema", 
521             getAttributeTypeRegistry().hasAttributeType( OID ) );
522 
523         LdapDN newdn = getAttributeTypeContainer( "apachemeta" );
524         newdn.add( MetaSchemaConstants.M_OID_AT + "=" + OID );
525         
526         getSchemaContext( service ).rename( dn, newdn );
527 
528         assertTrue( "attributeType OID should be present when moved to enabled schema", 
529             getAttributeTypeRegistry().hasAttributeType( OID ) );
530         
531         assertEquals( "attributeType should be in apachemeta schema after move", 
532             getAttributeTypeRegistry().getSchemaName( OID ), "apachemeta" );
533     }
534 }