Author: elecharny Date: Thu Aug 14 16:12:09 2008 New Revision: 686082 URL: http://svn.apache.org/viewvc?rev=686082&view=rev Log: o Replaced some of the ServerUtils methods by direct calls to the equivalent methods in the Server Entry/Attribute/Modification classes o Completely reviewed the serialization of entries/attributes/values/Modifications/LdifEnties o Added tests for all those serialization o Used Externalizable,instead of Serializable o Added some missing Javadoc o Fixed some failing tests in ModifyDN class o Fixed the wrong LDIF in referrals tests o Removed a lot of references on Attribute(s) and JNDI objects o Removed the password wrom the LdapPrincipal serialized form Added: directory/apacheds/branches/bigbang/core/src/test/java/org/apache/directory/server/core/authn/LdapPrincipalTest.java directory/shared/branches/bigbang/ldap/src/main/java/org/apache/directory/shared/ldap/entry/client/ClientModification.java directory/shared/branches/bigbang/ldap/src/test/java/org/apache/directory/shared/ldap/entry/client/ClientModificationTest.java Modified: directory/apacheds/branches/bigbang/core-entry/src/main/java/org/apache/directory/server/core/entry/ClonedServerEntry.java directory/apacheds/branches/bigbang/core-entry/src/main/java/org/apache/directory/server/core/entry/DefaultServerAttribute.java directory/apacheds/branches/bigbang/core-entry/src/main/java/org/apache/directory/server/core/entry/DefaultServerEntry.java directory/apacheds/branches/bigbang/core-entry/src/main/java/org/apache/directory/server/core/entry/ServerAttribute.java directory/apacheds/branches/bigbang/core-entry/src/main/java/org/apache/directory/server/core/entry/ServerBinaryValue.java directory/apacheds/branches/bigbang/core-entry/src/main/java/org/apache/directory/server/core/entry/ServerEntry.java directory/apacheds/branches/bigbang/core-entry/src/main/java/org/apache/directory/server/core/entry/ServerEntrySerializer.java directory/apacheds/branches/bigbang/core-entry/src/main/java/org/apache/directory/server/core/entry/ServerEntryUtils.java directory/apacheds/branches/bigbang/core-entry/src/main/java/org/apache/directory/server/core/entry/ServerModification.java directory/apacheds/branches/bigbang/core-entry/src/main/java/org/apache/directory/server/core/entry/ServerStringValue.java directory/apacheds/branches/bigbang/core-entry/src/test/java/org/apache/directory/server/core/entry/DefaultServerAttributeTest.java directory/apacheds/branches/bigbang/core-entry/src/test/java/org/apache/directory/server/core/entry/DefaultServerEntryTest.java directory/apacheds/branches/bigbang/core-entry/src/test/java/org/apache/directory/server/core/entry/ServerBinaryValueTest.java directory/apacheds/branches/bigbang/core-entry/src/test/java/org/apache/directory/server/core/entry/ServerEntrySerializerTest.java directory/apacheds/branches/bigbang/core-entry/src/test/java/org/apache/directory/server/core/entry/ServerModificationTest.java directory/apacheds/branches/bigbang/core-entry/src/test/java/org/apache/directory/server/core/entry/ServerStringValueTest.java directory/apacheds/branches/bigbang/core-integ/src/main/java/org/apache/directory/server/core/integ/IntegrationUtils.java directory/apacheds/branches/bigbang/core-integ/src/main/java/org/apache/directory/server/core/integ/state/AbstractState.java directory/apacheds/branches/bigbang/core-integ/src/test/java/org/apache/directory/server/core/authn/SimpleAuthenticationIT.java directory/apacheds/branches/bigbang/core-integ/src/test/java/org/apache/directory/server/core/authz/AuthorizationServiceAsNonAdminIT.java directory/apacheds/branches/bigbang/core-integ/src/test/java/org/apache/directory/server/core/jndi/ListIT.java directory/apacheds/branches/bigbang/core-integ/src/test/java/org/apache/directory/server/core/jndi/ModifyContextIT.java directory/apacheds/branches/bigbang/core-integ/src/test/java/org/apache/directory/server/core/jndi/ObjStateFactoryIT.java directory/apacheds/branches/bigbang/core-integ/src/test/java/org/apache/directory/server/core/jndi/ReferralIT.java directory/apacheds/branches/bigbang/core-integ/src/test/java/org/apache/directory/server/core/operational/OperationalAttributeServiceIT.java directory/apacheds/branches/bigbang/core-integ/src/test/java/org/apache/directory/server/core/schema/SchemaPersistenceIT.java directory/apacheds/branches/bigbang/core-integ/src/test/java/org/apache/directory/server/core/schema/SchemaServiceIT.java directory/apacheds/branches/bigbang/core-integ/src/test/java/org/apache/directory/server/core/schema/SubschemaSubentryIT.java directory/apacheds/branches/bigbang/core-jndi/src/main/java/org/apache/directory/server/core/jndi/ServerDirContext.java directory/apacheds/branches/bigbang/core-unit/src/main/java/org/apache/directory/server/core/unit/AbstractTestCase.java directory/apacheds/branches/bigbang/core-unit/src/main/java/org/apache/directory/server/core/unit/IntegrationUtils.java directory/apacheds/branches/bigbang/core/src/main/java/org/apache/directory/server/core/DefaultCoreSession.java directory/apacheds/branches/bigbang/core/src/main/java/org/apache/directory/server/core/DefaultDirectoryService.java directory/apacheds/branches/bigbang/core/src/main/java/org/apache/directory/server/core/authn/LdapPrincipal.java directory/apacheds/branches/bigbang/core/src/main/java/org/apache/directory/server/core/authz/AciAuthorizationInterceptor.java directory/apacheds/branches/bigbang/core/src/main/java/org/apache/directory/server/core/changelog/ChangeLogEvent.java directory/apacheds/branches/bigbang/core/src/main/java/org/apache/directory/server/core/changelog/ChangeLogInterceptor.java directory/apacheds/branches/bigbang/core/src/main/java/org/apache/directory/server/core/changelog/DefaultChangeLog.java directory/apacheds/branches/bigbang/core/src/main/java/org/apache/directory/server/core/changelog/MemoryChangeLogStore.java directory/apacheds/branches/bigbang/core/src/main/java/org/apache/directory/server/core/collective/CollectiveAttributesSchemaChecker.java directory/apacheds/branches/bigbang/core/src/main/java/org/apache/directory/server/core/interceptor/InterceptorChain.java directory/apacheds/branches/bigbang/core/src/main/java/org/apache/directory/server/core/interceptor/context/ModifyOperationContext.java directory/apacheds/branches/bigbang/core/src/main/java/org/apache/directory/server/core/partition/impl/btree/gui/PartitionFrame.java directory/apacheds/branches/bigbang/core/src/main/java/org/apache/directory/server/core/partition/impl/btree/jdbm/JdbmPartition.java directory/apacheds/branches/bigbang/core/src/main/java/org/apache/directory/server/core/schema/SchemaInterceptor.java directory/apacheds/branches/bigbang/core/src/main/java/org/apache/directory/server/core/sp/StoredProcExecutionManager.java directory/apacheds/branches/bigbang/core/src/test/java/org/apache/directory/server/core/changelog/MemoryChangeLogStoreTest.java directory/apacheds/branches/bigbang/protocol-shared/src/main/java/org/apache/directory/server/protocol/shared/store/LdifFileLoader.java directory/apacheds/branches/bigbang/protocol-shared/src/main/java/org/apache/directory/server/protocol/shared/store/LdifLoadFilter.java directory/apacheds/branches/bigbang/server-integ/src/main/java/org/apache/directory/server/integ/state/AbstractState.java directory/apacheds/branches/bigbang/server-integ/src/test/java/org/apache/directory/server/operations/bind/BindIT.java directory/apacheds/branches/bigbang/server-integ/src/test/java/org/apache/directory/server/operations/bind/SimpleBindIT.java directory/apacheds/branches/bigbang/server-integ/src/test/java/org/apache/directory/server/operations/modifydn/ModifyRdnIT.java directory/apacheds/branches/bigbang/server-integ/src/test/java/org/apache/directory/server/operations/search/ReferralSearchIT.java directory/apacheds/branches/bigbang/server-integ/src/test/java/org/apache/directory/server/operations/search/SearchIT.java directory/apacheds/branches/bigbang/server-jndi/src/main/java/org/apache/directory/server/configuration/ApacheDS.java directory/apacheds/branches/bigbang/server-jndi/src/test/java/org/apache/directory/server/configuration/ApacheDSTest.java directory/apacheds/branches/bigbang/server-tools/src/main/java/org/apache/directory/server/tools/ImportCommand.java directory/apacheds/branches/bigbang/server-unit/src/main/java/org/apache/directory/server/unit/AbstractServerTest.java directory/shared/branches/bigbang/convert/src/main/java/org/apache/directory/shared/converter/schema/AttributeTypeHolder.java directory/shared/branches/bigbang/convert/src/main/java/org/apache/directory/shared/converter/schema/ObjectClassHolder.java directory/shared/branches/bigbang/convert/src/main/java/org/apache/directory/shared/converter/schema/SchemaElementImpl.java directory/shared/branches/bigbang/ldap/src/main/java/org/apache/directory/shared/ldap/entry/Entry.java directory/shared/branches/bigbang/ldap/src/main/java/org/apache/directory/shared/ldap/entry/EntryAttribute.java directory/shared/branches/bigbang/ldap/src/main/java/org/apache/directory/shared/ldap/entry/Modification.java directory/shared/branches/bigbang/ldap/src/main/java/org/apache/directory/shared/ldap/entry/ModificationOperation.java directory/shared/branches/bigbang/ldap/src/main/java/org/apache/directory/shared/ldap/entry/client/ClientBinaryValue.java directory/shared/branches/bigbang/ldap/src/main/java/org/apache/directory/shared/ldap/entry/client/ClientStringValue.java directory/shared/branches/bigbang/ldap/src/main/java/org/apache/directory/shared/ldap/entry/client/DefaultClientAttribute.java directory/shared/branches/bigbang/ldap/src/main/java/org/apache/directory/shared/ldap/entry/client/DefaultClientEntry.java directory/shared/branches/bigbang/ldap/src/main/java/org/apache/directory/shared/ldap/ldif/LdifEntry.java directory/shared/branches/bigbang/ldap/src/main/java/org/apache/directory/shared/ldap/ldif/LdifReader.java directory/shared/branches/bigbang/ldap/src/main/java/org/apache/directory/shared/ldap/ldif/LdifUtils.java directory/shared/branches/bigbang/ldap/src/main/java/org/apache/directory/shared/ldap/name/LdapDN.java directory/shared/branches/bigbang/ldap/src/main/java/org/apache/directory/shared/ldap/name/Rdn.java directory/shared/branches/bigbang/ldap/src/main/java/org/apache/directory/shared/ldap/schema/SchemaUtils.java directory/shared/branches/bigbang/ldap/src/main/java/org/apache/directory/shared/ldap/util/AttributeUtils.java directory/shared/branches/bigbang/ldap/src/main/java/org/apache/directory/shared/ldap/util/DNUtils.java directory/shared/branches/bigbang/ldap/src/main/java/org/apache/directory/shared/ldap/util/Position.java directory/shared/branches/bigbang/ldap/src/main/java/org/apache/directory/shared/ldap/util/PropertiesUtils.java directory/shared/branches/bigbang/ldap/src/test/java/org/apache/directory/shared/ldap/entry/client/ClientBinaryValueTest.java directory/shared/branches/bigbang/ldap/src/test/java/org/apache/directory/shared/ldap/entry/client/ClientStringValueTest.java directory/shared/branches/bigbang/ldap/src/test/java/org/apache/directory/shared/ldap/entry/client/DefaultClientAttributeTest.java directory/shared/branches/bigbang/ldap/src/test/java/org/apache/directory/shared/ldap/entry/client/DefaultClientEntryTest.java directory/shared/branches/bigbang/ldap/src/test/java/org/apache/directory/shared/ldap/ldif/LdifReaderTest.java directory/shared/branches/bigbang/ldap/src/test/java/org/apache/directory/shared/ldap/ldif/LdifUtilsTest.java directory/shared/branches/bigbang/ldap/src/test/java/org/apache/directory/shared/ldap/name/AttributeTypeAndValueTest.java directory/shared/branches/bigbang/ldap/src/test/java/org/apache/directory/shared/ldap/name/RdnTest.java directory/shared/branches/bigbang/ldap/src/test/java/org/apache/directory/shared/ldap/util/AttributeUtilsTest.java Modified: directory/apacheds/branches/bigbang/core-entry/src/main/java/org/apache/directory/server/core/entry/ClonedServerEntry.java URL: http://svn.apache.org/viewvc/directory/apacheds/branches/bigbang/core-entry/src/main/java/org/apache/directory/server/core/entry/ClonedServerEntry.java?rev=686082&r1=686081&r2=686082&view=diff ============================================================================== --- directory/apacheds/branches/bigbang/core-entry/src/main/java/org/apache/directory/server/core/entry/ClonedServerEntry.java (original) +++ directory/apacheds/branches/bigbang/core-entry/src/main/java/org/apache/directory/server/core/entry/ClonedServerEntry.java Thu Aug 14 16:12:09 2008 @@ -20,6 +20,9 @@ package org.apache.directory.server.core.entry; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; import java.util.Collections; import java.util.Iterator; import java.util.List; @@ -27,8 +30,10 @@ import javax.naming.NamingException; +import org.apache.directory.shared.ldap.entry.Entry; import org.apache.directory.shared.ldap.entry.EntryAttribute; import org.apache.directory.shared.ldap.entry.Value; +import org.apache.directory.shared.ldap.entry.client.DefaultClientEntry; import org.apache.directory.shared.ldap.name.LdapDN; import org.apache.directory.shared.ldap.schema.AttributeType; @@ -75,7 +80,7 @@ /** * @return the cloned Entry */ - public ServerEntry getClonedEntry() + public Entry getClonedEntry() { return clonedEntry; } @@ -399,6 +404,44 @@ } + public Entry toClientEntry() throws NamingException + { + // Copy the DN + Entry clientEntry = new DefaultClientEntry( clonedEntry.getDn() ); + + // Convert each attribute + for ( EntryAttribute clonedEntry:this ) + { + EntryAttribute clientAttribute = ((ServerAttribute)clonedEntry).toClientAttribute(); + clientEntry.add( clientAttribute ); + } + + return clientEntry; + } + + + /** + * @see java.io.Externalizable#readExternal(ObjectInput) + * + * We can't use this method for a ServerEntry + */ + public void readExternal( ObjectInput in ) throws IOException, ClassNotFoundException + { + throw new IllegalStateException( "Cannot use standard serialization for a ServerAttribute" ); + } + + + /** + * @see java.io.Externalizable#writeExternal(ObjectOutput) + * + * We can't use this method for a ServerEntry + */ + public void writeExternal( ObjectOutput out ) throws IOException + { + throw new IllegalStateException( "Cannot use standard serialization for a ServerEntry" ); + } + + public ServerEntry clone() { return ( ServerEntry ) clonedEntry.clone(); @@ -676,9 +719,36 @@ return 0; } + public ServerEntry clone() { return new EmptyEntry( dn ); } + + + public void readExternal( ObjectInput in ) throws IOException, ClassNotFoundException + { + } + + + public void writeExternal( ObjectOutput out ) throws IOException + { + } + + + public Entry toClientEntry() throws NamingException + { + // Copy the DN + Entry clientEntry = new DefaultClientEntry( dn ); + + // Convert each attribute + for ( EntryAttribute serverAttribute:this ) + { + EntryAttribute clientAttribute = ((ServerAttribute)serverAttribute).toClientAttribute(); + clientEntry.add( clientAttribute ); + } + + return clientEntry; + } } } Modified: directory/apacheds/branches/bigbang/core-entry/src/main/java/org/apache/directory/server/core/entry/DefaultServerAttribute.java URL: http://svn.apache.org/viewvc/directory/apacheds/branches/bigbang/core-entry/src/main/java/org/apache/directory/server/core/entry/DefaultServerAttribute.java?rev=686082&r1=686081&r2=686082&view=diff ============================================================================== --- directory/apacheds/branches/bigbang/core-entry/src/main/java/org/apache/directory/server/core/entry/DefaultServerAttribute.java (original) +++ directory/apacheds/branches/bigbang/core-entry/src/main/java/org/apache/directory/server/core/entry/DefaultServerAttribute.java Thu Aug 14 16:12:09 2008 @@ -19,6 +19,10 @@ package org.apache.directory.server.core.entry; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; + import javax.naming.NamingException; import javax.naming.directory.InvalidAttributeValueException; @@ -42,6 +46,8 @@ */ public final class DefaultServerAttribute extends DefaultClientAttribute implements ServerAttribute { + public static final long serialVersionUID = 1L; + /** logger for reporting errors that might not be handled properly upstream */ private static final Logger LOG = LoggerFactory.getLogger( DefaultServerAttribute.class ); @@ -49,9 +55,9 @@ private AttributeType attributeType; - // ----------------------------------------------------------------------- + //----------------------------------------------------------------------- // utility methods - // ----------------------------------------------------------------------- + //----------------------------------------------------------------------- /** * Private helper method used to set an UpId from an attributeType * @@ -71,381 +77,157 @@ } + //------------------------------------------------------------------------- + // Constructors + //------------------------------------------------------------------------- /** - *

- * Check if the current attribute type is of the expected attributeType - *

- *

- * This method won't tell if the current attribute is a descendant of - * the attributeType. For instance, the "CN" serverAttribute will return - * false if we ask if it's an instance of "Name". - *

+ * + * Creates a new instance of DefaultServerAttribute, by copying + * another attribute, which can be a ClientAttribute. If the other + * attribute is a ServerAttribute, it will be copied. * - * @param attributeId The AttributeType ID to check - * @return True if the current attribute is of the expected attributeType - * @throws InvalidAttributeValueException If there is no AttributeType + * @param attributeType The attribute's type + * @param attribute The attribute to be copied */ - public boolean instanceOf( String attributeId ) throws InvalidAttributeValueException + public DefaultServerAttribute( AttributeType attributeType, EntryAttribute attribute ) { - String trimmedId = StringTools.trim( attributeId ); - - if ( StringTools.isEmpty( trimmedId ) ) - { - return false; - } - - String normId = StringTools.lowerCaseAscii( trimmedId ); - - for ( String name:attributeType.getNamesRef() ) + // Copy the common values. isHR is only available on a ServerAttribute + this.attributeType = attributeType; + this.id = attribute.getId(); + this.upId = attribute.getUpId(); + + if ( attribute instanceof ServerAttribute ) { - if ( normId.equalsIgnoreCase( name ) ) + isHR = attribute.isHR(); + + // Copy all the values + for ( Value value:attribute ) { - return true; + add( value.clone() ); } } - - return normId.equalsIgnoreCase( attributeType.getOid() ); - } - - - /** - *

- * Overload the {@link DefaultClientAttribute#setId(String)} method. - *

- *

- * As the attributeType has already been set, we have to be sure that the - * argument is compatible with the attributeType's name. - *

- *

- * If the given ID is not compatible with the attributeType's possible - * names, the previously loaded ID will be kept. - *

- * - * @param id The attribute ID - */ - public void setId( String id ) - { - if ( !StringTools.isEmpty( StringTools.trim( id ) ) ) + else { - if ( attributeType.getName() == null ) + + try { - // If the name is null, then we may have to store an OID - if ( OID.isOID( id ) && attributeType.getOid().equals( id ) ) - { - // Everything is fine, store the upId. - // This should not happen... - super.setId( id ); - } + isHR = attributeType.getSyntax().isHumanReadable(); } - else + catch ( NamingException ne ) { - // We have at least one name. Check that the normalized upId - // is one of those names. Otherwise, the upId may be an OID too. - // In this case, it must be equals to the attributeType OID. - String normId = StringTools.lowerCaseAscii( StringTools.trim( id ) ); - - for ( String atName:attributeType.getNamesRef() ) + // Do nothing : the syntax should always exist ... + } + + + // Copy all the values + for ( Value clientValue:attribute ) + { + Value serverValue = null; + + // We have to convert the value first + if ( clientValue instanceof ClientStringValue ) { - if ( atName.equalsIgnoreCase( normId ) ) + if ( isHR ) { - // Found ! We can store the upId and get out - super.setId( normId ); - return; + serverValue = new ServerStringValue( attributeType, (String)clientValue.get() ); + } + else + { + // We have to convert the value to a binary value first + serverValue = new ServerBinaryValue( attributeType, + StringTools.getBytesUtf8( (String)clientValue.get() ) ); } } - - // Last case, the UpId is an OID - if ( OID.isOID( normId ) && attributeType.getOid().equals( normId ) ) - { - // We have an OID : stores it - super.setUpId( normId ); - } - else + else if ( clientValue instanceof ClientBinaryValue ) { - // The id is incorrect : this is not allowed - throw new IllegalArgumentException( "The ID '" + id + "'is incompatible with the AttributeType's id '" + - attributeType.getName() + "'" ); + if ( isHR ) + { + // We have to convert the value to a String value first + serverValue = new ServerStringValue( attributeType, + StringTools.utf8ToString( (byte[])clientValue.get() ) ); + } + else + { + serverValue = new ServerBinaryValue( attributeType, (byte[])clientValue.get() ); + } } + + add( serverValue ); } } - else - { - throw new IllegalArgumentException( "An ID cannnot be null, empty, or resolved to an emtpy" + - " value when trimmed" ); - } } + // maybe have some additional convenience constructors which take + // an initial value as a string or a byte[] /** - *

- * Overload the {@link DefaultClientAttribute#setUpId(String)} method. - *

- *

- * As the attributeType has already been set, we have to be sure that the - * argument is compatible with the attributeType's name. - *

- *

- * If the given ID is not compatible with the attributeType's possible - * names, the previously loaded ID will be kept. - *

- * - * @param upId The attribute ID + * Create a new instance of a EntryAttribute, without ID nor value. + * + * @param attributeType the attributeType for the empty attribute added into the entry */ - public void setUpId( String upId ) + public DefaultServerAttribute( AttributeType attributeType ) { - if ( !StringTools.isEmpty( StringTools.trim( upId ) ) ) + if ( attributeType == null ) { - if ( attributeType.getName() == null ) - { - // If the name is null, then we may have to store an OID - if ( OID.isOID( upId ) && attributeType.getOid().equals( upId ) ) - { - // Everything is fine, store the upId. - // This should not happen... - super.setUpId( upId ); - - } - } - else - { - // We have at least one name. Check that the normalized upId - // is one of those names. Otherwise, the upId may be an OID too. - // In this case, it must be equals to the attributeType OID. - String normUpId = StringTools.lowerCaseAscii( StringTools.trim( upId ) ); - - for ( String atId:attributeType.getNamesRef() ) - { - if ( atId.equalsIgnoreCase( normUpId ) ) - { - // Found ! We can store the upId and get out - super.setUpId( upId ); - return; - } - } - - // Last case, the UpId is an OID - if ( OID.isOID( normUpId ) && attributeType.getOid().equals( normUpId ) ) - { - // We have an OID : stores it - super.setUpId( upId ); - } - } + throw new IllegalArgumentException( "The AttributeType parameter should not be null" ); } + + setAttributeType( attributeType ); } - - + + /** - *

- * Set the user provided ID. If we have none, the upId is assigned - * the attributetype's name. If it does not have any name, we will - * use the OID. - *

- *

- * If we have an upId and an AttributeType, they must be compatible. : - * - if the upId is an OID, it must be the AttributeType's OID - * - otherwise, its normalized form must be equals to ones of - * the attributeType's names. - *

- *

- * In any case, the ATtributeType will be changed. The caller is responsible for - * the present values to be compatoble with the new AttributeType. - *

- * - * @param upId The attribute ID - * @param attributeType The associated attributeType + * Create a new instance of a EntryAttribute, without value. + * + * @param upId the ID for the added attributeType + * @param attributeType the added AttributeType */ - public void setUpId( String upId, AttributeType attributeType ) + public DefaultServerAttribute( String upId, AttributeType attributeType ) { - if ( StringTools.isEmpty( StringTools.trim( upId ) ) ) + if ( attributeType == null ) { - super.setUpId( getUpId( attributeType ) ); - this.attributeType = attributeType; + String message = "The AttributeType parameter should not be null"; + LOG.error( message ); + throw new IllegalArgumentException( message ); } - else - { - String name = attributeType.getName(); - - if ( name == null ) - { - // If the name is null, then we may have to store an OID - if ( OID.isOID( upId ) && attributeType.getOid().equals( upId ) ) - { - // Everything is fine, store the upId. - super.setUpId( upId ); - this.attributeType = attributeType; - } - else - { - // We have a difference or the upId is not a valid OID : - // we will use the attributeTypeOID in this case. - LOG.warn( "The upID ({}) is not an OID or is different from the AttributeType OID({})", - upId, attributeType.getOid() ); - super.setUpId( attributeType.getOid() ); - this.attributeType = attributeType; - } - } - else - { - // We have at least one name. Check that the normalized upId - // is one of those names. Otherwise, the upId may be an OID too. - // In this case, it must be equals to the attributeType OID. - String normUpId = StringTools.lowerCaseAscii( StringTools.trim( upId ) ); - - for ( String atId:attributeType.getNamesRef() ) - { - if ( atId.equalsIgnoreCase( normUpId ) ) - { - // Found ! We can store the upId and get out - super.setUpId( upId ); - this.attributeType = attributeType; - return; - } - } - - // UpId was not found in names. It should be an OID, or if not, we - // will use the AttributeType name. - if ( OID.isOID( normUpId ) && attributeType.getOid().equals( normUpId ) ) - { - // We have an OID : stores it - super.setUpId( upId ); - this.attributeType = attributeType; - } - else - { - String message = "The upID (" + upId + ") is not an OID or is different from the AttributeType OID (" + - attributeType.getOid() + ")"; - // Not a valid OID : use the AttributeTypes OID name instead - LOG.error( message ); - throw new IllegalArgumentException( message ); - } - } - } - } - - - /** - *

- * Set the attribute type associated with this ServerAttribute. - *

- *

- * The current attributeType will be replaced. It is the responsibility of - * the caller to insure that the existing values are compatible with the new - * AttributeType - *

- * - * @param attributeType the attributeType associated with this entry attribute - */ - public void setAttributeType( AttributeType attributeType ) - { - if ( attributeType == null ) - { - throw new IllegalArgumentException( "The AttributeType parameter should not be null" ); - } - - this.attributeType = attributeType; - setUpId( null, attributeType ); - - try - { - if ( attributeType.getSyntax().isHumanReadable() ) - { - isHR = true; - } - else - { - isHR = false; - } - } - catch ( NamingException ne ) - { - // If we have an exception while trying to get the Syntax for this attribute - // just set it as Binary - isHR = false; - } - } - - - /** - * Get the attribute type associated with this ServerAttribute. - * - * @return the attributeType associated with this entry attribute - */ - public AttributeType getAttributeType() - { - return attributeType; - } - - - // maybe have some additional convenience constructors which take - // an initial value as a string or a byte[] - /** - * Create a new instance of a EntryAttribute, without ID nor value. - * - * @param attributeType the attributeType for the empty attribute added into the entry - */ - public DefaultServerAttribute( AttributeType attributeType ) - { - if ( attributeType == null ) - { - throw new IllegalArgumentException( "The AttributeType parameter should not be null" ); - } - - setAttributeType( attributeType ); - } - - - /** - * Create a new instance of a EntryAttribute, without value. - * - * @param upId the ID for the added attributeType - * @param attributeType the added AttributeType - */ - public DefaultServerAttribute( String upId, AttributeType attributeType ) - { - if ( attributeType == null ) - { - String message = "The AttributeType parameter should not be null"; - LOG.error( message ); - throw new IllegalArgumentException( message ); - } - - setAttributeType( attributeType ); - setUpId( upId ); - } - - - /** - * Doc me more! - * - * If the value does not correspond to the same attributeType, then it's - * wrapped value is copied into a new Value which uses the specified - * attributeType. - * - * @param attributeType the attribute type according to the schema - * @param vals an initial set of values for this attribute - */ - public DefaultServerAttribute( AttributeType attributeType, Value... vals ) - { - this( null, attributeType, vals ); - } - - - /** - * Doc me more! - * - * If the value does not correspond to the same attributeType, then it's - * wrapped value is copied into a new Value which uses the specified - * attributeType. - * - * Otherwise, the value is stored, but as a reference. It's not a copy. - * - * @param upId the ID of the added attribute - * @param attributeType the attribute type according to the schema - * @param vals an initial set of values for this attribute - */ - public DefaultServerAttribute( String upId, AttributeType attributeType, Value... vals ) - { - if ( attributeType == null ) + + setAttributeType( attributeType ); + setUpId( upId ); + } + + + /** + * Doc me more! + * + * If the value does not correspond to the same attributeType, then it's + * wrapped value is copied into a new Value which uses the specified + * attributeType. + * + * @param attributeType the attribute type according to the schema + * @param vals an initial set of values for this attribute + */ + public DefaultServerAttribute( AttributeType attributeType, Value... vals ) + { + this( null, attributeType, vals ); + } + + + /** + * Doc me more! + * + * If the value does not correspond to the same attributeType, then it's + * wrapped value is copied into a new Value which uses the specified + * attributeType. + * + * Otherwise, the value is stored, but as a reference. It's not a copy. + * + * @param upId the ID of the added attribute + * @param attributeType the attribute type according to the schema + * @param vals an initial set of values for this attribute + */ + public DefaultServerAttribute( String upId, AttributeType attributeType, Value... vals ) + { + if ( attributeType == null ) { throw new IllegalArgumentException( "The AttributeType parameter should not be null" ); } @@ -520,70 +302,115 @@ } - /** - * Clone an attribute. All the element are duplicated, so a modification on - * the original object won't affect the cloned object, as a modification - * on the cloned object has no impact on the original object - * - * @return a clone of the current attribute - */ - public ServerAttribute clone() - { - // clone the structure by cloner the inherited class - ServerAttribute clone = (ServerAttribute)super.clone(); - - // We are done ! - return clone; - } - - + //------------------------------------------------------------------------- + // API + //------------------------------------------------------------------------- /** *

- * Overload the ClientAttribte isHR method : we can't change this flag - * for a ServerAttribute, as the HR is already set using the AttributeType. - * Set the attribute to Human Readable or to Binary. + * Adds some values to this attribute. If the new values are already present in + * the attribute values, the method has no effect. *

- * - * @param isHR true for a Human Readable attribute, - * false for a Binary attribute. - */ - public void setHR( boolean isHR ) - { - // Do nothing... - } - - - /** *

- * Checks to see if this attribute is valid along with the values it contains. + * The new values are added at the end of list of values. *

*

- * An attribute is valid if : - *

  • All of its values are valid with respect to the attributeType's syntax checker
  • - *
  • If the attributeType is SINGLE-VALUE, then no more than a value should be present
  • - *

    - * @return true if the attribute and it's values are valid, false otherwise - * @throws NamingException if there is a failure to check syntaxes of values + * This method returns the number of values that were added. + *

    + *

    + * If the value's type is different from the attribute's type, + * the value is not added. + *

    + * It's the responsibility of the caller to check if the stored + * values are consistent with the attribute's type. + *

    + * + * @param vals some new values to be added which may be null + * @return the number of added values, or 0 if none has been added */ - public boolean isValid() throws NamingException + public int add( byte[]... vals ) { - // First check if the attribute has more than one value - // if the attribute is supposed to be SINGLE_VALUE - if ( attributeType.isSingleValue() && ( values.size() > 1 ) ) - { - return false; - } - - for ( Value value : values ) + if ( !isHR ) { - if ( ! value.isValid() ) + int nbAdded = 0; + + for ( byte[] val:vals ) { - return false; + Value value = new ServerBinaryValue( attributeType, val ); + + try + { + value.normalize(); + } + catch( NamingException ne ) + { + // The value can't be normalized : we don't add it. + LOG.error( "The value '" + val + "' can't be normalized, it hasn't been added" ); + return 0; + } + + if ( add( value ) != 0 ) + { + nbAdded++; + } + else + { + LOG.error( "The value '" + val + "' is incorrect, it hasn't been added" ); + } } + + return nbAdded; } + else + { + // We can't add Binary values into a String serverAttribute + return 0; + } + } - return true; - } + + /** + *

    + * Adds some values to this attribute. If the new values are already present in + * the attribute values, the method has no effect. + *

    + *

    + * The new values are added at the end of list of values. + *

    + *

    + * This method returns the number of values that were added. + *

    + * If the value's type is different from the attribute's type, + * the value is not added. + * + * @param vals some new values to be added which may be null + * @return the number of added values, or 0 if none has been added + */ + public int add( String... vals ) + { + if ( isHR ) + { + int nbAdded = 0; + + for ( String val:vals ) + { + if ( add( new ServerStringValue( attributeType, val ) ) != 0 ) + { + nbAdded++; + } + else + { + LOG.error( "The value '" + val + "' is incorrect, it hasn't been added" ); + } + } + + return nbAdded; + } + else + { + // We can't add String values into a Binary serverAttribute + return 0; + } + } /** @@ -693,111 +520,101 @@ /** + * Remove all the values from this attribute type, including a + * null value. + */ + public void clear() + { + values.clear(); + } + + + /** *

    - * Adds some values to this attribute. If the new values are already present in - * the attribute values, the method has no effect. - *

    - *

    - * The new values are added at the end of list of values. + * Indicates whether all the specified values are attribute's values. If + * at least one value is not an attribute's value, this method will return + * false *

    *

    - * This method returns the number of values that were added. + * If the Attribute is HR, this method will returns false *

    - * If the value's type is different from the attribute's type, - * the value is not added. * - * @param vals some new values to be added which may be null - * @return the number of added values, or 0 if none has been added + * @param vals the values + * @return true if this attribute contains all the values, otherwise false */ - public int add( String... vals ) + public boolean contains( byte[]... vals ) { - if ( isHR ) + if ( !isHR ) { - int nbAdded = 0; - - for ( String val:vals ) + // Iterate through all the values, and quit if we + // don't find one in the values + for ( byte[] val:vals ) { - if ( add( new ServerStringValue( attributeType, val ) ) != 0 ) + ServerBinaryValue value = new ServerBinaryValue( attributeType, val ); + + try { - nbAdded++; + value.normalize(); } - else + catch ( NamingException ne ) { - LOG.error( "The value '" + val + "' is incorrect, it hasn't been added" ); + return false; + } + + if ( !values.contains( value ) ) + { + return false; } } - return nbAdded; + return true; } else { - // We can't add String values into a Binary serverAttribute - return 0; + return false; } - } + } /** *

    - * Adds some values to this attribute. If the new values are already present in - * the attribute values, the method has no effect. - *

    - *

    - * The new values are added at the end of list of values. - *

    - *

    - * This method returns the number of values that were added. + * Indicates whether all the specified values are attribute's values. If + * at least one value is not an attribute's value, this method will return + * false *

    *

    - * If the value's type is different from the attribute's type, - * the value is not added. + * If the Attribute is not HR, this method will returns false *

    - * It's the responsibility of the caller to check if the stored - * values are consistent with the attribute's type. - *

    * - * @param vals some new values to be added which may be null - * @return the number of added values, or 0 if none has been added + * @param vals the values + * @return true if this attribute contains all the values, otherwise false */ - public int add( byte[]... vals ) + public boolean contains( String... vals ) { - if ( !isHR ) + if ( isHR ) { - int nbAdded = 0; - - for ( byte[] val:vals ) + // Iterate through all the values, and quit if we + // don't find one in the values + for ( String val:vals ) { - if ( add( new ServerBinaryValue( attributeType, val ) ) != 0 ) - { - nbAdded++; - } - else + ServerStringValue value = new ServerStringValue( attributeType, val ); + + if ( !values.contains( value ) ) { - LOG.error( "The value '" + val + "' is incorrect, it hasn't been added" ); + return false; } } - return nbAdded; + return true; } else { - // We can't add Binary values into a String serverAttribute - return 0; + return false; } - } + } /** - * Remove all the values from this attribute type, including a - * null value. - */ - public void clear() - { - values.clear(); - } - - - /** *

    * Indicates whether the specified values are some of the attribute's values. *

    @@ -840,230 +657,667 @@ return false; } } - } - else - { - for ( Value val:vals ) + } + else + { + for ( Value val:vals ) + { + if ( val instanceof ClientBinaryValue ) + { + if ( !values.contains( val ) ) + { + return false; + } + } + else + { + // Not a Binary value + return false; + } + } + } + + return true; + } + + + /** + * Get the attribute type associated with this ServerAttribute. + * + * @return the attributeType associated with this entry attribute + */ + public AttributeType getAttributeType() + { + return attributeType; + } + + + /** + *

    + * Check if the current attribute type is of the expected attributeType + *

    + *

    + * This method won't tell if the current attribute is a descendant of + * the attributeType. For instance, the "CN" serverAttribute will return + * false if we ask if it's an instance of "Name". + *

    + * + * @param attributeId The AttributeType ID to check + * @return True if the current attribute is of the expected attributeType + * @throws InvalidAttributeValueException If there is no AttributeType + */ + public boolean instanceOf( String attributeId ) throws InvalidAttributeValueException + { + String trimmedId = StringTools.trim( attributeId ); + + if ( StringTools.isEmpty( trimmedId ) ) + { + return false; + } + + String normId = StringTools.lowerCaseAscii( trimmedId ); + + for ( String name:attributeType.getNamesRef() ) + { + if ( normId.equalsIgnoreCase( name ) ) + { + return true; + } + } + + return normId.equalsIgnoreCase( attributeType.getOid() ); + } + + + /** + *

    + * Checks to see if this attribute is valid along with the values it contains. + *

    + *

    + * An attribute is valid if : + *

  • All of its values are valid with respect to the attributeType's syntax checker
  • + *
  • If the attributeType is SINGLE-VALUE, then no more than a value should be present
  • + *

    + * @return true if the attribute and it's values are valid, false otherwise + * @throws NamingException if there is a failure to check syntaxes of values + */ + public boolean isValid() throws NamingException + { + // First check if the attribute has more than one value + // if the attribute is supposed to be SINGLE_VALUE + if ( attributeType.isSingleValue() && ( values.size() > 1 ) ) + { + return false; + } + + for ( Value value : values ) + { + if ( ! value.isValid() ) + { + return false; + } + } + + return true; + } + + + /** + * @see EntryAttribute#remove(byte[]...) + * + * @return true if all the values shave been removed from this attribute + */ + public boolean remove( byte[]... vals ) + { + if ( isHR ) + { + return false; + } + + boolean removed = true; + + for ( byte[] val:vals ) + { + ServerBinaryValue value = new ServerBinaryValue( attributeType, val ); + removed &= values.remove( value ); + } + + return removed; + } + + + /** + * @see EntryAttribute#remove(String...) + * + * @return true if all the values shave been removed from this attribute + */ + public boolean remove( String... vals ) + { + if ( !isHR ) + { + return false; + } + + boolean removed = true; + + for ( String val:vals ) + { + ServerStringValue value = new ServerStringValue( attributeType, val ); + removed &= values.remove( value ); + } + + return removed; + } + + + /** + * @see EntryAttribute#remove(org.apache.directory.shared.ldap.entry.Value...) + * + * @return true if all the values shave been removed from this attribute + */ + public boolean remove( Value... vals ) + { + boolean removed = true; + + // Loop through all the values to remove. If one of + // them is not present, the method will return false. + // As the attribute may be HR or not, we have two separated treatments + if ( isHR ) + { + for ( Value val:vals ) + { + if ( val instanceof ClientStringValue ) + { + ServerStringValue ssv = new ServerStringValue( attributeType, (String)val.get() ); + removed &= values.remove( ssv ); + } + else if ( val instanceof ServerStringValue ) + { + removed &= values.remove( val ); + } + else + { + removed = false; + } + } + } + else + { + for ( Value val:vals ) + { + if ( val instanceof ClientBinaryValue ) + { + ServerBinaryValue sbv = new ServerBinaryValue( attributeType, (byte[])val.get() ); + removed &= values.remove( sbv ); + } + else if ( val instanceof ServerBinaryValue ) + { + removed &= values.remove( val ); + } + else + { + removed = false; + } + } + } + + return removed; + } + + + + /** + *

    + * Set the attribute type associated with this ServerAttribute. + *

    + *

    + * The current attributeType will be replaced. It is the responsibility of + * the caller to insure that the existing values are compatible with the new + * AttributeType + *

    + * + * @param attributeType the attributeType associated with this entry attribute + */ + public void setAttributeType( AttributeType attributeType ) + { + if ( attributeType == null ) + { + throw new IllegalArgumentException( "The AttributeType parameter should not be null" ); + } + + this.attributeType = attributeType; + setUpId( null, attributeType ); + + try + { + if ( attributeType.getSyntax().isHumanReadable() ) + { + isHR = true; + } + else + { + isHR = false; + } + } + catch ( NamingException ne ) + { + // If we have an exception while trying to get the Syntax for this attribute + // just set it as Binary + isHR = false; + } + } + + + /** + *

    + * Overload the ClientAttribte isHR method : we can't change this flag + * for a ServerAttribute, as the HR is already set using the AttributeType. + * Set the attribute to Human Readable or to Binary. + *

    + * + * @param isHR true for a Human Readable attribute, + * false for a Binary attribute. + */ + public void setHR( boolean isHR ) + { + // Do nothing... + } + + + /** + *

    + * Overload the {@link DefaultClientAttribute#setId(String)} method. + *

    + *

    + * As the attributeType has already been set, we have to be sure that the + * argument is compatible with the attributeType's name. + *

    + *

    + * If the given ID is not compatible with the attributeType's possible + * names, the previously loaded ID will be kept. + *

    + * + * @param id The attribute ID + */ + public void setId( String id ) + { + if ( !StringTools.isEmpty( StringTools.trim( id ) ) ) + { + if ( attributeType.getName() == null ) + { + // If the name is null, then we may have to store an OID + if ( OID.isOID( id ) && attributeType.getOid().equals( id ) ) + { + // Everything is fine, store the upId. + // This should not happen... + super.setId( id ); + } + } + else + { + // We have at least one name. Check that the normalized upId + // is one of those names. Otherwise, the upId may be an OID too. + // In this case, it must be equals to the attributeType OID. + String normId = StringTools.lowerCaseAscii( StringTools.trim( id ) ); + + for ( String atName:attributeType.getNamesRef() ) + { + if ( atName.equalsIgnoreCase( normId ) ) + { + // Found ! We can store the upId and get out + super.setId( normId ); + return; + } + } + + // Last case, the UpId is an OID + if ( OID.isOID( normId ) && attributeType.getOid().equals( normId ) ) + { + // We have an OID : stores it + super.setUpId( normId ); + } + else + { + // The id is incorrect : this is not allowed + throw new IllegalArgumentException( "The ID '" + id + "'is incompatible with the AttributeType's id '" + + attributeType.getName() + "'" ); + } + } + } + else + { + throw new IllegalArgumentException( "An ID cannnot be null, empty, or resolved to an emtpy" + + " value when trimmed" ); + } + } + + + /** + *

    + * Overload the {@link DefaultClientAttribute#setUpId(String)} method. + *

    + *

    + * As the attributeType has already been set, we have to be sure that the + * argument is compatible with the attributeType's name. + *

    + *

    + * If the given ID is not compatible with the attributeType's possible + * names, the previously loaded ID will be kept. + *

    + * + * @param upId The attribute ID + */ + public void setUpId( String upId ) + { + if ( !StringTools.isEmpty( StringTools.trim( upId ) ) ) + { + if ( attributeType.getName() == null ) + { + // If the name is null, then we may have to store an OID + if ( OID.isOID( upId ) && attributeType.getOid().equals( upId ) ) + { + // Everything is fine, store the upId. + // This should not happen... + super.setUpId( upId ); + + } + } + else + { + // We have at least one name. Check that the normalized upId + // is one of those names. Otherwise, the upId may be an OID too. + // In this case, it must be equals to the attributeType OID. + String normUpId = StringTools.lowerCaseAscii( StringTools.trim( upId ) ); + + for ( String atId:attributeType.getNamesRef() ) + { + if ( atId.equalsIgnoreCase( normUpId ) ) + { + // Found ! We can store the upId and get out + super.setUpId( upId ); + return; + } + } + + // Last case, the UpId is an OID + if ( OID.isOID( normUpId ) && attributeType.getOid().equals( normUpId ) ) + { + // We have an OID : stores it + super.setUpId( upId ); + } + } + } + } + + + /** + *

    + * Set the user provided ID. If we have none, the upId is assigned + * the attributetype's name. If it does not have any name, we will + * use the OID. + *

    + *

    + * If we have an upId and an AttributeType, they must be compatible. : + * - if the upId is an OID, it must be the AttributeType's OID + * - otherwise, its normalized form must be equals to ones of + * the attributeType's names. + *

    + *

    + * In any case, the ATtributeType will be changed. The caller is responsible for + * the present values to be compatoble with the new AttributeType. + *

    + * + * @param upId The attribute ID + * @param attributeType The associated attributeType + */ + public void setUpId( String upId, AttributeType attributeType ) + { + if ( StringTools.isEmpty( StringTools.trim( upId ) ) ) + { + super.setUpId( getUpId( attributeType ) ); + this.attributeType = attributeType; + } + else + { + String name = attributeType.getName(); + + if ( name == null ) + { + // If the name is null, then we may have to store an OID + if ( OID.isOID( upId ) && attributeType.getOid().equals( upId ) ) + { + // Everything is fine, store the upId. + super.setUpId( upId ); + this.attributeType = attributeType; + } + else + { + // We have a difference or the upId is not a valid OID : + // we will use the attributeTypeOID in this case. + LOG.warn( "The upID ({}) is not an OID or is different from the AttributeType OID({})", + upId, attributeType.getOid() ); + super.setUpId( attributeType.getOid() ); + this.attributeType = attributeType; + } + } + else { - if ( val instanceof ClientBinaryValue ) + // We have at least one name. Check that the normalized upId + // is one of those names. Otherwise, the upId may be an OID too. + // In this case, it must be equals to the attributeType OID. + String normUpId = StringTools.lowerCaseAscii( StringTools.trim( upId ) ); + + for ( String atId:attributeType.getNamesRef() ) { - if ( !values.contains( val ) ) + if ( atId.equalsIgnoreCase( normUpId ) ) { - return false; + // Found ! We can store the upId and get out + super.setUpId( upId ); + this.attributeType = attributeType; + return; } } + + // UpId was not found in names. It should be an OID, or if not, we + // will use the AttributeType name. + if ( OID.isOID( normUpId ) && attributeType.getOid().equals( normUpId ) ) + { + // We have an OID : stores it + super.setUpId( upId ); + this.attributeType = attributeType; + } else { - // Not a Binary value - return false; + String message = "The upID (" + upId + ") is not an OID or is different from the AttributeType OID (" + + attributeType.getOid() + ")"; + // Not a valid OID : use the AttributeTypes OID name instead + LOG.error( message ); + throw new IllegalArgumentException( message ); } } } - - return true; } /** - *

    - * Indicates whether all the specified values are attribute's values. If - * at least one value is not an attribute's value, this method will return - * false - *

    - *

    - * If the Attribute is not HR, this method will returns false - *

    + * Convert the ServerAttribute to a ClientAttribute * - * @param vals the values - * @return true if this attribute contains all the values, otherwise false + * @return An instance of ClientAttribute */ - public boolean contains( String... vals ) + public EntryAttribute toClientAttribute() { - if ( isHR ) + // Create the new EntryAttribute + EntryAttribute clientAttribute = new DefaultClientAttribute( upId ); + + // Copy the values + for ( Value value:this ) { - // Iterate through all the values, and quit if we - // don't find one in the values - for ( String val:vals ) + Value clientValue = null; + + if ( value instanceof ServerStringValue ) { - ServerStringValue value = new ServerStringValue( attributeType, val ); - - if ( !values.contains( value ) ) - { - return false; - } + clientValue = new ClientStringValue( (String)value.get() ); + } + else + { + clientValue = new ClientBinaryValue( (byte[])value.get() ); } - return true; - } - else - { - return false; + clientAttribute.add( clientValue ); } + + return clientAttribute; } - + + + //------------------------------------------------------------------------- + // Serialization methods + //------------------------------------------------------------------------- /** - *

    - * Indicates whether all the specified values are attribute's values. If - * at least one value is not an attribute's value, this method will return - * false - *

    - *

    - * If the Attribute is HR, this method will returns false - *

    - * - * @param vals the values - * @return true if this attribute contains all the values, otherwise false + * @see java.io.Externalizable#writeExternal(ObjectOutput) + * + * We can't use this method for a ServerAttribute, as we have to feed the value + * with an AttributeType object */ - public boolean contains( byte[]... vals ) + public void writeExternal( ObjectOutput out ) throws IOException { - if ( !isHR ) - { - // Iterate through all the values, and quit if we - // don't find one in the values - for ( byte[] val:vals ) - { - ServerBinaryValue value = new ServerBinaryValue( attributeType, val ); - - if ( !values.contains( value ) ) - { - return false; - } - } - - return true; - } - else - { - return false; - } + throw new IllegalStateException( "Cannot use standard serialization for a ServerAttribute" ); } /** - * @see EntryAttribute#remove(org.apache.directory.shared.ldap.entry.Value...) + * @see Externalizable#writeExternal(ObjectOutput) + *

    + * + * This is the place where we serialize attributes, and all theirs + * elements. + * + * The inner structure is the same as the client attribute, but we can't call + * it as we won't be able to serialize the serverValues * - * @return true if all the values shave been removed from this attribute */ - public boolean remove( Value... vals ) + public void serialize( ObjectOutput out ) throws IOException { - boolean removed = true; + // Write the UPId (the id will be deduced from the upID) + out.writeUTF( upId ); - // Loop through all the values to remove. If one of - // them is not present, the method will return false. - // As the attribute may be HR or not, we have two separated treatments - if ( isHR ) + // Write the HR flag, if not null + if ( isHR != null ) { - for ( Value val:vals ) - { - if ( val instanceof ClientStringValue ) - { - ServerStringValue ssv = new ServerStringValue( attributeType, (String)val.get() ); - removed &= values.remove( ssv ); - } - else if ( val instanceof ServerStringValue ) - { - removed &= values.remove( val ); - } - else - { - removed = false; - } - } + out.writeBoolean( true ); + out.writeBoolean( isHR ); } else { - for ( Value val:vals ) + out.writeBoolean( false ); + } + + // Write the number of values + out.writeInt( size() ); + + if ( size() > 0 ) + { + // Write each value + for ( Value value:values ) { - if ( val instanceof ClientBinaryValue ) - { - ServerBinaryValue sbv = new ServerBinaryValue( attributeType, (byte[])val.get() ); - removed &= values.remove( sbv ); - } - else if ( val instanceof ServerBinaryValue ) + // Write the value, using the correct method + if ( value instanceof ServerStringValue ) { - removed &= values.remove( val ); + ((ServerStringValue)value).serialize( out ); } else { - removed = false; + ((ServerBinaryValue)value).serialize( out ); } } } - return removed; + out.flush(); } - + /** - * @see EntryAttribute#remove(byte[]...) + * @see java.io.Externalizable#readExternal(ObjectInput) * - * @return true if all the values shave been removed from this attribute + * We can't use this method for a ServerAttribute, as we have to feed the value + * with an AttributeType object */ - public boolean remove( byte[]... vals ) + public void readExternal( ObjectInput in ) throws IOException, ClassNotFoundException { - if ( isHR ) - { - return false; - } - - boolean removed = true; - - for ( byte[] val:vals ) - { - ServerBinaryValue value = new ServerBinaryValue( attributeType, val ); - removed &= values.remove( value ); - } - - return removed; + throw new IllegalStateException( "Cannot use standard serialization for a ServerAttribute" ); } - - + + /** - * @see EntryAttribute#remove(String...) - * - * @return true if all the values shave been removed from this attribute + * @see Externalizable#readExternal(ObjectInput) */ - public boolean remove( String... vals ) + public void deserialize( ObjectInput in ) throws IOException, ClassNotFoundException { - if ( !isHR ) - { - return false; - } + // Read the ID and the UPId + upId = in.readUTF(); - boolean removed = true; + // Compute the id + setUpId( upId ); - for ( String val:vals ) + // Read the HR flag, if not null + if ( in.readBoolean() ) { - ServerStringValue value = new ServerStringValue( attributeType, val ); - removed &= values.remove( value ); + isHR = in.readBoolean(); } - - return removed; - } + // Read the number of values + int nbValues = in.readInt(); + if ( nbValues > 0 ) + { + for ( int i = 0; i < nbValues; i++ ) + { + Value value = null; + + if ( isHR ) + { + value = new ServerStringValue( attributeType ); + ((ServerStringValue)value).deserialize( in ); + } + else + { + value = new ServerBinaryValue( attributeType ); + ((ServerBinaryValue)value).deserialize( in ); + } + + try + { + value.normalize(); + } + catch ( NamingException ne ) + { + // Do nothing... + } + + values.add( value ); + } + } + } + + //------------------------------------------------------------------------- - // Overloaded Object classes + // Overloaded Object class methods //------------------------------------------------------------------------- /** - * The hashCode is based on the id, the isHR flag and - * on the internal values. - * - * @see Object#hashCode() + * Clone an attribute. All the element are duplicated, so a modification on + * the original object won't affect the cloned object, as a modification + * on the cloned object has no impact on the original object * - * @return the instance's hash code + * @return a clone of the current attribute */ - public int hashCode() + public ServerAttribute clone() { - int h = super.hashCode(); - - if ( attributeType != null ) - { - h = h*17 + attributeType.hashCode(); - } + // clone the structure by cloner the inherited class + ServerAttribute clone = (ServerAttribute)super.clone(); - return h; + // We are done ! + return clone; } @@ -1109,6 +1363,27 @@ /** + * The hashCode is based on the id, the isHR flag and + * on the internal values. + * + * @see Object#hashCode() + * + * @return the instance's hash code + */ + public int hashCode() + { + int h = super.hashCode(); + + if ( attributeType != null ) + { + h = h*17 + attributeType.hashCode(); + } + + return h; + } + + + /** * @see Object#toString() * * @return A String representation of this instance