View Javadoc
1   /*
2    *  Licensed to the Apache Software Foundation (ASF) under one
3    *  or more contributor license agreements.  See the NOTICE file
4    *  distributed with this work for additional information
5    *  regarding copyright ownership.  The ASF licenses this file
6    *  to you under the Apache License, Version 2.0 (the
7    *  "License"); you may not use this file except in compliance
8    *  with the License.  You may obtain a copy of the License at
9    *
10   *    http://www.apache.org/licenses/LICENSE-2.0
11   *
12   *  Unless required by applicable law or agreed to in writing,
13   *  software distributed under the License is distributed on an
14   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *  KIND, either express or implied.  See the License for the
16   *  specific language governing permissions and limitations
17   *  under the License.
18   *
19   */
20  package org.apache.directory.api.ldap.model.schema.registries.helper;
21  
22  import java.util.List;
23  
24  import org.apache.directory.api.i18n.I18n;
25  import org.apache.directory.api.ldap.model.exception.LdapException;
26  import org.apache.directory.api.ldap.model.exception.LdapSchemaException;
27  import org.apache.directory.api.ldap.model.exception.LdapSchemaExceptionCodes;
28  import org.apache.directory.api.ldap.model.schema.AttributeType;
29  import org.apache.directory.api.ldap.model.schema.ObjectClass;
30  import org.apache.directory.api.ldap.model.schema.ObjectClassTypeEnum;
31  import org.apache.directory.api.ldap.model.schema.registries.AttributeTypeRegistry;
32  import org.apache.directory.api.ldap.model.schema.registries.ObjectClassRegistry;
33  import org.apache.directory.api.ldap.model.schema.registries.Registries;
34  import org.slf4j.Logger;
35  import org.slf4j.LoggerFactory;
36  
37  /**
38   * An helper class used to store all the methods associated with an ObjectClass
39   * in relation with the Registries and SchemaManager.
40   * 
41   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
42   */
43  public class ObjectClassHelper
44  {
45      /** A logger for this class */
46      private static final Logger LOG = LoggerFactory.getLogger( ObjectClassHelper.class );
47  
48      /**
49       * Inject the ObjectClass into the registries, updating the references to
50       * other SchemaObject
51       *
52       * @param objectClass The ObjectClass to add to the Registries
53       * @param errors The errors we got while adding the ObjectClass to the Registries
54       * @param registries The Registries
55       * @throws Exception on failure
56       */
57      public static void addToRegistries( ObjectClass objectClass, List<Throwable> errors, Registries registries ) throws LdapException
58      {
59          if ( registries != null )
60          {
61              try
62              {
63                  objectClass.unlock();
64                  
65                  // The superiors
66                  buildSuperiors( objectClass, errors, registries );
67      
68                  // The MAY AttributeTypes
69                  buildMay( objectClass, errors, registries );
70      
71                  // The MUST AttributeTypes
72                  buildMust( objectClass, errors, registries );
73      
74                  /**
75                   * Add the OC references (using and usedBy) :
76                   * OC -> AT (MAY and MUST)
77                   * OC -> OC (SUPERIORS)
78                   */
79                  for ( AttributeType mayAttributeType : objectClass.getMayAttributeTypes() )
80                  {
81                      registries.addReference( objectClass, mayAttributeType );
82                  }
83      
84                  for ( AttributeType mustAttributeType : objectClass.getMustAttributeTypes() )
85                  {
86                      registries.addReference( objectClass, mustAttributeType );
87                  }
88      
89                  for ( ObjectClass superiorObjectClass : objectClass.getSuperiors() )
90                  {
91                      registries.addReference( objectClass, superiorObjectClass );
92                  }
93              }
94              finally
95              {
96                  objectClass.lock();
97              }
98          }
99      }
100 
101 
102     /**
103      * Build the references to this ObjectClass SUPERIORS, checking that the type
104      * hierarchy is correct.
105      */
106     private static void buildSuperiors( ObjectClass objectClass, List<Throwable> errors, Registries registries )
107     {
108         ObjectClassRegistry ocRegistry = registries.getObjectClassRegistry();
109         List<String> superiorOids = objectClass.getSuperiorOids();
110 
111         if ( superiorOids != null )
112         {
113             objectClass.getSuperiors().clear();
114 
115             for ( String superiorName : superiorOids )
116             {
117                 try
118                 {
119                     ObjectClass superior = ocRegistry.lookup( ocRegistry.getOidByName( superiorName ) );
120 
121                     // Before adding the superior, check that the ObjectClass type is consistent
122                     switch ( objectClass.getType() )
123                     {
124                         case ABSTRACT:
125                             if ( superior.getType() != ObjectClassTypeEnum.ABSTRACT )
126                             {
127                                 // An ABSTRACT OC can only inherit from ABSTRACT OCs
128                                 String msg = I18n.err( I18n.ERR_04318, objectClass.getOid(), superior.getObjectType(), superior );
129 
130                                 LdapSchemaException ldapSchemaException = new LdapSchemaException(
131                                     LdapSchemaExceptionCodes.OC_ABSTRACT_MUST_INHERIT_FROM_ABSTRACT_OC, msg );
132                                 ldapSchemaException.setSourceObject( objectClass );
133                                 errors.add( ldapSchemaException );
134                                 LOG.info( msg );
135 
136                                 continue;
137                             }
138 
139                             break;
140 
141                         case AUXILIARY:
142                             if ( superior.getType() == ObjectClassTypeEnum.STRUCTURAL )
143                             {
144                                 // An AUXILIARY OC cannot inherit from STRUCTURAL OCs
145                                 String msg = I18n.err( I18n.ERR_04319, objectClass.getOid(), superior );
146 
147                                 LdapSchemaException ldapSchemaException = new LdapSchemaException(
148                                     LdapSchemaExceptionCodes.OC_AUXILIARY_CANNOT_INHERIT_FROM_STRUCTURAL_OC, msg );
149                                 ldapSchemaException.setSourceObject( objectClass );
150                                 errors.add( ldapSchemaException );
151                                 LOG.info( msg );
152 
153                                 continue;
154                             }
155 
156                             break;
157 
158                         case STRUCTURAL:
159                             if ( superior.getType() == ObjectClassTypeEnum.AUXILIARY )
160                             {
161                                 // A STRUCTURAL OC cannot inherit from AUXILIARY OCs
162                                 String msg = I18n.err( I18n.ERR_04320, objectClass.getOid(), superior );
163 
164                                 LdapSchemaException ldapSchemaException = new LdapSchemaException(
165                                     LdapSchemaExceptionCodes.OC_STRUCTURAL_CANNOT_INHERIT_FROM_AUXILIARY_OC, msg );
166                                 ldapSchemaException.setSourceObject( objectClass );
167                                 errors.add( ldapSchemaException );
168                                 LOG.info( msg );
169 
170                                 continue;
171                             }
172 
173                             break;
174                     }
175 
176                     objectClass.getSuperiors().add( superior );
177                 }
178                 catch ( LdapException ne )
179                 {
180                     // Cannot find the OC
181                     String msg = I18n.err( I18n.ERR_04321, objectClass.getOid(), superiorName );
182 
183                     LdapSchemaException ldapSchemaException = new LdapSchemaException(
184                         LdapSchemaExceptionCodes.OC_NONEXISTENT_SUPERIOR, msg, ne );
185                     ldapSchemaException.setSourceObject( objectClass );
186                     ldapSchemaException.setRelatedId( superiorName );
187                     errors.add( ldapSchemaException );
188                     LOG.info( msg );
189 
190                     return;
191                 }
192             }
193         }
194     }
195 
196 
197     /**
198      * Build and check the MUST AT for this ObjectClass.
199      */
200     private static void buildMust( ObjectClass objectClass, List<Throwable> errors, Registries registries )
201     {
202         AttributeTypeRegistry atRegistry = registries.getAttributeTypeRegistry();
203         List<String> mustAttributeTypeOids = objectClass.getMustAttributeTypeOids();
204 
205         if ( mustAttributeTypeOids != null )
206         {
207             objectClass.getMustAttributeTypes().clear();
208 
209             for ( String mustAttributeTypeName : mustAttributeTypeOids )
210             {
211                 try
212                 {
213                     AttributeType attributeType = atRegistry.lookup( mustAttributeTypeName );
214 
215                     if ( attributeType.isCollective() )
216                     {
217                         // Collective Attributes are not allowed in MAY or MUST
218                         String msg = I18n.err( I18n.ERR_04484_COLLECTIVE_NOT_ALLOWED_IN_MUST, mustAttributeTypeName,
219                             objectClass.getOid() );
220 
221                         LdapSchemaException ldapSchemaException = new LdapSchemaException(
222                             LdapSchemaExceptionCodes.OC_COLLECTIVE_NOT_ALLOWED_IN_MUST, msg );
223                         ldapSchemaException.setSourceObject( objectClass );
224                         ldapSchemaException.setRelatedId( mustAttributeTypeName );
225                         errors.add( ldapSchemaException );
226                         LOG.info( msg );
227 
228                         break;
229                     }
230 
231                     if ( objectClass.getMustAttributeTypes().contains( attributeType ) )
232                     {
233                         // Already registered : this is an error
234                         String msg = I18n.err( I18n.ERR_04324, objectClass.getOid(), mustAttributeTypeName );
235 
236                         LdapSchemaException ldapSchemaException = new LdapSchemaException(
237                             LdapSchemaExceptionCodes.OC_DUPLICATE_AT_IN_MUST, msg );
238                         ldapSchemaException.setSourceObject( objectClass );
239                         ldapSchemaException.setRelatedId( mustAttributeTypeName );
240                         errors.add( ldapSchemaException );
241                         LOG.info( msg );
242 
243                         break;
244                     }
245 
246                     // Check that the MUST AT is not also present in the MAY AT
247                     if ( objectClass.getMayAttributeTypes().contains( attributeType ) )
248                     {
249                         // Already registered : this is an error
250                         String msg = I18n.err( I18n.ERR_04325, objectClass.getOid(), mustAttributeTypeName );
251 
252                         LdapSchemaException ldapSchemaException = new LdapSchemaException(
253                             LdapSchemaExceptionCodes.OC_DUPLICATE_AT_IN_MAY_AND_MUST,
254                             msg );
255                         ldapSchemaException.setSourceObject( objectClass );
256                         ldapSchemaException.setRelatedId( mustAttributeTypeName );
257                         errors.add( ldapSchemaException );
258                         LOG.info( msg );
259 
260                         break;
261                     }
262 
263                     objectClass.getMustAttributeTypes().add( attributeType );
264                 }
265                 catch ( LdapException ne )
266                 {
267                     // Cannot find the AT
268                     String msg = I18n.err( I18n.ERR_04326, objectClass.getOid(), mustAttributeTypeName );
269 
270                     LdapSchemaException ldapSchemaException = new LdapSchemaException(
271                         LdapSchemaExceptionCodes.OC_NONEXISTENT_MUST_AT, msg, ne );
272                     ldapSchemaException.setSourceObject( objectClass );
273                     ldapSchemaException.setRelatedId( mustAttributeTypeName );
274                     errors.add( ldapSchemaException );
275                     LOG.info( msg );
276 
277                     break;
278                 }
279             }
280         }
281     }
282     
283     
284     /**
285      * Build and check the MAY AT for this ObjectClass
286      */
287     private static void buildMay( ObjectClass objectClass, List<Throwable> errors, Registries registries )
288     {
289         AttributeTypeRegistry atRegistry = registries.getAttributeTypeRegistry();
290         List<String> mayAttributeTypeOids = objectClass.getMayAttributeTypeOids();
291 
292         if ( mayAttributeTypeOids != null )
293         {
294             objectClass.getMayAttributeTypes().clear();
295 
296             for ( String mayAttributeTypeName : mayAttributeTypeOids )
297             {
298                 try
299                 {
300                     AttributeType attributeType = atRegistry.lookup( mayAttributeTypeName );
301 
302                     if ( attributeType.isCollective() )
303                     {
304                         // Collective Attributes are not allowed in MAY or MUST
305                         String msg = I18n.err( I18n.ERR_04485_COLLECTIVE_NOT_ALLOWED_IN_MAY, mayAttributeTypeName, objectClass.getOid() );
306 
307                         LdapSchemaException ldapSchemaException = new LdapSchemaException(
308                             LdapSchemaExceptionCodes.OC_COLLECTIVE_NOT_ALLOWED_IN_MAY, msg );
309                         ldapSchemaException.setSourceObject( objectClass );
310                         ldapSchemaException.setRelatedId( mayAttributeTypeName );
311                         errors.add( ldapSchemaException );
312                         LOG.info( msg );
313 
314                         break;
315                     }
316 
317                     if ( objectClass.getMayAttributeTypes().contains( attributeType ) )
318                     {
319                         // Already registered : this is an error
320                         String msg = I18n.err( I18n.ERR_04322, objectClass.getOid(), mayAttributeTypeName );
321 
322                         LdapSchemaException ldapSchemaException = new LdapSchemaException(
323                             LdapSchemaExceptionCodes.OC_DUPLICATE_AT_IN_MAY, msg );
324                         ldapSchemaException.setSourceObject( objectClass );
325                         ldapSchemaException.setRelatedId( mayAttributeTypeName );
326                         errors.add( ldapSchemaException );
327                         LOG.info( msg );
328 
329                         break;
330                     }
331 
332                     objectClass.getMayAttributeTypes().add( attributeType );
333                 }
334                 catch ( LdapException ne )
335                 {
336                     // Cannot find the AT
337                     String msg = I18n.err( I18n.ERR_04323, objectClass.getOid(), mayAttributeTypeName );
338 
339                     LdapSchemaException ldapSchemaException = new LdapSchemaException(
340                         LdapSchemaExceptionCodes.OC_NONEXISTENT_MAY_AT, msg, ne );
341                     ldapSchemaException.setSourceObject( objectClass );
342                     ldapSchemaException.setRelatedId( mayAttributeTypeName );
343                     errors.add( ldapSchemaException );
344                     LOG.info( msg );
345 
346                     break;
347                 }
348             }
349         }
350     }
351     
352     
353     /**
354      * Remove the ObjectClass from the registries, updating the references to
355      * other SchemaObject.
356      *
357      * If one of the referenced SchemaObject does not exist (SUPERIORS, MAY, MUST),
358      * an exception is thrown.
359      *
360      * @param objectClass The ObjectClass to remove fro the registries
361      * @param errors The errors we got while removing the ObjectClass from the registries
362      * @param registries The Registries
363      * @exception If the ObjectClass is not valid
364      */
365     public static void removeFromRegistries( ObjectClass objectClass, List<Throwable> errors, Registries registries ) throws LdapException
366     {
367         if ( registries != null )
368         {
369             ObjectClassRegistry objectClassRegistry = registries.getObjectClassRegistry();
370 
371             // Unregister this ObjectClass into the Descendant map
372             objectClassRegistry.unregisterDescendants( objectClass, objectClass.getSuperiors() );
373 
374             /**
375              * Remove the OC references (using and usedBy) :
376              * OC -> AT (for MAY and MUST)
377              * OC -> OC
378              */
379             if ( objectClass.getMayAttributeTypes() != null )
380             {
381                 for ( AttributeType may : objectClass.getMayAttributeTypes() )
382                 {
383                     registries.delReference( objectClass, may );
384                 }
385             }
386 
387             if ( objectClass.getMustAttributeTypes() != null )
388             {
389                 for ( AttributeType must : objectClass.getMustAttributeTypes() )
390                 {
391                     registries.delReference( objectClass, must );
392                 }
393             }
394 
395             if ( objectClass.getSuperiors() != null )
396             {
397                 for ( ObjectClass superior : objectClass.getSuperiors() )
398                 {
399                     registries.delReference( objectClass, superior );
400                 }
401             }
402         }
403     }
404 }