Added: directory/apacheds/trunk/interceptors/operational/src/main/java/org/apache/directory/server/core/operational/OperationalAttributeInterceptor.java URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/interceptors/operational/src/main/java/org/apache/directory/server/core/operational/OperationalAttributeInterceptor.java?rev=1183537&view=auto ============================================================================== --- directory/apacheds/trunk/interceptors/operational/src/main/java/org/apache/directory/server/core/operational/OperationalAttributeInterceptor.java (added) +++ directory/apacheds/trunk/interceptors/operational/src/main/java/org/apache/directory/server/core/operational/OperationalAttributeInterceptor.java Fri Oct 14 22:36:08 2011 @@ -0,0 +1,594 @@ +/* + * 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.operational; + + +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; +import java.util.UUID; + +import org.apache.directory.server.constants.ApacheSchemaConstants; +import org.apache.directory.server.constants.ServerDNConstants; +import org.apache.directory.server.core.api.DirectoryService; +import org.apache.directory.server.core.api.entry.ClonedServerEntry; +import org.apache.directory.server.core.api.filtering.EntryFilter; +import org.apache.directory.server.core.api.filtering.EntryFilteringCursor; +import org.apache.directory.server.core.api.interceptor.BaseInterceptor; +import org.apache.directory.server.core.api.interceptor.Interceptor; +import org.apache.directory.server.core.api.interceptor.NextInterceptor; +import org.apache.directory.server.core.api.interceptor.context.AddOperationContext; +import org.apache.directory.server.core.api.interceptor.context.ListOperationContext; +import org.apache.directory.server.core.api.interceptor.context.LookupOperationContext; +import org.apache.directory.server.core.api.interceptor.context.ModifyOperationContext; +import org.apache.directory.server.core.api.interceptor.context.MoveAndRenameOperationContext; +import org.apache.directory.server.core.api.interceptor.context.MoveOperationContext; +import org.apache.directory.server.core.api.interceptor.context.RenameOperationContext; +import org.apache.directory.server.core.api.interceptor.context.SearchOperationContext; +import org.apache.directory.server.core.api.interceptor.context.SearchingOperationContext; +import org.apache.directory.server.i18n.I18n; +import org.apache.directory.shared.ldap.model.constants.SchemaConstants; +import org.apache.directory.shared.ldap.model.entry.Attribute; +import org.apache.directory.shared.ldap.model.entry.DefaultAttribute; +import org.apache.directory.shared.ldap.model.entry.DefaultModification; +import org.apache.directory.shared.ldap.model.entry.Entry; +import org.apache.directory.shared.ldap.model.entry.Modification; +import org.apache.directory.shared.ldap.model.entry.ModificationOperation; +import org.apache.directory.shared.ldap.model.entry.Value; +import org.apache.directory.shared.ldap.model.exception.LdapException; +import org.apache.directory.shared.ldap.model.exception.LdapNoPermissionException; +import org.apache.directory.shared.ldap.model.exception.LdapSchemaViolationException; +import org.apache.directory.shared.ldap.model.message.ResultCodeEnum; +import org.apache.directory.shared.ldap.model.name.Ava; +import org.apache.directory.shared.ldap.model.name.Dn; +import org.apache.directory.shared.ldap.model.name.Rdn; +import org.apache.directory.shared.ldap.model.schema.AttributeType; +import org.apache.directory.shared.ldap.model.schema.UsageEnum; +import org.apache.directory.shared.util.DateUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +/** + * An {@link Interceptor} that adds or modifies the default attributes + * of entries. There are six default attributes for now; + * 'creatorsName', 'createTimestamp', 'modifiersName', + * 'modifyTimestamp', entryUUID and entryCSN. + * + * @author Apache Directory Project + */ +public class OperationalAttributeInterceptor extends BaseInterceptor +{ + /** The LoggerFactory used by this Interceptor */ + private static Logger LOG = LoggerFactory.getLogger( OperationalAttributeInterceptor.class ); + + /** + * the search result filter to use for collective attribute injection + */ + private class OperationalAttributeDenormalizingSearchFilter implements EntryFilter + { + public boolean accept( SearchingOperationContext operation, Entry entry ) throws Exception + { + if ( operation.getSearchControls().getReturningAttributes() == null ) + { + return true; + } + + return filterDenormalized( entry ); + } + } + + private final EntryFilter DENORMALIZING_SEARCH_FILTER = new OperationalAttributeDenormalizingSearchFilter(); + + /** + * the database search result filter to register with filter service + */ + private class OperationalAttributeSearchFilter implements EntryFilter + { + public boolean accept( SearchingOperationContext operation, Entry entry ) throws Exception + { + return operation.getSearchControls().getReturningAttributes() != null + || filterOperationalAttributes( entry ); + } + } + + private final EntryFilter SEARCH_FILTER = new OperationalAttributeSearchFilter(); + + /** The subschemasubentry Dn */ + private Dn subschemaSubentryDn; + + /** The admin Dn */ + private Dn adminDn; + + /** + * Creates the operational attribute management service interceptor. + */ + public OperationalAttributeInterceptor() + { + } + + + public void init( DirectoryService directoryService ) throws LdapException + { + super.init( directoryService ); + + // stuff for dealing with subentries (garbage for now) + Value subschemaSubentry = directoryService.getPartitionNexus().getRootDSE( null ).get( + SchemaConstants.SUBSCHEMA_SUBENTRY_AT ).get(); + subschemaSubentryDn = directoryService.getDnFactory().create( subschemaSubentry.getString() ); + + // Create the Admin Dn + adminDn = directoryService.getDnFactory().create( ServerDNConstants.ADMIN_SYSTEM_DN ); + } + + + public void destroy() + { + } + + + /** + * Check if we have to add an operational attribute, or if the admin has injected one + */ + private boolean checkAddOperationalAttribute( boolean isAdmin, Entry entry, String attribute ) throws LdapException + { + if ( entry.containsAttribute( attribute ) ) + { + if ( !isAdmin ) + { + // Wrong ! + String message = I18n.err( I18n.ERR_30, attribute ); + LOG.error( message ); + throw new LdapNoPermissionException( message ); + } + else + { + return true; + } + } + else + { + return false; + } + } + + + /** + * Adds extra operational attributes to the entry before it is added. + * + * We add those attributes : + * - creatorsName + * - createTimestamp + * - entryCSN + * - entryUUID + */ + public void add( NextInterceptor nextInterceptor, AddOperationContext addContext ) throws LdapException + { + String principal = getPrincipal().getName(); + + Entry entry = addContext.getEntry(); + + // If we are using replication, the below four OAs may already be present and we retain + // those values if the user is admin. + boolean isAdmin = addContext.getSession().getAuthenticatedPrincipal().getName().equals( + ServerDNConstants.ADMIN_SYSTEM_DN_NORMALIZED ); + + // The EntryUUID attribute + if ( !checkAddOperationalAttribute( isAdmin, entry, SchemaConstants.ENTRY_UUID_AT ) ) + { + entry.put( SchemaConstants.ENTRY_UUID_AT, UUID.randomUUID().toString() ); + } + + // The EntryCSN attribute + if ( !checkAddOperationalAttribute( isAdmin, entry, SchemaConstants.ENTRY_CSN_AT ) ) + { + entry.put( SchemaConstants.ENTRY_CSN_AT, directoryService.getCSN().toString() ); + } + + // The CreatorsName attribute + if ( !checkAddOperationalAttribute( isAdmin, entry, SchemaConstants.CREATORS_NAME_AT ) ) + { + entry.put( SchemaConstants.CREATORS_NAME_AT, principal ); + } + + // The CreateTimeStamp attribute + if ( !checkAddOperationalAttribute( isAdmin, entry, SchemaConstants.CREATE_TIMESTAMP_AT ) ) + { + entry.put( SchemaConstants.CREATE_TIMESTAMP_AT, DateUtils.getGeneralizedTime() ); + } + + // Now, check that the user does not add operational attributes + // The accessControlSubentries attribute + checkAddOperationalAttribute( isAdmin, entry, SchemaConstants.ACCESS_CONTROL_SUBENTRIES_AT ); + + // The CollectiveAttributeSubentries attribute + checkAddOperationalAttribute( isAdmin, entry, SchemaConstants.COLLECTIVE_ATTRIBUTE_SUBENTRIES_AT ); + + // The TriggerExecutionSubentries attribute + checkAddOperationalAttribute( isAdmin, entry, SchemaConstants.TRIGGER_EXECUTION_SUBENTRIES_AT ); + + // The SubSchemaSybentry attribute + checkAddOperationalAttribute( isAdmin, entry, SchemaConstants.SUBSCHEMA_SUBENTRY_AT ); + + nextInterceptor.add( addContext ); + } + + + /** + * {@inheritDoc} + */ + public void modify( NextInterceptor nextInterceptor, ModifyOperationContext modifyContext ) throws LdapException + { + // We must check that the user hasn't injected either the modifiersName + // or the modifyTimestamp operational attributes : they are not supposed to be + // added at this point EXCEPT in cases of replication by a admin user. + // If so, remove them, and if there are no more attributes, simply return. + // otherwise, inject those values into the list of modifications + List mods = modifyContext.getModItems(); + + boolean isAdmin = modifyContext.getSession().getAuthenticatedPrincipal().getDn().equals( adminDn ); + + boolean modifierAtPresent = false; + boolean modifiedTimeAtPresent = false; + boolean entryCsnAtPresent = false; + + for ( Modification modification : mods ) + { + AttributeType attributeType = modification.getAttribute().getAttributeType(); + + if ( attributeType.equals( MODIFIERS_NAME_AT ) ) + { + if ( !isAdmin ) + { + String message = I18n.err( I18n.ERR_31 ); + LOG.error( message ); + throw new LdapSchemaViolationException( ResultCodeEnum.INSUFFICIENT_ACCESS_RIGHTS, message ); + } + else + { + modifierAtPresent = true; + } + } + + if ( attributeType.equals( MODIFY_TIMESTAMP_AT ) ) + { + if ( !isAdmin ) + { + String message = I18n.err( I18n.ERR_32 ); + LOG.error( message ); + throw new LdapSchemaViolationException( ResultCodeEnum.INSUFFICIENT_ACCESS_RIGHTS, message ); + } + else + { + modifiedTimeAtPresent = true; + } + } + + if ( attributeType.equals( ENTRY_CSN_AT ) ) + { + if ( !isAdmin ) + { + String message = I18n.err( I18n.ERR_32 ); + LOG.error( message ); + throw new LdapSchemaViolationException( ResultCodeEnum.INSUFFICIENT_ACCESS_RIGHTS, message ); + } + else + { + entryCsnAtPresent = true; + } + } + + if ( PWD_POLICY_STATE_ATTRIBUTE_TYPES.contains( attributeType ) && !isAdmin ) + { + String message = I18n.err( I18n.ERR_32 ); + LOG.error( message ); + throw new LdapSchemaViolationException( ResultCodeEnum.INSUFFICIENT_ACCESS_RIGHTS, message ); + } + } + + if ( !modifierAtPresent ) + { + // Inject the ModifiersName AT if it's not present + Attribute attribute = new DefaultAttribute( MODIFIERS_NAME_AT, getPrincipal() + .getName() ); + + Modification modifiersName = new DefaultModification( ModificationOperation.REPLACE_ATTRIBUTE, attribute ); + + mods.add( modifiersName ); + } + + if ( !modifiedTimeAtPresent ) + { + // Inject the ModifyTimestamp AT if it's not present + Attribute attribute = new DefaultAttribute( MODIFY_TIMESTAMP_AT, DateUtils + .getGeneralizedTime() ); + + Modification timestamp = new DefaultModification( ModificationOperation.REPLACE_ATTRIBUTE, attribute ); + + mods.add( timestamp ); + } + + if ( !entryCsnAtPresent ) + { + String csn = directoryService.getCSN().toString(); + Attribute attribute = new DefaultAttribute( ENTRY_CSN_AT, csn ); + Modification updatedCsn = new DefaultModification( ModificationOperation.REPLACE_ATTRIBUTE, attribute ); + mods.add( updatedCsn ); + } + + // Go down in the chain + nextInterceptor.modify( modifyContext ); + } + + + public void rename( NextInterceptor nextInterceptor, RenameOperationContext renameContext ) throws LdapException + { + Entry entry = ( ( ClonedServerEntry ) renameContext.getEntry() ).getClonedEntry(); + entry.put( SchemaConstants.MODIFIERS_NAME_AT, getPrincipal().getName() ); + entry.put( SchemaConstants.MODIFY_TIMESTAMP_AT, DateUtils.getGeneralizedTime() ); + + Entry modifiedEntry = renameContext.getOriginalEntry().clone(); + modifiedEntry.put( SchemaConstants.MODIFIERS_NAME_AT, getPrincipal().getName() ); + modifiedEntry.put( SchemaConstants.MODIFY_TIMESTAMP_AT, DateUtils.getGeneralizedTime() ); + //modifiedEntry.setDn( renameContext.getNewDn() ); + renameContext.setModifiedEntry( modifiedEntry ); + + nextInterceptor.rename( renameContext ); + } + + + /** + * {@inheritDoc} + */ + public void move( NextInterceptor nextInterceptor, MoveOperationContext moveContext ) throws LdapException + { + Entry modifiedEntry = moveContext.getOriginalEntry().clone(); + modifiedEntry.put( SchemaConstants.MODIFIERS_NAME_AT, getPrincipal().getName() ); + modifiedEntry.put( SchemaConstants.MODIFY_TIMESTAMP_AT, DateUtils.getGeneralizedTime() ); + modifiedEntry.setDn( moveContext.getNewDn() ); + moveContext.setModifiedEntry( modifiedEntry ); + + nextInterceptor.move( moveContext ); + } + + + public void moveAndRename( NextInterceptor nextInterceptor, MoveAndRenameOperationContext moveAndRenameContext ) + throws LdapException + { + Entry modifiedEntry = moveAndRenameContext.getOriginalEntry().clone(); + modifiedEntry.put( SchemaConstants.MODIFIERS_NAME_AT, getPrincipal().getName() ); + modifiedEntry.put( SchemaConstants.MODIFY_TIMESTAMP_AT, DateUtils.getGeneralizedTime() ); + modifiedEntry.setDn( moveAndRenameContext.getNewDn() ); + moveAndRenameContext.setModifiedEntry( modifiedEntry ); + + nextInterceptor.moveAndRename( moveAndRenameContext ); + } + + + public Entry lookup( NextInterceptor nextInterceptor, LookupOperationContext lookupContext ) throws LdapException + { + Entry result = nextInterceptor.lookup( lookupContext ); + + if ( lookupContext.getAttrsId() == null ) + { + filterOperationalAttributes( result ); + } + else if ( !lookupContext.hasAllOperational() ) + { + filter( lookupContext, result ); + } + + denormalizeEntryOpAttrs( result ); + return result; + } + + + public EntryFilteringCursor list( NextInterceptor nextInterceptor, ListOperationContext listContext ) + throws LdapException + { + EntryFilteringCursor cursor = nextInterceptor.list( listContext ); + cursor.addEntryFilter( SEARCH_FILTER ); + return cursor; + } + + + public EntryFilteringCursor search( NextInterceptor nextInterceptor, SearchOperationContext searchContext ) + throws LdapException + { + EntryFilteringCursor cursor = nextInterceptor.search( searchContext ); + + if ( searchContext.isAllOperationalAttributes() + || ( searchContext.getReturningAttributes() != null && !searchContext.getReturningAttributes().isEmpty() ) ) + { + if ( directoryService.isDenormalizeOpAttrsEnabled() ) + { + cursor.addEntryFilter( DENORMALIZING_SEARCH_FILTER ); + } + + return cursor; + } + + cursor.addEntryFilter( SEARCH_FILTER ); + return cursor; + } + + + /** + * Filters out the operational attributes within a search results attributes. The attributes are directly + * modified. + * + * @param attributes the resultant attributes to filter + * @return true always + * @throws Exception if there are failures in evaluation + */ + private boolean filterOperationalAttributes( Entry attributes ) throws LdapException + { + Set removedAttributes = new HashSet(); + + // Build a list of attributeType to remove + for ( Attribute attribute : attributes.getAttributes() ) + { + AttributeType attributeType = attribute.getAttributeType(); + + if ( attributeType.getUsage() != UsageEnum.USER_APPLICATIONS ) + { + removedAttributes.add( attributeType ); + } + } + + // Now remove the attributes which are not USERs + for ( AttributeType attributeType : removedAttributes ) + { + attributes.removeAttributes( attributeType ); + } + + return true; + } + + + private void filter( LookupOperationContext lookupContext, Entry entry ) throws LdapException + { + Dn dn = lookupContext.getDn(); + List ids = lookupContext.getAttrsId(); + + // still need to protect against returning op attrs when ids is null + if ( ids == null || ids.isEmpty() ) + { + filterOperationalAttributes( entry ); + return; + } + + if ( dn.size() == 0 ) + { + for ( Attribute attribute : entry.getAttributes() ) + { + AttributeType attributeType = attribute.getAttributeType(); + + if ( !ids.contains( attributeType.getOid() ) ) + { + entry.removeAttributes( attributeType ); + } + } + } + + denormalizeEntryOpAttrs( entry ); + + // do nothing past here since this explicity specifies which + // attributes to include - backends will automatically populate + // with right set of attributes using ids array + } + + + public void denormalizeEntryOpAttrs( Entry entry ) throws LdapException + { + if ( directoryService.isDenormalizeOpAttrsEnabled() ) + { + Attribute attr = entry.get( SchemaConstants.CREATORS_NAME_AT ); + + if ( attr != null ) + { + Dn creatorsName = directoryService.getDnFactory().create( attr.getString() ); + + attr.clear(); + attr.add( denormalizeTypes( creatorsName ).getName() ); + } + + attr = entry.get( SchemaConstants.MODIFIERS_NAME_AT ); + + if ( attr != null ) + { + Dn modifiersName = directoryService.getDnFactory().create( attr.getString() ); + + attr.clear(); + attr.add( denormalizeTypes( modifiersName ).getName() ); + } + + attr = entry.get( ApacheSchemaConstants.SCHEMA_MODIFIERS_NAME_AT ); + + if ( attr != null ) + { + Dn modifiersName = directoryService.getDnFactory().create( attr.getString() ); + + attr.clear(); + attr.add( denormalizeTypes( modifiersName ).getName() ); + } + } + } + + + /** + * Does not create a new Dn but alters existing Dn by using the first + * short name for an attributeType definition. + * + * @param dn the normalized distinguished name + * @return the distinuished name denormalized + * @throws Exception if there are problems denormalizing + */ + private Dn denormalizeTypes( Dn dn ) throws LdapException + { + Dn newDn = new Dn( schemaManager ); + int size = dn.size(); + + for ( int pos = 0; pos < size; pos++ ) + { + Rdn rdn = dn.getRdn( size - 1 - pos ); + + if ( rdn.size() == 0 ) + { + newDn = newDn.add( new Rdn() ); + continue; + } + else if ( rdn.size() == 1 ) + { + String name = schemaManager.lookupAttributeTypeRegistry( rdn.getNormType() ).getName(); + String value = rdn.getNormValue().getString(); + newDn = newDn.add( new Rdn( name, value ) ); + continue; + } + + // below we only process multi-valued rdns + StringBuffer buf = new StringBuffer(); + + for ( Iterator atavs = rdn.iterator(); atavs.hasNext(); /**/) + { + Ava atav = atavs.next(); + String type = schemaManager.lookupAttributeTypeRegistry( rdn.getNormType() ).getName(); + buf.append( type ).append( '=' ).append( atav.getNormValue() ); + + if ( atavs.hasNext() ) + { + buf.append( '+' ); + } + } + + newDn = newDn.add( new Rdn( buf.toString() ) ); + } + + return newDn; + } + + + private boolean filterDenormalized( Entry entry ) throws Exception + { + denormalizeEntryOpAttrs( entry ); + return true; + } +} \ No newline at end of file Propchange: directory/apacheds/trunk/interceptors/referral/ ------------------------------------------------------------------------------ --- svn:ignore (added) +++ svn:ignore Fri Oct 14 22:36:08 2011 @@ -0,0 +1,10 @@ +.project +.classpath +.settings +eclipse-classes +*.log +*.iml +*.ipr +dependency-reduced-pom.xml +META-INF + Added: directory/apacheds/trunk/interceptors/referral/pom.xml URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/interceptors/referral/pom.xml?rev=1183537&view=auto ============================================================================== --- directory/apacheds/trunk/interceptors/referral/pom.xml (added) +++ directory/apacheds/trunk/interceptors/referral/pom.xml Fri Oct 14 22:36:08 2011 @@ -0,0 +1,183 @@ + + + + + + 4.0.0 + + org.apache.directory.server + apacheds-interceptors + 2.0.0-M4-SNAPSHOT + + + apacheds-interceptors-referral + ApacheDS Referral Interceptor + jar + + + Referral interceptor + + + + + org.apache.directory.junit + junit-addons + test + + + + ${project.groupId} + apacheds-i18n + + + + ${project.groupId} + apacheds-core-api + + + + ${project.groupId} + apacheds-core-api + tests + test + + + + ${project.groupId} + apacheds-core-shared + + + + commons-collections + commons-collections + + + + commons-lang + commons-lang + + + + org.apache.directory.shared + shared-ldap-client-api + + + + org.apache.directory.shared + shared-i18n + + + + org.apache.directory.shared + shared-ldap-codec-standalone + provided + + + + org.apache.directory.shared + shared-ldap-codec-core + + + + org.apache.directory.shared + shared-ldap-extras-aci + + + + org.apache.directory.shared + shared-ldap-extras-trigger + + + + org.apache.directory.shared + shared-ldap-extras-util + + + + org.apache.directory.shared + shared-ldap-model + + + + org.apache.directory.shared + shared-ldap-schema-data + + + + org.apache.directory.shared + shared-util + + + + bouncycastle + bcprov-jdk15 + + + + net.sf.ehcache + ehcache-core + + + + org.apache.directory.shared + shared-ldap-extras-codec + provided + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + ${basedir}/target/server-work + + + + + + org.apache.maven.plugins + maven-source-plugin + + + attach-sources + verify + + jar + + + + + + + + + src/main/resources + true + + **/*.gif + + + + + + Added: directory/apacheds/trunk/interceptors/referral/src/main/java/org/apache/directory/server/core/referral/ReferralInterceptor.java URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/interceptors/referral/src/main/java/org/apache/directory/server/core/referral/ReferralInterceptor.java?rev=1183537&view=auto ============================================================================== --- directory/apacheds/trunk/interceptors/referral/src/main/java/org/apache/directory/server/core/referral/ReferralInterceptor.java (added) +++ directory/apacheds/trunk/interceptors/referral/src/main/java/org/apache/directory/server/core/referral/ReferralInterceptor.java Fri Oct 14 22:36:08 2011 @@ -0,0 +1,408 @@ +/* + * 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.referral; + + +import javax.naming.Context; + +import org.apache.directory.server.core.shared.ReferralManagerImpl; +import org.apache.directory.server.core.api.DirectoryService; +import org.apache.directory.server.core.api.ReferralManager; +import org.apache.directory.server.core.api.entry.ClonedServerEntry; +import org.apache.directory.server.core.api.interceptor.BaseInterceptor; +import org.apache.directory.server.core.api.interceptor.NextInterceptor; +import org.apache.directory.server.core.api.interceptor.context.AddOperationContext; +import org.apache.directory.server.core.api.interceptor.context.DeleteOperationContext; +import org.apache.directory.server.core.api.interceptor.context.LookupOperationContext; +import org.apache.directory.server.core.api.interceptor.context.ModifyOperationContext; +import org.apache.directory.server.core.api.interceptor.context.MoveAndRenameOperationContext; +import org.apache.directory.server.core.api.interceptor.context.MoveOperationContext; +import org.apache.directory.server.core.api.interceptor.context.RenameOperationContext; +import org.apache.directory.server.core.api.partition.PartitionNexus; +import org.apache.directory.server.i18n.I18n; +import org.apache.directory.shared.ldap.model.constants.SchemaConstants; +import org.apache.directory.shared.ldap.model.entry.Attribute; +import org.apache.directory.shared.ldap.model.entry.Entry; +import org.apache.directory.shared.ldap.model.entry.StringValue; +import org.apache.directory.shared.ldap.model.entry.Value; +import org.apache.directory.shared.ldap.model.exception.LdapException; +import org.apache.directory.shared.ldap.model.exception.LdapURLEncodingException; +import org.apache.directory.shared.ldap.model.message.SearchScope; +import org.apache.directory.shared.ldap.model.name.Dn; +import org.apache.directory.shared.ldap.model.url.LdapUrl; +import org.apache.directory.shared.util.Strings; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +/** + * An service which is responsible referral handling behavoirs. It manages + * referral handling behavoir when the {@link Context#REFERRAL} is implicitly + * or explicitly set to "ignore", when set to "throw" and when set to "follow". + * + * @author Apache Directory Project + */ +public class ReferralInterceptor extends BaseInterceptor +{ + private static final Logger LOG = LoggerFactory.getLogger( ReferralInterceptor.class ); + + private PartitionNexus nexus; + + /** The referralManager */ + private ReferralManager referralManager; + + /** A normalized form for the SubschemaSubentry Dn */ + private Dn subschemaSubentryDn; + + static private void checkRefAttributeValue( Value value ) throws LdapException, LdapURLEncodingException + { + StringValue ref = (StringValue) value; + + String refVal = ref.getString(); + + LdapUrl ldapUrl = new LdapUrl( refVal ); + + // We have a LDAP URL, we have to check that : + // - we don't have scope specifier + // - we don't have filters + // - we don't have attribute description list + // - we don't have extensions + // - the Dn is not empty + + if ( ldapUrl.getScope() != SearchScope.OBJECT ) + { + // This is the default value if we don't have any scope + // Let's assume that it's incorrect if we get something + // else in the LdapURL + String message = I18n.err( I18n.ERR_36 ); + LOG.error( message ); + throw new LdapException( message ); + } + + if ( !Strings.isEmpty(ldapUrl.getFilter()) ) + { + String message = I18n.err( I18n.ERR_37 ); + LOG.error( message ); + throw new LdapException( message ); + } + + if ( ( ldapUrl.getAttributes() != null ) && ( ldapUrl.getAttributes().size() != 0 ) ) + { + String message = I18n.err( I18n.ERR_38 ); + LOG.error( message ); + throw new LdapException( message ); + } + + if ( ( ldapUrl.getExtensions() != null ) && ( ldapUrl.getExtensions().size() != 0 ) ) + { + String message = I18n.err( I18n.ERR_39 ); + LOG.error( message ); + throw new LdapException( message ); + } + + if ( ( ldapUrl.getExtensions() != null ) && ( ldapUrl.getExtensions().size() != 0 ) ) + { + String message = I18n.err( I18n.ERR_40 ); + LOG.error( message ); + throw new LdapException( message ); + } + + Dn dn = ldapUrl.getDn(); + + if ( ( dn == null ) || dn.isEmpty() ) + { + String message = I18n.err( I18n.ERR_41 ); + LOG.error( message ); + throw new LdapException( message ); + } + } + + + // This will suppress PMD.EmptyCatchBlock warnings in this method + @SuppressWarnings("PMD.EmptyCatchBlock") + static private boolean isReferral( Entry entry ) throws LdapException + { + // Check that the entry is not null, otherwise return FALSE. + // This is typically to cover the case where the entry has not + // been added into the context because it does not exists. + if ( entry == null ) + { + return false; + } + + Attribute oc = entry.get( OBJECT_CLASS_AT ); + + if ( oc == null ) + { + LOG.warn( "could not find objectClass attribute in entry: " + entry ); + return false; + } + + if ( !oc.contains( SchemaConstants.REFERRAL_OC ) ) + { + return false; + } + else + { + // We have a referral ObjectClass, let's check that the ref is + // valid, accordingly to the RFC + + // Get the 'ref' attributeType + Attribute refAttr = entry.get( SchemaConstants.REF_AT ); + + if ( refAttr == null ) + { + // very unlikely, as we have already checked the entry in SchemaInterceptor + String message = I18n.err( I18n.ERR_42 ); + LOG.error( message ); + throw new LdapException( message ); + } + + for ( Value value : refAttr ) + { + try + { + checkRefAttributeValue( value ); + } + catch ( LdapURLEncodingException luee ) + { + // Either the URL is invalid, or it's not a LDAP URL. + // we will just ignore this LdapURL. + } + } + + return true; + } + } + + + public void init( DirectoryService directoryService ) throws LdapException + { + super.init( directoryService ); + + nexus = directoryService.getPartitionNexus(); + + // Initialize the referralManager + referralManager = new ReferralManagerImpl( directoryService ); + directoryService.setReferralManager( referralManager ); + + Value subschemaSubentry = nexus.getRootDSE( null ).get( SchemaConstants.SUBSCHEMA_SUBENTRY_AT ).get(); + subschemaSubentryDn = directoryService.getDnFactory().create( subschemaSubentry.getString() ); + } + + + /** + * Add an entry into the server. We have 3 cases : + * (1) The entry does not have any parent referral and is not a referral itself + * (2) The entry does not have any parent referral and is a referral itself + * (3) The entry has a parent referral + * + * Case (1) is easy : we inject the entry into the server and we are done. + * Case (2) is the same as case (1), but we have to update the referral manager. + * Case (3) is handled by the LdapProcotol handler, as we have to return a + * LdapResult containing a list of this entry's parent's referrals URL, if the + * ManageDSAIT control is not present, or the parent's entry if the control + * is present. + * + * Of course, if the entry already exists, nothing will be done, as we will get an + * entryAlreadyExists error. + * + */ + public void add( NextInterceptor next, AddOperationContext addContext ) throws LdapException + { + Entry entry = addContext.getEntry(); + + // Check if the entry is a referral itself + boolean isReferral = isReferral( entry ); + + // We add the entry into the server + next.add( addContext ); + + // If the addition is successful, we update the referralManager + if ( isReferral ) + { + // We have to add it to the referralManager + referralManager.lockWrite(); + + referralManager.addReferral( entry ); + + referralManager.unlock(); + } + } + + + /** + * Delete an entry in the server. We have 4 cases : + * (1) the entry is not a referral and does not have a parent referral + * (2) the entry is not a referral but has a parent referral + * (3) the entry is a referral + * + * Case (1) is handled by removing the entry from the server + * In case (2), we return an exception build using the parent referral + * For case(3), we remove the entry from the server and remove the referral + * from the referral manager. + * + * If the entry does not exist in the server, we will get a NoSuchObject error + */ + public void delete( NextInterceptor next, DeleteOperationContext deleteContext ) throws LdapException + { + // First delete the entry into the server + next.delete( deleteContext ); + + Entry entry = deleteContext.getEntry(); + + // Check if the entry exists and is a referral itself + // If so, we have to update the referralManager + if ( ( entry != null ) && isReferral( entry ) ) + { + // We have to remove it from the referralManager + referralManager.lockWrite(); + + referralManager.removeReferral( entry ); + + referralManager.unlock(); + } + } + + + /** + * {@inheritDoc} + **/ + public void move( NextInterceptor next, MoveOperationContext moveContext ) throws LdapException + { + Dn newDn = moveContext.getNewDn(); + + // Check if the entry is a referral itself + boolean isReferral = isReferral( moveContext.getOriginalEntry() ); + + next.move( moveContext ); + + if ( isReferral ) + { + // Update the referralManager + referralManager.lockWrite(); + + referralManager.addReferral( moveContext.getModifiedEntry() ); + referralManager.removeReferral( moveContext.getOriginalEntry() ); + + referralManager.unlock(); + } + } + + + /** + * {@inheritDoc} + **/ + public void moveAndRename( NextInterceptor next, MoveAndRenameOperationContext moveAndRenameContext ) throws LdapException + { + // Check if the entry is a referral itself + boolean isReferral = isReferral( moveAndRenameContext.getOriginalEntry() ); + + next.moveAndRename( moveAndRenameContext ); + + if ( isReferral ) + { + // Update the referralManager + Entry newEntry = moveAndRenameContext.getModifiedEntry(); + + referralManager.lockWrite(); + + referralManager.addReferral( newEntry ); + referralManager.removeReferral( moveAndRenameContext.getOriginalEntry() ); + + referralManager.unlock(); + } + } + + + /** + * {@inheritDoc} + **/ + public void rename( NextInterceptor next, RenameOperationContext renameContext ) throws LdapException + { + // Check if the entry is a referral itself + boolean isReferral = isReferral( renameContext.getOriginalEntry() ); + + next.rename( renameContext ); + + if ( isReferral ) + { + // Update the referralManager + LookupOperationContext lookupContext = new LookupOperationContext( renameContext.getSession(), renameContext + .getNewDn() ); + lookupContext.setAttrsId( SchemaConstants.ALL_ATTRIBUTES_ARRAY ); + + Entry newEntry = nexus.lookup( lookupContext ); + + referralManager.lockWrite(); + + referralManager.addReferral( newEntry ); + referralManager.removeReferral( ((ClonedServerEntry)renameContext.getEntry()).getOriginalEntry() ); + + referralManager.unlock(); + } + } + + + /** + * Modify an entry in the server. + */ + public void modify( NextInterceptor next, ModifyOperationContext modifyContext ) throws LdapException + { + Dn dn = modifyContext.getDn(); + + // handle a normal modify without following referrals + next.modify( modifyContext ); + + // Check if we are trying to modify the schema or the rootDSE, + // if so, we don't modify the referralManager + if ( dn.isEmpty() || dn.equals( subschemaSubentryDn ) ) + { + // Do nothing + return; + } + + // Update the referralManager. We have to read the entry again + // as it has been modified, before updating the ReferralManager + // TODO: this can be spare, as we already have the altered entry + // into the opContext, but for an unknow reason, this will fail + // on eferral tests... + LookupOperationContext lookupContext = new LookupOperationContext( modifyContext.getSession(), dn ); + lookupContext.setAttrsId( SchemaConstants.ALL_ATTRIBUTES_ARRAY ); + + Entry newEntry = nexus.lookup( lookupContext ); + + // Update the referralManager. + // Check that we have the entry, just in case + // TODO : entries should be locked until the operation is done on it. + if ( newEntry != null ) + { + referralManager.lockWrite(); + + if ( referralManager.isReferral( newEntry.getDn() ) ) + { + referralManager.removeReferral( modifyContext.getEntry() ); + referralManager.addReferral( newEntry ); + } + + referralManager.unlock(); + } + } +} Propchange: directory/apacheds/trunk/interceptors/schema/ ------------------------------------------------------------------------------ --- svn:ignore (added) +++ svn:ignore Fri Oct 14 22:36:08 2011 @@ -0,0 +1,11 @@ +.project +.classpath +.settings +eclipse-classes +*.log +*.iml +*.ipr +dependency-reduced-pom.xml +META-INF + + Added: directory/apacheds/trunk/interceptors/schema/pom.xml URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/interceptors/schema/pom.xml?rev=1183537&view=auto ============================================================================== --- directory/apacheds/trunk/interceptors/schema/pom.xml (added) +++ directory/apacheds/trunk/interceptors/schema/pom.xml Fri Oct 14 22:36:08 2011 @@ -0,0 +1,198 @@ + + + + + + 4.0.0 + + org.apache.directory.server + apacheds-interceptors + 2.0.0-M4-SNAPSHOT + + + apacheds-interceptors-schema + ApacheDS Schema Interceptor + jar + + + Schema interceptor + + + + + org.apache.directory.junit + junit-addons + test + + + + ${project.groupId} + apacheds-i18n + + + + ${project.groupId} + apacheds-core-api + + + + ${project.groupId} + apacheds-core-api + tests + test + + + + ${project.groupId} + apacheds-core-shared + + + + ${project.groupId} + apacheds-interceptors-authn + + + + ${project.groupId} + apacheds-interceptors-exception + + + + ${project.groupId} + apacheds-interceptors-normalization + + + + commons-collections + commons-collections + + + + commons-lang + commons-lang + + + + org.apache.directory.shared + shared-ldap-client-api + + + + org.apache.directory.shared + shared-i18n + + + + org.apache.directory.shared + shared-ldap-codec-standalone + provided + + + + org.apache.directory.shared + shared-ldap-codec-core + + + + org.apache.directory.shared + shared-ldap-extras-aci + + + + org.apache.directory.shared + shared-ldap-extras-trigger + + + + org.apache.directory.shared + shared-ldap-extras-util + + + + org.apache.directory.shared + shared-ldap-model + + + + org.apache.directory.shared + shared-ldap-schema-data + + + + org.apache.directory.shared + shared-util + + + + bouncycastle + bcprov-jdk15 + + + + net.sf.ehcache + ehcache-core + + + + org.apache.directory.shared + shared-ldap-extras-codec + provided + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + ${basedir}/target/server-work + + + + + + org.apache.maven.plugins + maven-source-plugin + + + attach-sources + verify + + jar + + + + + + + + + src/main/resources + true + + **/*.gif + + + + + + Added: directory/apacheds/trunk/interceptors/schema/src/main/java/org/apache/directory/server/core/schema/AttributesFactory.java URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/interceptors/schema/src/main/java/org/apache/directory/server/core/schema/AttributesFactory.java?rev=1183537&view=auto ============================================================================== --- directory/apacheds/trunk/interceptors/schema/src/main/java/org/apache/directory/server/core/schema/AttributesFactory.java (added) +++ directory/apacheds/trunk/interceptors/schema/src/main/java/org/apache/directory/server/core/schema/AttributesFactory.java Fri Oct 14 22:36:08 2011 @@ -0,0 +1,420 @@ +/* + * 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.List; + +import org.apache.directory.server.i18n.I18n; +import org.apache.directory.shared.ldap.model.constants.MetaSchemaConstants; +import org.apache.directory.shared.ldap.model.constants.SchemaConstants; +import org.apache.directory.shared.ldap.model.entry.DefaultEntry; +import org.apache.directory.shared.ldap.model.entry.DefaultAttribute; +import org.apache.directory.shared.ldap.model.entry.Attribute; +import org.apache.directory.shared.ldap.model.entry.Entry; +import org.apache.directory.shared.ldap.model.exception.LdapException; +import org.apache.directory.shared.ldap.model.schema.AttributeType; +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.LdapComparator; +import org.apache.directory.shared.ldap.model.schema.LdapSyntax; +import org.apache.directory.shared.ldap.model.schema.MatchingRule; +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.Normalizer; +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.SchemaObject; +import org.apache.directory.shared.ldap.model.schema.SyntaxChecker; +import org.apache.directory.shared.ldap.model.schema.registries.Schema; +import org.apache.directory.shared.util.DateUtils; + + +/** + * A factory that generates an entry using the meta schema for schema + * elements. + * + * @author Apache Directory Project + */ +public class AttributesFactory +{ + public Entry getAttributes( SchemaObject obj, Schema schema, SchemaManager schemaManager ) throws LdapException + { + if ( obj instanceof LdapSyntax ) + { + return getAttributes( ( LdapSyntax ) obj, schema, schemaManager ); + } + else if ( obj instanceof MatchingRule ) + { + return getAttributes( ( MatchingRule ) obj, schema, schemaManager ); + } + else if ( obj instanceof AttributeType ) + { + return getAttributes( ( AttributeType ) obj, schema, schemaManager ); + } + else if ( obj instanceof ObjectClass ) + { + return getAttributes( ( ObjectClass ) obj, schema, schemaManager ); + } + else if ( obj instanceof MatchingRuleUse ) + { + return getAttributes( ( MatchingRuleUse ) obj, schema, schemaManager ); + } + else if ( obj instanceof DITStructureRule ) + { + return getAttributes( ( DITStructureRule ) obj, schema, schemaManager ); + } + else if ( obj instanceof DITContentRule ) + { + return getAttributes( ( DITContentRule ) obj, schema, schemaManager ); + } + else if ( obj instanceof NameForm ) + { + return getAttributes( ( NameForm ) obj, schema, schemaManager ); + } + + throw new IllegalArgumentException( I18n.err( I18n.ERR_698, obj.getClass() ) ); + } + + + public Entry getAttributes( Schema schema, SchemaManager schemaManager ) throws LdapException + { + Entry entry = new DefaultEntry( schemaManager ); + + entry.put( SchemaConstants.OBJECT_CLASS_AT, SchemaConstants.TOP_OC, MetaSchemaConstants.META_SCHEMA_OC ); + entry.put( SchemaConstants.CN_AT, schema.getSchemaName() ); + entry.put( SchemaConstants.CREATORS_NAME_AT, schema.getOwner() ); + entry.put( SchemaConstants.CREATE_TIMESTAMP_AT, DateUtils.getGeneralizedTime() ); + + if ( schema.isDisabled() ) + { + entry.put( MetaSchemaConstants.M_DISABLED_AT, "TRUE" ); + } + + String[] dependencies = schema.getDependencies(); + + if ( dependencies != null && dependencies.length > 0 ) + { + Attribute attr = new DefaultAttribute( schemaManager.getAttributeType( MetaSchemaConstants.M_DEPENDENCIES_AT ) ); + + for ( String dependency:dependencies ) + { + attr.add( dependency ); + } + + entry.put( attr ); + } + + return entry; + } + + + public Entry getAttributes( SyntaxChecker syntaxChecker, Schema schema, SchemaManager schemaManager ) + { + Entry entry = new DefaultEntry( schemaManager ); + + entry.put( SchemaConstants.OBJECT_CLASS_AT, SchemaConstants.TOP_OC, MetaSchemaConstants.META_SYNTAX_CHECKER_OC ); + entry.put( MetaSchemaConstants.M_OID_AT, syntaxChecker.getOid() ); + entry.put( MetaSchemaConstants.M_FQCN_AT, syntaxChecker.getClass().getName() ); + entry.put( SchemaConstants.CREATORS_NAME_AT, schema.getOwner() ); + entry.put( SchemaConstants.CREATE_TIMESTAMP_AT, DateUtils.getGeneralizedTime() ); + + return entry; + } + + + public Entry getAttributes( LdapSyntax syntax, Schema schema, SchemaManager schemaManager ) throws LdapException + { + Entry entry = new DefaultEntry( schemaManager ); + + entry.put( SchemaConstants.OBJECT_CLASS_AT, SchemaConstants.TOP_OC, MetaSchemaConstants.META_SYNTAX_OC ); + entry.put( MetaSchemaConstants.X_HUMAN_READABLE_AT, getBoolean( syntax.isHumanReadable() ) ); + entry.put( SchemaConstants.CREATORS_NAME_AT, schema.getOwner() ); + entry.put( SchemaConstants.CREATE_TIMESTAMP_AT, DateUtils.getGeneralizedTime() ); + injectCommon( syntax, entry, schemaManager ); + + return entry; + } + + + public Entry getAttributes( String oid, Normalizer normalizer, Schema schema, SchemaManager schemaManager ) + { + Entry entry = new DefaultEntry( schemaManager ); + + entry.put( SchemaConstants.OBJECT_CLASS_AT, SchemaConstants.TOP_OC, MetaSchemaConstants.META_NORMALIZER_OC ); + entry.put( MetaSchemaConstants.M_OID_AT, oid ); + entry.put( MetaSchemaConstants.M_FQCN_AT, normalizer.getClass().getName() ); + entry.put( SchemaConstants.CREATORS_NAME_AT, schema.getOwner() ); + entry.put( SchemaConstants.CREATE_TIMESTAMP_AT, DateUtils.getGeneralizedTime() ); + return entry; + } + + + public Entry getAttributes( String oid, LdapComparator comparator, Schema schema, SchemaManager schemaManager ) + { + Entry entry = new DefaultEntry( schemaManager ); + + entry.put( SchemaConstants.OBJECT_CLASS_AT, SchemaConstants.TOP_OC, MetaSchemaConstants.META_COMPARATOR_OC ); + entry.put( MetaSchemaConstants.M_OID_AT, oid ); + entry.put( MetaSchemaConstants.M_FQCN_AT, comparator.getClass().getName() ); + entry.put( SchemaConstants.CREATORS_NAME_AT, schema.getOwner() ); + entry.put( SchemaConstants.CREATE_TIMESTAMP_AT, DateUtils.getGeneralizedTime() ); + return entry; + } + + + /** + * + * @param matchingRule + * @return Attributes + * @throws LdapException + */ + public Entry getAttributes( MatchingRule matchingRule, Schema schema, SchemaManager schemaManager ) throws LdapException + { + Entry entry = new DefaultEntry( schemaManager ); + + entry.put( SchemaConstants.OBJECT_CLASS_AT, SchemaConstants.TOP_OC, MetaSchemaConstants.META_MATCHING_RULE_OC ); + entry.put( MetaSchemaConstants.M_SYNTAX_AT, matchingRule.getSyntaxOid() ); + entry.put( SchemaConstants.CREATORS_NAME_AT, schema.getOwner() ); + entry.put( SchemaConstants.CREATE_TIMESTAMP_AT, DateUtils.getGeneralizedTime() ); + injectCommon( matchingRule, entry, schemaManager ); + return entry; + } + + + public Entry getAttributes( MatchingRuleUse matchingRuleUse, Schema schema, SchemaManager schemaManager ) + { + Entry entry = new DefaultEntry( schemaManager ); + + entry.put( SchemaConstants.OBJECT_CLASS_AT, SchemaConstants.TOP_OC, "" ); + entry.put( SchemaConstants.CREATORS_NAME_AT, schema.getOwner() ); + entry.put( SchemaConstants.CREATE_TIMESTAMP_AT, DateUtils.getGeneralizedTime() ); + return entry; + } + + + public Entry getAttributes( DITStructureRule dITStructureRule, Schema schema, SchemaManager schemaManager ) + { + Entry entry = new DefaultEntry( schemaManager ); + + entry.put( SchemaConstants.OBJECT_CLASS_AT, SchemaConstants.TOP_OC, "" ); + entry.put( SchemaConstants.CREATORS_NAME_AT, schema.getOwner() ); + entry.put( SchemaConstants.CREATE_TIMESTAMP_AT, DateUtils.getGeneralizedTime() ); + return entry; + } + + + public Entry getAttributes( DITContentRule dITContentRule, Schema schema, SchemaManager schemaManager ) + { + Entry entry = new DefaultEntry( schemaManager ); + + entry.put( SchemaConstants.OBJECT_CLASS_AT, SchemaConstants.TOP_OC, "" ); + entry.put( SchemaConstants.CREATORS_NAME_AT, schema.getOwner() ); + entry.put( SchemaConstants.CREATE_TIMESTAMP_AT, DateUtils.getGeneralizedTime() ); + return entry; + } + + + public Entry getAttributes( NameForm nameForm, Schema schema, SchemaManager schemaManager ) + { + Entry entry = new DefaultEntry( schemaManager ); + + entry.put( SchemaConstants.OBJECT_CLASS_AT, SchemaConstants.TOP_OC, "" ); + entry.put( SchemaConstants.CREATORS_NAME_AT, schema.getOwner() ); + entry.put( SchemaConstants.CREATE_TIMESTAMP_AT, DateUtils.getGeneralizedTime() ); + return entry; + } + + + /** + *
+     *    objectclass ( 1.3.6.1.4.1.18060.0.4.0.3.3
+     *       NAME 'metaAttributeType'
+     *       DESC 'meta definition of the AttributeType object'
+     *       SUP metaTop
+     *       STRUCTURAL
+     *       MUST ( m-name $ m-syntax )
+     *       MAY ( m-supAttributeType $ m-obsolete $ m-equality $ m-ordering $ 
+     *             m-substr $ m-singleValue $ m-collective $ m-noUserModification $ 
+     *             m-usage $ m-extensionAttributeType )
+     *    )
+     * 
+ * + * @param attributeType + * @return Attributes + * @throws LdapException + */ + public Entry getAttributes( AttributeType attributeType, Schema schema, SchemaManager schemaManager ) throws LdapException + { + Entry entry = new DefaultEntry( schemaManager ); + + entry.put( SchemaConstants.OBJECT_CLASS_AT, SchemaConstants.TOP_OC, MetaSchemaConstants.META_ATTRIBUTE_TYPE_OC ); + entry.put( MetaSchemaConstants.M_SYNTAX_AT, attributeType.getSyntaxOid() ); + entry.put( MetaSchemaConstants.M_COLLECTIVE_AT, getBoolean( attributeType.isCollective() ) ); + entry.put( MetaSchemaConstants.M_NO_USER_MODIFICATION_AT, getBoolean( ! attributeType.isUserModifiable() ) ); + entry.put( MetaSchemaConstants.M_SINGLE_VALUE_AT, getBoolean( attributeType.isSingleValued() ) ); + entry.put( MetaSchemaConstants.M_USAGE_AT, attributeType.getUsage().toString() ); + entry.put( SchemaConstants.CREATORS_NAME_AT, schema.getOwner() ); + entry.put( SchemaConstants.CREATE_TIMESTAMP_AT, DateUtils.getGeneralizedTime() ); + + injectCommon( attributeType, entry, schemaManager ); + + String superiorOid = attributeType.getSuperiorOid(); + + if ( superiorOid != null ) + { + entry.put( MetaSchemaConstants.M_SUP_ATTRIBUTE_TYPE_AT, superiorOid ); + } + + if ( attributeType.getEqualityOid() != null ) + { + entry.put( MetaSchemaConstants.M_EQUALITY_AT, attributeType.getEqualityOid() ); + } + + if ( attributeType.getSubstringOid() != null ) + { + entry.put( MetaSchemaConstants.M_SUBSTR_AT, attributeType.getSubstringOid() ); + } + + if ( attributeType.getOrderingOid() != null ) + { + entry.put( MetaSchemaConstants.M_ORDERING_AT, attributeType.getOrderingOid() ); + } + + return entry; + } + + + /** + * Creates the attributes of an entry representing an objectClass. + * + *
+     *  objectclass ( 1.3.6.1.4.1.18060.0.4.0.3.2
+     *      NAME 'metaObjectClass'
+     *      DESC 'meta definition of the objectclass object'
+     *      SUP metaTop
+     *      STRUCTURAL
+     *      MUST m-oid
+     *      MAY ( m-name $ m-obsolete $ m-supObjectClass $ m-typeObjectClass $ m-must $ 
+     *            m-may $ m-extensionObjectClass )
+     *  )
+     * 
+ * + * @param objectClass the objectClass to produce a meta schema entry for + * @return the attributes of the metaSchema entry representing the objectClass + * @throws LdapException if there are any problems + */ + public Entry getAttributes( ObjectClass objectClass, Schema schema, SchemaManager schemaManager ) throws LdapException + { + Entry entry = new DefaultEntry( schemaManager ); + + entry.put( SchemaConstants.OBJECT_CLASS_AT, SchemaConstants.TOP_OC, MetaSchemaConstants.META_OBJECT_CLASS_OC ); + entry.put( MetaSchemaConstants.M_TYPE_OBJECT_CLASS_AT, objectClass.getType().toString() ); + entry.put( SchemaConstants.CREATORS_NAME_AT, schema.getOwner() ); + entry.put( SchemaConstants.CREATE_TIMESTAMP_AT, DateUtils.getGeneralizedTime() ); + + injectCommon( objectClass, entry, schemaManager ); + + // handle the superior objectClasses + if ( objectClass.getSuperiorOids() != null && objectClass.getSuperiorOids().size() != 0 ) + { + Attribute attr = new DefaultAttribute( schemaManager.getAttributeType( MetaSchemaConstants.M_SUP_OBJECT_CLASS_AT ) ); + + for ( String superior:objectClass.getSuperiorOids() ) + { + attr.add( superior ); + } + + entry.put( attr ); + } + + // add the must list + if ( objectClass.getMustAttributeTypeOids() != null && objectClass.getMustAttributeTypeOids().size() != 0 ) + { + Attribute attr = new DefaultAttribute( schemaManager.getAttributeType( MetaSchemaConstants.M_MUST_AT ) ); + + for ( String mustOid :objectClass.getMustAttributeTypeOids() ) + { + attr.add( mustOid ); + } + + entry.put( attr ); + } + + // add the may list + if ( objectClass.getMayAttributeTypeOids() != null && objectClass.getMayAttributeTypeOids().size() != 0 ) + { + Attribute attr = new DefaultAttribute( schemaManager.getAttributeType( MetaSchemaConstants.M_MAY_AT ) ); + + for ( String mayOid :objectClass.getMayAttributeTypeOids() ) + { + attr.add( mayOid ); + } + + entry.put( attr ); + } + + return entry; + } + + + private final void injectCommon( SchemaObject object, Entry entry, SchemaManager schemaManager ) throws LdapException + { + injectNames( object.getNames(), entry, schemaManager ); + entry.put( MetaSchemaConstants.M_OBSOLETE_AT, getBoolean( object.isObsolete() ) ); + entry.put( MetaSchemaConstants.M_OID_AT, object.getOid() ); + + if ( object.getDescription() != null ) + { + entry.put( MetaSchemaConstants.M_DESCRIPTION_AT, object.getDescription() ); + } + } + + + private final void injectNames( List names, Entry entry, SchemaManager schemaManager ) throws LdapException + { + if ( ( names == null ) || ( names.size() == 0 ) ) + { + return; + } + + Attribute attr = new DefaultAttribute( schemaManager.getAttributeType( MetaSchemaConstants.M_NAME_AT ) ); + + for ( String name:names ) + { + attr.add( name ); + } + + entry.put( attr ); + } + + + private final String getBoolean( boolean value ) + { + if ( value ) + { + return "TRUE"; + } + else + { + return "FALSE"; + } + } +}