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.registries.synchronizers; 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 org.apache.directory.server.constants.ApacheSchemaConstants; 029 import org.apache.directory.server.core.interceptor.context.AddOperationContext; 030 import org.apache.directory.server.core.interceptor.context.DeleteOperationContext; 031 import org.apache.directory.server.core.interceptor.context.ModifyOperationContext; 032 import org.apache.directory.server.core.interceptor.context.MoveAndRenameOperationContext; 033 import org.apache.directory.server.core.interceptor.context.MoveOperationContext; 034 import org.apache.directory.server.core.interceptor.context.RenameOperationContext; 035 import org.apache.directory.server.i18n.I18n; 036 import org.apache.directory.shared.ldap.constants.MetaSchemaConstants; 037 import org.apache.directory.shared.ldap.constants.SchemaConstants; 038 import org.apache.directory.shared.ldap.entry.EntryAttribute; 039 import org.apache.directory.shared.ldap.entry.ServerEntry; 040 import org.apache.directory.shared.ldap.entry.Value; 041 import org.apache.directory.shared.ldap.exception.LdapInvalidDnException; 042 import org.apache.directory.shared.ldap.exception.LdapUnwillingToPerformException; 043 import org.apache.directory.shared.ldap.message.ResultCodeEnum; 044 import org.apache.directory.shared.ldap.schema.AttributeType; 045 import org.apache.directory.shared.ldap.schema.ObjectClass; 046 import org.apache.directory.shared.ldap.schema.SchemaManager; 047 import org.apache.directory.shared.ldap.schema.registries.ObjectClassRegistry; 048 import org.apache.directory.shared.ldap.schema.registries.Registries; 049 import org.slf4j.Logger; 050 import org.slf4j.LoggerFactory; 051 052 053 /** 054 * Central point of control for schemas enforced by the server. The 055 * following duties are presently performed by this class: 056 * 057 * <ul> 058 * <li>Provide central point of access for all registries: global and SAA specific registries</li> 059 * <li>Manage enabling and disabling schemas</li> 060 * <li>Responding to specific schema object changes</li> 061 * </ul> 062 * 063 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 064 * @version $Rev$, $Date$ 065 */ 066 public class RegistrySynchronizerAdaptor 067 { 068 /** A logger for this class */ 069 private static final Logger LOG = LoggerFactory.getLogger( RegistrySynchronizerAdaptor.class ); 070 071 // indices of handlers and object ids into arrays 072 private static final int COMPARATOR_INDEX = 0; 073 private static final int NORMALIZER_INDEX = 1; 074 private static final int SYNTAX_CHECKER_INDEX = 2; 075 private static final int SYNTAX_INDEX = 3; 076 private static final int MATCHING_RULE_INDEX = 4; 077 private static final int ATTRIBUTE_TYPE_INDEX = 5; 078 private static final int OBJECT_CLASS_INDEX = 6; 079 private static final int MATCHING_RULE_USE_INDEX = 7; 080 private static final int DIT_STRUCTURE_RULE_INDEX = 8; 081 private static final int DIT_CONTENT_RULE_INDEX = 9; 082 private static final int NAME_FORM_INDEX = 10; 083 084 private static final Set<String> VALID_OU_VALUES = new HashSet<String>(); 085 private static final String[] META_OBJECT_CLASSES = new String[] { 086 MetaSchemaConstants.META_COMPARATOR_OC, 087 MetaSchemaConstants.META_NORMALIZER_OC, 088 MetaSchemaConstants.META_SYNTAX_CHECKER_OC, 089 MetaSchemaConstants.META_SYNTAX_OC, 090 MetaSchemaConstants.META_MATCHING_RULE_OC, 091 MetaSchemaConstants.META_ATTRIBUTE_TYPE_OC, 092 MetaSchemaConstants.META_OBJECT_CLASS_OC, 093 MetaSchemaConstants.META_MATCHING_RULE_USE_OC, 094 MetaSchemaConstants.META_DIT_STRUCTURE_RULE_OC, 095 MetaSchemaConstants.META_DIT_CONTENT_RULE_OC, 096 MetaSchemaConstants.META_NAME_FORM_OC 097 }; 098 099 private final Registries registries; 100 private final AttributeType objectClassAT; 101 private final RegistrySynchronizer[] registrySynchronizers = new RegistrySynchronizer[11]; 102 private final Map<String, RegistrySynchronizer> objectClass2synchronizerMap = new HashMap<String, RegistrySynchronizer>(); 103 private final SchemaSynchronizer schemaSynchronizer; 104 105 static 106 { 107 VALID_OU_VALUES.add( SchemaConstants.NORMALIZERS_AT.toLowerCase() ); 108 VALID_OU_VALUES.add( SchemaConstants.COMPARATORS_AT.toLowerCase() ); 109 VALID_OU_VALUES.add( SchemaConstants.SYNTAX_CHECKERS_AT.toLowerCase() ); 110 VALID_OU_VALUES.add( "syntaxes".toLowerCase() ); 111 VALID_OU_VALUES.add( SchemaConstants.MATCHING_RULES_AT.toLowerCase() ); 112 VALID_OU_VALUES.add( SchemaConstants.MATCHING_RULE_USE_AT.toLowerCase() ); 113 VALID_OU_VALUES.add( SchemaConstants.ATTRIBUTE_TYPES_AT.toLowerCase() ); 114 VALID_OU_VALUES.add( SchemaConstants.OBJECT_CLASSES_AT.toLowerCase() ); 115 VALID_OU_VALUES.add( SchemaConstants.NAME_FORMS_AT.toLowerCase() ); 116 VALID_OU_VALUES.add( SchemaConstants.DIT_CONTENT_RULES_AT.toLowerCase() ); 117 VALID_OU_VALUES.add( SchemaConstants.DIT_STRUCTURE_RULES_AT.toLowerCase() ); 118 } 119 120 121 public RegistrySynchronizerAdaptor( SchemaManager schemaManager ) throws Exception 122 { 123 this.registries = schemaManager.getRegistries(); 124 this.schemaSynchronizer = new SchemaSynchronizer( schemaManager ); 125 this.objectClassAT = this.registries.getAttributeTypeRegistry() 126 .lookup( SchemaConstants.OBJECT_CLASS_AT ); 127 128 this.registrySynchronizers[COMPARATOR_INDEX] = new ComparatorSynchronizer( schemaManager ); 129 this.registrySynchronizers[NORMALIZER_INDEX] = new NormalizerSynchronizer( schemaManager ); 130 this.registrySynchronizers[SYNTAX_CHECKER_INDEX] = new SyntaxCheckerSynchronizer( schemaManager ); 131 this.registrySynchronizers[SYNTAX_INDEX] = new SyntaxSynchronizer( schemaManager ); 132 this.registrySynchronizers[MATCHING_RULE_INDEX] = new MatchingRuleSynchronizer( schemaManager ); 133 this.registrySynchronizers[ATTRIBUTE_TYPE_INDEX] = new AttributeTypeSynchronizer( schemaManager ); 134 this.registrySynchronizers[OBJECT_CLASS_INDEX] = new ObjectClassSynchronizer( schemaManager ); 135 this.registrySynchronizers[MATCHING_RULE_USE_INDEX] = new MatchingRuleUseSynchronizer( schemaManager ); 136 this.registrySynchronizers[DIT_STRUCTURE_RULE_INDEX] = new DitStructureRuleSynchronizer( schemaManager ); 137 this.registrySynchronizers[DIT_CONTENT_RULE_INDEX] = new DitContentRuleSynchronizer( schemaManager ); 138 this.registrySynchronizers[NAME_FORM_INDEX] = new NameFormSynchronizer( schemaManager ); 139 140 ObjectClassRegistry ocReg = registries.getObjectClassRegistry(); 141 for ( int ii = 0; ii < META_OBJECT_CLASSES.length; ii++ ) 142 { 143 ObjectClass oc = ocReg.lookup( META_OBJECT_CLASSES[ii] ); 144 objectClass2synchronizerMap.put( oc.getOid(), registrySynchronizers[ii] ); 145 } 146 } 147 148 149 /** 150 * Add a new SchemaObject or a new Schema in the Schema partition. 151 * 152 * @param opContext The Add context, containing the entry to be added 153 * @throws Exception If the addition failed 154 */ 155 public void add( AddOperationContext opContext ) throws Exception 156 { 157 EntryAttribute oc = opContext.getEntry().get( objectClassAT ); 158 159 // First check if we are adding a schemaObject 160 for ( Value<?> value:oc ) 161 { 162 163 String oid = registries.getObjectClassRegistry().getOidByName( value.getString() ); 164 165 if ( objectClass2synchronizerMap.containsKey( oid ) ) 166 { 167 // This is one of the eleven SchemaObject : 168 // AT, C, DCR, DSR, MR, MRU, NF, N, OC, S, SC 169 RegistrySynchronizer synchronizer = objectClass2synchronizerMap.get( oid ); 170 ServerEntry entry = opContext.getEntry(); 171 synchronizer.add( entry ); 172 return; 173 } 174 } 175 176 // This is a Schema 177 // e.g. ou=my custom schema,ou=schema 178 if ( oc.contains( MetaSchemaConstants.META_SCHEMA_OC ) ) 179 { 180 ServerEntry entry = opContext.getEntry(); 181 schemaSynchronizer.add( entry ); 182 return; 183 } 184 185 // Check if it is a valid container for AT, C, DCR, DSR, MR, MRU, NF, N, OC, S, SC 186 // e.g. ou=attributeTypes,ou=my custom schema,ou=schema 187 if ( oc.contains( SchemaConstants.ORGANIZATIONAL_UNIT_OC ) ) 188 { 189 if ( opContext.getDn().size() != 3 ) 190 { 191 String msg = I18n.err( I18n.ERR_81 ); 192 LOG.error( msg ); 193 throw new LdapInvalidDnException( ResultCodeEnum.NAMING_VIOLATION, msg ); 194 } 195 196 String ouValue = ( String ) opContext.getDn().getRdn().getNormValue(); 197 ouValue = ouValue.trim().toLowerCase(); 198 199 if ( ! VALID_OU_VALUES.contains( ouValue ) ) 200 { 201 String msg = I18n.err( I18n.ERR_82, VALID_OU_VALUES ); 202 LOG.error( msg ); 203 throw new LdapInvalidDnException( ResultCodeEnum.NAMING_VIOLATION, msg ); 204 } 205 206 // this is a valid container. 207 return; 208 } 209 210 211 String msg = I18n.err( I18n.ERR_83, opContext.getDn() ); 212 LOG.error( msg ); 213 throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, msg ); 214 } 215 216 217 /** 218 * {@inheritDoc} 219 */ 220 public void delete( DeleteOperationContext opContext, boolean doCascadeDelete ) 221 throws Exception 222 { 223 ServerEntry entry = opContext.getEntry(); 224 225 EntryAttribute oc = entry.get( objectClassAT ); 226 227 for ( Value<?> value:oc ) 228 { 229 String oid = registries.getObjectClassRegistry().getOidByName( value.getString() ); 230 231 if ( objectClass2synchronizerMap.containsKey( oid ) ) 232 { 233 RegistrySynchronizer synchronizer = objectClass2synchronizerMap.get( oid ); 234 synchronizer.delete( entry, doCascadeDelete ); 235 return; 236 } 237 } 238 239 if ( oc.contains( MetaSchemaConstants.META_SCHEMA_OC ) ) 240 { 241 schemaSynchronizer.delete( entry, doCascadeDelete ); 242 return; 243 } 244 245 if ( oc.contains( SchemaConstants.ORGANIZATIONAL_UNIT_OC ) ) 246 { 247 if ( opContext.getDn().size() != 3 ) 248 { 249 throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, I18n.err( I18n.ERR_378 ) ); 250 } 251 252 String ouValue = ( String ) opContext.getDn().getRdn().getNormValue(); 253 ouValue = ouValue.trim().toLowerCase(); 254 255 if ( ! VALID_OU_VALUES.contains( ouValue ) ) 256 { 257 throw new LdapInvalidDnException( ResultCodeEnum.NAMING_VIOLATION, 258 I18n.err( I18n.ERR_379, VALID_OU_VALUES ) ); 259 } 260 261 return; 262 } 263 264 throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM ); 265 } 266 267 268 /** 269 * Modify the schema 270 * 271 * @param opContext The context 272 * @param targetEntry The modified entry 273 * @param doCascadeModify Not used 274 * @throws Exception If the modification failed 275 */ 276 public boolean modify( ModifyOperationContext opContext, ServerEntry targetEntry, boolean doCascadeModify ) throws Exception 277 { 278 ServerEntry entry = opContext.getEntry(); 279 EntryAttribute oc = entry.get( objectClassAT ); 280 281 for ( Value<?> value:oc ) 282 { 283 String oid = registries.getObjectClassRegistry().getOidByName( value.getString() ); 284 285 if ( objectClass2synchronizerMap.containsKey( oid ) ) 286 { 287 RegistrySynchronizer synchronizer = objectClass2synchronizerMap.get( oid ); 288 boolean hasModification = synchronizer.modify( opContext, targetEntry, doCascadeModify ); 289 return hasModification; 290 } 291 } 292 293 if ( oc.contains( MetaSchemaConstants.META_SCHEMA_OC ) ) 294 { 295 boolean hasModification = schemaSynchronizer.modify( opContext, targetEntry, doCascadeModify ); 296 return hasModification; 297 } 298 299 if ( oc.contains( ApacheSchemaConstants.SCHEMA_MODIFICATION_ATTRIBUTES_OC ) ) 300 { 301 return false; 302 } 303 304 LOG.error( String.format( I18n.err( I18n.ERR_84 ), 305 opContext.getDn(), entry, opContext.getModItems() ) ); 306 throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM ); 307 } 308 309 310 /** 311 * Rename a Schema Object. 312 * 313 * @param opContext The contect contaoning the rename informations 314 * @param doCascadeModify unused 315 * @throws Exception If the rename failed 316 */ 317 public void rename( RenameOperationContext opContext, boolean doCascadeModify ) 318 throws Exception 319 { 320 ServerEntry originalEntry = opContext.getEntry().getOriginalEntry(); 321 EntryAttribute oc = originalEntry.get( objectClassAT ); 322 323 for ( Value<?> value:oc ) 324 { 325 String oid = registries.getObjectClassRegistry().getOidByName( value.getString() ); 326 327 if ( objectClass2synchronizerMap.containsKey( oid ) ) 328 { 329 RegistrySynchronizer synchronizer = objectClass2synchronizerMap.get( oid ); 330 synchronizer.rename( originalEntry, opContext.getNewRdn(), doCascadeModify ); 331 return; 332 } 333 } 334 335 if ( oc.contains( MetaSchemaConstants.META_SCHEMA_OC ) ) 336 { 337 schemaSynchronizer.rename( originalEntry, opContext.getNewRdn(), doCascadeModify ); 338 return; 339 } 340 341 throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM ); 342 } 343 344 345 /* (non-Javadoc) 346 * @see org.apache.directory.server.core.schema.SchemaChangeManager#replace(org.apache.directory.server.core.interceptor.context.MoveOperationContext, org.apache.directory.server.core.entry.ServerEntry, boolean) 347 */ 348 public void move( MoveOperationContext opContext, ServerEntry entry, boolean cascade ) throws Exception 349 { 350 EntryAttribute oc = entry.get( objectClassAT ); 351 352 for ( Value<?> value:oc ) 353 { 354 String oid = registries.getObjectClassRegistry().getOidByName( value.getString() ); 355 356 if ( objectClass2synchronizerMap.containsKey( oid ) ) 357 { 358 RegistrySynchronizer synchronizer = objectClass2synchronizerMap.get( oid ); 359 synchronizer.move( opContext.getDn(), opContext.getParent(), entry, cascade ); 360 return; 361 } 362 } 363 364 if ( oc.contains( MetaSchemaConstants.META_SCHEMA_OC ) ) 365 { 366 schemaSynchronizer.move( opContext.getDn(), opContext.getParent(), entry, cascade ); 367 return; 368 } 369 370 throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM ); 371 } 372 373 374 /* (non-Javadoc) 375 * @see org.apache.directory.server.core.schema.SchemaChangeManager#move(org.apache.directory.server.core.interceptor.context.MoveAndRenameOperationContext, org.apache.directory.server.core.entry.ServerEntry, boolean) 376 */ 377 public void moveAndRename( MoveAndRenameOperationContext opContext, ServerEntry entry, boolean cascade ) throws Exception 378 { 379 EntryAttribute oc = entry.get( objectClassAT ); 380 381 for ( Value<?> value:oc ) 382 { 383 String oid = registries.getObjectClassRegistry().getOidByName( value.getString() ); 384 385 if ( objectClass2synchronizerMap.containsKey( oid ) ) 386 { 387 RegistrySynchronizer synchronizer = objectClass2synchronizerMap.get( oid ); 388 synchronizer.moveAndRename( opContext.getDn(), opContext.getParent(), opContext.getNewRdn(), 389 opContext.getDelOldDn(), entry, cascade ); 390 return; 391 } 392 } 393 394 if ( oc.contains( MetaSchemaConstants.META_SCHEMA_OC ) ) 395 { 396 schemaSynchronizer.moveAndRename( opContext.getDn(), opContext.getParent(), opContext.getNewRdn(), 397 opContext.getDelOldDn(), entry, cascade ); 398 return; 399 } 400 401 throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM ); 402 } 403 }