All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.directory.api.ldap.model.schema.registries.Registries Maven / Gradle / Ivy

There is a newer version: 2.1.6
Show newest version
/*
 *  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.api.ldap.model.schema.registries;


import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.directory.api.i18n.I18n;
import org.apache.directory.api.ldap.model.constants.MetaSchemaConstants;
import org.apache.directory.api.ldap.model.exception.LdapException;
import org.apache.directory.api.ldap.model.exception.LdapProtocolErrorException;
import org.apache.directory.api.ldap.model.exception.LdapSchemaException;
import org.apache.directory.api.ldap.model.exception.LdapSchemaExceptionCodes;
import org.apache.directory.api.ldap.model.exception.LdapSchemaViolationException;
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.DitContentRule;
import org.apache.directory.api.ldap.model.schema.DitStructureRule;
import org.apache.directory.api.ldap.model.schema.LdapComparator;
import org.apache.directory.api.ldap.model.schema.LdapSyntax;
import org.apache.directory.api.ldap.model.schema.LoadableSchemaObject;
import org.apache.directory.api.ldap.model.schema.MatchingRule;
import org.apache.directory.api.ldap.model.schema.MatchingRuleUse;
import org.apache.directory.api.ldap.model.schema.MutableAttributeType;
import org.apache.directory.api.ldap.model.schema.MutableMatchingRule;
import org.apache.directory.api.ldap.model.schema.NameForm;
import org.apache.directory.api.ldap.model.schema.Normalizer;
import org.apache.directory.api.ldap.model.schema.ObjectClass;
import org.apache.directory.api.ldap.model.schema.SchemaErrorHandler;
import org.apache.directory.api.ldap.model.schema.SchemaObject;
import org.apache.directory.api.ldap.model.schema.SchemaObjectWrapper;
import org.apache.directory.api.ldap.model.schema.SyntaxChecker;
import org.apache.directory.api.ldap.model.schema.registries.helper.AttributeTypeHelper;
import org.apache.directory.api.ldap.model.schema.registries.helper.DitContentRuleHelper;
import org.apache.directory.api.ldap.model.schema.registries.helper.DitStructureRuleHelper;
import org.apache.directory.api.ldap.model.schema.registries.helper.LdapSyntaxHelper;
import org.apache.directory.api.ldap.model.schema.registries.helper.MatchingRuleHelper;
import org.apache.directory.api.ldap.model.schema.registries.helper.MatchingRuleUseHelper;
import org.apache.directory.api.ldap.model.schema.registries.helper.NameFormHelper;
import org.apache.directory.api.ldap.model.schema.registries.helper.ObjectClassHelper;
import org.apache.directory.api.util.Strings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


/**
 * Document this class.
 *
 * @author Apache Directory Project
 */
public class Registries implements SchemaLoaderListener, Cloneable
{
    /** A logger for this class */
    private static final Logger LOG = LoggerFactory.getLogger( Registries.class );

    /**
     * A String name to Schema object map for the schemas loaded into this
     * registry. The loaded schemas may be disabled.
     */
    protected Map loadedSchemas = new HashMap<>();

    /** The AttributeType registry */
    protected DefaultAttributeTypeRegistry attributeTypeRegistry;

    /** The ObjectClass registry */
    protected DefaultObjectClassRegistry objectClassRegistry;

    /** The LdapSyntax registry */
    protected DefaultComparatorRegistry comparatorRegistry;

    /** The DitContentRule registry */
    protected DefaultDitContentRuleRegistry ditContentRuleRegistry;

    /** The DitStructureRule registry */
    protected DefaultDitStructureRuleRegistry ditStructureRuleRegistry;

    /** The MatchingRule registry */
    protected DefaultMatchingRuleRegistry matchingRuleRegistry;

    /** The MatchingRuleUse registry */
    protected DefaultMatchingRuleUseRegistry matchingRuleUseRegistry;

    /** The NameForm registry */
    protected DefaultNameFormRegistry nameFormRegistry;

    /** The Normalizer registry */
    protected DefaultNormalizerRegistry normalizerRegistry;

    /** The global OID registry */
    protected OidRegistry globalOidRegistry;

    /** The SyntaxChecker registry */
    protected DefaultSyntaxCheckerRegistry syntaxCheckerRegistry;

    /** The LdapSyntax registry */
    protected DefaultLdapSyntaxRegistry ldapSyntaxRegistry;

    /** A map storing all the schema objects associated with a schema */
    private Map> schemaObjects;

    /** A flag indicating that the Registries is relaxed or not */
    private boolean isRelaxed;

    /** A flag indicating that disabled SchemaObject are accepted */
    private boolean disabledAccepted;

    private SchemaErrorHandler errorHandler;

    /** Two flags for RELAXED and STRICT modes */
    /** The strict mode */
    public static final boolean STRICT = false;
    
    /** The relaxed mode */
    public static final boolean RELAXED = true;

    /**
     *  A map storing a relation between a SchemaObject and all the
     *  referencing SchemaObjects.
     */
    protected Map> usedBy;

    /**
     *  A map storing a relation between a SchemaObject and all the
     *  SchemaObjects it uses.
     */
    protected Map> using;


    /**
     * Creates a new instance of Registries.
     */
    public Registries()
    {
        globalOidRegistry = new OidRegistry<>();
        attributeTypeRegistry = new DefaultAttributeTypeRegistry();
        comparatorRegistry = new DefaultComparatorRegistry();
        ditContentRuleRegistry = new DefaultDitContentRuleRegistry();
        ditStructureRuleRegistry = new DefaultDitStructureRuleRegistry();
        ldapSyntaxRegistry = new DefaultLdapSyntaxRegistry();
        matchingRuleRegistry = new DefaultMatchingRuleRegistry();
        matchingRuleUseRegistry = new DefaultMatchingRuleUseRegistry();
        nameFormRegistry = new DefaultNameFormRegistry();
        normalizerRegistry = new DefaultNormalizerRegistry();
        objectClassRegistry = new DefaultObjectClassRegistry();
        syntaxCheckerRegistry = new DefaultSyntaxCheckerRegistry();
        schemaObjects = new HashMap<>();
        usedBy = new HashMap<>();
        using = new HashMap<>();

        isRelaxed = STRICT;
        disabledAccepted = false;
    }


    /**
     * @return The AttributeType registry
     */
    public AttributeTypeRegistry getAttributeTypeRegistry()
    {
        return attributeTypeRegistry;
    }


    /**
     * @return The Comparator registry
     */
    public ComparatorRegistry getComparatorRegistry()
    {
        return comparatorRegistry;
    }


    /**
     * @return The DitContentRule registry
     */
    public DitContentRuleRegistry getDitContentRuleRegistry()
    {
        return ditContentRuleRegistry;
    }


    /**
     * @return The DitStructureRule registry
     */
    public DitStructureRuleRegistry getDitStructureRuleRegistry()
    {
        return ditStructureRuleRegistry;
    }


    /**
     * @return The MatchingRule registry
     */
    public MatchingRuleRegistry getMatchingRuleRegistry()
    {
        return matchingRuleRegistry;
    }


    /**
     * @return The MatchingRuleUse registry
     */
    public MatchingRuleUseRegistry getMatchingRuleUseRegistry()
    {
        return matchingRuleUseRegistry;
    }


    /**
     * @return The NameForm registry
     */
    public NameFormRegistry getNameFormRegistry()
    {
        return nameFormRegistry;
    }


    /**
     * @return The Normalizer registry
     */
    public NormalizerRegistry getNormalizerRegistry()
    {
        return normalizerRegistry;
    }


    /**
     * @return The ObjectClass registry
     */
    public ObjectClassRegistry getObjectClassRegistry()
    {
        return objectClassRegistry;
    }


    /**
     * @return The global Oid registry
     */
    public OidRegistry getGlobalOidRegistry()
    {
        return globalOidRegistry;
    }


    /**
     * @return The SyntaxChecker registry
     */
    public SyntaxCheckerRegistry getSyntaxCheckerRegistry()
    {
        return syntaxCheckerRegistry;
    }


    /**
     * @return The LdapSyntax registry
     */
    public LdapSyntaxRegistry getLdapSyntaxRegistry()
    {
        return ldapSyntaxRegistry;
    }


    /**
     * Get an OID from a name. As we have many possible registries, we
     * have to look in all of them to get the one containing the OID.
     *
     * @param name The name we are looking at
     * @return The associated OID
     */
    public String getOid( String name )
    {
        // we have many possible Registries to look at.
        // AttributeType
        try
        {
            AttributeType attributeType = attributeTypeRegistry.lookup( name );

            if ( attributeType != null )
            {
                return attributeType.getOid();
            }
        }
        catch ( LdapException ne )
        {
            // Fall down to the next registry
        }

        // ObjectClass
        try
        {
            ObjectClass objectClass = objectClassRegistry.lookup( name );

            if ( objectClass != null )
            {
                return objectClass.getOid();
            }
        }
        catch ( LdapException ne )
        {
            // Fall down to the next registry
        }

        // LdapSyntax
        try
        {
            LdapSyntax ldapSyntax = ldapSyntaxRegistry.lookup( name );

            if ( ldapSyntax != null )
            {
                return ldapSyntax.getOid();
            }
        }
        catch ( LdapException ne )
        {
            // Fall down to the next registry
        }

        // MatchingRule
        try
        {
            MatchingRule matchingRule = matchingRuleRegistry.lookup( name );

            if ( matchingRule != null )
            {
                return matchingRule.getOid();
            }
        }
        catch ( LdapException ne )
        {
            // Fall down to the next registry
        }

        // MatchingRuleUse
        try
        {
            MatchingRuleUse matchingRuleUse = matchingRuleUseRegistry.lookup( name );

            if ( matchingRuleUse != null )
            {
                return matchingRuleUse.getOid();
            }
        }
        catch ( LdapException ne )
        {
            // Fall down to the next registry
        }

        // NameForm
        try
        {
            NameForm nameForm = nameFormRegistry.lookup( name );

            if ( nameForm != null )
            {
                return nameForm.getOid();
            }
        }
        catch ( LdapException ne )
        {
            // Fall down to the next registry
        }

        // DitContentRule
        try
        {
            DitContentRule ditContentRule = ditContentRuleRegistry.lookup( name );

            if ( ditContentRule != null )
            {
                return ditContentRule.getOid();
            }
        }
        catch ( LdapException ne )
        {
            // Fall down to the next registry
        }

        // DitStructureRule
        try
        {
            DitStructureRule ditStructureRule = ditStructureRuleRegistry.lookup( name );

            if ( ditStructureRule != null )
            {
                return ditStructureRule.getOid();
            }
        }
        catch ( LdapException ne )
        {
            // No more registries to look at...
        }

        return null;
    }


    /**
     * Gets a schema that has been loaded into these Registries.
     * 
     * @param schemaName the name of the schema to lookup
     * @return the loaded Schema if one corresponding to the name exists
     */
    public Schema getLoadedSchema( String schemaName )
    {
        return loadedSchemas.get( Strings.toLowerCaseAscii( schemaName ) );
    }


    /**
     * Checks to see if a particular Schema is loaded.
     *
     * @param schemaName the name of the Schema to check
     * @return true if the Schema is loaded, false otherwise
     */
    public boolean isSchemaLoaded( String schemaName )
    {
        return loadedSchemas.containsKey( Strings.toLowerCaseAscii( schemaName ) );
    }


    // ------------------------------------------------------------------------
    // Code used to sanity check the resolution of entities in registries
    // ------------------------------------------------------------------------
    /**
     * Attempts to resolve the dependent schema objects of all entities that
     * refer to other objects within the registries.  Null references will be
     * handed appropriately.
     * The order in which the SchemaObjects must be :
     * 
    *
  • 1) Normalizers, Comparators and SyntaxCheckers (as they depend on nothing)
  • *
  • 2) Syntaxes (depend on SyntaxCheckers)
  • *
  • 3) MatchingRules (depend on Syntaxes, Normalizers and Comparators
  • *
  • 4) AttributeTypes (depend on MatchingRules, Syntaxes and AttributeTypes : in this case, we first handle the superior)
  • *
  • 5) ObjectClasses (depend on AttributeTypes and ObjectClasses)
  • *
*

* Later, when we will support them : *
    *
  • 6) MatchingRuleUses (depend on matchingRules and AttributeTypes)
  • *
  • 7) DitContentRules (depend on ObjectClasses and AttributeTypes)
  • *
  • 8) NameForms (depends on ObjectClasses and AttributeTypes)
  • *
  • 9) DitStructureRules (depends onNameForms and DitStructureRules)
  • *
*/ public void checkRefInteg() { // Step 1 : // We start with Normalizers, Comparators and SyntaxCheckers // as they depend on nothing // Check the Normalizers for ( Normalizer normalizer : normalizerRegistry ) { resolve( normalizer ); } // Check the Comparators for ( LdapComparator comparator : comparatorRegistry ) { resolve( comparator ); } // Check the SyntaxCheckers for ( SyntaxChecker syntaxChecker : syntaxCheckerRegistry ) { resolve( syntaxChecker ); } // Step 2 : // Check the LdapSyntaxes for ( LdapSyntax ldapSyntax : ldapSyntaxRegistry ) { resolve( ldapSyntax ); } // Step 3 : // Check the matchingRules for ( MatchingRule matchingRule : matchingRuleRegistry ) { resolve( matchingRule ); } // Step 4 : // Check the AttributeTypes for ( AttributeType attributeType : attributeTypeRegistry ) { resolve( attributeType ); } // Step 5 : // Check the ObjectClasses for ( ObjectClass objectClass : objectClassRegistry ) { resolve( objectClass ); } // Step 6-9 aren't yet defined } /** * Add the SchemaObjectReferences. This method does nothing, it's just * a catch all. The other methods will be called for each specific * schemaObject * public void addCrossReferences( SchemaObject schemaObject ) { // Do nothing : it's a catch all method. } /** * Delete the AT references (using and usedBy) : * AT -> MR (for EQUALITY, ORDERING and SUBSTR) * AT -> S * AT -> AT * * @param attributeType The AttributeType to remove */ public void delCrossReferences( AttributeType attributeType ) { if ( attributeType.getEquality() != null ) { delReference( attributeType, attributeType.getEquality() ); } if ( attributeType.getOrdering() != null ) { delReference( attributeType, attributeType.getOrdering() ); } if ( attributeType.getSubstring() != null ) { delReference( attributeType, attributeType.getSubstring() ); } if ( attributeType.getSyntax() != null ) { delReference( attributeType, attributeType.getSyntax() ); } if ( attributeType.getSuperior() != null ) { delReference( attributeType, attributeType.getSuperior() ); } } /** * Build the AttributeType references. This has to be done recursively, as * an AttributeType may inherit its parent's MatchingRules. The references * to update are : * - EQUALITY MR * - ORDERING MR * - SUBSTRING MR * - SUP AT * - SYNTAX */ private void buildAttributeTypeReferences() { for ( AttributeType attributeType : attributeTypeRegistry ) { if ( ( getUsing( attributeType ) == null ) || getUsing( attributeType ).isEmpty() ) { buildReference( attributeType ); } } } /** * Build the Comparator references */ private void buildComparatorReferences() { for ( LdapComparator comparator : comparatorRegistry ) { buildReference( comparator ); } } /** * Build the DitContentRule references */ private void buildDitContentRuleReferences() { // TODO: implement } /** * Build the DitStructureRule references */ private void buildDitStructureRuleReferences() { // TODO: implement } /** * Delete the MR references (using and usedBy) : * MR -> C * MR -> N * MR -> S * * @param matchingRule The MatchinRule refere ce to delete */ public void delCrossReferences( MatchingRule matchingRule ) { if ( matchingRule.getLdapComparator() != null ) { delReference( matchingRule, matchingRule.getLdapComparator() ); } if ( matchingRule.getNormalizer() != null ) { delReference( matchingRule, matchingRule.getNormalizer() ); } if ( matchingRule.getSyntax() != null ) { delReference( matchingRule, matchingRule.getSyntax() ); } } /** * Build the SchemaObject references * * @param schemaObject The SchemaObject to add */ public void buildReference( SchemaObject schemaObject ) { try { switch ( schemaObject.getObjectType() ) { case ATTRIBUTE_TYPE: AttributeTypeHelper.addToRegistries( ( MutableAttributeType ) schemaObject, errorHandler, this ); break; case DIT_CONTENT_RULE: DitContentRuleHelper.addToRegistries( ( DitContentRule ) schemaObject, errorHandler, this ); break; case DIT_STRUCTURE_RULE: DitStructureRuleHelper.addToRegistries( ( DitStructureRule ) schemaObject, errorHandler, this ); break; case LDAP_SYNTAX: LdapSyntaxHelper.addToRegistries( ( LdapSyntax ) schemaObject, errorHandler, this ); break; case MATCHING_RULE: MatchingRuleHelper.addToRegistries( ( MutableMatchingRule ) schemaObject, errorHandler, this ); break; case MATCHING_RULE_USE: MatchingRuleUseHelper.addToRegistries( ( MatchingRuleUse ) schemaObject, errorHandler, this ); break; case NAME_FORM: NameFormHelper.addToRegistries( ( NameForm ) schemaObject, errorHandler, this ); break; case OBJECT_CLASS: ObjectClassHelper.addToRegistries( ( ObjectClass ) schemaObject, errorHandler, this ); break; case SYNTAX_CHECKER: case NORMALIZER: case COMPARATOR: // Those are not registered break; default: throw new IllegalArgumentException( I18n.err( I18n.ERR_13718_UNEXPECTED_SCHEMA_OBJECT_TYPE, schemaObject.getObjectType() ) ); } } catch ( LdapException ne ) { // Not allowed. String msg = I18n.err( I18n.ERR_13746_CANNOT_BUILD_REFERENCES, schemaObject.getName(), ne.getLocalizedMessage() ); LdapProtocolErrorException error = new LdapProtocolErrorException( msg, ne ); errorHandler.handle( LOG, msg, error ); } } /** * Unlink the SchemaObject references * * @param schemaObject The SchemaObject to remove */ public void removeReference( SchemaObject schemaObject ) { try { switch ( schemaObject.getObjectType() ) { case ATTRIBUTE_TYPE: AttributeTypeHelper.removeFromRegistries( ( AttributeType ) schemaObject, errorHandler, this ); break; case LDAP_SYNTAX: LdapSyntaxHelper.removeFromRegistries( ( LdapSyntax ) schemaObject, errorHandler, this ); break; case MATCHING_RULE: MatchingRuleHelper.removeFromRegistries( ( MatchingRule ) schemaObject, errorHandler, this ); break; case OBJECT_CLASS: ObjectClassHelper.removeFromRegistries( ( ObjectClass ) schemaObject, errorHandler, this ); break; case DIT_CONTENT_RULE : // TODO break; case DIT_STRUCTURE_RULE : // TODO break; case NAME_FORM : // TODO break; case MATCHING_RULE_USE : // TODO break; case SYNTAX_CHECKER: case NORMALIZER: case COMPARATOR: // Those were not registered break; default: throw new IllegalArgumentException( I18n.err( I18n.ERR_13718_UNEXPECTED_SCHEMA_OBJECT_TYPE, schemaObject.getObjectType() ) ); } } catch ( LdapException ne ) { // Not allowed. String msg = I18n.err( I18n.ERR_13747_CANNOT_REMOVE_REFERENCES, schemaObject.getName(), ne.getLocalizedMessage() ); LdapSchemaViolationException error = new LdapSchemaViolationException( ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX, msg, ne ); errorHandler.handle( LOG, msg, error ); } } /** * Build the MatchingRule references */ private void buildMatchingRuleReferences() { for ( MatchingRule matchingRule : matchingRuleRegistry ) { buildReference( matchingRule ); } } /** * Build the MatchingRuleUse references */ private void buildMatchingRuleUseReferences() { for ( MatchingRuleUse matchingRuleUse : matchingRuleUseRegistry ) { buildReference( matchingRuleUse ); } } /** * Build the NameForm references */ private void buildNameFormReferences() { // TODO: implement } /** * Build the Normalizer references */ private void buildNormalizerReferences() { for ( Normalizer normalizer : normalizerRegistry ) { buildReference( normalizer ); } } /** * Build the ObjectClasses references */ private void buildObjectClassReferences() { // Remember the OC we have already processed Set done = new HashSet<>(); // The ObjectClass for ( ObjectClass objectClass : objectClassRegistry ) { if ( done.contains( objectClass.getOid() ) ) { continue; } else { done.add( objectClass.getOid() ); } buildReference( objectClass ); } } /** * Build the Syntax references */ private void buildLdapSyntaxReferences() { for ( LdapSyntax syntax : ldapSyntaxRegistry ) { buildReference( syntax ); } } /** * Build the SyntaxChecker references */ private void buildSyntaxCheckerReferences() { for ( SyntaxChecker syntaxChecker : syntaxCheckerRegistry ) { buildReference( syntaxChecker ); } } /** * Build the usedBy and using references from the stored elements. */ public void buildReferences() { // The Comparator references buildComparatorReferences(); // The Normalizer references buildNormalizerReferences(); // The SyntaxChecker references buildSyntaxCheckerReferences(); // The Syntax references buildLdapSyntaxReferences(); // The MatchingRules references buildMatchingRuleReferences(); // The AttributeType references buildAttributeTypeReferences(); // The MatchingRuleUse references buildMatchingRuleUseReferences(); // The ObjectClasses references buildObjectClassReferences(); // The DitContentRules references buildDitContentRuleReferences(); // The NameForms references buildNameFormReferences(); // The DitStructureRules references buildDitStructureRuleReferences(); } /** * Attempts to resolve the SyntaxChecker associated with a Syntax. * * @param syntax the LdapSyntax to resolve the SyntaxChecker of */ private void resolve( LdapSyntax syntax ) { // A LdapSyntax must point to a valid SyntaxChecker // or to the OctetString SyntaxChecker try { LdapSyntaxHelper.addToRegistries( syntax, errorHandler, this ); } catch ( LdapException e ) { errorHandler.handle( LOG, e.getMessage(), e ); } } /** * Attempts to resolve the Normalizer * * @param normalizer the Normalizer */ private void resolve( Normalizer normalizer ) { // This is currently doing nothing. } /** * Attempts to resolve the LdapComparator * * @param comparator the LdapComparator */ private void resolve( LdapComparator comparator ) { // This is currently doing nothing. } /** * Attempts to resolve the SyntaxChecker * * @param syntaxChecker the SyntaxChecker */ private void resolve( SyntaxChecker syntaxChecker ) { // This is currently doing nothing. } /** * Check if the Comparator, Normalizer and the syntax are * existing for a matchingRule. * * @param matchingRule The matching rule to use */ private void resolve( MatchingRule matchingRule ) { // Process the Syntax. It can't be null String syntaxOid = matchingRule.getSyntaxOid(); if ( syntaxOid != null ) { // Check if the Syntax is present in the registries try { ldapSyntaxRegistry.lookup( syntaxOid ); } catch ( LdapException ne ) { // This MR's syntax has not been loaded into the Registries. LdapSchemaException ldapSchemaException = new LdapSchemaException( LdapSchemaExceptionCodes.OID_ALREADY_REGISTERED, I18n.err( I18n.ERR_13748_MATCHING_RULE_NO_SYNTAX, matchingRule.getOid() ), ne ); ldapSchemaException.setSourceObject( matchingRule ); errorHandler.handle( LOG, ldapSchemaException.getMessage(), ldapSchemaException ); } } else { // This is an error. LdapSchemaException ldapSchemaException = new LdapSchemaException( LdapSchemaExceptionCodes.OID_ALREADY_REGISTERED, I18n.err( I18n.ERR_13748_MATCHING_RULE_NO_SYNTAX, matchingRule.getOid() ) ); ldapSchemaException.setSourceObject( matchingRule ); errorHandler.handle( LOG, ldapSchemaException.getMessage(), ldapSchemaException ); } // Process the Normalizer Normalizer normalizer = matchingRule.getNormalizer(); if ( normalizer == null ) { // Ok, no normalizer, this is an error LdapSchemaViolationException error = new LdapSchemaViolationException( ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX, I18n.err( I18n.ERR_13220_NO_NORMALIZER, matchingRule.getOid() ) ); errorHandler.handle( LOG, error.getMessage(), error ); } // Process the Comparator LdapComparator comparator = matchingRule.getLdapComparator(); if ( comparator == null ) { // Ok, no comparator, this is an error LdapSchemaViolationException error = new LdapSchemaViolationException( ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX, I18n.err( I18n.ERR_13413_MR_DOES_NOT_HAVE_A_COMP, matchingRule.getOid() ) ); errorHandler.handle( LOG, error.getMessage(), error ); } } /** * Check AttributeType referential integrity * * @param attributeType The AttributeType * @param processed The set of superior to check */ private void resolveRecursive( AttributeType attributeType, Set processed ) { // Process the Superior, if any String superiorOid = attributeType.getSuperiorOid(); AttributeType superior = null; if ( superiorOid != null ) { // Check if the Superior is present in the registries try { superior = attributeTypeRegistry.lookup( superiorOid ); } catch ( LdapException ne ) { // This AT's superior has not been loaded into the Registries. if ( !processed.contains( superiorOid ) ) { errorHandler.handle( LOG, ne.getMessage(), ne ); } } // We now have to process the superior, if it hasn't been // processed yet. if ( superior != null ) { if ( !processed.contains( superiorOid ) ) { resolveRecursive( superior, processed ); processed.add( attributeType.getOid() ); } else { // Not allowed : we have a cyle LdapSchemaViolationException error = new LdapSchemaViolationException( ResultCodeEnum.OTHER, I18n.err( I18n.ERR_13749_AT_WITH_CYCLE, attributeType.getOid() ) ); errorHandler.handle( LOG, error.getMessage(), error ); return; } } } // Process the Syntax. If it's null, the attributeType must have // a Superior. String syntaxOid = attributeType.getSyntaxOid(); if ( syntaxOid != null ) { // Check if the Syntax is present in the registries try { ldapSyntaxRegistry.lookup( syntaxOid ); } catch ( LdapException ne ) { // This AT's syntax has not been loaded into the Registries. errorHandler.handle( LOG, ne.getMessage(), ne ); } } else { // No Syntax : get it from the AttributeType's superior if ( superior == null ) { // This is an error. if the AT does not have a Syntax, // then it must have a superior, which syntax is get from. LdapSchemaViolationException error = new LdapSchemaViolationException( ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX, I18n.err( I18n.ERR_13414_AT_DOES_NOT_HAVE_A_SUPERIOR_NOR_SYNTAX, attributeType.getOid() ) ); errorHandler.handle( LOG, error.getMessage(), error ); } } // Process the EQUALITY MatchingRule. It may be null, but if it's not // it must have been processed before String equalityOid = attributeType.getEqualityOid(); if ( equalityOid != null ) { // Check if the MatchingRule is present in the registries try { matchingRuleRegistry.lookup( equalityOid ); } catch ( LdapException ne ) { // This AT's EQUALITY matchingRule has not been loaded into the Registries. errorHandler.handle( LOG, ne.getMessage(), ne ); } } // Process the ORDERING MatchingRule. It may be null, but if it's not // it must have been processed before String orderingOid = attributeType.getOrderingOid(); if ( orderingOid != null ) { // Check if the MatchingRule is present in the registries try { matchingRuleRegistry.lookup( orderingOid ); } catch ( LdapException ne ) { // This AT's ORDERING matchingRule has not been loaded into the Registries. errorHandler.handle( LOG, ne.getMessage(), ne ); } } // Process the SUBSTR MatchingRule. It may be null, but if it's not // it must have been processed before String substringOid = attributeType.getSubstringOid(); if ( substringOid != null ) { // Check if the MatchingRule is present in the registries try { matchingRuleRegistry.lookup( substringOid ); } catch ( LdapException ne ) { // This AT's SUBSTR matchingRule has not been loaded into the Registries. errorHandler.handle( LOG, ne.getMessage(), ne ); } } } /** * Check the inheritance, and the existence of MatchingRules and LdapSyntax * for an attribute * * @param attributeType The AttributeType */ private void resolve( AttributeType attributeType ) { // This set is used to avoid having more than one error // for an AttributeType. It's mandatory when processing // a Superior, as it may be broken and referenced more than once. Set processed = new HashSet<>(); // Store the AttributeType itself in the processed, to avoid cycle processed.add( attributeType.getOid() ); // Call the recursive method, as we may have superiors to deal with resolveRecursive( attributeType, processed ); } private List getMustRecursive( List musts, Set processed, ObjectClass objectClass ) { if ( objectClass != null ) { if ( processed.contains( objectClass ) ) { // We have found a cycle. It has already been reported, // don't add a new error, just exit. return null; } processed.add( objectClass ); for ( AttributeType must : objectClass.getMustAttributeTypes() ) { musts.add( must ); } for ( ObjectClass superior : objectClass.getSuperiors() ) { getMustRecursive( musts, processed, superior ); } } return musts; } private void resolve( ObjectClass objectClass ) { // This set is used to avoid having more than one error // for an ObjectClass. It's mandatory when processing // the Superiors, as they may be broken and referenced more than once. Set processed = new HashSet<>(); // Store the ObjectClass itself in the processed, to avoid cycle processed.add( objectClass.getOid() ); // Call the recursive method, as we may have superiors to deal with resolveRecursive( objectClass, processed ); // Check that the MAY and MUST AT are consistent (no AT in MAY and in MUST // in one of its superior List musts = getMustRecursive( new ArrayList(), new HashSet(), objectClass ); if ( musts != null ) { for ( AttributeType may : objectClass.getMayAttributeTypes() ) { if ( musts.contains( may ) ) { // This is not allowed. LdapSchemaException ldapSchemaException = new LdapSchemaException( LdapSchemaExceptionCodes.OC_DUPLICATE_AT_IN_MAY_AND_MUST ); ldapSchemaException.setSourceObject( objectClass ); ldapSchemaException.setOtherObject( may ); errorHandler.handle( LOG, ldapSchemaException.getMessage(), ldapSchemaException ); } } } } private void resolveRecursive( ObjectClass objectClass, Set processed ) { // Process the Superiors, if any List superiorOids = objectClass.getSuperiorOids(); ObjectClass superior = null; for ( String superiorOid : superiorOids ) { // Check if the Superior is present in the registries try { superior = objectClassRegistry.lookup( superiorOid ); } catch ( LdapException ne ) { // This OC's superior has not been loaded into the Registries. if ( !processed.contains( superiorOid ) ) { LdapSchemaException ldapSchemaException = new LdapSchemaException( LdapSchemaExceptionCodes.OC_NONEXISTENT_SUPERIOR, ne ); ldapSchemaException.setSourceObject( objectClass ); ldapSchemaException.setRelatedId( superiorOid ); errorHandler.handle( LOG, ldapSchemaException.getMessage(), ldapSchemaException ); } } // We now have to process the superior, if it hasn't been // processed yet. if ( superior != null ) { if ( !processed.contains( superior.getOid() ) ) { resolveRecursive( superior, processed ); processed.add( objectClass.getOid() ); } else { // Not allowed : we have a cyle LdapSchemaException ldapSchemaException = new LdapSchemaException( LdapSchemaExceptionCodes.OC_CYCLE_CLASS_HIERARCHY ); ldapSchemaException.setSourceObject( objectClass ); ldapSchemaException.setOtherObject( superior ); errorHandler.handle( LOG, ldapSchemaException.getMessage(), ldapSchemaException ); return; } } } // Process the MAY attributeTypes. for ( String mayOid : objectClass.getMayAttributeTypeOids() ) { // Check if the MAY AttributeType is present in the registries try { attributeTypeRegistry.lookup( mayOid ); } catch ( LdapException ne ) { // This AT has not been loaded into the Registries. errorHandler.handle( LOG, ne.getMessage(), ne ); } } // Process the MUST attributeTypes. for ( String mustOid : objectClass.getMustAttributeTypeOids() ) { // Check if the MUST AttributeType is present in the registries try { attributeTypeRegistry.lookup( mustOid ); } catch ( LdapException ne ) { // This AT has not been loaded into the Registries. errorHandler.handle( LOG, ne.getMessage(), ne ); } } // All is done for this ObjectClass, let's apply the registries ObjectClassHelper.addToRegistries( objectClass, errorHandler, this ); } /** * Applies the added SchemaObject to the given register * * @param schemaObject The SchemaObject to add * @param check A flag set when we want the schema checks to be done * @throws LdapException If we weren't able to add the SchemaObject */ public void add( SchemaObject schemaObject, boolean check ) throws LdapException { // Relax the registries boolean wasRelaxed = isRelaxed; setRelaxed(); // Register the SchemaObject in the registries register( schemaObject ); // Associate the SchemaObject with its schema associateWithSchema( schemaObject ); // Build the SchemaObject references if ( check ) { buildReference( schemaObject ); } // Lock the SchemaObject schemaObject.lock(); if ( check && ( !errorHandler.wasError() ) ) { // Check the registries now checkRefInteg(); } // Get back to Strict mode if ( !wasRelaxed ) { setStrict(); } } /** * Remove the given SchemaObject from the registries * * @param schemaObject The SchemaObject to delete * @throws LdapException If the deletion failed */ public void delete( SchemaObject schemaObject ) throws LdapException { // Relax the registries boolean wasRelaxed = isRelaxed; setRelaxed(); // Remove the SchemaObject from the registries SchemaObject removed = unregister( schemaObject ); // Remove the SchemaObject from its schema dissociateFromSchema( removed ); // Unlink the SchemaObject references removeReference( removed ); if ( !errorHandler.wasError() ) { // Check the registries now checkRefInteg(); } // Restore the previous registries state if ( !wasRelaxed ) { setStrict(); } } /** * Merely adds the schema to the set of loaded schemas. Does not * actually do any work to add schema objects to registries. * * {@inheritDoc} */ @Override public void schemaLoaded( Schema schema ) { this.loadedSchemas.put( Strings.toLowerCaseAscii( schema.getSchemaName() ), schema ); } /** * Merely removes the schema from the set of loaded schemas. Does not * actually do any work to remove schema objects from registries. * * {@inheritDoc} */ @Override public void schemaUnloaded( Schema schema ) { this.loadedSchemas.remove( Strings.toLowerCaseAscii( schema.getSchemaName() ) ); } /** * Gets an unmodifiable Map of schema names to loaded Schema objects. * * @return the map of loaded Schema objects */ public Map getLoadedSchemas() { return Collections.unmodifiableMap( loadedSchemas ); } /** * @return Gets a reference to the Map associating a schemaName to * its contained SchemaObjects */ public Map> getObjectBySchemaName() { return schemaObjects; } /** * Retrieve the schema name for a specific SchemaObject, or return "other" if none is found. * * @param schemaObject The SchemaObject * @return The associated Schema */ private String getSchemaName( SchemaObject schemaObject ) { String schemaName = Strings.toLowerCaseAscii( schemaObject.getSchemaName() ); if ( loadedSchemas.containsKey( schemaName ) ) { return schemaName; } else { return MetaSchemaConstants.SCHEMA_OTHER; } } /** * Tells if the given SchemaObject is present in one schema. The schema * may be disabled. * * @param schemaObject The schemaObject we are looking for * @return true if the schemaObject is present in a schema */ public boolean contains( SchemaObject schemaObject ) { String schemaName = schemaObject.getSchemaName(); Set setSchemaObjects = schemaObjects.get( schemaName ); if ( ( setSchemaObjects == null ) || setSchemaObjects.isEmpty() ) { return false; } SchemaObjectWrapper wrapper = new SchemaObjectWrapper( schemaObject ); return setSchemaObjects.contains( wrapper ); } /** * Create a new schema association with its content * * @param schemaName The schema name * @return A set containing the associations */ public Set addSchema( String schemaName ) { Set content = new HashSet<>(); schemaObjects.put( schemaName, content ); return content; } /** * Register the given SchemaObject into the associated Registry * * @param schemaObject The SchemaObject to register * @throws LdapException If the SchemaObject cannot be registered */ private void register( SchemaObject schemaObject ) throws LdapException { if ( LOG.isDebugEnabled() ) { LOG.debug( I18n.msg( I18n.MSG_13720_REGISTRING, schemaObject.getObjectType(), schemaObject.getOid() ) ); } // Check that the SchemaObject is not already registered if ( !( schemaObject instanceof LoadableSchemaObject ) && globalOidRegistry.contains( schemaObject.getOid() ) ) { String msg = I18n.err( I18n.ERR_13750_REGISTERING_FAILED_ALREADY_PRESENT, schemaObject.getObjectType(), schemaObject.getOid() ); LOG.error( msg ); LdapUnwillingToPerformException error = new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, msg ); errorHandler.handle( LOG, msg, error ); return; } try { // First call the specific registry's register method switch ( schemaObject.getObjectType() ) { case ATTRIBUTE_TYPE: attributeTypeRegistry.register( ( AttributeType ) schemaObject ); break; case COMPARATOR: comparatorRegistry.register( ( LdapComparator ) schemaObject ); break; case DIT_CONTENT_RULE: ditContentRuleRegistry.register( ( DitContentRule ) schemaObject ); break; case DIT_STRUCTURE_RULE: ditStructureRuleRegistry.register( ( DitStructureRule ) schemaObject ); break; case LDAP_SYNTAX: ldapSyntaxRegistry.register( ( LdapSyntax ) schemaObject ); break; case MATCHING_RULE: matchingRuleRegistry.register( ( MatchingRule ) schemaObject ); break; case MATCHING_RULE_USE: matchingRuleUseRegistry.register( ( MatchingRuleUse ) schemaObject ); break; case NAME_FORM: nameFormRegistry.register( ( NameForm ) schemaObject ); break; case NORMALIZER: normalizerRegistry.register( ( Normalizer ) schemaObject ); break; case OBJECT_CLASS: objectClassRegistry.register( ( ObjectClass ) schemaObject ); break; case SYNTAX_CHECKER: syntaxCheckerRegistry.register( ( SyntaxChecker ) schemaObject ); break; default: throw new IllegalArgumentException( I18n.err( I18n.ERR_13718_UNEXPECTED_SCHEMA_OBJECT_TYPE, schemaObject.getObjectType() ) ); } } catch ( Exception e ) { errorHandler.handle( LOG, e.getMessage(), e ); } } /** * Store the given SchemaObject in the Map associating SchemaObjetcs to their * related Schema. * * @param schemaObject The schemaObject to register */ public void associateWithSchema( SchemaObject schemaObject ) { if ( LOG.isDebugEnabled() ) { LOG.debug( I18n.msg( I18n.MSG_13720_REGISTRING, schemaObject.getObjectType(), schemaObject.getOid() ) ); } // Check that the SchemaObject is not already registered if ( !( schemaObject instanceof LoadableSchemaObject ) && globalOidRegistry.contains( schemaObject.getOid() ) ) { String msg = I18n.err( I18n.ERR_13750_REGISTERING_FAILED_ALREADY_PRESENT, schemaObject.getObjectType(), schemaObject.getOid() ); LOG.error( msg ); LdapUnwillingToPerformException error = new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, msg ); errorHandler.handle( LOG, msg, error ); return; } // Get a normalized form of schema name String schemaName = getSchemaName( schemaObject ); // And register the schemaObject within its schema Set content = schemaObjects.get( schemaName ); if ( content == null ) { content = new HashSet<>(); schemaObjects.put( Strings.toLowerCaseAscii( schemaName ), content ); } SchemaObjectWrapper schemaObjectWrapper = new SchemaObjectWrapper( schemaObject ); if ( content.contains( schemaObjectWrapper ) ) { // Already present ! // What should we do ? errorHandler.handle( LOG, I18n.msg( I18n.MSG_13719_REGISTRING_FAILED_ALREADY_PRESENT, schemaObject.getObjectType(), schemaObject.getOid() ), null ); } else { // Create the association content.add( schemaObjectWrapper ); // Update the global OidRegistry if the SchemaObject is not // an instance of LoadableSchemaObject if ( !( schemaObject instanceof LoadableSchemaObject ) ) { try { globalOidRegistry.register( schemaObject ); } catch ( LdapException ne ) { errorHandler.handle( LOG, ne.getMessage(), ne ); return; } } if ( LOG.isDebugEnabled() ) { LOG.debug( I18n.msg( I18n.MSG_13731_REGISTRED_FOR_OID, schemaObject.getName(), schemaObject.getOid() ) ); } } } /** * Store the given SchemaObject in the Map associating SchemaObjetcs to their * related Schema. * * @param schemaObject The schemaObject to register * @throws LdapException If there is a problem */ public void dissociateFromSchema( SchemaObject schemaObject ) throws LdapException { if ( LOG.isDebugEnabled() ) { LOG.debug( I18n.msg( I18n.MSG_13741_UNREGISTRING, schemaObject.getObjectType(), schemaObject.getOid() ) ); } // Check that the SchemaObject is already registered if ( !( schemaObject instanceof LoadableSchemaObject ) && !globalOidRegistry.contains( schemaObject.getOid() ) ) { String msg = I18n.err( I18n.ERR_13751_UNREGISTERING_FAILED_NOT_PRESENT, schemaObject.getObjectType(), schemaObject.getOid() ); LOG.error( msg ); Throwable error = new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, msg ); errorHandler.handle( LOG, msg, error ); return; } // Get a normalized form of schema name String schemaName = getSchemaName( schemaObject ); String oid = schemaObject.getOid(); // And unregister the schemaObject from its schema Set content = schemaObjects.get( schemaName ); SchemaObjectWrapper schemaObjectWrapper = new SchemaObjectWrapper( schemaObject ); if ( !content.contains( schemaObjectWrapper ) ) { // Not present ! // What should we do ? if ( LOG.isInfoEnabled() ) { LOG.info( I18n.msg( I18n.MSG_13739_UNREGISTERED_FAILED_NOT_PRESENT, schemaObject.getObjectType(), schemaObject.getOid() ) ); } } else { // Remove the association content.remove( schemaObjectWrapper ); // Update the global OidRegistry if the SchemaObject is not // an instance of LoadableSchemaObject if ( !( schemaObject instanceof LoadableSchemaObject ) ) { try { globalOidRegistry.unregister( oid ); } catch ( LdapException ne ) { errorHandler.handle( LOG, ne.getMessage(), ne ); return; } } if ( LOG.isDebugEnabled() ) { LOG.debug( I18n.msg( I18n.MSG_13737_UNREGISTERED_FOR_OID, schemaObject.getName(), schemaObject.getOid() ) ); } } } /** * Unregister a SchemaObject from the registries * * @param schemaObject The SchemaObject we want to deregister * @return The unregistred SchemaObject * @throws LdapException If the removal failed */ private SchemaObject unregister( SchemaObject schemaObject ) throws LdapException { if ( LOG.isDebugEnabled() ) { LOG.debug( I18n.msg( I18n.MSG_13741_UNREGISTRING, schemaObject.getObjectType(), schemaObject.getOid() ) ); } // Check that the SchemaObject is present in the registries if ( !( schemaObject instanceof LoadableSchemaObject ) && !globalOidRegistry.contains( schemaObject.getOid() ) ) { String msg = I18n.err( I18n.ERR_13751_UNREGISTERING_FAILED_NOT_PRESENT, schemaObject.getObjectType(), schemaObject.getOid() ); LOG.error( msg ); throw new LdapUnwillingToPerformException( ResultCodeEnum.UNWILLING_TO_PERFORM, msg ); } SchemaObject unregistered; // First call the specific registry's register method switch ( schemaObject.getObjectType() ) { case ATTRIBUTE_TYPE: unregistered = attributeTypeRegistry.unregister( ( AttributeType ) schemaObject ); break; case COMPARATOR: unregistered = comparatorRegistry.unregister( ( LdapComparator ) schemaObject ); break; case DIT_CONTENT_RULE: unregistered = ditContentRuleRegistry.unregister( ( DitContentRule ) schemaObject ); break; case DIT_STRUCTURE_RULE: unregistered = ditStructureRuleRegistry.unregister( ( DitStructureRule ) schemaObject ); break; case LDAP_SYNTAX: unregistered = ldapSyntaxRegistry.unregister( ( LdapSyntax ) schemaObject ); break; case MATCHING_RULE: unregistered = matchingRuleRegistry.unregister( ( MatchingRule ) schemaObject ); break; case MATCHING_RULE_USE: unregistered = matchingRuleUseRegistry.unregister( ( MatchingRuleUse ) schemaObject ); break; case NAME_FORM: unregistered = nameFormRegistry.unregister( ( NameForm ) schemaObject ); break; case NORMALIZER: unregistered = normalizerRegistry.unregister( ( Normalizer ) schemaObject ); break; case OBJECT_CLASS: unregistered = objectClassRegistry.unregister( ( ObjectClass ) schemaObject ); break; case SYNTAX_CHECKER: unregistered = syntaxCheckerRegistry.unregister( ( SyntaxChecker ) schemaObject ); break; default: throw new IllegalArgumentException( I18n.err( I18n.ERR_13718_UNEXPECTED_SCHEMA_OBJECT_TYPE, schemaObject.getObjectType() ) ); } return unregistered; } /** * Checks if a specific SchemaObject is referenced by any other SchemaObject. * * @param schemaObject The SchemaObject we are looking for * @return true if there is at least one SchemaObjetc referencing the given one */ public boolean isReferenced( SchemaObject schemaObject ) { SchemaObjectWrapper wrapper = new SchemaObjectWrapper( schemaObject ); Set set = usedBy.get( wrapper ); boolean referenced = ( set != null ) && !set.isEmpty(); if ( LOG.isDebugEnabled() ) { if ( referenced ) { LOG.debug( I18n.msg( I18n.MSG_13735_REFERENCED, schemaObject.getObjectType(), schemaObject.getOid() ) ); } else { LOG.debug( I18n.msg( I18n.MSG_13734_NOT_REFERENCED, schemaObject.getObjectType(), schemaObject.getOid() ) ); } } return referenced; } /** * Gets the Set of SchemaObjects referencing the given SchemaObject * * @param schemaObject The SchemaObject we are looking for * @return The Set of referencing SchemaObject, or null */ public Set getUsedBy( SchemaObject schemaObject ) { SchemaObjectWrapper wrapper = new SchemaObjectWrapper( schemaObject ); return usedBy.get( wrapper ); } /** * Dump the UsedBy data structure as a String * * @return The UsedBy data structure */ public String dumpUsedBy() { StringBuilder sb = new StringBuilder(); sb.append( "USED BY :\n" ); try { for ( Map.Entry> entry : usedBy.entrySet() ) { SchemaObjectWrapper wrapper = entry.getKey(); sb.append( wrapper.get().getObjectType() ).append( '[' ).append( wrapper.get().getOid() ) .append( "] : {" ); boolean isFirst = true; for ( SchemaObjectWrapper uses : entry.getValue() ) { if ( isFirst ) { isFirst = false; } else { sb.append( ", " ); } sb.append( uses.get().getObjectType() ).append( '[' ).append( wrapper.get().getOid() ).append( "]" ); } sb.append( "}\n" ); } } catch ( Exception e ) { e.printStackTrace(); } return sb.toString(); } /** * Dump the Using data structure as a String * * @return The Using data structure */ public String dumpUsing() { StringBuilder sb = new StringBuilder(); sb.append( "USING :\n" ); try { for ( Map.Entry> entry : using.entrySet() ) { SchemaObjectWrapper wrapper = entry.getKey(); sb.append( wrapper.get().getObjectType() ).append( '[' ).append( wrapper.get().getOid() ) .append( "] : {" ); boolean isFirst = true; for ( SchemaObjectWrapper uses : entry.getValue() ) { if ( isFirst ) { isFirst = false; } else { sb.append( ", " ); } sb.append( uses.get().getObjectType() ).append( '[' ).append( wrapper.get().getOid() ).append( "]" ); } sb.append( "}\n" ); } } catch ( Exception e ) { e.printStackTrace(); } return sb.toString(); } /** * Gets the Set of SchemaObjects referenced by the given SchemaObject * * @param schemaObject The SchemaObject we are looking for * @return The Set of referenced SchemaObject, or null */ public Set getUsing( SchemaObject schemaObject ) { SchemaObjectWrapper wrapper = new SchemaObjectWrapper( schemaObject ); return using.get( wrapper ); } /** * Add an association between a SchemaObject an the SchemaObject it refers * * @param reference The base SchemaObject * @param referee The SchemaObject pointing on the reference */ private void addUsing( SchemaObject reference, SchemaObject referee ) { if ( ( reference == null ) || ( referee == null ) ) { return; } SchemaObjectWrapper wrapper = new SchemaObjectWrapper( reference ); Set uses = getUsing( reference ); if ( uses == null ) { uses = new HashSet<>(); } uses.add( new SchemaObjectWrapper( referee ) ); // Put back the set (this is a concurrentHashMap, it won't be replaced implicitly using.put( wrapper, uses ); } /** * Add an association between a SchemaObject an the SchemaObject it refers * * @param base The base SchemaObject * @param referenced The referenced SchemaObject */ public void addReference( SchemaObject base, SchemaObject referenced ) { if ( LOG.isDebugEnabled() ) { LOG.debug( dump( "add", base, referenced ) ); } addUsing( base, referenced ); addUsedBy( referenced, base ); // do not change to debug mode, this makes the server logs hard to read and useless // and even prevents the server from starting up if ( LOG.isTraceEnabled() ) { LOG.trace( dumpUsedBy() ); LOG.trace( dumpUsing() ); } } /** * Add an association between a SchemaObject an the SchemaObject that refers it * * @param reference The base SchemaObject * @param referee The SchemaObject pointing on the reference */ private void addUsedBy( SchemaObject referee, SchemaObject reference ) { if ( ( reference == null ) || ( referee == null ) ) { return; } SchemaObjectWrapper wrapper = new SchemaObjectWrapper( referee ); Set uses = getUsedBy( referee ); if ( uses == null ) { uses = new HashSet<>(); } uses.add( new SchemaObjectWrapper( reference ) ); // Put back the set (this is a concurrentHashMap, it won't be replaced implicitly usedBy.put( wrapper, uses ); } /** * Del an association between a SchemaObject an the SchemaObject it refers * * @param reference The base SchemaObject * @param referee The SchemaObject pointing on the reference */ private void delUsing( SchemaObject reference, SchemaObject referee ) { if ( ( reference == null ) || ( referee == null ) ) { return; } Set uses = getUsing( reference ); if ( uses == null ) { return; } uses.remove( new SchemaObjectWrapper( referee ) ); SchemaObjectWrapper wrapper = new SchemaObjectWrapper( reference ); if ( uses.isEmpty() ) { using.remove( wrapper ); } else { using.put( wrapper, uses ); } } /** * Del an association between a SchemaObject an the SchemaObject that refers it * * @param reference The base SchemaObject * @param referee The SchemaObject pointing on the reference */ private void delUsedBy( SchemaObject referee, SchemaObject reference ) { if ( ( reference == null ) || ( referee == null ) ) { return; } Set uses = getUsedBy( referee ); if ( uses == null ) { return; } uses.remove( new SchemaObjectWrapper( reference ) ); SchemaObjectWrapper wrapper = new SchemaObjectWrapper( referee ); if ( uses.isEmpty() ) { usedBy.remove( wrapper ); } else { usedBy.put( wrapper, uses ); } } /** * Delete an association between a SchemaObject an the SchemaObject it refers * * @param base The base SchemaObject * @param referenced The referenced SchemaObject */ public void delReference( SchemaObject base, SchemaObject referenced ) { if ( LOG.isDebugEnabled() ) { LOG.debug( dump( "del", base, referenced ) ); } delUsing( base, referenced ); delUsedBy( referenced, base ); if ( LOG.isDebugEnabled() ) { LOG.debug( dumpUsedBy() ); LOG.debug( dumpUsing() ); } } /** * Dump the reference operation as a String * * @param op The operation * @param reference The reference * @param referee The referee * @return The resulting string */ private String dump( String op, SchemaObject reference, SchemaObject referee ) { return op + " : " + reference.getObjectType() + "[" + reference.getOid() + "]/[" + referee.getObjectType() + "[" + referee.getOid() + "]"; } private boolean checkReferences( SchemaObject reference, SchemaObject referee, String message ) { SchemaObjectWrapper referenceWrapper = new SchemaObjectWrapper( reference ); SchemaObjectWrapper refereeWrapper = new SchemaObjectWrapper( referee ); // Check the references : Syntax -> SyntaxChecker if ( !using.containsKey( referenceWrapper ) ) { if ( LOG.isDebugEnabled() ) { LOG.debug( I18n.msg( I18n.MSG_13730_SYN_DOES_NOT_REFERENCE, reference.getObjectType(), reference.getOid(), message ) ); } return false; } Set usings = using.get( referenceWrapper ); if ( !usings.contains( refereeWrapper ) ) { if ( LOG.isDebugEnabled() ) { LOG.debug( I18n.msg( I18n.MSG_13732_NOT_REFERENCE_ANY, reference.getObjectType(), reference.getOid(), message ) ); } return false; } // Check the referees : SyntaxChecker -> Syntax if ( !usedBy.containsKey( refereeWrapper ) ) { if ( LOG.isDebugEnabled() ) { LOG.debug( I18n.msg( I18n.MSG_13733_NOT_REFERENCED_BY_ANY, referee.getObjectType(), referee.getOid(), message ) ); } return false; } Set used = usedBy.get( refereeWrapper ); if ( !used.contains( referenceWrapper ) ) { if ( LOG.isDebugEnabled() ) { LOG.debug( I18n.msg( I18n.MSG_13733_NOT_REFERENCED_BY_ANY, referee.getObjectType(), referee.getOid(), message ) ); } return false; } return true; } /** * Check the registries for invalid relations. This check stops at the first error. * * @return true if the Registries is consistent, false otherwise */ public boolean check() { // Check the Syntaxes : check for a SyntaxChecker if ( LOG.isDebugEnabled() ) { LOG.debug( I18n.msg( I18n.MSG_13717_CHECKING_SYNTAXES ) ); } for ( LdapSyntax syntax : ldapSyntaxRegistry ) { // Check that each Syntax has a SyntaxChecker if ( syntax.getSyntaxChecker() == null ) { if ( LOG.isDebugEnabled() ) { LOG.debug( I18n.msg( I18n.MSG_13729_SYN_WITH_NO_SYNTAX_CHECKER, syntax ) ); } return false; } if ( !syntaxCheckerRegistry.contains( syntax.getSyntaxChecker().getOid() ) ) { if ( LOG.isDebugEnabled() ) { LOG.debug( I18n.msg( I18n.MSG_13713_CANT_FIND_SC_FOR_SYN, syntax.getSyntaxChecker().getOid(), syntax ) ); } return false; } // Check the references : Syntax -> SyntaxChecker and SyntaxChecker -> Syntax if ( !checkReferences( syntax, syntax.getSyntaxChecker(), "SyntaxChecker" ) ) { return false; } } // Check the MatchingRules : check for a Normalizer, a Comparator and a Syntax if ( LOG.isDebugEnabled() ) { LOG.debug( I18n.msg( I18n.MSG_13715_CHECKING_MATCHING_RULES ) ); } for ( MatchingRule matchingRule : matchingRuleRegistry ) { // Check that each MatchingRule has a Normalizer if ( matchingRule.getNormalizer() == null ) { if ( LOG.isDebugEnabled() ) { LOG.debug( I18n.msg( I18n.MSG_13727_MR_WITH_NO_NORMALIZER, matchingRule ) ); } return false; } // Check that each MatchingRule has a Normalizer if ( !normalizerRegistry.contains( matchingRule.getNormalizer().getOid() ) ) { if ( LOG.isDebugEnabled() ) { LOG.debug( I18n.msg( I18n.MSG_13709_CANT_FIND_NORM_FOR_MR, matchingRule.getNormalizer() .getOid(), matchingRule ) ); } return false; } // Check that each MatchingRule has a Comparator if ( matchingRule.getLdapComparator() == null ) { if ( LOG.isDebugEnabled() ) { LOG.debug( I18n.msg( I18n.MSG_13726_MR_WITH_NO_COMPARATOR, matchingRule ) ); } return false; } if ( !comparatorRegistry.contains( matchingRule.getLdapComparator().getOid() ) ) { if ( LOG.isDebugEnabled() ) { LOG.debug( I18n.msg( I18n.MSG_13707_CANT_FIND_AT_FOR_MR, matchingRule.getLdapComparator().getOid(), matchingRule ) ); } return false; } // Check that each MatchingRule has a Syntax if ( matchingRule.getSyntax() == null ) { if ( LOG.isDebugEnabled() ) { LOG.debug( I18n.msg( I18n.MSG_13728_MR_WITH_NO_SYNTAX, matchingRule ) ); } return false; } if ( !ldapSyntaxRegistry.contains( matchingRule.getSyntax().getOid() ) ) { if ( LOG.isDebugEnabled() ) { LOG.debug( I18n.msg( I18n.MSG_13712_CANT_FIND_SYN_FOR_MR, matchingRule.getSyntax().getOid(), matchingRule ) ); } return false; } // Check the references : MR -> S and S -> MR if ( !checkReferences( matchingRule, matchingRule.getSyntax(), "Syntax" ) ) { return false; } // Check the references : MR -> N if ( !checkReferences( matchingRule, matchingRule.getNormalizer(), "Normalizer" ) ) { return false; } // Check the references : MR -> C and C -> MR if ( !checkReferences( matchingRule, matchingRule.getLdapComparator(), "Comparator" ) ) { return false; } } // Check the ObjectClasses : check for MAY, MUST, SUPERIORS if ( LOG.isDebugEnabled() ) { LOG.debug( I18n.msg( I18n.MSG_13716_CHECKING_OBJECT_CLASSES ) ); } for ( ObjectClass objectClass : objectClassRegistry ) { // Check that each ObjectClass has all the MAY AttributeTypes if ( objectClass.getMayAttributeTypes() != null ) { for ( AttributeType may : objectClass.getMayAttributeTypes() ) { if ( !attributeTypeRegistry.contains( may.getOid() ) ) { if ( LOG.isDebugEnabled() ) { LOG.debug( I18n.msg( I18n.MSG_13705_CANT_FIND_AT_IN_MAY, may, objectClass ) ); } return false; } // Check the references : OC -> AT and AT -> OC (MAY) if ( !checkReferences( objectClass, may, "AttributeType" ) ) { return false; } } } // Check that each ObjectClass has all the MUST AttributeTypes if ( objectClass.getMustAttributeTypes() != null ) { for ( AttributeType must : objectClass.getMustAttributeTypes() ) { if ( !attributeTypeRegistry.contains( must.getOid() ) ) { if ( LOG.isDebugEnabled() ) { LOG.debug( I18n.msg( I18n.MSG_13706_CANT_FIND_AT_IN_MUST, must, objectClass ) ); } return false; } // Check the references : OC -> AT and AT -> OC (MUST) if ( !checkReferences( objectClass, must, "AttributeType" ) ) { return false; } } } // Check that each ObjectClass has all the SUPERIORS ObjectClasses if ( objectClass.getSuperiors() != null ) { for ( ObjectClass superior : objectClass.getSuperiors() ) { if ( !objectClassRegistry.contains( objectClass.getOid() ) ) { if ( LOG.isDebugEnabled() ) { LOG.debug( I18n.msg( I18n.MSG_13710_CANT_FIND_OC_WITH_SUPERIOR, superior, objectClass ) ); } return false; } // Check the references : OC -> OC and OC -> OC (SUPERIORS) if ( !checkReferences( objectClass, superior, "ObjectClass" ) ) { return false; } } } } // Check the AttributeTypes : check for MatchingRules, Syntaxes if ( LOG.isDebugEnabled() ) { LOG.debug( I18n.msg( I18n.MSG_13714_CHECKING_ATTRIBUTE_TYPES ) ); } for ( AttributeType attributeType : attributeTypeRegistry ) { // Check that each AttributeType has a SYNTAX if ( attributeType.getSyntax() == null ) { if ( LOG.isDebugEnabled() ) { LOG.debug( I18n.msg( I18n.MSG_13725_AT_WITH_NO_SYNTAX, attributeType ) ); } return false; } if ( !ldapSyntaxRegistry.contains( attributeType.getSyntax().getOid() ) ) { if ( LOG.isDebugEnabled() ) { LOG.debug( I18n.msg( I18n.MSG_13711_CANT_FIND_SYN_FOR_AT, attributeType.getSyntax().getOid(), attributeType ) ); } return false; } // Check the references for AT -> S and S -> AT if ( !checkReferences( attributeType, attributeType.getSyntax(), "AttributeType" ) ) { return false; } // Check the EQUALITY MatchingRule if ( attributeType.getEquality() != null ) { if ( !matchingRuleRegistry.contains( attributeType.getEquality().getOid() ) ) { if ( LOG.isDebugEnabled() ) { LOG.debug( I18n.msg( I18n.MSG_13708_CANT_FIND_MR_FOR_AT, attributeType.getEquality() .getOid(), attributeType ) ); } return false; } // Check the references for AT -> MR and MR -> AT if ( !checkReferences( attributeType, attributeType.getEquality(), "AttributeType" ) ) { return false; } } // Check the ORDERING MatchingRule if ( attributeType.getOrdering() != null ) { if ( !matchingRuleRegistry.contains( attributeType.getOrdering().getOid() ) ) { if ( LOG.isDebugEnabled() ) { LOG.debug( I18n.msg( I18n.MSG_13708_CANT_FIND_MR_FOR_AT, attributeType.getOrdering() .getOid(), attributeType ) ); } return false; } // Check the references for AT -> MR and MR -> AT if ( !checkReferences( attributeType, attributeType.getOrdering(), "AttributeType" ) ) { return false; } } // Check the SUBSTR MatchingRule if ( attributeType.getSubstring() != null ) { if ( !matchingRuleRegistry.contains( attributeType.getSubstring().getOid() ) ) { if ( LOG.isDebugEnabled() ) { LOG.debug( I18n.msg( I18n.MSG_13708_CANT_FIND_MR_FOR_AT, attributeType.getSubstring() .getOid(), attributeType ) ); } return false; } // Check the references for AT -> MR and MR -> AT if ( !checkReferences( attributeType, attributeType.getSubstring(), "AttributeType" ) ) { return false; } } // Check the SUP if ( attributeType.getSuperior() != null ) { AttributeType superior = attributeType.getSuperior(); if ( !attributeTypeRegistry.contains( superior.getOid() ) ) { if ( LOG.isDebugEnabled() ) { LOG.debug( I18n.msg( I18n.MSG_13704_CANT_FIND_AT_WITH_SUPERIOR, superior, attributeType ) ); } return false; } // Check the references : AT -> AT and AT -> AT (SUPERIOR) if ( !checkReferences( attributeType, superior, "AttributeType" ) ) { return false; } } } return true; } /** * Clone the Registries. This is done in two steps : * - first clone the SchemaObjetc registries * - second restore the relation between them */ // False positive @Override public Registries clone() throws CloneNotSupportedException { // First clone the structure Registries clone = ( Registries ) super.clone(); // Now, clone the oidRegistry clone.globalOidRegistry = globalOidRegistry.copy(); // We have to clone every SchemaObject registries now clone.attributeTypeRegistry = attributeTypeRegistry.copy(); clone.comparatorRegistry = comparatorRegistry.copy(); clone.ditContentRuleRegistry = ditContentRuleRegistry.copy(); clone.ditStructureRuleRegistry = ditStructureRuleRegistry.copy(); clone.ldapSyntaxRegistry = ldapSyntaxRegistry.copy(); clone.matchingRuleRegistry = matchingRuleRegistry.copy(); clone.matchingRuleUseRegistry = matchingRuleUseRegistry.copy(); clone.nameFormRegistry = nameFormRegistry.copy(); clone.normalizerRegistry = normalizerRegistry.copy(); clone.objectClassRegistry = objectClassRegistry.copy(); clone.syntaxCheckerRegistry = syntaxCheckerRegistry.copy(); clone.errorHandler = errorHandler; // Store all the SchemaObjects into the globalOid registry for ( AttributeType attributeType : clone.attributeTypeRegistry ) { clone.globalOidRegistry.put( attributeType ); } for ( DitContentRule ditContentRule : clone.ditContentRuleRegistry ) { clone.globalOidRegistry.put( ditContentRule ); } for ( DitStructureRule ditStructureRule : clone.ditStructureRuleRegistry ) { clone.globalOidRegistry.put( ditStructureRule ); } for ( MatchingRule matchingRule : clone.matchingRuleRegistry ) { clone.globalOidRegistry.put( matchingRule ); } for ( MatchingRuleUse matchingRuleUse : clone.matchingRuleUseRegistry ) { clone.globalOidRegistry.put( matchingRuleUse ); } for ( NameForm nameForm : clone.nameFormRegistry ) { clone.globalOidRegistry.put( nameForm ); } for ( ObjectClass objectClass : clone.objectClassRegistry ) { clone.globalOidRegistry.put( objectClass ); } for ( LdapSyntax syntax : clone.ldapSyntaxRegistry ) { clone.globalOidRegistry.put( syntax ); } // Clone the schema list clone.loadedSchemas = new HashMap<>(); for ( Map.Entry> entry : schemaObjects.entrySet() ) { // We don't clone the schemas clone.loadedSchemas.put( entry.getKey(), loadedSchemas.get( entry.getKey() ) ); } // Clone the Using and usedBy structures // They will be empty clone.using = new HashMap<>(); clone.usedBy = new HashMap<>(); // Last, rebuild the using and usedBy references clone.buildReferences(); // Now, check the registries. We don't care about errors clone.checkRefInteg(); clone.schemaObjects = new HashMap<>(); // Last, not least, clone the SchemaObjects Map, and reference all the copied // SchemaObjects for ( Map.Entry> entry : schemaObjects.entrySet() ) { Set objects = new HashSet<>(); for ( SchemaObjectWrapper schemaObjectWrapper : entry.getValue() ) { SchemaObject original = schemaObjectWrapper.get(); try { if ( !( original instanceof LoadableSchemaObject ) ) { SchemaObject copy = clone.globalOidRegistry.getSchemaObject( original.getOid() ); SchemaObjectWrapper newWrapper = new SchemaObjectWrapper( copy ); objects.add( newWrapper ); } else { SchemaObjectWrapper newWrapper = new SchemaObjectWrapper( original ); objects.add( newWrapper ); } } catch ( LdapException ne ) { // Nothing to do } } clone.schemaObjects.put( entry.getKey(), objects ); } return clone; } /** * Tells if the Registries is permissive or if it must be checked * against inconsistencies. * * @return True if SchemaObjects can be added even if they break the consistency */ public boolean isRelaxed() { return isRelaxed; } /** * Tells if the Registries is strict. * * @return True if SchemaObjects cannot be added if they break the consistency */ public boolean isStrict() { return !isRelaxed; } /** * Change the Registries to a relaxed mode, where invalid SchemaObjects * can be registered. */ public void setRelaxed() { isRelaxed = RELAXED; globalOidRegistry.setRelaxed(); attributeTypeRegistry.setRelaxed(); comparatorRegistry.setRelaxed(); ditContentRuleRegistry.setRelaxed(); ditStructureRuleRegistry.setRelaxed(); ldapSyntaxRegistry.setRelaxed(); matchingRuleRegistry.setRelaxed(); matchingRuleUseRegistry.setRelaxed(); nameFormRegistry.setRelaxed(); normalizerRegistry.setRelaxed(); objectClassRegistry.setRelaxed(); syntaxCheckerRegistry.setRelaxed(); } /** * Change the Registries to a strict mode, where invalid SchemaObjects * cannot be registered. */ public void setStrict() { isRelaxed = STRICT; globalOidRegistry.setStrict(); attributeTypeRegistry.setStrict(); comparatorRegistry.setStrict(); ditContentRuleRegistry.setStrict(); ditStructureRuleRegistry.setStrict(); ldapSyntaxRegistry.setStrict(); matchingRuleRegistry.setStrict(); matchingRuleUseRegistry.setStrict(); nameFormRegistry.setStrict(); normalizerRegistry.setStrict(); objectClassRegistry.setStrict(); syntaxCheckerRegistry.setStrict(); } public SchemaErrorHandler getErrorHandler() { return errorHandler; } public void setErrorHandler( SchemaErrorHandler errorHandler ) { this.errorHandler = errorHandler; globalOidRegistry.setErrorHandler( errorHandler ); attributeTypeRegistry.setErrorHandler( errorHandler ); comparatorRegistry.setErrorHandler( errorHandler ); ditContentRuleRegistry.setErrorHandler( errorHandler ); ditStructureRuleRegistry.setErrorHandler( errorHandler ); ldapSyntaxRegistry.setErrorHandler( errorHandler ); matchingRuleRegistry.setErrorHandler( errorHandler ); matchingRuleUseRegistry.setErrorHandler( errorHandler ); nameFormRegistry.setErrorHandler( errorHandler ); normalizerRegistry.setErrorHandler( errorHandler ); objectClassRegistry.setErrorHandler( errorHandler ); syntaxCheckerRegistry.setErrorHandler( errorHandler ); } /** * Tells if the Registries accept disabled elements. * * @return True if disabled SchemaObjects can be added */ public boolean isDisabledAccepted() { return disabledAccepted; } /** * Check that we can remove a given SchemaObject without breaking some of its references. * We will return the list of refereing objects. * * @param schemaObject The SchemaObject to remove * @return The list of SchemaObjects referencing the SchemaObjetc we want to remove */ public Set getReferencing( SchemaObject schemaObject ) { SchemaObjectWrapper schemaObjectWrapper = new SchemaObjectWrapper( schemaObject ); return usedBy.get( schemaObjectWrapper ); } /** * Change the Registries behavior regarding disabled SchemaObject element. * * @param disabledAccepted If false, then the Registries won't accept * disabled SchemaObject or enabled SchemaObject from disabled schema */ public void setDisabledAccepted( boolean disabledAccepted ) { this.disabledAccepted = disabledAccepted; } /** * Clear the registries from all its elements * * @throws LdapException If something goes wrong */ public void clear() throws LdapException { // The AttributeTypeRegistry if ( attributeTypeRegistry != null ) { attributeTypeRegistry.clear(); } // The ComparatorRegistry if ( comparatorRegistry != null ) { comparatorRegistry.clear(); } // The DitContentRuleRegistry if ( ditContentRuleRegistry != null ) { ditContentRuleRegistry.clear(); } // The DitStructureRuleRegistry if ( ditStructureRuleRegistry != null ) { ditStructureRuleRegistry.clear(); } // The MatchingRuleRegistry if ( matchingRuleRegistry != null ) { matchingRuleRegistry.clear(); } // The MatchingRuleUseRegistry if ( matchingRuleUseRegistry != null ) { matchingRuleUseRegistry.clear(); } // The NameFormRegistry if ( nameFormRegistry != null ) { nameFormRegistry.clear(); } // The NormalizerRegistry if ( normalizerRegistry != null ) { normalizerRegistry.clear(); } // The ObjectClassRegistry if ( objectClassRegistry != null ) { objectClassRegistry.clear(); } // The SyntaxRegistry if ( ldapSyntaxRegistry != null ) { ldapSyntaxRegistry.clear(); } // The SyntaxCheckerRegistry if ( syntaxCheckerRegistry != null ) { syntaxCheckerRegistry.clear(); } // Clear the schemaObjects map for ( Map.Entry> entry : schemaObjects.entrySet() ) { entry.getValue().clear(); } schemaObjects.clear(); // Clear the usedBy map for ( Map.Entry> entry : usedBy.entrySet() ) { entry.getValue().clear(); } usedBy.clear(); // Clear the using map for ( Map.Entry> entry : using.entrySet() ) { entry.getValue().clear(); } using.clear(); // Clear the global OID registry globalOidRegistry.clear(); // Clear the loadedSchema Map loadedSchemas.clear(); } /** * @see Object#toString() */ @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append( "Registries [" ); if ( isRelaxed ) { sb.append( "RELAXED," ); } else { sb.append( "STRICT," ); } if ( disabledAccepted ) { sb.append( " Disabled accepted] :\n" ); } else { sb.append( " Disabled forbidden] :\n" ); } sb.append( "loaded schemas [" ); boolean isFirst = true; for ( String schema : loadedSchemas.keySet() ) { if ( isFirst ) { isFirst = false; } else { sb.append( ", " ); } sb.append( schema ); } sb.append( "]\n" ); sb.append( "AttributeTypes : " ).append( attributeTypeRegistry.size() ).append( "\n" ); sb.append( "Comparators : " ).append( comparatorRegistry.size() ).append( "\n" ); sb.append( "DitContentRules : " ).append( ditContentRuleRegistry.size() ).append( "\n" ); sb.append( "DitStructureRules : " ).append( ditStructureRuleRegistry.size() ).append( "\n" ); sb.append( "MatchingRules : " ).append( matchingRuleRegistry.size() ).append( "\n" ); sb.append( "MatchingRuleUses : " ).append( matchingRuleUseRegistry.size() ).append( "\n" ); sb.append( "NameForms : " ).append( nameFormRegistry.size() ).append( "\n" ); sb.append( "Normalizers : " ).append( normalizerRegistry.size() ).append( "\n" ); sb.append( "ObjectClasses : " ).append( objectClassRegistry.size() ).append( "\n" ); sb.append( "Syntaxes : " ).append( ldapSyntaxRegistry.size() ).append( "\n" ); sb.append( "SyntaxCheckers : " ).append( syntaxCheckerRegistry.size() ).append( "\n" ); sb.append( "GlobalOidRegistry : " ).append( globalOidRegistry.size() ).append( '\n' ); return sb.toString(); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy