001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 * 019 */ 020package org.apache.directory.api.ldap.model.schema.registries.helper; 021 022import java.util.List; 023 024import org.apache.directory.api.i18n.I18n; 025import org.apache.directory.api.ldap.model.exception.LdapException; 026import org.apache.directory.api.ldap.model.exception.LdapSchemaException; 027import org.apache.directory.api.ldap.model.exception.LdapSchemaExceptionCodes; 028import org.apache.directory.api.ldap.model.schema.AttributeType; 029import org.apache.directory.api.ldap.model.schema.ObjectClass; 030import org.apache.directory.api.ldap.model.schema.ObjectClassTypeEnum; 031import org.apache.directory.api.ldap.model.schema.registries.AttributeTypeRegistry; 032import org.apache.directory.api.ldap.model.schema.registries.ObjectClassRegistry; 033import org.apache.directory.api.ldap.model.schema.registries.Registries; 034import org.slf4j.Logger; 035import org.slf4j.LoggerFactory; 036 037/** 038 * An helper class used to store all the methods associated with an ObjectClass 039 * in relation with the Registries and SchemaManager. 040 * 041 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 042 */ 043public class ObjectClassHelper 044{ 045 /** A logger for this class */ 046 private static final Logger LOG = LoggerFactory.getLogger( ObjectClassHelper.class ); 047 048 /** 049 * Inject the ObjectClass into the registries, updating the references to 050 * other SchemaObject 051 * 052 * @param objectClass The ObjectClass to add to the Registries 053 * @param errors The errors we got while adding the ObjectClass to the Registries 054 * @param registries The Registries 055 * @throws Exception on failure 056 */ 057 public static void addToRegistries( ObjectClass objectClass, List<Throwable> errors, Registries registries ) throws LdapException 058 { 059 if ( registries != null ) 060 { 061 try 062 { 063 objectClass.unlock(); 064 065 // The superiors 066 buildSuperiors( objectClass, errors, registries ); 067 068 // The MAY AttributeTypes 069 buildMay( objectClass, errors, registries ); 070 071 // The MUST AttributeTypes 072 buildMust( objectClass, errors, registries ); 073 074 /** 075 * Add the OC references (using and usedBy) : 076 * OC -> AT (MAY and MUST) 077 * OC -> OC (SUPERIORS) 078 */ 079 for ( AttributeType mayAttributeType : objectClass.getMayAttributeTypes() ) 080 { 081 registries.addReference( objectClass, mayAttributeType ); 082 } 083 084 for ( AttributeType mustAttributeType : objectClass.getMustAttributeTypes() ) 085 { 086 registries.addReference( objectClass, mustAttributeType ); 087 } 088 089 for ( ObjectClass superiorObjectClass : objectClass.getSuperiors() ) 090 { 091 registries.addReference( objectClass, superiorObjectClass ); 092 } 093 } 094 finally 095 { 096 objectClass.lock(); 097 } 098 } 099 } 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}