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 final class ObjectClassHelper 044{ 045 private ObjectClassHelper() 046 { 047 } 048 049 /** A logger for this class */ 050 private static final Logger LOG = LoggerFactory.getLogger( ObjectClassHelper.class ); 051 052 /** 053 * Inject the ObjectClass into the registries, updating the references to 054 * other SchemaObject 055 * 056 * @param objectClass The ObjectClass to add to the Registries 057 * @param errors The errors we got while adding the ObjectClass to the Registries 058 * @param registries The Registries 059 * @throws LdapException on failure 060 */ 061 public static void addToRegistries( ObjectClass objectClass, List<Throwable> errors, Registries registries ) throws LdapException 062 { 063 if ( registries != null ) 064 { 065 try 066 { 067 objectClass.unlock(); 068 069 // The superiors 070 buildSuperiors( objectClass, errors, registries ); 071 072 // The MAY AttributeTypes 073 buildMay( objectClass, errors, registries ); 074 075 // The MUST AttributeTypes 076 buildMust( objectClass, errors, registries ); 077 078 /** 079 * Add the OC references (using and usedBy) : 080 * OC -> AT (MAY and MUST) 081 * OC -> OC (SUPERIORS) 082 */ 083 for ( AttributeType mayAttributeType : objectClass.getMayAttributeTypes() ) 084 { 085 registries.addReference( objectClass, mayAttributeType ); 086 } 087 088 for ( AttributeType mustAttributeType : objectClass.getMustAttributeTypes() ) 089 { 090 registries.addReference( objectClass, mustAttributeType ); 091 } 092 093 for ( ObjectClass superiorObjectClass : objectClass.getSuperiors() ) 094 { 095 registries.addReference( objectClass, superiorObjectClass ); 096 } 097 } 098 finally 099 { 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}