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 */ 020 package org.apache.directory.server.core.schema; 021 022 023 import java.util.HashMap; 024 import java.util.HashSet; 025 import java.util.Map; 026 import java.util.Set; 027 028 import javax.naming.directory.DirContext; 029 030 import org.apache.directory.server.core.interceptor.context.ModifyOperationContext; 031 import org.apache.directory.server.i18n.I18n; 032 import org.apache.directory.shared.ldap.constants.SchemaConstants; 033 import org.apache.directory.shared.ldap.entry.EntryAttribute; 034 import org.apache.directory.shared.ldap.entry.Modification; 035 import org.apache.directory.shared.ldap.entry.ServerEntry; 036 import org.apache.directory.shared.ldap.exception.LdapUnwillingToPerformException; 037 import org.apache.directory.shared.ldap.message.ResultCodeEnum; 038 import org.apache.directory.shared.ldap.name.DN; 039 import org.apache.directory.shared.ldap.schema.AttributeType; 040 import org.apache.directory.shared.ldap.schema.DITContentRule; 041 import org.apache.directory.shared.ldap.schema.DITStructureRule; 042 import org.apache.directory.shared.ldap.schema.LdapSyntax; 043 import org.apache.directory.shared.ldap.schema.MatchingRule; 044 import org.apache.directory.shared.ldap.schema.MatchingRuleUse; 045 import org.apache.directory.shared.ldap.schema.NameForm; 046 import org.apache.directory.shared.ldap.schema.ObjectClass; 047 import org.apache.directory.shared.ldap.schema.SchemaManager; 048 import org.apache.directory.shared.ldap.schema.parsers.LdapComparatorDescription; 049 import org.apache.directory.shared.ldap.schema.parsers.NormalizerDescription; 050 import org.apache.directory.shared.ldap.schema.parsers.SyntaxCheckerDescription; 051 import org.apache.directory.shared.ldap.schema.registries.SchemaLoader; 052 import org.slf4j.Logger; 053 import org.slf4j.LoggerFactory; 054 055 056 /** 057 * 058 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 059 * @version $Rev$, $Date$ 060 */ 061 public class SchemaSubentryManager 062 { 063 /** A logger for this class */ 064 private static final Logger LOG = LoggerFactory.getLogger( SchemaSubentryManager.class ); 065 066 // indices of handlers and object ids into arrays 067 private static final int COMPARATOR_INDEX = 0; 068 private static final int NORMALIZER_INDEX = 1; 069 private static final int SYNTAX_CHECKER_INDEX = 2; 070 private static final int SYNTAX_INDEX = 3; 071 private static final int MATCHING_RULE_INDEX = 4; 072 private static final int ATTRIBUTE_TYPE_INDEX = 5; 073 private static final int OBJECT_CLASS_INDEX = 6; 074 private static final int MATCHING_RULE_USE_INDEX = 7; 075 private static final int DIT_STRUCTURE_RULE_INDEX = 8; 076 private static final int DIT_CONTENT_RULE_INDEX = 9; 077 private static final int NAME_FORM_INDEX = 10; 078 079 private static final Set<String> VALID_OU_VALUES = new HashSet<String>(); 080 081 /** The schemaManager */ 082 private final SchemaManager schemaManager; 083 084 private final SchemaSubentryModifier subentryModifier; 085 086 /** The description parsers */ 087 private final DescriptionParsers parsers; 088 089 /** 090 * Maps the OID of a subschemaSubentry operational attribute to the index of 091 * the handler in the schemaObjectHandlers array. 092 */ 093 private final Map<String, Integer> opAttr2handlerIndex = new HashMap<String, Integer>( 11 ); 094 private static final String CASCADING_ERROR = 095 "Cascading has not yet been implemented: standard operation is in effect."; 096 097 static 098 { 099 VALID_OU_VALUES.add( SchemaConstants.NORMALIZERS_AT.toLowerCase() ); 100 VALID_OU_VALUES.add( SchemaConstants.COMPARATORS_AT.toLowerCase() ); 101 VALID_OU_VALUES.add( SchemaConstants.SYNTAX_CHECKERS_AT.toLowerCase() ); 102 VALID_OU_VALUES.add( "syntaxes".toLowerCase() ); 103 VALID_OU_VALUES.add( SchemaConstants.MATCHING_RULES_AT.toLowerCase() ); 104 VALID_OU_VALUES.add( SchemaConstants.MATCHING_RULE_USE_AT.toLowerCase() ); 105 VALID_OU_VALUES.add( SchemaConstants.ATTRIBUTE_TYPES_AT.toLowerCase() ); 106 VALID_OU_VALUES.add( SchemaConstants.OBJECT_CLASSES_AT.toLowerCase() ); 107 VALID_OU_VALUES.add( SchemaConstants.NAME_FORMS_AT.toLowerCase() ); 108 VALID_OU_VALUES.add( SchemaConstants.DIT_CONTENT_RULES_AT.toLowerCase() ); 109 VALID_OU_VALUES.add( SchemaConstants.DIT_STRUCTURE_RULES_AT.toLowerCase() ); 110 } 111 112 113 public SchemaSubentryManager( SchemaManager schemaManager, SchemaLoader loader ) 114 throws Exception 115 { 116 this.schemaManager = schemaManager; 117 this.subentryModifier = new SchemaSubentryModifier( schemaManager ); 118 this.parsers = new DescriptionParsers( schemaManager ); 119 120 String comparatorsOid = schemaManager.getAttributeTypeRegistry().getOidByName( SchemaConstants.COMPARATORS_AT ); 121 opAttr2handlerIndex.put( comparatorsOid, COMPARATOR_INDEX ); 122 123 String normalizersOid = schemaManager.getAttributeTypeRegistry().getOidByName( SchemaConstants.NORMALIZERS_AT ); 124 opAttr2handlerIndex.put( normalizersOid, NORMALIZER_INDEX ); 125 126 String syntaxCheckersOid = schemaManager.getAttributeTypeRegistry().getOidByName( SchemaConstants.SYNTAX_CHECKERS_AT ); 127 opAttr2handlerIndex.put( syntaxCheckersOid, SYNTAX_CHECKER_INDEX ); 128 129 String ldapSyntaxesOid = schemaManager.getAttributeTypeRegistry().getOidByName( SchemaConstants.LDAP_SYNTAXES_AT ); 130 opAttr2handlerIndex.put( ldapSyntaxesOid, SYNTAX_INDEX ); 131 132 String matchingRulesOid = schemaManager.getAttributeTypeRegistry().getOidByName( SchemaConstants.MATCHING_RULES_AT ); 133 opAttr2handlerIndex.put( matchingRulesOid, MATCHING_RULE_INDEX ); 134 135 String attributeTypesOid = schemaManager.getAttributeTypeRegistry().getOidByName( SchemaConstants.ATTRIBUTE_TYPES_AT ); 136 opAttr2handlerIndex.put( attributeTypesOid, ATTRIBUTE_TYPE_INDEX ); 137 138 String objectClassesOid = schemaManager.getAttributeTypeRegistry().getOidByName( SchemaConstants.OBJECT_CLASSES_AT ); 139 opAttr2handlerIndex.put( objectClassesOid, OBJECT_CLASS_INDEX ); 140 141 String matchingRuleUseOid = schemaManager.getAttributeTypeRegistry().getOidByName( SchemaConstants.MATCHING_RULE_USE_AT ); 142 opAttr2handlerIndex.put( matchingRuleUseOid, MATCHING_RULE_USE_INDEX ); 143 144 String ditStructureRulesOid = schemaManager.getAttributeTypeRegistry().getOidByName( SchemaConstants.DIT_STRUCTURE_RULES_AT ); 145 opAttr2handlerIndex.put( ditStructureRulesOid, DIT_STRUCTURE_RULE_INDEX ); 146 147 String ditContentRulesOid = schemaManager.getAttributeTypeRegistry().getOidByName( SchemaConstants.DIT_CONTENT_RULES_AT ); 148 opAttr2handlerIndex.put( ditContentRulesOid, DIT_CONTENT_RULE_INDEX ); 149 150 String nameFormsOid = schemaManager.getAttributeTypeRegistry().getOidByName( SchemaConstants.NAME_FORMS_AT ); 151 opAttr2handlerIndex.put( nameFormsOid, NAME_FORM_INDEX ); 152 } 153 154 155 /* (non-Javadoc) 156 * @see org.apache.directory.server.core.schema.SchemaChangeManager#modifySchemaSubentry(org.apache.directory.server.core.interceptor.context.ModifyOperationContext, org.apache.directory.server.core.entry.ServerEntry, org.apache.directory.server.core.entry.ServerEntry, boolean) 157 */ 158 public void modifySchemaSubentry( ModifyOperationContext opContext, boolean doCascadeModify ) throws Exception 159 { 160 for ( Modification mod : opContext.getModItems() ) 161 { 162 String opAttrOid = schemaManager.getAttributeTypeRegistry().getOidByName( mod.getAttribute().getId() ); 163 164 EntryAttribute serverAttribute = mod.getAttribute(); 165 166 switch ( mod.getOperation() ) 167 { 168 case ADD_ATTRIBUTE : 169 modifyAddOperation( opContext, opAttrOid, serverAttribute, doCascadeModify ); 170 break; 171 172 case REMOVE_ATTRIBUTE : 173 modifyRemoveOperation( opContext, opAttrOid, serverAttribute, doCascadeModify ); 174 break; 175 176 case REPLACE_ATTRIBUTE : 177 throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, 178 I18n.err( I18n.ERR_283 ) ); 179 180 default: 181 throw new IllegalStateException( I18n.err( I18n.ERR_284, mod.getOperation() ) ); 182 } 183 } 184 } 185 186 187 /* (non-Javadoc) 188 * @see org.apache.directory.server.core.schema.SchemaChangeManager#modifySchemaSubentry(org.apache.directory.server.core.interceptor.context.ModifyOperationContext, org.apache.directory.shared.ldap.name.DN, int, org.apache.directory.server.core.entry.ServerEntry, org.apache.directory.server.core.entry.ServerEntry, org.apache.directory.server.core.entry.ServerEntry, boolean) 189 */ 190 public void modifySchemaSubentry( ModifyOperationContext opContext, DN name, int modOp, ServerEntry mods, 191 ServerEntry subentry, ServerEntry targetSubentry, boolean doCascadeModify ) throws Exception 192 { 193 Set<AttributeType> attributeTypes = mods.getAttributeTypes(); 194 195 switch ( modOp ) 196 { 197 case( DirContext.ADD_ATTRIBUTE ): 198 for ( AttributeType attributeType:attributeTypes ) 199 { 200 modifyAddOperation( opContext, attributeType.getOid(), 201 mods.get( attributeType ), doCascadeModify ); 202 } 203 204 break; 205 206 case( DirContext.REMOVE_ATTRIBUTE ): 207 for ( AttributeType attributeType:attributeTypes ) 208 { 209 modifyRemoveOperation( opContext, attributeType.getOid(), 210 mods.get( attributeType ), doCascadeModify ); 211 } 212 213 break; 214 215 case( DirContext.REPLACE_ATTRIBUTE ): 216 throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, 217 I18n.err( I18n.ERR_283 ) ); 218 219 default: 220 throw new IllegalStateException( I18n.err( I18n.ERR_284, modOp ) ); 221 } 222 } 223 224 225 /** 226 * Handles the modify remove operation on the subschemaSubentry for schema entities. 227 * 228 * @param opAttrOid the numeric id of the operational attribute modified 229 * @param mods the attribute with the modifications 230 * @param doCascadeModify determines if a cascading operation should be performed 231 * to effect all dependents on the changed entity 232 * @throws Exception if there are problems updating the registries and the 233 * schema partition 234 */ 235 private void modifyRemoveOperation( ModifyOperationContext opContext, String opAttrOid, 236 EntryAttribute mods, boolean doCascadeModify ) throws Exception 237 { 238 int index = opAttr2handlerIndex.get( opAttrOid ); 239 240 switch( index ) 241 { 242 case( COMPARATOR_INDEX ): 243 LdapComparatorDescription[] comparatorDescriptions = parsers.parseComparators( mods ); 244 245 for ( LdapComparatorDescription comparatorDescription : comparatorDescriptions ) 246 { 247 subentryModifier.delete( opContext, comparatorDescription ); 248 } 249 break; 250 case( NORMALIZER_INDEX ): 251 NormalizerDescription[] normalizerDescriptions = parsers.parseNormalizers( mods ); 252 253 for ( NormalizerDescription normalizerDescription : normalizerDescriptions ) 254 { 255 subentryModifier.delete( opContext, normalizerDescription ); 256 } 257 break; 258 case( SYNTAX_CHECKER_INDEX ): 259 SyntaxCheckerDescription[] syntaxCheckerDescriptions = parsers.parseSyntaxCheckers( mods ); 260 261 for ( SyntaxCheckerDescription syntaxCheckerDescription : syntaxCheckerDescriptions ) 262 { 263 subentryModifier.delete( opContext, syntaxCheckerDescription ); 264 } 265 break; 266 case( SYNTAX_INDEX ): 267 LdapSyntax[] syntaxes = parsers.parseLdapSyntaxes( mods ); 268 269 for ( LdapSyntax syntax : syntaxes ) 270 { 271 subentryModifier.deleteSchemaObject( opContext, syntax ); 272 } 273 break; 274 case( MATCHING_RULE_INDEX ): 275 MatchingRule[] mrs = parsers.parseMatchingRules( mods ); 276 277 for ( MatchingRule mr : mrs ) 278 { 279 subentryModifier.deleteSchemaObject( opContext, mr ); 280 } 281 break; 282 case( ATTRIBUTE_TYPE_INDEX ): 283 AttributeType[] ats = parsers.parseAttributeTypes( mods ); 284 285 for ( AttributeType at : ats ) 286 { 287 subentryModifier.deleteSchemaObject( opContext, at ); 288 } 289 break; 290 case( OBJECT_CLASS_INDEX ): 291 ObjectClass[] ocs = parsers.parseObjectClasses( mods ); 292 293 for ( ObjectClass oc : ocs ) 294 { 295 subentryModifier.deleteSchemaObject( opContext, oc ); 296 } 297 break; 298 case( MATCHING_RULE_USE_INDEX ): 299 MatchingRuleUse[] mrus = parsers.parseMatchingRuleUses( mods ); 300 301 for ( MatchingRuleUse mru : mrus ) 302 { 303 subentryModifier.deleteSchemaObject( opContext, mru ); 304 } 305 break; 306 case( DIT_STRUCTURE_RULE_INDEX ): 307 DITStructureRule[] dsrs = parsers.parseDitStructureRules( mods ); 308 309 for ( DITStructureRule dsr : dsrs ) 310 { 311 subentryModifier.deleteSchemaObject( opContext, dsr ); 312 } 313 break; 314 case( DIT_CONTENT_RULE_INDEX ): 315 DITContentRule[] dcrs = parsers.parseDitContentRules( mods ); 316 317 for ( DITContentRule dcr : dcrs ) 318 { 319 subentryModifier.deleteSchemaObject( opContext, dcr ); 320 } 321 break; 322 case( NAME_FORM_INDEX ): 323 NameForm[] nfs = parsers.parseNameForms( mods ); 324 325 for ( NameForm nf : nfs ) 326 { 327 subentryModifier.deleteSchemaObject( opContext, nf ); 328 } 329 break; 330 default: 331 throw new IllegalStateException( I18n.err( I18n.ERR_285, index ) ); 332 } 333 } 334 335 336 /** 337 * Handles the modify add operation on the subschemaSubentry for schema entities. 338 * 339 * @param opAttrOid the numeric id of the operational attribute modified 340 * @param mods the attribute with the modifications 341 * @param doCascadeModify determines if a cascading operation should be performed 342 * to effect all dependents on the changed entity 343 * @throws Exception if there are problems updating the registries and the 344 * schema partition 345 */ 346 private void modifyAddOperation( ModifyOperationContext opContext, String opAttrOid, 347 EntryAttribute mods, boolean doCascadeModify ) throws Exception 348 { 349 if ( doCascadeModify ) 350 { 351 LOG.error( CASCADING_ERROR ); 352 } 353 354 int index = opAttr2handlerIndex.get( opAttrOid ); 355 356 switch( index ) 357 { 358 case( COMPARATOR_INDEX ): 359 LdapComparatorDescription[] comparatorDescriptions = parsers.parseComparators( mods ); 360 361 for ( LdapComparatorDescription comparatorDescription : comparatorDescriptions ) 362 { 363 subentryModifier.add( opContext, comparatorDescription ); 364 } 365 366 break; 367 368 case( NORMALIZER_INDEX ): 369 NormalizerDescription[] normalizerDescriptions = parsers.parseNormalizers( mods ); 370 371 for ( NormalizerDescription normalizerDescription : normalizerDescriptions ) 372 { 373 subentryModifier.add( opContext, normalizerDescription ); 374 } 375 376 break; 377 378 case( SYNTAX_CHECKER_INDEX ): 379 SyntaxCheckerDescription[] syntaxCheckerDescriptions = parsers.parseSyntaxCheckers( mods ); 380 381 for ( SyntaxCheckerDescription syntaxCheckerDescription : syntaxCheckerDescriptions ) 382 { 383 subentryModifier.add( opContext, syntaxCheckerDescription ); 384 } 385 386 break; 387 388 case( SYNTAX_INDEX ): 389 LdapSyntax[] syntaxes = parsers.parseLdapSyntaxes( mods ); 390 391 for ( LdapSyntax syntax : syntaxes ) 392 { 393 subentryModifier.addSchemaObject( opContext, syntax ); 394 } 395 396 break; 397 398 case( MATCHING_RULE_INDEX ): 399 MatchingRule[] mrs = parsers.parseMatchingRules( mods ); 400 401 for ( MatchingRule mr : mrs ) 402 { 403 subentryModifier.addSchemaObject( opContext, mr ); 404 } 405 406 break; 407 408 case( ATTRIBUTE_TYPE_INDEX ): 409 AttributeType[] ats = parsers.parseAttributeTypes( mods ); 410 411 for ( AttributeType at : ats ) 412 { 413 subentryModifier.addSchemaObject( opContext, at ); 414 } 415 416 break; 417 418 case( OBJECT_CLASS_INDEX ): 419 ObjectClass[] ocs = parsers.parseObjectClasses( mods ); 420 421 for ( ObjectClass oc : ocs ) 422 { 423 subentryModifier.addSchemaObject( opContext, oc ); 424 } 425 426 break; 427 428 case( MATCHING_RULE_USE_INDEX ): 429 MatchingRuleUse[] mrus = parsers.parseMatchingRuleUses( mods ); 430 431 for ( MatchingRuleUse mru : mrus ) 432 { 433 subentryModifier.addSchemaObject( opContext, mru ); 434 } 435 436 break; 437 438 case( DIT_STRUCTURE_RULE_INDEX ): 439 DITStructureRule[] dsrs = parsers.parseDitStructureRules( mods ); 440 441 for ( DITStructureRule dsr : dsrs ) 442 { 443 subentryModifier.addSchemaObject( opContext, dsr ); 444 } 445 446 break; 447 448 case( DIT_CONTENT_RULE_INDEX ): 449 DITContentRule[] dcrs = parsers.parseDitContentRules( mods ); 450 451 for ( DITContentRule dcr : dcrs ) 452 { 453 subentryModifier.addSchemaObject( opContext, dcr ); 454 } 455 456 break; 457 458 case( NAME_FORM_INDEX ): 459 NameForm[] nfs = parsers.parseNameForms( mods ); 460 461 for ( NameForm nf : nfs ) 462 { 463 subentryModifier.addSchemaObject( opContext, nf ); 464 } 465 466 break; 467 468 default: 469 throw new IllegalStateException( I18n.err( I18n.ERR_285, index ) ); 470 } 471 } 472 }