blob: 02db858ecea0a9a866e863b9a1246cc3530cc0b9 [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.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.naming.NamingException;
import org.apache.directory.server.core.entry.ClonedServerEntry;
import org.apache.directory.server.core.entry.ServerEntry;
import org.apache.directory.server.core.filtering.EntryFilteringCursor;
import org.apache.directory.server.core.interceptor.context.EntryOperationContext;
import org.apache.directory.server.core.interceptor.context.ListOperationContext;
import org.apache.directory.server.core.interceptor.context.LookupOperationContext;
import org.apache.directory.server.core.partition.Partition;
import org.apache.directory.shared.ldap.constants.MetaSchemaConstants;
import org.apache.directory.shared.ldap.constants.SchemaConstants;
import org.apache.directory.shared.ldap.entry.Entry;
import org.apache.directory.shared.ldap.entry.EntryAttribute;
import org.apache.directory.shared.ldap.name.LdapDN;
import org.apache.directory.shared.ldap.schema.AttributeType;
import org.apache.directory.shared.ldap.schema.SchemaManager;
import org.apache.directory.shared.ldap.schema.parsers.LdapComparatorDescription;
import org.apache.directory.shared.ldap.schema.parsers.NormalizerDescription;
import org.apache.directory.shared.ldap.schema.parsers.SyntaxCheckerDescription;
import org.apache.directory.shared.ldap.schema.registries.AbstractSchemaLoader;
import org.apache.directory.shared.ldap.schema.registries.Registries;
import org.apache.directory.shared.ldap.schema.registries.Schema;
import org.apache.directory.shared.ldap.util.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* A class that loads schemas from a partition.
*
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
* @version $Rev$
*/
public class PartitionSchemaLoader extends AbstractSchemaLoader
{
/** static class logger */
private static final Logger LOG = LoggerFactory.getLogger( PartitionSchemaLoader.class );
private final SchemaPartitionDao dao;
private Partition partition;
/** The attributeType registry */
private SchemaManager schemaManager;
private final AttributeType mOidAT;
private final AttributeType mNameAT;
private final AttributeType cnAT;
private final AttributeType byteCodeAT;
private final AttributeType descAT;
private final AttributeType fqcnAT;
private static Map<String, LdapDN> staticAttributeTypeDNs = new HashMap<String, LdapDN>();
private static Map<String, LdapDN> staticMatchingRulesDNs = new HashMap<String, LdapDN>();
private static Map<String, LdapDN> staticObjectClassesDNs = new HashMap<String, LdapDN>();
private static Map<String, LdapDN> staticComparatorsDNs = new HashMap<String, LdapDN>();
private static Map<String, LdapDN> staticNormalizersDNs = new HashMap<String, LdapDN>();
private static Map<String, LdapDN> staticSyntaxCheckersDNs = new HashMap<String, LdapDN>();
private static Map<String, LdapDN> staticSyntaxesDNs = new HashMap<String, LdapDN>();
public PartitionSchemaLoader( Partition partition, SchemaManager schemaManager ) throws Exception
{
this.partition = partition;
this.schemaManager = schemaManager;
dao = new SchemaPartitionDaoImpl( this.partition, schemaManager );
mOidAT = schemaManager.lookupAttributeTypeRegistry( MetaSchemaConstants.M_OID_AT );
mNameAT = schemaManager.lookupAttributeTypeRegistry( MetaSchemaConstants.M_NAME_AT );
cnAT = schemaManager.lookupAttributeTypeRegistry( SchemaConstants.CN_AT );
byteCodeAT = schemaManager.lookupAttributeTypeRegistry( MetaSchemaConstants.M_BYTECODE_AT );
descAT = schemaManager.lookupAttributeTypeRegistry( MetaSchemaConstants.M_DESCRIPTION_AT );
fqcnAT = schemaManager.lookupAttributeTypeRegistry( MetaSchemaConstants.M_FQCN_AT );
initStaticDNs( "system" );
initStaticDNs( "core" );
initStaticDNs( "apache" );
initStaticDNs( "apachemeta" );
initStaticDNs( MetaSchemaConstants.SCHEMA_OTHER );
initStaticDNs( "collective" );
initStaticDNs( "java" );
initStaticDNs( "cosine" );
initStaticDNs( "inetorgperson" );
}
private void initStaticDNs( String schemaName ) throws Exception
{
// Initialize AttributeType Dns
LdapDN dn = new LdapDN( SchemaConstants.ATTRIBUTES_TYPE_PATH, "cn=" + schemaName, SchemaConstants.OU_SCHEMA );
dn.normalize( schemaManager.getNormalizerMapping() );
staticAttributeTypeDNs.put( schemaName, dn );
// Initialize ObjectClasses Dns
dn = new LdapDN( SchemaConstants.OBJECT_CLASSES_PATH, "cn=" + schemaName, SchemaConstants.OU_SCHEMA );
dn.normalize( schemaManager.getNormalizerMapping() );
staticObjectClassesDNs.put( schemaName, dn );
// Initialize MatchingRules Dns
dn = new LdapDN( SchemaConstants.MATCHING_RULES_PATH, "cn=" + schemaName, SchemaConstants.OU_SCHEMA );
dn.normalize( schemaManager.getNormalizerMapping() );
staticMatchingRulesDNs.put( schemaName, dn );
// Initialize Comparators Dns
dn = new LdapDN( SchemaConstants.COMPARATORS_PATH, "cn=" + schemaName, SchemaConstants.OU_SCHEMA );
dn.normalize( schemaManager.getNormalizerMapping() );
staticComparatorsDNs.put( schemaName, dn );
// Initialize Normalizers Dns
dn = new LdapDN( SchemaConstants.NORMALIZERS_PATH, "cn=" + schemaName, SchemaConstants.OU_SCHEMA );
dn.normalize( schemaManager.getNormalizerMapping() );
staticNormalizersDNs.put( schemaName, dn );
// Initialize SyntaxCheckers Dns
dn = new LdapDN( SchemaConstants.SYNTAX_CHECKERS_PATH, "cn=" + schemaName, SchemaConstants.OU_SCHEMA );
dn.normalize( schemaManager.getNormalizerMapping() );
staticSyntaxCheckersDNs.put( schemaName, dn );
// Initialize Syntaxes Dns
dn = new LdapDN( SchemaConstants.SYNTAXES_PATH, "cn=" + schemaName, SchemaConstants.OU_SCHEMA );
dn.normalize( schemaManager.getNormalizerMapping() );
staticSyntaxesDNs.put( schemaName, dn );
}
/**
* Helper class used to update the static DNs for each kind of Schema Object
*/
private LdapDN updateDNs( Map<String, LdapDN> staticDNs, String path, Schema schema ) throws NamingException
{
LdapDN dn = staticDNs.get( schema.getSchemaName() );
if ( dn == null )
{
dn = new LdapDN( path, "cn=" + schema.getSchemaName(), SchemaConstants.OU_SCHEMA );
dn.normalize( schemaManager.getNormalizerMapping() );
staticDNs.put( schema.getSchemaName(), dn );
}
return dn;
}
/**
* Lists the names of the schemas that depend on the schema name provided.
*
* @param schemaName the name of the schema to find dependents for
* @return a set of schemas (String names) that depend on the schema
* @throws NamingException if there are problems searching the schema partition
*/
public Set<String> listDependentSchemaNames( String schemaName ) throws Exception
{
Set<String> dependees = new HashSet<String>();
Set<ServerEntry> results = dao.listSchemaDependents( schemaName );
if ( results.isEmpty() )
{
return dependees;
}
for ( ServerEntry sr : results )
{
EntryAttribute cn = sr.get( cnAT );
dependees.add( cn.getString() );
}
return dependees;
}
/**
* Lists the names of the enabled schemas that depend on the schema name
* provided.
*
* @param schemaName the name of the schema to find dependents for
* @return a set of enabled schemas (String names) that depend on the schema
* @throws NamingException if there are problems searching the schema partition
*/
public Set<String> listEnabledDependentSchemaNames( String schemaName ) throws Exception
{
Set<String> dependees = new HashSet<String>();
Set<ServerEntry> results = dao.listEnabledSchemaDependents( schemaName );
if ( results.isEmpty() )
{
return dependees;
}
for ( ServerEntry sr : results )
{
EntryAttribute cn = sr.get( cnAT );
dependees.add( cn.getString() );
}
return dependees;
}
public Map<String, Schema> getSchemas() throws Exception
{
return dao.getSchemas();
}
public Set<String> getSchemaNames() throws Exception
{
return dao.getSchemaNames();
}
public Schema getSchema( String schemaName )
{
try
{
return dao.getSchema( schemaName );
}
catch ( Exception e )
{
// TODO fixme
return null;
}
}
/**
* {@inheritDoc}
*/
public final void load( Schema schema, Registries targetRegistries, boolean isDepLoad ) throws Exception
{
// if we're loading a dependency and it has not been enabled on
// disk then enable it on disk before we proceed to load it
if ( schema.isDisabled() && isDepLoad )
{
dao.enableSchema( schema.getSchemaName() );
}
if ( targetRegistries.isSchemaLoaded( schema.getSchemaName() ) )
{
LOG.debug( "schema {} already seems to be loaded", schema.getSchemaName() );
return;
}
LOG.debug( "loading {} schema ...", schema.getSchemaName() );
loadComparators( schema );
loadNormalizers( schema );
loadSyntaxCheckers( schema );
loadSyntaxes( schema );
loadMatchingRules( schema );
loadAttributeTypes( schema );
loadObjectClasses( schema );
loadMatchingRuleUses( schema );
loadDitContentRules( schema );
loadNameForms( schema );
// order does matter here so some special trickery is needed
// we cannot load a DSR before the DSRs it depends on are loaded?
// TODO need to confirm this ( or we must make the class for this and use deferred
// resolution until everything is available?
loadDitStructureRules( schema );
notifyListenerOrRegistries( schema, targetRegistries );
}
/**
* {@inheritDoc}
*/
public List<Entry> loadAttributeTypes( Schema... schemas ) throws Exception
{
List<Entry> attributeTypeList = new ArrayList<Entry>();
for ( Schema schema : schemas )
{
LdapDN dn = updateDNs( staticAttributeTypeDNs, SchemaConstants.ATTRIBUTES_TYPE_PATH, schema );
// Check that we don't have an entry in the Dit for this schema
if ( !partition.hasEntry( new EntryOperationContext( null, dn ) ) )
{
// No : get out, no AttributeType to load
return attributeTypeList;
}
LOG.debug( "{} schema: loading attributeTypes", schema.getSchemaName() );
EntryFilteringCursor list = partition.list( new ListOperationContext( null, dn ) );
// Loop on all the AttributeTypes and add them to the list
while ( list.next() )
{
ServerEntry result = list.get();
attributeTypeList.add( result );
}
}
return attributeTypeList;
}
/**
* {@inheritDoc}
*/
public List<Entry> loadComparators( Schema... schemas ) throws Exception
{
List<Entry> comparatorList = new ArrayList<Entry>();
if ( schemas == null )
{
return comparatorList;
}
for ( Schema schema : schemas )
{
LdapDN dn = updateDNs( staticComparatorsDNs, SchemaConstants.COMPARATORS_PATH, schema );
if ( !partition.hasEntry( new EntryOperationContext( null, dn ) ) )
{
return comparatorList;
}
LOG.debug( "{} schema: loading comparators", schema.getSchemaName() );
EntryFilteringCursor list = partition.list( new ListOperationContext( null, dn ) );
while ( list.next() )
{
ClonedServerEntry entry = list.get();
comparatorList.add( entry );
}
}
return comparatorList;
}
/**
* {@inheritDoc}
*/
public List<Entry> loadDitContentRules( Schema... schemas ) throws Exception
{
LOG.error( "DitContentRule loading NYI" );
return null;
}
/**
* {@inheritDoc}
*/
public List<Entry> loadDitStructureRules( Schema... schemas ) throws Exception
{
LOG.error( "DitStructureRule loading NYI" );
return null;
}
/**
* {@inheritDoc}
*/
public List<Entry> loadMatchingRules( Schema... schemas ) throws Exception
{
List<Entry> matchingRuleList = new ArrayList<Entry>();
if ( schemas == null )
{
return matchingRuleList;
}
for ( Schema schema : schemas )
{
LdapDN dn = updateDNs( staticMatchingRulesDNs, SchemaConstants.MATCHING_RULES_PATH, schema );
if ( !partition.hasEntry( new EntryOperationContext( null, dn ) ) )
{
return matchingRuleList;
}
LOG.debug( "{} schema: loading matchingRules", schema.getSchemaName() );
EntryFilteringCursor list = partition.list( new ListOperationContext( null, dn ) );
while ( list.next() )
{
ServerEntry entry = list.get();
matchingRuleList.add( entry );
}
}
return matchingRuleList;
}
/**
* {@inheritDoc}
*/
public List<Entry> loadMatchingRuleUses( Schema... schemas ) throws Exception
{
LOG.error( "MatchingRuleUse loading NYI" );
return null;
}
/**
* {@inheritDoc}
*/
public List<Entry> loadNameForms( Schema... schemas ) throws Exception
{
LOG.error( "NameForm loading NYI" );
return null;
}
/**
* {@inheritDoc}
*/
public List<Entry> loadNormalizers( Schema... schemas ) throws Exception
{
List<Entry> normalizerList = new ArrayList<Entry>();
if ( schemas == null )
{
return normalizerList;
}
for ( Schema schema : schemas )
{
LdapDN dn = updateDNs( staticNormalizersDNs, SchemaConstants.NORMALIZERS_PATH, schema );
if ( !partition.hasEntry( new EntryOperationContext( null, dn ) ) )
{
return normalizerList;
}
LOG.debug( "{} schema: loading normalizers", schema.getSchemaName() );
EntryFilteringCursor list = partition.list( new ListOperationContext( null, dn ) );
while ( list.next() )
{
ClonedServerEntry entry = list.get();
normalizerList.add( entry );
}
}
return normalizerList;
}
/**
* {@inheritDoc}
*/
public List<Entry> loadObjectClasses( Schema... schemas ) throws Exception
{
List<Entry> objectClassList = new ArrayList<Entry>();
if ( schemas == null )
{
return objectClassList;
}
for ( Schema schema : schemas )
{
LdapDN dn = updateDNs( staticObjectClassesDNs, SchemaConstants.OBJECT_CLASSES_PATH, schema );
if ( !partition.hasEntry( new EntryOperationContext( null, dn ) ) )
{
return objectClassList;
}
LOG.debug( "{} schema: loading objectClasses", schema.getSchemaName() );
EntryFilteringCursor list = partition.list( new ListOperationContext( null, dn ) );
while ( list.next() )
{
ClonedServerEntry entry = list.get();
objectClassList.add( entry );
}
}
return objectClassList;
}
/**
* {@inheritDoc}
*/
public List<Entry> loadSyntaxes( Schema... schemas ) throws Exception
{
List<Entry> syntaxList = new ArrayList<Entry>();
if ( schemas == null )
{
return syntaxList;
}
for ( Schema schema : schemas )
{
LdapDN dn = updateDNs( staticSyntaxesDNs, SchemaConstants.SYNTAXES_PATH, schema );
if ( !partition.hasEntry( new EntryOperationContext( null, dn ) ) )
{
return syntaxList;
}
LOG.debug( "{} schema: loading syntaxes", schema.getSchemaName() );
EntryFilteringCursor list = partition.list( new ListOperationContext( null, dn ) );
while ( list.next() )
{
ServerEntry entry = list.get();
syntaxList.add( entry );
}
}
return syntaxList;
}
/**
* {@inheritDoc}
*/
public List<Entry> loadSyntaxCheckers( Schema... schemas ) throws Exception
{
List<Entry> syntaxCheckerList = new ArrayList<Entry>();
if ( schemas == null )
{
return syntaxCheckerList;
}
for ( Schema schema : schemas )
{
LdapDN dn = updateDNs( staticSyntaxCheckersDNs, SchemaConstants.SYNTAX_CHECKERS_PATH, schema );
if ( !partition.hasEntry( new EntryOperationContext( null, dn ) ) )
{
return syntaxCheckerList;
}
LOG.debug( "{} schema: loading syntaxCsheckers", schema.getSchemaName() );
EntryFilteringCursor list = partition.list( new ListOperationContext( null, dn ) );
while ( list.next() )
{
ServerEntry entry = list.get();
syntaxCheckerList.add( entry );
}
}
return syntaxCheckerList;
}
private String getOid( ServerEntry entry ) throws Exception
{
EntryAttribute oid = entry.get( mOidAT );
if ( oid == null )
{
return null;
}
return oid.getString();
}
private NormalizerDescription getNormalizerDescription( String schemaName, ServerEntry entry ) throws Exception
{
NormalizerDescription description = new NormalizerDescription( getOid( entry ) );
List<String> values = new ArrayList<String>();
values.add( schemaName );
description.addExtension( MetaSchemaConstants.X_SCHEMA, values );
description.setFqcn( entry.get( fqcnAT ).getString() );
EntryAttribute desc = entry.get( descAT );
if ( desc != null && desc.size() > 0 )
{
description.setDescription( desc.getString() );
}
EntryAttribute bytecode = entry.get( byteCodeAT );
if ( bytecode != null && bytecode.size() > 0 )
{
byte[] bytes = bytecode.getBytes();
description.setBytecode( new String( Base64.encode( bytes ) ) );
}
return description;
}
private ClonedServerEntry lookupPartition( LdapDN dn ) throws Exception
{
return partition.lookup( new LookupOperationContext( null, dn ) );
}
private LdapComparatorDescription getLdapComparatorDescription( String schemaName, ServerEntry entry )
throws Exception
{
LdapComparatorDescription description = new LdapComparatorDescription( getOid( entry ) );
List<String> values = new ArrayList<String>();
values.add( schemaName );
description.addExtension( MetaSchemaConstants.X_SCHEMA, values );
description.setFqcn( entry.get( fqcnAT ).getString() );
EntryAttribute desc = entry.get( descAT );
if ( desc != null && desc.size() > 0 )
{
description.setDescription( desc.getString() );
}
EntryAttribute bytecode = entry.get( byteCodeAT );
if ( bytecode != null && bytecode.size() > 0 )
{
byte[] bytes = bytecode.getBytes();
description.setBytecode( new String( Base64.encode( bytes ) ) );
}
return description;
}
private SyntaxCheckerDescription getSyntaxCheckerDescription( String schemaName, ServerEntry entry )
throws Exception
{
SyntaxCheckerDescription description = new SyntaxCheckerDescription( getOid( entry ) );
List<String> values = new ArrayList<String>();
values.add( schemaName );
description.addExtension( MetaSchemaConstants.X_SCHEMA, values );
description.setFqcn( entry.get( fqcnAT ).getString() );
EntryAttribute desc = entry.get( descAT );
if ( desc != null && desc.size() > 0 )
{
description.setDescription( desc.getString() );
}
EntryAttribute bytecode = entry.get( byteCodeAT );
if ( bytecode != null && bytecode.size() > 0 )
{
byte[] bytes = bytecode.getBytes();
description.setBytecode( new String( Base64.encode( bytes ) ) );
}
return description;
}
/**
* @return the dao
*/
public SchemaPartitionDao getDao()
{
return dao;
}
}