blob: d40cbc06be0cc4b080ffa9f17cc3e447774d6c36 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/
package org.apache.directory.server.core.api.schema.registries.synchronizers;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.apache.directory.api.ldap.model.constants.MetaSchemaConstants;
import org.apache.directory.api.ldap.model.constants.SchemaConstants;
import org.apache.directory.api.ldap.model.entry.Attribute;
import org.apache.directory.api.ldap.model.entry.Entry;
import org.apache.directory.api.ldap.model.entry.Value;
import org.apache.directory.api.ldap.model.exception.LdapException;
import org.apache.directory.api.ldap.model.exception.LdapInvalidDnException;
import org.apache.directory.api.ldap.model.exception.LdapUnwillingToPerformException;
import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
import org.apache.directory.api.ldap.model.schema.AttributeType;
import org.apache.directory.api.ldap.model.schema.ObjectClass;
import org.apache.directory.api.ldap.model.schema.SchemaManager;
import org.apache.directory.api.ldap.model.schema.registries.ObjectClassRegistry;
import org.apache.directory.api.util.Strings;
import org.apache.directory.server.constants.ApacheSchemaConstants;
import org.apache.directory.server.core.api.entry.ClonedServerEntry;
import org.apache.directory.server.core.api.interceptor.context.AddOperationContext;
import org.apache.directory.server.core.api.interceptor.context.DeleteOperationContext;
import org.apache.directory.server.core.api.interceptor.context.ModifyOperationContext;
import org.apache.directory.server.core.api.interceptor.context.MoveAndRenameOperationContext;
import org.apache.directory.server.core.api.interceptor.context.MoveOperationContext;
import org.apache.directory.server.core.api.interceptor.context.RenameOperationContext;
import org.apache.directory.server.i18n.I18n;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Central point of control for schemas enforced by the server. The
* following duties are presently performed by this class:
*
* <ul>
* <li>Provide central point of access for all registries: global and SAA specific registries</li>
* <li>Manage enabling and disabling schemas</li>
* <li>Responding to specific schema object changes</li>
* </ul>
*
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
*/
public class RegistrySynchronizerAdaptor
{
/** A logger for this class */
private static final Logger LOG = LoggerFactory.getLogger( RegistrySynchronizerAdaptor.class );
// indices of handlers and object ids into arrays
private static final int COMPARATOR_INDEX = 0;
private static final int NORMALIZER_INDEX = 1;
private static final int SYNTAX_CHECKER_INDEX = 2;
private static final int SYNTAX_INDEX = 3;
private static final int MATCHING_RULE_INDEX = 4;
private static final int ATTRIBUTE_TYPE_INDEX = 5;
private static final int OBJECT_CLASS_INDEX = 6;
private static final int MATCHING_RULE_USE_INDEX = 7;
private static final int DIT_STRUCTURE_RULE_INDEX = 8;
private static final int DIT_CONTENT_RULE_INDEX = 9;
private static final int NAME_FORM_INDEX = 10;
private static final Set<String> VALID_OU_VALUES = new HashSet<String>();
private static final String[] META_OBJECT_CLASSES = new String[]
{
MetaSchemaConstants.META_COMPARATOR_OC,
MetaSchemaConstants.META_NORMALIZER_OC,
MetaSchemaConstants.META_SYNTAX_CHECKER_OC,
MetaSchemaConstants.META_SYNTAX_OC,
MetaSchemaConstants.META_MATCHING_RULE_OC,
MetaSchemaConstants.META_ATTRIBUTE_TYPE_OC,
MetaSchemaConstants.META_OBJECT_CLASS_OC,
MetaSchemaConstants.META_MATCHING_RULE_USE_OC,
MetaSchemaConstants.META_DIT_STRUCTURE_RULE_OC,
MetaSchemaConstants.META_DIT_CONTENT_RULE_OC,
MetaSchemaConstants.META_NAME_FORM_OC
};
/** The SchemaManager */
private final SchemaManager schemaManager;
/** The ObjectClss Attribute */
private final AttributeType objectClassAT;
private final RegistrySynchronizer[] registrySynchronizers = new RegistrySynchronizer[11];
private final Map<String, RegistrySynchronizer> objectClass2synchronizerMap = new HashMap<String, RegistrySynchronizer>();
private final SchemaSynchronizer schemaSynchronizer;
static
{
VALID_OU_VALUES.add( Strings.toLowerCase( SchemaConstants.NORMALIZERS_AT ) );
VALID_OU_VALUES.add( Strings.toLowerCase( SchemaConstants.COMPARATORS_AT ) );
VALID_OU_VALUES.add( Strings.toLowerCase( SchemaConstants.SYNTAX_CHECKERS_AT ) );
VALID_OU_VALUES.add( Strings.toLowerCase( "syntaxes" ) );
VALID_OU_VALUES.add( Strings.toLowerCase( SchemaConstants.MATCHING_RULES_AT ) );
VALID_OU_VALUES.add( Strings.toLowerCase( SchemaConstants.MATCHING_RULE_USE_AT ) );
VALID_OU_VALUES.add( Strings.toLowerCase( SchemaConstants.ATTRIBUTE_TYPES_AT ) );
VALID_OU_VALUES.add( Strings.toLowerCase( SchemaConstants.OBJECT_CLASSES_AT ) );
VALID_OU_VALUES.add( Strings.toLowerCase( SchemaConstants.NAME_FORMS_AT ) );
VALID_OU_VALUES.add( Strings.toLowerCase( SchemaConstants.DIT_CONTENT_RULES_AT ) );
VALID_OU_VALUES.add( Strings.toLowerCase( SchemaConstants.DIT_STRUCTURE_RULES_AT ) );
}
public RegistrySynchronizerAdaptor( SchemaManager schemaManager ) throws Exception
{
this.schemaManager = schemaManager;
this.schemaSynchronizer = new SchemaSynchronizer( schemaManager );
this.objectClassAT = schemaManager.lookupAttributeTypeRegistry( SchemaConstants.OBJECT_CLASS_AT );
this.registrySynchronizers[COMPARATOR_INDEX] = new ComparatorSynchronizer( schemaManager );
this.registrySynchronizers[NORMALIZER_INDEX] = new NormalizerSynchronizer( schemaManager );
this.registrySynchronizers[SYNTAX_CHECKER_INDEX] = new SyntaxCheckerSynchronizer( schemaManager );
this.registrySynchronizers[SYNTAX_INDEX] = new SyntaxSynchronizer( schemaManager );
this.registrySynchronizers[MATCHING_RULE_INDEX] = new MatchingRuleSynchronizer( schemaManager );
this.registrySynchronizers[ATTRIBUTE_TYPE_INDEX] = new AttributeTypeSynchronizer( schemaManager );
this.registrySynchronizers[OBJECT_CLASS_INDEX] = new ObjectClassSynchronizer( schemaManager );
this.registrySynchronizers[MATCHING_RULE_USE_INDEX] = new MatchingRuleUseSynchronizer( schemaManager );
this.registrySynchronizers[DIT_STRUCTURE_RULE_INDEX] = new DitStructureRuleSynchronizer( schemaManager );
this.registrySynchronizers[DIT_CONTENT_RULE_INDEX] = new DitContentRuleSynchronizer( schemaManager );
this.registrySynchronizers[NAME_FORM_INDEX] = new NameFormSynchronizer( schemaManager );
ObjectClassRegistry ocReg = schemaManager.getObjectClassRegistry();
for ( int ii = 0; ii < META_OBJECT_CLASSES.length; ii++ )
{
ObjectClass oc = ocReg.lookup( META_OBJECT_CLASSES[ii] );
objectClass2synchronizerMap.put( oc.getOid(), registrySynchronizers[ii] );
}
}
/**
* Add a new SchemaObject or a new Schema in the Schema partition.
*
* @param addContext The Add context, containing the entry to be added
* @throws Exception If the addition failed
*/
public void add( AddOperationContext addContext ) throws LdapException
{
Attribute oc = addContext.getEntry().get( objectClassAT );
// First check if we are adding a schemaObject
for ( Value<?> value : oc )
{
String oid = schemaManager.getObjectClassRegistry().getOidByName( value.getString() );
if ( objectClass2synchronizerMap.containsKey( oid ) )
{
// This is one of the eleven SchemaObject :
// AT, C, DCR, DSR, MR, MRU, NF, N, OC, S, SC
RegistrySynchronizer synchronizer = objectClass2synchronizerMap.get( oid );
Entry entry = addContext.getEntry();
synchronizer.add( entry );
return;
}
}
// This is a Schema
// e.g. ou=my custom schema,ou=schema
if ( oc.contains( MetaSchemaConstants.META_SCHEMA_OC ) )
{
Entry entry = addContext.getEntry();
schemaSynchronizer.add( entry );
return;
}
// Check if it is a valid container for AT, C, DCR, DSR, MR, MRU, NF, N, OC, S, SC
// e.g. ou=attributeTypes,ou=my custom schema,ou=schema
if ( oc.contains( SchemaConstants.ORGANIZATIONAL_UNIT_OC ) )
{
if ( addContext.getDn().size() != 3 )
{
String msg = I18n.err( I18n.ERR_81 );
LOG.error( msg );
throw new LdapInvalidDnException( ResultCodeEnum.NAMING_VIOLATION, msg );
}
String ouValue = addContext.getDn().getRdn().getNormValue().getString();
ouValue = Strings.toLowerCase( Strings.trim( ouValue ) );
if ( !VALID_OU_VALUES.contains( ouValue ) )
{
String msg = I18n.err( I18n.ERR_82, VALID_OU_VALUES );
LOG.error( msg );
throw new LdapInvalidDnException( ResultCodeEnum.NAMING_VIOLATION, msg );
}
// this is a valid container.
return;
}
String msg = I18n.err( I18n.ERR_83, addContext.getDn() );
LOG.error( msg );
throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, msg );
}
/**
* {@inheritDoc}
*/
public void delete( DeleteOperationContext deleteContext, boolean doCascadeDelete )
throws LdapException
{
Entry entry = deleteContext.getEntry();
Attribute oc = entry.get( objectClassAT );
for ( Value<?> value : oc )
{
String oid = schemaManager.getObjectClassRegistry().getOidByName( value.getString() );
if ( objectClass2synchronizerMap.containsKey( oid ) )
{
RegistrySynchronizer synchronizer = objectClass2synchronizerMap.get( oid );
synchronizer.delete( entry, doCascadeDelete );
return;
}
}
if ( oc.contains( MetaSchemaConstants.META_SCHEMA_OC ) )
{
schemaSynchronizer.delete( entry, doCascadeDelete );
return;
}
if ( oc.contains( SchemaConstants.ORGANIZATIONAL_UNIT_OC ) )
{
if ( deleteContext.getDn().size() != 3 )
{
throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, I18n.err( I18n.ERR_378 ) );
}
String ouValue = deleteContext.getDn().getRdn().getNormValue().getString();
ouValue = Strings.toLowerCase( Strings.trim( ouValue ) );
if ( !VALID_OU_VALUES.contains( ouValue ) )
{
throw new LdapInvalidDnException( ResultCodeEnum.NAMING_VIOLATION,
I18n.err( I18n.ERR_379, VALID_OU_VALUES ) );
}
return;
}
throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM );
}
/**
* Modify the schema
*
* @param modifyContext The context
* @param targetEntry The modified entry
* @param doCascadeModify Not used
* @throws Exception If the modification failed
*/
public boolean modify( ModifyOperationContext modifyContext, Entry targetEntry, boolean doCascadeModify )
throws LdapException
{
Entry entry = modifyContext.getEntry();
Attribute oc = entry.get( objectClassAT );
for ( Value<?> value : oc )
{
String oid = schemaManager.getObjectClassRegistry().getOidByName( value.getString() );
if ( objectClass2synchronizerMap.containsKey( oid ) )
{
RegistrySynchronizer synchronizer = objectClass2synchronizerMap.get( oid );
boolean hasModification = synchronizer.modify( modifyContext, targetEntry, doCascadeModify );
return hasModification;
}
}
if ( oc.contains( MetaSchemaConstants.META_SCHEMA_OC ) )
{
boolean hasModification = schemaSynchronizer.modify( modifyContext, targetEntry, doCascadeModify );
return hasModification;
}
if ( oc.contains( ApacheSchemaConstants.SCHEMA_MODIFICATION_ATTRIBUTES_OC ) )
{
return false;
}
LOG.error( String.format( I18n.err( I18n.ERR_84 ),
modifyContext.getDn(), entry, modifyContext.getModItems() ) );
throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM );
}
/**
* Rename a Schema Object.
*
* @param renameContext The contect contaoning the rename informations
* @param doCascadeModify unused
* @throws Exception If the rename failed
*/
public void rename( RenameOperationContext renameContext, boolean doCascadeModify )
throws LdapException
{
Entry originalEntry = ( ( ClonedServerEntry ) renameContext.getEntry() ).getOriginalEntry();
Attribute oc = originalEntry.get( objectClassAT );
for ( Value<?> value : oc )
{
String oid = schemaManager.getObjectClassRegistry().getOidByName( value.getString() );
if ( objectClass2synchronizerMap.containsKey( oid ) )
{
RegistrySynchronizer synchronizer = objectClass2synchronizerMap.get( oid );
synchronizer.rename( originalEntry, renameContext.getNewRdn(), doCascadeModify );
return;
}
}
if ( oc.contains( MetaSchemaConstants.META_SCHEMA_OC ) )
{
schemaSynchronizer.rename( originalEntry, renameContext.getNewRdn(), doCascadeModify );
return;
}
throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM );
}
/* (non-Javadoc)
* @see org.apache.directory.server.core.schema.SchemaChangeManager#replace(org.apache.directory.server.core.interceptor.context.MoveOperationContext, org.apache.directory.server.core.entry.Entry, boolean)
*/
public void move( MoveOperationContext moveContext, Entry entry, boolean cascade ) throws LdapException
{
Attribute oc = entry.get( objectClassAT );
for ( Value<?> value : oc )
{
String oid = schemaManager.getObjectClassRegistry().getOidByName( value.getString() );
if ( objectClass2synchronizerMap.containsKey( oid ) )
{
RegistrySynchronizer synchronizer = objectClass2synchronizerMap.get( oid );
synchronizer.move( moveContext.getDn(), moveContext.getNewSuperior(), entry, cascade );
return;
}
}
if ( oc.contains( MetaSchemaConstants.META_SCHEMA_OC ) )
{
schemaSynchronizer.move( moveContext.getDn(), moveContext.getNewSuperior(), entry, cascade );
return;
}
throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM );
}
/* (non-Javadoc)
* @see org.apache.directory.server.core.schema.SchemaChangeManager#move(org.apache.directory.server.core.interceptor.context.MoveAndRenameOperationContext, org.apache.directory.server.core.entry.Entry, boolean)
*/
public void moveAndRename( MoveAndRenameOperationContext moveAndRenameContext, Entry entry, boolean cascade )
throws LdapException
{
Attribute oc = entry.get( objectClassAT );
for ( Value<?> value : oc )
{
String oid = schemaManager.getObjectClassRegistry().getOidByName( value.getString() );
if ( objectClass2synchronizerMap.containsKey( oid ) )
{
RegistrySynchronizer synchronizer = objectClass2synchronizerMap.get( oid );
synchronizer.moveAndRename( moveAndRenameContext.getDn(), moveAndRenameContext.getNewSuperiorDn(),
moveAndRenameContext.getNewRdn(),
moveAndRenameContext.getDeleteOldRdn(), entry, cascade );
return;
}
}
if ( oc.contains( MetaSchemaConstants.META_SCHEMA_OC ) )
{
schemaSynchronizer.moveAndRename( moveAndRenameContext.getDn(), moveAndRenameContext.getNewSuperiorDn(),
moveAndRenameContext.getNewRdn(),
moveAndRenameContext.getDeleteOldRdn(), entry, cascade );
return;
}
throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM );
}
}