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   *    https://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.SchemaErrorHandler;
32  import org.apache.directory.api.ldap.model.schema.registries.AttributeTypeRegistry;
33  import org.apache.directory.api.ldap.model.schema.registries.ObjectClassRegistry;
34  import org.apache.directory.api.ldap.model.schema.registries.Registries;
35  import org.slf4j.Logger;
36  import org.slf4j.LoggerFactory;
37  
38  /**
39   * An helper class used to store all the methods associated with an ObjectClass
40   * in relation with the Registries and SchemaManager.
41   * 
42   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
43   */
44  public final class ObjectClassHelper
45  {
46      /** A logger for this class */
47      private static final Logger LOG = LoggerFactory.getLogger( ObjectClassHelper.class );
48  
49      private ObjectClassHelper()
50      {
51      }
52  
53  
54      /**
55       * Inject the ObjectClass into the registries, updating the references to
56       * other SchemaObject
57       *
58       * @param objectClass The ObjectClass to add to the Registries
59       * @param errorHandler Error handler
60       * @param registries The Registries
61       */
62      public static void addToRegistries( ObjectClass objectClass, SchemaErrorHandler errorHandler, Registries registries )
63      {
64          if ( registries != null )
65          {
66              try
67              {
68                  objectClass.unlock();
69                  
70                  // The superiors
71                  buildSuperiors( objectClass, errorHandler, registries );
72      
73                  // The MAY AttributeTypes
74                  buildMay( objectClass, errorHandler, registries );
75      
76                  // The MUST AttributeTypes
77                  buildMust( objectClass, errorHandler, registries );
78      
79                  /**
80                   * Add the OC references (using and usedBy) :
81                   * OC -> AT (MAY and MUST)
82                   * OC -> OC (SUPERIORS)
83                   */
84                  for ( AttributeType mayAttributeType : objectClass.getMayAttributeTypes() )
85                  {
86                      registries.addReference( objectClass, mayAttributeType );
87                  }
88      
89                  for ( AttributeType mustAttributeType : objectClass.getMustAttributeTypes() )
90                  {
91                      registries.addReference( objectClass, mustAttributeType );
92                  }
93      
94                  for ( ObjectClass superiorObjectClass : objectClass.getSuperiors() )
95                  {
96                      registries.addReference( objectClass, superiorObjectClass );
97                  }
98              }
99              finally
100             {
101                 objectClass.lock();
102             }
103         }
104     }
105 
106 
107     /**
108      * Build the references to this ObjectClass SUPERIORS, checking that the type
109      * hierarchy is correct.
110      * 
111      * @param objectClass The oOjectClass to process
112      * @param errorHandler The error handler
113      * @param registries The Registries instance
114      */
115     private static void buildSuperiors( ObjectClass objectClass, SchemaErrorHandler errorHandler, Registries registries )
116     {
117         ObjectClassRegistry ocRegistry = registries.getObjectClassRegistry();
118         List<String> superiorOids = objectClass.getSuperiorOids();
119 
120         if ( superiorOids != null )
121         {
122             objectClass.getSuperiors().clear();
123 
124             for ( String superiorName : superiorOids )
125             {
126                 try
127                 {
128                     ObjectClass superior = ocRegistry.lookup( ocRegistry.getOidByName( superiorName ) );
129 
130                     // Before adding the superior, check that the ObjectClass type is consistent
131                     switch ( objectClass.getType() )
132                     {
133                         case ABSTRACT:
134                             if ( superior.getType() != ObjectClassTypeEnum.ABSTRACT )
135                             {
136                                 // An ABSTRACT OC can only inherit from ABSTRACT OCs
137                                 String msg = I18n.err( I18n.ERR_13766_ABSTRACT_OC_CANNOT_INHERIT_FROM_OC, 
138                                     objectClass.getOid(), superior.getObjectType(), superior );
139 
140                                 LdapSchemaException ldapSchemaException = new LdapSchemaException(
141                                     LdapSchemaExceptionCodes.OC_ABSTRACT_MUST_INHERIT_FROM_ABSTRACT_OC, msg );
142                                 ldapSchemaException.setSourceObject( objectClass );
143                                 errorHandler.handle( LOG, msg, ldapSchemaException );
144 
145                                 continue;
146                             }
147 
148                             break;
149 
150                         case AUXILIARY:
151                             if ( superior.getType() == ObjectClassTypeEnum.STRUCTURAL )
152                             {
153                                 // An AUXILIARY OC cannot inherit from STRUCTURAL OCs
154                                 String msg = I18n.err( I18n.ERR_13767_AUX_OC_CANNOT_INHERIT_FROM_STRUCT_OC, objectClass.getOid(), superior );
155 
156                                 LdapSchemaException ldapSchemaException = new LdapSchemaException(
157                                     LdapSchemaExceptionCodes.OC_AUXILIARY_CANNOT_INHERIT_FROM_STRUCTURAL_OC, msg );
158                                 ldapSchemaException.setSourceObject( objectClass );
159                                 errorHandler.handle( LOG, msg, ldapSchemaException );
160 
161                                 continue;
162                             }
163 
164                             break;
165 
166                         case STRUCTURAL:
167                             if ( superior.getType() == ObjectClassTypeEnum.AUXILIARY )
168                             {
169                                 // A STRUCTURAL OC cannot inherit from AUXILIARY OCs
170                                 String msg = I18n.err( I18n.ERR_13768_STRUCT_OC_CANNOT_INHERIT_FROM_AUX_OC, objectClass.getOid(), superior );
171 
172                                 LdapSchemaException ldapSchemaException = new LdapSchemaException(
173                                     LdapSchemaExceptionCodes.OC_STRUCTURAL_CANNOT_INHERIT_FROM_AUXILIARY_OC, msg );
174                                 ldapSchemaException.setSourceObject( objectClass );
175                                 errorHandler.handle( LOG, msg, ldapSchemaException );
176 
177                                 continue;
178                             }
179 
180                             break;
181 
182                         default:
183                             throw new IllegalArgumentException( I18n.err( I18n.ERR_13717_UNEXPECTED_OBJECT_CLASS_TYPE_ENUM, 
184                                 objectClass.getType() ) );
185                     }
186 
187                     objectClass.getSuperiors().add( superior );
188                 }
189                 catch ( LdapException ne )
190                 {
191                     // Cannot find the OC
192                     String msg = I18n.err( I18n.ERR_13769_CANNOT_REGISTER_SUPERIOR_MISSING, 
193                         objectClass.getOid(), superiorName );
194 
195                     LdapSchemaException ldapSchemaException = new LdapSchemaException(
196                         LdapSchemaExceptionCodes.OC_NONEXISTENT_SUPERIOR, msg, ne );
197                     ldapSchemaException.setSourceObject( objectClass );
198                     ldapSchemaException.setRelatedId( superiorName );
199                     errorHandler.handle( LOG, msg, ldapSchemaException );
200 
201                     return;
202                 }
203             }
204         }
205     }
206 
207 
208     /**
209      * Build and check the MUST AT for this ObjectClass.
210      * 
211      * @param objectClass The oOjectClass to process
212      * @param errorHandler The error handler
213      * @param registries The Registries instance
214      */
215     private static void buildMust( ObjectClass objectClass, SchemaErrorHandler errorHandler, Registries registries )
216     {
217         AttributeTypeRegistry atRegistry = registries.getAttributeTypeRegistry();
218         List<String> mustAttributeTypeOids = objectClass.getMustAttributeTypeOids();
219 
220         if ( mustAttributeTypeOids != null )
221         {
222             objectClass.getMustAttributeTypes().clear();
223 
224             for ( String mustAttributeTypeName : mustAttributeTypeOids )
225             {
226                 try
227                 {
228                     AttributeType attributeType = atRegistry.lookup( mustAttributeTypeName );
229 
230                     if ( attributeType.isCollective() )
231                     {
232                         // Collective Attributes are not allowed in MAY or MUST
233                         String msg = I18n.err( I18n.ERR_13778_COLLECTIVE_NOT_ALLOWED_IN_MUST, mustAttributeTypeName,
234                             objectClass.getOid() );
235 
236                         LdapSchemaException ldapSchemaException = new LdapSchemaException(
237                             LdapSchemaExceptionCodes.OC_COLLECTIVE_NOT_ALLOWED_IN_MUST, msg );
238                         ldapSchemaException.setSourceObject( objectClass );
239                         ldapSchemaException.setRelatedId( mustAttributeTypeName );
240                         errorHandler.handle( LOG, msg, ldapSchemaException );
241 
242                         continue;
243                     }
244 
245                     if ( objectClass.getMustAttributeTypes().contains( attributeType ) )
246                     {
247                         // Already registered : this is an error
248                         String msg = I18n.err( I18n.ERR_13772_CANNOT_REGISTER_DUPLICATE_AT_IN_MUST, 
249                             objectClass.getOid(), mustAttributeTypeName );
250 
251                         LdapSchemaException ldapSchemaException = new LdapSchemaException(
252                             LdapSchemaExceptionCodes.OC_DUPLICATE_AT_IN_MUST, msg );
253                         ldapSchemaException.setSourceObject( objectClass );
254                         ldapSchemaException.setRelatedId( mustAttributeTypeName );
255                         errorHandler.handle( LOG, msg, ldapSchemaException );
256 
257                         continue;
258                     }
259 
260                     // Check that the MUST AT is not also present in the MAY AT
261                     if ( objectClass.getMayAttributeTypes().contains( attributeType ) )
262                     {
263                         // Already registered : this is an error
264                         String msg = I18n.err( I18n.ERR_13773_CANNOT_REGISTER_DUPLICATE_AT_IN_MAY_AND_MUST, 
265                             objectClass.getOid(), mustAttributeTypeName );
266 
267                         LdapSchemaException ldapSchemaException = new LdapSchemaException(
268                             LdapSchemaExceptionCodes.OC_DUPLICATE_AT_IN_MAY_AND_MUST,
269                             msg );
270                         ldapSchemaException.setSourceObject( objectClass );
271                         ldapSchemaException.setRelatedId( mustAttributeTypeName );
272                         errorHandler.handle( LOG, msg, ldapSchemaException );
273 
274                         continue;
275                     }
276 
277                     objectClass.getMustAttributeTypes().add( attributeType );
278                 }
279                 catch ( LdapException ne )
280                 {
281                     // Cannot find the AT
282                     String msg = I18n.err( I18n.ERR_13774_CANNOT_REGISTER_AT_IN_MUST_DOES_NOT_EXIST, 
283                         objectClass.getOid(), mustAttributeTypeName );
284 
285                     LdapSchemaException ldapSchemaException = new LdapSchemaException(
286                         LdapSchemaExceptionCodes.OC_NONEXISTENT_MUST_AT, msg, ne );
287                     ldapSchemaException.setSourceObject( objectClass );
288                     ldapSchemaException.setRelatedId( mustAttributeTypeName );
289                     errorHandler.handle( LOG, msg, ldapSchemaException );
290                 }
291             }
292         }
293     }
294     
295     
296     /**
297      * Build and check the MAY AT for this ObjectClass
298      * 
299      * @param objectClass The oOjectClass to process
300      * @param errorHandler The error handler
301      * @param registries The Registries instance
302      */
303     private static void buildMay( ObjectClass objectClass, SchemaErrorHandler errorHandler, Registries registries )
304     {
305         AttributeTypeRegistry atRegistry = registries.getAttributeTypeRegistry();
306         List<String> mayAttributeTypeOids = objectClass.getMayAttributeTypeOids();
307 
308         if ( mayAttributeTypeOids != null )
309         {
310             objectClass.getMayAttributeTypes().clear();
311 
312             for ( String mayAttributeTypeName : mayAttributeTypeOids )
313             {
314                 try
315                 {
316                     AttributeType attributeType = atRegistry.lookup( mayAttributeTypeName );
317 
318                     if ( attributeType.isCollective() )
319                     {
320                         // Collective Attributes are not allowed in MAY or MUST
321                         String msg = I18n.err( I18n.ERR_13779_COLLECTIVE_NOT_ALLOWED_IN_MAY, mayAttributeTypeName, objectClass.getOid() );
322 
323                         LdapSchemaException ldapSchemaException = new LdapSchemaException(
324                             LdapSchemaExceptionCodes.OC_COLLECTIVE_NOT_ALLOWED_IN_MAY, msg );
325                         ldapSchemaException.setSourceObject( objectClass );
326                         ldapSchemaException.setRelatedId( mayAttributeTypeName );
327                         errorHandler.handle( LOG, msg, ldapSchemaException );
328 
329                         continue;
330                     }
331 
332                     if ( objectClass.getMayAttributeTypes().contains( attributeType ) )
333                     {
334                         // Already registered : this is an error
335                         String msg = I18n.err( 
336                             I18n.ERR_13770_CANNOT_REGISTER_DUPLICATE_AT_IN_MAY, objectClass.getOid(), mayAttributeTypeName );
337 
338                         LdapSchemaException ldapSchemaException = new LdapSchemaException(
339                             LdapSchemaExceptionCodes.OC_DUPLICATE_AT_IN_MAY, msg );
340                         ldapSchemaException.setSourceObject( objectClass );
341                         ldapSchemaException.setRelatedId( mayAttributeTypeName );
342                         errorHandler.handle( LOG, msg, ldapSchemaException );
343 
344                         continue;
345                     }
346 
347                     objectClass.getMayAttributeTypes().add( attributeType );
348                 }
349                 catch ( LdapException ne )
350                 {
351                     // Cannot find the AT
352                     String msg = I18n.err( I18n.ERR_13771_CANNOT_REGISTER_AT_IN_MAY_DOES_NOT_EXIST, objectClass.getOid(), mayAttributeTypeName );
353 
354                     LdapSchemaException ldapSchemaException = new LdapSchemaException(
355                         LdapSchemaExceptionCodes.OC_NONEXISTENT_MAY_AT, msg, ne );
356                     ldapSchemaException.setSourceObject( objectClass );
357                     ldapSchemaException.setRelatedId( mayAttributeTypeName );
358                     errorHandler.handle( LOG, msg, ldapSchemaException );
359                 }
360             }
361         }
362     }
363     
364     
365     /**
366      * Remove the ObjectClass from the registries, updating the references to
367      * other SchemaObject.
368      *
369      * If one of the referenced SchemaObject does not exist (SUPERIORS, MAY, MUST),
370      * an exception is thrown.
371      *
372      * @param objectClass The ObjectClass to remove fro the registries
373      * @param errorHandler Error handler
374      * @param registries The Registries
375      * @throws LdapException If the ObjectClass is not valid
376      */
377     public static void removeFromRegistries( ObjectClass objectClass, SchemaErrorHandler errorHandler, Registries registries ) throws LdapException
378     {
379         if ( registries != null )
380         {
381             ObjectClassRegistry objectClassRegistry = registries.getObjectClassRegistry();
382 
383             // Unregister this ObjectClass into the Descendant map
384             objectClassRegistry.unregisterDescendants( objectClass, objectClass.getSuperiors() );
385 
386             /**
387              * Remove the OC references (using and usedBy) :
388              * OC -> AT (for MAY and MUST)
389              * OC -> OC
390              */
391             if ( objectClass.getMayAttributeTypes() != null )
392             {
393                 for ( AttributeType may : objectClass.getMayAttributeTypes() )
394                 {
395                     registries.delReference( objectClass, may );
396                 }
397             }
398 
399             if ( objectClass.getMustAttributeTypes() != null )
400             {
401                 for ( AttributeType must : objectClass.getMustAttributeTypes() )
402                 {
403                     registries.delReference( objectClass, must );
404                 }
405             }
406 
407             if ( objectClass.getSuperiors() != null )
408             {
409                 for ( ObjectClass superior : objectClass.getSuperiors() )
410                 {
411                     registries.delReference( objectClass, superior );
412                 }
413             }
414         }
415     }
416 }