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.SchemaErrorHandler; 032import org.apache.directory.api.ldap.model.schema.registries.AttributeTypeRegistry; 033import org.apache.directory.api.ldap.model.schema.registries.ObjectClassRegistry; 034import org.apache.directory.api.ldap.model.schema.registries.Registries; 035import org.slf4j.Logger; 036import org.slf4j.LoggerFactory; 037 038/** 039 * An helper class used to store all the methods associated with an ObjectClass 040 * in relation with the Registries and SchemaManager. 041 * 042 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 043 */ 044public final class ObjectClassHelper 045{ 046 /** A logger for this class */ 047 private static final Logger LOG = LoggerFactory.getLogger( ObjectClassHelper.class ); 048 049 private ObjectClassHelper() 050 { 051 } 052 053 054 /** 055 * Inject the ObjectClass into the registries, updating the references to 056 * other SchemaObject 057 * 058 * @param objectClass The ObjectClass to add to the Registries 059 * @param errorHandler Error handler 060 * @param registries The Registries 061 */ 062 public static void addToRegistries( ObjectClass objectClass, SchemaErrorHandler errorHandler, Registries registries ) 063 { 064 if ( registries != null ) 065 { 066 try 067 { 068 objectClass.unlock(); 069 070 // The superiors 071 buildSuperiors( objectClass, errorHandler, registries ); 072 073 // The MAY AttributeTypes 074 buildMay( objectClass, errorHandler, registries ); 075 076 // The MUST AttributeTypes 077 buildMust( objectClass, errorHandler, registries ); 078 079 /** 080 * Add the OC references (using and usedBy) : 081 * OC -> AT (MAY and MUST) 082 * OC -> OC (SUPERIORS) 083 */ 084 for ( AttributeType mayAttributeType : objectClass.getMayAttributeTypes() ) 085 { 086 registries.addReference( objectClass, mayAttributeType ); 087 } 088 089 for ( AttributeType mustAttributeType : objectClass.getMustAttributeTypes() ) 090 { 091 registries.addReference( objectClass, mustAttributeType ); 092 } 093 094 for ( ObjectClass superiorObjectClass : objectClass.getSuperiors() ) 095 { 096 registries.addReference( objectClass, superiorObjectClass ); 097 } 098 } 099 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}