blob: 2fcdf62863c20a60ad69608fa0884a9ccf6a1451 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/
package org.apache.directory.api.ldap.model.name;
import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.Arrays;
import org.apache.directory.api.i18n.I18n;
import org.apache.directory.api.ldap.model.entry.BinaryValue;
import org.apache.directory.api.ldap.model.entry.StringValue;
import org.apache.directory.api.ldap.model.entry.Value;
import org.apache.directory.api.ldap.model.exception.LdapException;
import org.apache.directory.api.ldap.model.exception.LdapInvalidAttributeValueException;
import org.apache.directory.api.ldap.model.exception.LdapInvalidDnException;
import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
import org.apache.directory.api.ldap.model.schema.AttributeType;
import org.apache.directory.api.ldap.model.schema.LdapComparator;
import org.apache.directory.api.ldap.model.schema.MatchingRule;
import org.apache.directory.api.ldap.model.schema.SchemaManager;
import org.apache.directory.api.util.Serialize;
import org.apache.directory.api.util.Strings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* A Attribute Type And Value, which is the basis of all Rdn. It contains a
* type, and a value. The type must not be case sensitive. Superfluous leading
* and trailing spaces MUST have been trimmed before. The value MUST be in UTF8
* format, according to RFC 2253. If the type is in OID form, then the value
* must be a hexadecimal string prefixed by a '#' character. Otherwise, the
* string must respect the RC 2253 grammar.
*
* We will also keep a User Provided form of the AVA (Attribute Type And Value),
* called upName.
*
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
*/
public class Ava implements Externalizable, Cloneable, Comparable<Ava>
{
/**
* Declares the Serial Version Uid.
*
* @see <a
* href="http://c2.com/cgi/wiki?AlwaysDeclareSerialVersionUid">Always
* Declare Serial Version Uid</a>
*/
private static final long serialVersionUID = 1L;
/** The LoggerFactory used by this class */
private static final Logger LOG = LoggerFactory.getLogger( Ava.class );
/** The normalized Name type */
private String normType;
/** The user provided Name type */
private String upType;
/** The value. It can be a String or a byte array */
private Value<?> value;
/** The user provided Ava */
private String upName;
/** The attributeType if the Ava is schemaAware */
private AttributeType attributeType;
/** the schema manager */
private SchemaManager schemaManager;
/** The computed hashcode */
private volatile int h;
/**
* Constructs an empty Ava
*/
public Ava()
{
this( null );
}
/**
* Constructs an empty schema aware Ava.
*
* @param schemaManager The SchemaManager instance
*/
public Ava( SchemaManager schemaManager )
{
normType = null;
upType = null;
value = null;
upName = "";
this.schemaManager = schemaManager;
this.attributeType = null;
}
/**
* Construct an Ava containing a binary value.
* <p>
* Note that the upValue should <b>not</b> be null or empty, or resolve
* to an empty string after having trimmed it.
*
* @param upType The User Provided type
* @param upValue The User Provided binary value
*
* @throws LdapInvalidDnException If the given type or value are invalid
*/
public Ava( String upType, byte[] upValue ) throws LdapInvalidDnException
{
this( null, upType, upValue );
}
/**
* Construct a schema aware Ava containing a binary value. The AttributeType
* and value will be normalized accordingly to the given SchemaManager.
* <p>
* Note that the upValue should <b>not</b> be null or empty, or resolve
* to an empty string after having trimmed it.
*
* @param schemaManager The SchemaManager instance
* @param upType The User Provided type
* @param upValue The User Provided binary value
*
* @throws LdapInvalidDnException If the given type or value are invalid
*/
public Ava( SchemaManager schemaManager, String upType, byte[] upValue ) throws LdapInvalidDnException
{
if ( schemaManager != null )
{
this.schemaManager = schemaManager;
try
{
attributeType = schemaManager.lookupAttributeTypeRegistry( upType );
}
catch ( LdapException le )
{
String message = I18n.err( I18n.ERR_04188 );
LOG.error( message );
throw new LdapInvalidDnException( ResultCodeEnum.INVALID_DN_SYNTAX, message, le );
}
try
{
createAva( schemaManager, upType, new BinaryValue( attributeType, upValue ) );
}
catch ( LdapInvalidAttributeValueException liave )
{
String message = I18n.err( I18n.ERR_04188 );
LOG.error( message );
throw new LdapInvalidDnException( ResultCodeEnum.INVALID_DN_SYNTAX, message, liave );
}
}
else
{
createAva( upType, new BinaryValue( upValue ) );
}
}
/**
* Construct an Ava with a String value.
* <p>
* Note that the upValue should <b>not</b> be null or empty, or resolve
* to an empty string after having trimmed it.
*
* @param upType The User Provided type
* @param upValue The User Provided String value
*
* @throws LdapInvalidDnException If the given type or value are invalid
*/
public Ava( String upType, String upValue ) throws LdapInvalidDnException
{
this( null, upType, upValue );
}
/**
* Construct a schema aware Ava with a String value.
* <p>
* Note that the upValue should <b>not</b> be null or empty, or resolve
* to an empty string after having trimmed it.
*
* @param schemaManager The SchemaManager instance
* @param upType The User Provided type
* @param upValue The User Provided String value
*
* @throws LdapInvalidDnException If the given type or value are invalid
*/
public Ava( SchemaManager schemaManager, String upType, String upValue ) throws LdapInvalidDnException
{
if ( schemaManager != null )
{
this.schemaManager = schemaManager;
try
{
attributeType = schemaManager.lookupAttributeTypeRegistry( upType );
}
catch ( LdapException le )
{
String message = I18n.err( I18n.ERR_04188 );
LOG.error( message );
throw new LdapInvalidDnException( ResultCodeEnum.INVALID_DN_SYNTAX, message, le );
}
try
{
createAva( schemaManager, upType, new StringValue( attributeType, upValue ) );
}
catch ( LdapInvalidAttributeValueException liave )
{
String message = I18n.err( I18n.ERR_04188 );
LOG.error( message );
throw new LdapInvalidDnException( ResultCodeEnum.INVALID_DN_SYNTAX, message, liave );
}
}
else
{
createAva( upType, new StringValue( upValue ) );
}
}
/**
* Construct a schema aware Ava. The AttributeType and value will be checked accordingly
* to the SchemaManager.
* <p>
* Note that the upValue should <b>not</b> be null or empty, or resolve
* to an empty string after having trimmed it.
*
* @param schemaManager The SchemaManager instance
* @param upType The User Provided type
* @param value The value
*
* @throws LdapInvalidDnException If the given type or value are invalid
*/
private void createAva( SchemaManager schemaManager, String upType, Value<?> value )
throws LdapInvalidDnException
{
normType = attributeType.getOid();
this.upType = upType;
this.value = value;
upName = this.upType + '=' + ( value == null ? "" : Rdn.escapeValue( value.getString() ) );
hashCode();
}
/**
* Construct an Ava. The type and value are normalized :
* <li> the type is trimmed and lowercased </li>
* <li> the value is trimmed </li>
* <p>
* Note that the upValue should <b>not</b> be null or empty, or resolved
* to an empty string after having trimmed it.
*
* @param upType The User Provided type
* @param upValue The User Provided value
*
* @throws LdapInvalidDnException If the given type or value are invalid
*/
private void createAva( String upType, Value<?> upValue ) throws LdapInvalidDnException
{
String upTypeTrimmed = Strings.trim( upType );
String normTypeTrimmed = Strings.trim( normType );
if ( Strings.isEmpty( upTypeTrimmed ) )
{
if ( Strings.isEmpty( normTypeTrimmed ) )
{
String message = I18n.err( I18n.ERR_04188 );
LOG.error( message );
throw new LdapInvalidDnException( ResultCodeEnum.INVALID_DN_SYNTAX, message );
}
else
{
// In this case, we will use the normType instead
this.normType = Strings.lowerCaseAscii( normTypeTrimmed );
this.upType = normType;
}
}
else if ( Strings.isEmpty( normTypeTrimmed ) )
{
// In this case, we will use the upType instead
this.normType = Strings.lowerCaseAscii( upTypeTrimmed );
this.upType = upType;
}
else
{
this.normType = Strings.lowerCaseAscii( normTypeTrimmed );
this.upType = upType;
}
value = upValue;
upName = this.upType + '=' + ( value == null ? "" : Rdn.escapeValue( value.getString() ) );
hashCode();
}
/**
* Construct an Ava. The type and value are normalized :
* <li> the type is trimmed and lowercased </li>
* <li> the value is trimmed </li>
* <p>
* Note that the upValue should <b>not</b> be null or empty, or resolved
* to an empty string after having trimmed it.
*
* @param schemaManager The SchemaManager
* @param upType The User Provided type
* @param normType The normalized type
* @param value The value
*
* @throws LdapInvalidDnException If the given type or value are invalid
*/
// WARNING : The protection level is left unspecified intentionally.
// We need this method to be visible from the DnParser class, but not
// from outside this package.
/* Unspecified protection */Ava( SchemaManager schemaManager, String upType, String normType, Value<?> value )
throws LdapInvalidDnException
{
this.upType = upType;
this.normType = normType;
this.value = value;
upName = this.upType + '=' + ( this.value == null ? "" : this.value.getString() );
if ( schemaManager != null )
{
apply( schemaManager );
}
hashCode();
}
/**
* Construct an Ava. The type and value are normalized :
* <li> the type is trimmed and lowercased </li>
* <li> the value is trimmed </li>
* <p>
* Note that the upValue should <b>not</b> be null or empty, or resolved
* to an empty string after having trimmed it.
*
* @param upType The User Provided type
* @param normType The normalized type
* @param value The User Provided value
* @param upName The User Provided name (may be escaped)
*
* @throws LdapInvalidDnException If the given type or value are invalid
*/
// WARNING : The protection level is left unspecified intentionally.
// We need this method to be visible from the DnParser class, but not
// from outside this package.
/* Unspecified protection */Ava( String upType, String normType, Value<?> value, String upName )
throws LdapInvalidDnException
{
this( null, upType, normType, value, upName );
}
/**
* Construct an Ava. The type and value are normalized :
* <li> the type is trimmed and lowercased </li>
* <li> the value is trimmed </li>
* <p>
* Note that the upValue should <b>not</b> be null or empty, or resolved
* to an empty string after having trimmed it.
*
* @param attributeType The AttributeType for this value
* @param upType The User Provided type
* @param normType The normalized type
* @param value The value
* @param upName The User Provided name (may be escaped)
*
* @throws LdapInvalidDnException If the given type or value are invalid
*/
// WARNING : The protection level is left unspecified intentionally.
// We need this method to be visible from the DnParser class, but not
// from outside this package.
/* Unspecified protection */Ava( AttributeType attributeType, String upType, String normType, Value<?> value, String upName )
throws LdapInvalidDnException
{
this.attributeType = attributeType;
String upTypeTrimmed = Strings.trim( upType );
String normTypeTrimmed = Strings.trim( normType );
if ( Strings.isEmpty( upTypeTrimmed ) )
{
if ( Strings.isEmpty( normTypeTrimmed ) )
{
String message = I18n.err( I18n.ERR_04188 );
LOG.error( message );
throw new LdapInvalidDnException( ResultCodeEnum.INVALID_DN_SYNTAX, message );
}
else
{
// In this case, we will use the normType instead
this.normType = Strings.lowerCaseAscii( normTypeTrimmed );
this.upType = normType;
}
}
else if ( Strings.isEmpty( normTypeTrimmed ) )
{
// In this case, we will use the upType instead
this.normType = Strings.lowerCaseAscii( upTypeTrimmed );
this.upType = upType;
}
else
{
this.normType = Strings.lowerCaseAscii( normTypeTrimmed );
this.upType = upType;
}
this.value = value;
this.upName = upName;
hashCode();
}
/**
* Apply a SchemaManager to the Ava. It will normalize the Ava.<br/>
* If the Ava already had a SchemaManager, then the new SchemaManager will be
* used instead.
*
* @param schemaManager The SchemaManager instance to use
* @throws LdapInvalidDnException If the Ava can't be normalized accordingly
* to the given SchemaManager
*/
public void apply( SchemaManager schemaManager ) throws LdapInvalidDnException
{
if ( schemaManager != null )
{
this.schemaManager = schemaManager;
AttributeType tmpAttributeType = null;
try
{
tmpAttributeType = schemaManager.lookupAttributeTypeRegistry( normType );
}
catch ( LdapException le )
{
String message = I18n.err( I18n.ERR_04188 );
LOG.error( message );
throw new LdapInvalidDnException( ResultCodeEnum.INVALID_DN_SYNTAX, message, le );
}
if ( this.attributeType == tmpAttributeType )
{
// No need to normalize again
return;
}
else
{
this.attributeType = tmpAttributeType;
}
normType = tmpAttributeType.getOid();
try
{
this.value.apply( tmpAttributeType );
}
catch ( LdapException le )
{
String message = I18n.err( I18n.ERR_04188 );
LOG.error( message );
throw new LdapInvalidDnException( ResultCodeEnum.INVALID_DN_SYNTAX, message, le );
}
hashCode();
}
}
/**
* Get the normalized type of a Ava
*
* @return The normalized type
*/
public String getNormType()
{
return normType;
}
/**
* Get the user provided type of a Ava
*
* @return The user provided type
*/
public String getType()
{
return upType;
}
/**
* Get the Value of a Ava
*
* @return The value
*/
public Value<?> getValue()
{
return value.clone();
}
/**
* Get the normalized Name of a Ava
*
* @return The name
*/
public String getNormName()
{
return normalize();
}
/**
* Get the user provided form of this attribute type and value
*
* @return The user provided form of this ava
*/
public String getName()
{
return upName;
}
/**
* Implements the cloning.
*
* @return a clone of this object
*/
public Ava clone()
{
try
{
Ava clone = ( Ava ) super.clone();
clone.value = value.clone();
return clone;
}
catch ( CloneNotSupportedException cnse )
{
throw new Error( "Assertion failure", cnse );
}
}
/**
* A Normalized String representation of a Ava :
* <ul>
* <li>type is trimed and lowercased</li>
* <li>value is trimed and lowercased, and special characters are escaped if needed.</li>
* </ul>
*
* @return A normalized string representing an Ava
*/
public String normalize()
{
if ( value.isHumanReadable() )
{
// The result will be gathered in a stringBuilder
StringBuilder sb = new StringBuilder();
// First, store the type and the '=' char
sb.append( normType ).append( '=' );
String normalizedValue = ( String ) value.getNormValue();
if ( ( normalizedValue != null ) && ( normalizedValue.length() > 0 ) )
{
sb.append( Rdn.escapeValue( normalizedValue ) );
}
return sb.toString();
}
else
{
return normType + "=#"
+ Strings.dumpHexPairs( value.getBytes() );
}
}
/**
* Gets the hashcode of this object.
*
* @see java.lang.Object#hashCode()
* @return The instance hash code
*/
public int hashCode()
{
if ( h == 0 )
{
h = 37;
h = h * 17 + ( normType != null ? normType.hashCode() : 0 );
h = h * 17 + ( value != null ? value.hashCode() : 0 );
}
return h;
}
/**
* @see Object#equals(Object)
*/
public boolean equals( Object obj )
{
if ( this == obj )
{
return true;
}
if ( !( obj instanceof Ava ) )
{
return false;
}
Ava instance = ( Ava ) obj;
// Compare the type
if ( normType == null )
{
if ( instance.normType != null )
{
return false;
}
}
else
{
if ( !normType.equals( instance.normType ) )
{
return false;
}
}
// Compare the values
if ( value.isNull() )
{
return instance.value.isNull();
}
else
{
if ( schemaManager != null )
{
MatchingRule equalityMatchingRule = attributeType.getEquality();
if ( equalityMatchingRule != null )
{
return equalityMatchingRule.getLdapComparator().compare( value.getValue(),
instance.value.getValue() ) == 0;
}
else
{
// No Equality MR, use a direct comparison
if ( value instanceof BinaryValue )
{
return Arrays.equals( value.getBytes(), instance.value.getBytes() );
}
else
{
return value.getString().equals( instance.value.getString() );
}
}
}
else
{
return value.equals( instance.value );
}
}
}
/**
* Serialize the AVA into a buffer at the given position.
*
* @param buffer The buffer which will contain the serialized Ava
* @param pos The position in the buffer for the serialized value
* @return The new position in the buffer
*/
public int serialize( byte[] buffer, int pos ) throws IOException
{
if ( Strings.isEmpty( upName )
|| Strings.isEmpty( upType )
|| Strings.isEmpty( normType )
|| ( value.isNull() )
|| ( value.isNull() ) )
{
String message = "Cannot serialize an wrong ATAV, ";
if ( Strings.isEmpty( upName ) )
{
message += "the upName should not be null or empty";
}
else if ( Strings.isEmpty( upType ) )
{
message += "the upType should not be null or empty";
}
else if ( Strings.isEmpty( normType ) )
{
message += "the normType should not be null or empty";
}
else if ( value.isNull() )
{
message += "the value should not be null";
}
LOG.error( message );
throw new IOException( message );
}
int length = 0;
// The upName
byte[] upNameBytes = null;
if ( upName != null )
{
upNameBytes = Strings.getBytesUtf8( upName );
length += 1 + 4 + upNameBytes.length;
}
// The upType
byte[] upTypeBytes = null;
if ( upType != null )
{
upTypeBytes = Strings.getBytesUtf8( upType );
length += 1 + 4 + upTypeBytes.length;
}
// The normType
byte[] normTypeBytes = null;
if ( normType != null )
{
normTypeBytes = Strings.getBytesUtf8( normType );
length += 1 + 4 + normTypeBytes.length;
}
// Is HR
length++;
// The hash code
length += 4;
// Check that we will be able to store the data in the buffer
if ( buffer.length - pos < length )
{
throw new ArrayIndexOutOfBoundsException();
}
// Write the upName
if ( upName != null )
{
buffer[pos++] = Serialize.TRUE;
pos = Serialize.serialize( upNameBytes, buffer, pos );
}
else
{
buffer[pos++] = Serialize.FALSE;
}
// Write the upType
if ( upType != null )
{
buffer[pos++] = Serialize.TRUE;
pos = Serialize.serialize( upTypeBytes, buffer, pos );
}
else
{
buffer[pos++] = Serialize.FALSE;
}
// Write the normType
if ( normType != null )
{
buffer[pos++] = Serialize.TRUE;
pos = Serialize.serialize( normTypeBytes, buffer, pos );
}
else
{
buffer[pos++] = Serialize.FALSE;
}
// Write the isHR flag
if ( value.isHumanReadable() )
{
buffer[pos++] = Serialize.TRUE;
}
else
{
buffer[pos++] = Serialize.FALSE;
}
// Write the upValue
if ( value.isHumanReadable() )
{
pos = ( ( StringValue ) value ).serialize( buffer, pos );
}
// Write the hash code
pos = Serialize.serialize( h, buffer, pos );
return pos;
}
/**
* Deserialize an AVA from a byte[], starting at a given position
*
* @param buffer The buffer containing the AVA
* @param pos The position in the buffer
* @return The new position
* @throws IOException If the serialized value is not an AVA
* @throws LdapInvalidAttributeValueException If the serialized AVA is invalid
*/
public int deserialize( byte[] buffer, int pos ) throws IOException, LdapInvalidAttributeValueException
{
if ( ( pos < 0 ) || ( pos >= buffer.length ) )
{
throw new ArrayIndexOutOfBoundsException();
}
// Read the upName value, if it's not null
boolean hasUpName = Serialize.deserializeBoolean( buffer, pos );
pos++;
if ( hasUpName )
{
byte[] wrappedValueBytes = Serialize.deserializeBytes( buffer, pos );
pos += 4 + wrappedValueBytes.length;
upName = Strings.utf8ToString( wrappedValueBytes );
}
// Read the upType value, if it's not null
boolean hasUpType = Serialize.deserializeBoolean( buffer, pos );
pos++;
if ( hasUpType )
{
byte[] upTypeBytes = Serialize.deserializeBytes( buffer, pos );
pos += 4 + upTypeBytes.length;
upType = Strings.utf8ToString( upTypeBytes );
}
// Read the normType value, if it's not null
boolean hasNormType = Serialize.deserializeBoolean( buffer, pos );
pos++;
if ( hasNormType )
{
byte[] normTypeBytes = Serialize.deserializeBytes( buffer, pos );
pos += 4 + normTypeBytes.length;
normType = Strings.utf8ToString( normTypeBytes );
}
// Update the AtributeType
if ( schemaManager != null )
{
if ( !Strings.isEmpty( upType ) )
{
attributeType = schemaManager.getAttributeType( upType );
}
else
{
attributeType = schemaManager.getAttributeType( normType );
}
}
// Read the isHR flag
boolean isHR = Serialize.deserializeBoolean( buffer, pos );
pos++;
if ( isHR )
{
// Read the upValue
value = new StringValue( attributeType );
pos = ( ( StringValue ) value ).deserialize( buffer, pos );
}
// Read the hashCode
h = Serialize.deserializeInt( buffer, pos );
pos += 4;
return pos;
}
/**
*
* An Ava is composed of a type and a value.
* The data are stored following the structure :
* <ul>
* <li>
* <b>upName</b> The User provided ATAV
* </li>
* <li>
* <b>start</b> The position of this ATAV in the Dn
* </li>
* <li>
* <b>length</b> The ATAV length
* </li>
* <li>
* <b>upType</b> The user Provided Type
* </li>
* <li>
* <b>normType</b> The normalized AttributeType
* </li>
* <li>
* <b>isHR</b> Tells if the value is a String or not
* </li>
* </ul>
* <br/>
* if the value is a String :
* <ul>
* <li>
* <b>value</b> The value
* </li>
* </ul>
* <br/>
* if the value is binary :
* <ul>
* <li>
* <b>valueLength</b>
* </li>
* <li>
* <b>value</b> The value
* </li>
* </ul>
*
* @see Externalizable#readExternal(ObjectInput)
*
* @throws IoException If the Ava can't be written in the stream
*/
public void writeExternal( ObjectOutput out ) throws IOException
{
if ( Strings.isEmpty( upName )
|| Strings.isEmpty( upType )
|| Strings.isEmpty( normType )
|| ( value.isNull() ) )
{
String message = "Cannot serialize a wrong ATAV, ";
if ( Strings.isEmpty( upName ) )
{
message += "the upName should not be null or empty";
}
else if ( Strings.isEmpty( upType ) )
{
message += "the upType should not be null or empty";
}
else if ( Strings.isEmpty( normType ) )
{
message += "the normType should not be null or empty";
}
else if ( value.isNull() )
{
message += "the value should not be null";
}
LOG.error( message );
throw new IOException( message );
}
if ( upName != null )
{
out.writeBoolean( true );
out.writeUTF( upName );
}
else
{
out.writeBoolean( false );
}
if ( upType != null )
{
out.writeBoolean( true );
out.writeUTF( upType );
}
else
{
out.writeBoolean( false );
}
if ( normType != null )
{
out.writeBoolean( true );
out.writeUTF( normType );
}
else
{
out.writeBoolean( false );
}
boolean isHR = value.isHumanReadable();
out.writeBoolean( isHR );
value.writeExternal( out );
// Write the hashCode
out.writeInt( h );
out.flush();
}
/**
* We read back the data to create a new ATAV. The structure
* read is exposed in the {@link Ava#writeExternal(ObjectOutput)}
* method
*
* @see Externalizable#readExternal(ObjectInput)
*
* @throws IOException If the Ava can't b written to the stream
* @throws ClassNotFoundException If we can't deserialize an Ava from the stream
*/
public void readExternal( ObjectInput in ) throws IOException, ClassNotFoundException
{
boolean hasUpName = in.readBoolean();
if ( hasUpName )
{
upName = in.readUTF();
}
boolean hasUpType = in.readBoolean();
if ( hasUpType )
{
upType = in.readUTF();
}
boolean hasNormType = in.readBoolean();
if ( hasNormType )
{
normType = in.readUTF();
}
if ( schemaManager != null )
{
if ( !Strings.isEmpty( upType ) )
{
attributeType = schemaManager.getAttributeType( upType );
}
else
{
attributeType = schemaManager.getAttributeType( normType );
}
}
boolean isHR = in.readBoolean();
if ( isHR )
{
value = StringValue.deserialize( attributeType, in );
}
else
{
value = BinaryValue.deserialize( attributeType, in );
}
h = in.readInt();
if ( schemaManager != null )
{
attributeType = schemaManager.getAttributeType( upType );
}
}
/**
* Tells if the Ava is schema aware or not.
*
* @return true if the Ava is schema aware
*/
public boolean isSchemaAware()
{
return attributeType != null;
}
/**
* @return the attributeType
*/
public AttributeType getAttributeType()
{
return attributeType;
}
private int compareValues( Ava that )
{
int comp = 0;
if ( value.getNormValue() instanceof String )
{
comp = ( ( String ) value.getNormValue() ).compareTo( ( ( String ) that.value.getNormValue() ) );
return comp;
}
else
{
byte[] bytes1 = ( byte[] ) value.getNormValue();
byte[] bytes2 = ( byte[] ) that.value.getNormValue();
for ( int pos = 0; pos < bytes1.length; pos++ )
{
int v1 = ( bytes1[pos] & 0x00FF );
int v2 = ( bytes2[pos] & 0x00FF );
if ( v1 > v2 )
{
return 1;
}
else if ( v2 > v1 )
{
return -1;
}
}
return 0;
}
}
/**
* @see Comparable#compareTo(Object)
*/
@SuppressWarnings("unchecked")
public int compareTo( Ava that )
{
if ( that == null )
{
return 1;
}
int comp = 0;
if ( schemaManager == null )
{
// Compare the ATs
comp = normType.compareTo( that.normType );
if ( comp != 0 )
{
return comp;
}
// and compare the values
if ( value == null )
{
if ( that.value == null )
{
return 0;
}
else
{
return -1;
}
}
else
{
if ( that.value == null )
{
return 1;
}
else
{
if ( value instanceof StringValue )
{
comp = ( ( StringValue ) value ).compareTo( ( StringValue ) that.value );
return comp;
}
else
{
comp = ( ( BinaryValue ) value ).compareTo( ( BinaryValue ) that.value );
return comp;
}
}
}
}
else
{
if ( that.schemaManager == null )
{
// Problem : we will apply the current Ava SchemaManager to the given Ava
try
{
that.apply( schemaManager );
}
catch ( LdapInvalidDnException lide )
{
return 1;
}
}
// First compare the AT OID
comp = attributeType.getOid().compareTo( that.attributeType.getOid() );
if ( comp != 0 )
{
return comp;
}
// Now, compare the two values using the ordering matchingRule comparator, if any
MatchingRule orderingMR = attributeType.getOrdering();
if ( orderingMR != null )
{
LdapComparator<Object> comparator = ( LdapComparator<Object> ) orderingMR.getLdapComparator();
if ( comparator != null )
{
comp = comparator.compare( value.getNormValue(), that.value.getNormValue() );
return comp;
}
else
{
comp = compareValues( that );
return comp;
}
}
else
{
comp = compareValues( that );
return comp;
}
}
}
/**
* A String representation of an Ava, as provided by the user.
*
* @return A string representing an Ava
*/
public String toString()
{
return upName;
}
}