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