/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at * trunk/opends/resource/legal-notices/OpenDS.LICENSE * or https://OpenDS.dev.java.net/OpenDS.LICENSE. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, * add the following below this CDDL HEADER, with the fields enclosed * by brackets "[]" replaced with your own identifying information: * Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * * Copyright 2006-2009 Sun Microsystems, Inc. */ package org.opends.server.types; import static org.opends.messages.CoreMessages.*; import static org.opends.server.loggers.debug.DebugLogger.*; import org.opends.messages.Message; import org.opends.server.api.EqualityMatchingRule; import org.opends.server.loggers.debug.DebugTracer; /** * This class contains various methods for manipulating * {@link AttributeValue}s as well as static factory methods for * facilitating common {@link AttributeValue} construction use-cases. * <p> * Of particular interest are the following three factory methods: * * <pre> * create(AttributeType, ByteString); * create(ByteString, ByteString); * </pre> * * These are provided in order to facilitate construction of delayed * normalization using AttributeType and pre-normalized attributes * values respectively. */ public final class AttributeValues { /** * Prevent instantiation. */ private AttributeValues() { // Do nothing. } /** * Creates an AttributeValue where the value will the normalized on * demand using the matching rules of the provided AttributeType. * Equality matching involving this AttributeValue will be based on * the matching rules of the provided AttributeType. * * @param attributeType * The AttributeType to use. * @param value * The attribute value as a ByteString. * @return The newly created AttributeValue. */ public static AttributeValue create(AttributeType attributeType, ByteString value) { return new DelayedNormalizationValue(attributeType, value); } /** * Creates an AttributeValue where the UTF-8 encoded value of the * string will the normalized on demand sing the matching rules of * the provided AttributeType. Equality matching involving this * AttributeValue will be based on the matching rules of the * provided AttributeType. * * @param attributeType * The AttributeType to use. * @param value * The attribute value as a String. * @return The newly created AttributeValue. */ public static AttributeValue create(AttributeType attributeType, String value) { return new DelayedNormalizationValue(attributeType, ByteString .valueOf(value)); } /** * Creates an AttributeValue where the value is pre-normalized. * Equality matching will be based on a byte-by-byte comparison. * * @param value * The attribute value as a ByteString. * @param normalizedValue * The normalized attribute value as a ByteString. * @return The newly created AttributeValue. */ public static AttributeValue create(ByteString value, ByteString normalizedValue) { return new PreNormalizedValue(value, normalizedValue); } /** * This attribute value implementation will always store the value * in user-provided form, and a reference to the associated * attribute type. The normalized form of the value will be * initialized upon first request. The normalized form of the value * should only be used in cases where equality matching between two * values can be performed with byte-for-byte comparisons of the * normalized values. */ private static final class DelayedNormalizationValue implements AttributeValue { /** * The tracer object for the debug logger. */ private static final DebugTracer TRACER = getTracer(); private final AttributeType attributeType; private final ByteString value; private ByteString normalizedValue; /** * Construct a new DelayedNormalizationValue. * * @param attributeType The attribute type. * @param value The value of the attriute. */ private DelayedNormalizationValue( AttributeType attributeType, ByteString value) { this.attributeType = attributeType; this.value = value; this.normalizedValue = null; } /** * {@inheritDoc} */ public ByteString getNormalizedValue() throws DirectoryException { if (normalizedValue == null) { EqualityMatchingRule equalityMatchingRule = attributeType .getEqualityMatchingRule(); if (equalityMatchingRule == null) { Message message = ERR_ATTR_TYPE_NORMALIZE_NO_MR.get(String .valueOf(value), attributeType.getNameOrOID()); throw new DirectoryException( ResultCode.INAPPROPRIATE_MATCHING, message); } normalizedValue = equalityMatchingRule.normalizeValue(value); } return normalizedValue; } /** * {@inheritDoc} */ public ByteString getValue() { return value; } /** * {@inheritDoc} */ public boolean equals(Object o) { if (this == o) { return true; } else if (o instanceof AttributeValue) { AttributeValue attrValue = (AttributeValue) o; try { return getNormalizedValue().equals( attrValue.getNormalizedValue()); } catch (Exception e) { if (debugEnabled()) { TRACER.debugCaught(DebugLogLevel.ERROR, e); } return value.equals(attrValue.getValue()); } } return false; } /** * {@inheritDoc} */ public int hashCode() { EqualityMatchingRule equalityMatchingRule = attributeType .getEqualityMatchingRule(); ByteString valueToHash; try { valueToHash = getNormalizedValue(); } catch (Exception e) { if (debugEnabled()) { TRACER.debugCaught(DebugLogLevel.ERROR, e); } valueToHash = value; } if (equalityMatchingRule != null) { return equalityMatchingRule.generateHashCode(valueToHash); } else { return valueToHash.hashCode(); } } /** * {@inheritDoc} */ public String toString() { if (value == null) { return "null"; } else { return value.toString(); } } /** * {@inheritDoc} */ public void toString(StringBuilder buffer) { buffer.append(value.toString()); } } /** * This attribute value implementation will always store the value * in user-provided form, and the normalized form. The normalized * form of the value should only be used in cases where equality * matching between two values can be performed with byte-for-byte * comparisons of the normalized values. */ private static final class PreNormalizedValue implements AttributeValue { /** * The tracer object for the debug logger. */ private static final DebugTracer TRACER = getTracer(); private final ByteString value; private final ByteString normalizedValue; /** * Construct a new PreNormalizedValue. * @param value The user provided value of the attribute. * @param normalizedValue The normalized value of the attribute. */ private PreNormalizedValue(ByteString value, ByteString normalizedValue) { this.value = value; this.normalizedValue = normalizedValue; } /** * {@inheritDoc} */ public ByteString getNormalizedValue() { return normalizedValue; } /** * {@inheritDoc} */ public ByteString getValue() { return value; } /** * {@inheritDoc} */ public boolean equals(Object o) { if (this == o) { return true; } else if (o instanceof AttributeValue) { AttributeValue attrValue = (AttributeValue) o; try { return normalizedValue.equals( attrValue.getNormalizedValue()); } catch (Exception e) { if (debugEnabled()) { TRACER.debugCaught(DebugLogLevel.ERROR, e); } return value.equals(attrValue.getValue()); } } return false; } /** * {@inheritDoc} */ public int hashCode() { return normalizedValue.hashCode(); } /** * {@inheritDoc} */ public String toString() { if (value == null) { return "null"; } else { return value.toString(); } } /** * {@inheritDoc} */ public void toString(StringBuilder buffer) { buffer.append(value.toString()); } } }