blob: 10a73277af675ab723f144446f3fac2d7577e6a5 [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.schema;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.apache.directory.server.core.DnFactory;
import org.apache.directory.server.core.interceptor.context.ModifyOperationContext;
import org.apache.directory.server.i18n.I18n;
import org.apache.directory.shared.ldap.model.constants.SchemaConstants;
import org.apache.directory.shared.ldap.model.entry.EntryAttribute;
import org.apache.directory.shared.ldap.model.entry.Modification;
import org.apache.directory.shared.ldap.model.exception.LdapException;
import org.apache.directory.shared.ldap.model.exception.LdapUnwillingToPerformException;
import org.apache.directory.shared.ldap.model.message.ResultCodeEnum;
import org.apache.directory.shared.ldap.model.schema.MutableAttributeTypeImpl;
import org.apache.directory.shared.ldap.model.schema.DITContentRule;
import org.apache.directory.shared.ldap.model.schema.DITStructureRule;
import org.apache.directory.shared.ldap.model.schema.MutableLdapSyntax;
import org.apache.directory.shared.ldap.model.schema.MutableMatchingRule;
import org.apache.directory.shared.ldap.model.schema.MatchingRuleUse;
import org.apache.directory.shared.ldap.model.schema.NameForm;
import org.apache.directory.shared.ldap.model.schema.ObjectClass;
import org.apache.directory.shared.ldap.model.schema.SchemaManager;
import org.apache.directory.shared.ldap.model.schema.parsers.LdapComparatorDescription;
import org.apache.directory.shared.ldap.model.schema.parsers.NormalizerDescription;
import org.apache.directory.shared.ldap.model.schema.parsers.SyntaxCheckerDescription;
import org.apache.directory.shared.ldap.model.schema.registries.SchemaLoader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
*/
public class SchemaSubentryManager
{
/** A logger for this class */
private static final Logger LOG = LoggerFactory.getLogger( SchemaSubentryManager.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>();
/** The schemaManager */
private final SchemaManager schemaManager;
private final SchemaSubentryModifier subentryModifier;
/** The description parsers */
private final DescriptionParsers parsers;
/**
* Maps the OID of a subschemaSubentry operational attribute to the index of
* the handler in the schemaObjectHandlers array.
*/
private final Map<String, Integer> opAttr2handlerIndex = new HashMap<String, Integer>( 11 );
private static final String CASCADING_ERROR =
"Cascading has not yet been implemented: standard operation is in effect.";
private static MutableAttributeTypeImpl ENTRY_CSN_ATTRIBUTE_TYPE;
static
{
VALID_OU_VALUES.add( SchemaConstants.NORMALIZERS_AT.toLowerCase() );
VALID_OU_VALUES.add( SchemaConstants.COMPARATORS_AT.toLowerCase() );
VALID_OU_VALUES.add( SchemaConstants.SYNTAX_CHECKERS_AT.toLowerCase() );
VALID_OU_VALUES.add( "syntaxes".toLowerCase() );
VALID_OU_VALUES.add( SchemaConstants.MATCHING_RULES_AT.toLowerCase() );
VALID_OU_VALUES.add( SchemaConstants.MATCHING_RULE_USE_AT.toLowerCase() );
VALID_OU_VALUES.add( SchemaConstants.ATTRIBUTE_TYPES_AT.toLowerCase() );
VALID_OU_VALUES.add( SchemaConstants.OBJECT_CLASSES_AT.toLowerCase() );
VALID_OU_VALUES.add( SchemaConstants.NAME_FORMS_AT.toLowerCase() );
VALID_OU_VALUES.add( SchemaConstants.DIT_CONTENT_RULES_AT.toLowerCase() );
VALID_OU_VALUES.add( SchemaConstants.DIT_STRUCTURE_RULES_AT.toLowerCase() );
}
public SchemaSubentryManager( SchemaManager schemaManager, SchemaLoader loader, DnFactory dnFactory )
throws LdapException
{
this.schemaManager = schemaManager;
this.subentryModifier = new SchemaSubentryModifier( schemaManager, dnFactory );
this.parsers = new DescriptionParsers( schemaManager );
String comparatorsOid = schemaManager.getAttributeTypeRegistry().getOidByName( SchemaConstants.COMPARATORS_AT );
opAttr2handlerIndex.put( comparatorsOid, COMPARATOR_INDEX );
String normalizersOid = schemaManager.getAttributeTypeRegistry().getOidByName( SchemaConstants.NORMALIZERS_AT );
opAttr2handlerIndex.put( normalizersOid, NORMALIZER_INDEX );
String syntaxCheckersOid = schemaManager.getAttributeTypeRegistry().getOidByName( SchemaConstants.SYNTAX_CHECKERS_AT );
opAttr2handlerIndex.put( syntaxCheckersOid, SYNTAX_CHECKER_INDEX );
String ldapSyntaxesOid = schemaManager.getAttributeTypeRegistry().getOidByName( SchemaConstants.LDAP_SYNTAXES_AT );
opAttr2handlerIndex.put( ldapSyntaxesOid, SYNTAX_INDEX );
String matchingRulesOid = schemaManager.getAttributeTypeRegistry().getOidByName( SchemaConstants.MATCHING_RULES_AT );
opAttr2handlerIndex.put( matchingRulesOid, MATCHING_RULE_INDEX );
String attributeTypesOid = schemaManager.getAttributeTypeRegistry().getOidByName( SchemaConstants.ATTRIBUTE_TYPES_AT );
opAttr2handlerIndex.put( attributeTypesOid, ATTRIBUTE_TYPE_INDEX );
String objectClassesOid = schemaManager.getAttributeTypeRegistry().getOidByName( SchemaConstants.OBJECT_CLASSES_AT );
opAttr2handlerIndex.put( objectClassesOid, OBJECT_CLASS_INDEX );
String matchingRuleUseOid = schemaManager.getAttributeTypeRegistry().getOidByName( SchemaConstants.MATCHING_RULE_USE_AT );
opAttr2handlerIndex.put( matchingRuleUseOid, MATCHING_RULE_USE_INDEX );
String ditStructureRulesOid = schemaManager.getAttributeTypeRegistry().getOidByName( SchemaConstants.DIT_STRUCTURE_RULES_AT );
opAttr2handlerIndex.put( ditStructureRulesOid, DIT_STRUCTURE_RULE_INDEX );
String ditContentRulesOid = schemaManager.getAttributeTypeRegistry().getOidByName( SchemaConstants.DIT_CONTENT_RULES_AT );
opAttr2handlerIndex.put( ditContentRulesOid, DIT_CONTENT_RULE_INDEX );
String nameFormsOid = schemaManager.getAttributeTypeRegistry().getOidByName( SchemaConstants.NAME_FORMS_AT );
opAttr2handlerIndex.put( nameFormsOid, NAME_FORM_INDEX );
ENTRY_CSN_ATTRIBUTE_TYPE = schemaManager.getAttributeType( SchemaConstants.ENTRY_CSN_AT );
}
/* (non-Javadoc)
* @see org.apache.directory.server.core.schema.SchemaChangeManager#modifySchemaSubentry(org.apache.directory.server.core.interceptor.context.ModifyOperationContext, org.apache.directory.server.core.entry.Entry, org.apache.directory.server.core.entry.Entry, boolean)
*/
public void modifySchemaSubentry( ModifyOperationContext modifyContext, boolean doCascadeModify ) throws LdapException
{
for ( Modification mod : modifyContext.getModItems() )
{
String opAttrOid = schemaManager.getAttributeTypeRegistry().getOidByName( mod.getAttribute().getId() );
EntryAttribute serverAttribute = mod.getAttribute();
switch ( mod.getOperation() )
{
case ADD_ATTRIBUTE :
modifyAddOperation( modifyContext, opAttrOid, serverAttribute, doCascadeModify );
break;
case REMOVE_ATTRIBUTE :
modifyRemoveOperation( modifyContext, opAttrOid, serverAttribute );
break;
case REPLACE_ATTRIBUTE :
// a hack to allow entryCSN modification
if ( ENTRY_CSN_ATTRIBUTE_TYPE.equals( serverAttribute.getAttributeType() ) )
{
break;
}
throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM,
I18n.err( I18n.ERR_283 ) );
default:
throw new IllegalStateException( I18n.err( I18n.ERR_284, mod.getOperation() ) );
}
}
}
/**
* Handles the modify remove operation on the subschemaSubentry for schema entities.
*
* @param opAttrOid the numeric id of the operational attribute modified
* @param mods the attribute with the modifications
* to effect all dependents on the changed entity
* @throws Exception if there are problems updating the registries and the
* schema partition
*/
private void modifyRemoveOperation( ModifyOperationContext modifyContext, String opAttrOid,
EntryAttribute mods ) throws LdapException
{
int index = opAttr2handlerIndex.get( opAttrOid );
switch( index )
{
case( COMPARATOR_INDEX ):
LdapComparatorDescription[] comparatorDescriptions = parsers.parseComparators( mods );
for ( LdapComparatorDescription comparatorDescription : comparatorDescriptions )
{
subentryModifier.delete( modifyContext, comparatorDescription );
}
break;
case( NORMALIZER_INDEX ):
NormalizerDescription[] normalizerDescriptions = parsers.parseNormalizers( mods );
for ( NormalizerDescription normalizerDescription : normalizerDescriptions )
{
subentryModifier.delete( modifyContext, normalizerDescription );
}
break;
case( SYNTAX_CHECKER_INDEX ):
SyntaxCheckerDescription[] syntaxCheckerDescriptions = parsers.parseSyntaxCheckers( mods );
for ( SyntaxCheckerDescription syntaxCheckerDescription : syntaxCheckerDescriptions )
{
subentryModifier.delete( modifyContext, syntaxCheckerDescription );
}
break;
case( SYNTAX_INDEX ):
MutableLdapSyntax[] syntaxes = parsers.parseLdapSyntaxes( mods );
for ( MutableLdapSyntax syntax : syntaxes )
{
subentryModifier.deleteSchemaObject( modifyContext, syntax );
}
break;
case( MATCHING_RULE_INDEX ):
MutableMatchingRule[] mrs = parsers.parseMatchingRules( mods );
for ( MutableMatchingRule mr : mrs )
{
subentryModifier.deleteSchemaObject( modifyContext, mr );
}
break;
case( ATTRIBUTE_TYPE_INDEX ):
MutableAttributeTypeImpl[] ats = parsers.parseAttributeTypes( mods );
for ( MutableAttributeTypeImpl at : ats )
{
subentryModifier.deleteSchemaObject( modifyContext, at );
}
break;
case( OBJECT_CLASS_INDEX ):
ObjectClass[] ocs = parsers.parseObjectClasses( mods );
for ( ObjectClass oc : ocs )
{
subentryModifier.deleteSchemaObject( modifyContext, oc );
}
break;
case( MATCHING_RULE_USE_INDEX ):
MatchingRuleUse[] mrus = parsers.parseMatchingRuleUses( mods );
for ( MatchingRuleUse mru : mrus )
{
subentryModifier.deleteSchemaObject( modifyContext, mru );
}
break;
case( DIT_STRUCTURE_RULE_INDEX ):
DITStructureRule[] dsrs = parsers.parseDitStructureRules( mods );
for ( DITStructureRule dsr : dsrs )
{
subentryModifier.deleteSchemaObject( modifyContext, dsr );
}
break;
case( DIT_CONTENT_RULE_INDEX ):
DITContentRule[] dcrs = parsers.parseDitContentRules( mods );
for ( DITContentRule dcr : dcrs )
{
subentryModifier.deleteSchemaObject( modifyContext, dcr );
}
break;
case( NAME_FORM_INDEX ):
NameForm[] nfs = parsers.parseNameForms( mods );
for ( NameForm nf : nfs )
{
subentryModifier.deleteSchemaObject( modifyContext, nf );
}
break;
default:
throw new IllegalStateException( I18n.err( I18n.ERR_285, index ) );
}
}
/**
* Handles the modify add operation on the subschemaSubentry for schema entities.
*
* @param opAttrOid the numeric id of the operational attribute modified
* @param mods the attribute with the modifications
* @param doCascadeModify determines if a cascading operation should be performed
* to effect all dependents on the changed entity
* @throws Exception if there are problems updating the registries and the
* schema partition
*/
private void modifyAddOperation( ModifyOperationContext modifyContext, String opAttrOid,
EntryAttribute mods, boolean doCascadeModify ) throws LdapException
{
if ( doCascadeModify )
{
LOG.error( CASCADING_ERROR );
}
int index = opAttr2handlerIndex.get( opAttrOid );
switch( index )
{
case( COMPARATOR_INDEX ):
LdapComparatorDescription[] comparatorDescriptions = parsers.parseComparators( mods );
for ( LdapComparatorDescription comparatorDescription : comparatorDescriptions )
{
subentryModifier.add( modifyContext, comparatorDescription );
}
break;
case( NORMALIZER_INDEX ):
NormalizerDescription[] normalizerDescriptions = parsers.parseNormalizers( mods );
for ( NormalizerDescription normalizerDescription : normalizerDescriptions )
{
subentryModifier.add( modifyContext, normalizerDescription );
}
break;
case( SYNTAX_CHECKER_INDEX ):
SyntaxCheckerDescription[] syntaxCheckerDescriptions = parsers.parseSyntaxCheckers( mods );
for ( SyntaxCheckerDescription syntaxCheckerDescription : syntaxCheckerDescriptions )
{
subentryModifier.add( modifyContext, syntaxCheckerDescription );
}
break;
case( SYNTAX_INDEX ):
MutableLdapSyntax[] syntaxes = parsers.parseLdapSyntaxes( mods );
for ( MutableLdapSyntax syntax : syntaxes )
{
subentryModifier.addSchemaObject( modifyContext, syntax );
}
break;
case( MATCHING_RULE_INDEX ):
MutableMatchingRule[] mrs = parsers.parseMatchingRules( mods );
for ( MutableMatchingRule mr : mrs )
{
subentryModifier.addSchemaObject( modifyContext, mr );
}
break;
case( ATTRIBUTE_TYPE_INDEX ):
MutableAttributeTypeImpl[] ats = parsers.parseAttributeTypes( mods );
for ( MutableAttributeTypeImpl at : ats )
{
subentryModifier.addSchemaObject( modifyContext, at );
}
break;
case( OBJECT_CLASS_INDEX ):
ObjectClass[] ocs = parsers.parseObjectClasses( mods );
for ( ObjectClass oc : ocs )
{
subentryModifier.addSchemaObject( modifyContext, oc );
}
break;
case( MATCHING_RULE_USE_INDEX ):
MatchingRuleUse[] mrus = parsers.parseMatchingRuleUses( mods );
for ( MatchingRuleUse mru : mrus )
{
subentryModifier.addSchemaObject( modifyContext, mru );
}
break;
case( DIT_STRUCTURE_RULE_INDEX ):
DITStructureRule[] dsrs = parsers.parseDitStructureRules( mods );
for ( DITStructureRule dsr : dsrs )
{
subentryModifier.addSchemaObject( modifyContext, dsr );
}
break;
case( DIT_CONTENT_RULE_INDEX ):
DITContentRule[] dcrs = parsers.parseDitContentRules( mods );
for ( DITContentRule dcr : dcrs )
{
subentryModifier.addSchemaObject( modifyContext, dcr );
}
break;
case( NAME_FORM_INDEX ):
NameForm[] nfs = parsers.parseNameForms( mods );
for ( NameForm nf : nfs )
{
subentryModifier.addSchemaObject( modifyContext, nf );
}
break;
default:
throw new IllegalStateException( I18n.err( I18n.ERR_285, index ) );
}
}
}