001/*
002 * CDDL HEADER START
003 *
004 * The contents of this file are subject to the terms of the
005 * Common Development and Distribution License, Version 1.0 only
006 * (the "License").  You may not use this file except in compliance
007 * with the License.
008 *
009 * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
010 * or http://forgerock.org/license/CDDLv1.0.html.
011 * See the License for the specific language governing permissions
012 * and limitations under the License.
013 *
014 * When distributing Covered Code, include this CDDL HEADER in each
015 * file and include the License file at legal-notices/CDDLv1_0.txt.
016 * If applicable, add the following below this CDDL HEADER, with the
017 * fields enclosed by brackets "[]" replaced with your own identifying
018 * information:
019 *      Portions Copyright [yyyy] [name of copyright owner]
020 *
021 * CDDL HEADER END
022 *
023 *
024 *      Copyright 2006-2008 Sun Microsystems, Inc.
025 *      Portions Copyright 2014-2015 ForgeRock AS
026 */
027package org.opends.server.types;
028
029import java.util.Collection;
030import java.util.Set;
031
032import org.forgerock.opendj.ldap.ByteString;
033import org.forgerock.opendj.ldap.DecodeException;
034import org.forgerock.opendj.ldap.schema.MatchingRule;
035
036/** An abstract base class for implementing new types of {@link Attribute}. */
037@org.opends.server.types.PublicAPI(
038    stability = org.opends.server.types.StabilityLevel.UNCOMMITTED,
039    mayInstantiate = false,
040    mayExtend = false,
041    mayInvoke = true)
042public abstract class AbstractAttribute implements Attribute
043{
044  /** Creates a new abstract attribute. */
045  protected AbstractAttribute()
046  {
047    // No implementation required.
048  }
049
050  /**
051   * {@inheritDoc}
052   * <p>
053   * This implementation iterates through each attribute value in the
054   * provided collection, checking to see if this attribute contains
055   * the value using {@link #contains(ByteString)}.
056   */
057  @Override
058  public boolean containsAll(Collection<ByteString> values)
059  {
060    for (ByteString value : values)
061    {
062      if (!contains(value))
063      {
064        return false;
065      }
066    }
067    return true;
068  }
069
070  @Override
071  public final boolean equals(Object o)
072  {
073    if (this == o)
074    {
075      return true;
076    }
077    if (!(o instanceof Attribute))
078    {
079      return false;
080    }
081
082    Attribute a = (Attribute) o;
083    return getAttributeType().equals(a.getAttributeType())
084        && valuesEqual(a)
085        && optionsEqual(a.getOptions());
086  }
087
088  private boolean valuesEqual(Attribute a)
089  {
090    if (size() != a.size())
091    {
092      return false;
093    }
094
095    for (ByteString v : a)
096    {
097      if (!contains(v))
098      {
099        return false;
100      }
101    }
102    return true;
103  }
104
105  /**
106   * {@inheritDoc}
107   * <p>
108   * This implementation returns the primary name associated with this
109   * attribute's attribute type or, if there is no primary name, the
110   * attribute type's OID.
111   */
112  @Override
113  public String getName()
114  {
115    return getAttributeType().getNameOrOID();
116  }
117
118  /**
119   * {@inheritDoc}
120   * <p>
121   * This implementation returns this attribute's name if there are no
122   * attribute options, otherwise it constructs a string comprising of
123   * this attribute's name followed by a semi-colon and a semi-colon
124   * separated list of its attribute options.
125   */
126  @Override
127  public String getNameWithOptions()
128  {
129    if (!hasOptions())
130    {
131      return getName();
132    }
133
134    StringBuilder buffer = new StringBuilder();
135    buffer.append(getName());
136    for (String option : getOptions())
137    {
138      buffer.append(';');
139      buffer.append(option);
140    }
141    return buffer.toString();
142  }
143
144  /**
145   * {@inheritDoc}
146   * <p>
147   * This implementation returns {@code true} if the provided
148   * collection of options is {@code null} or empty. If the
149   * collection is non-empty and this attribute does not have any
150   * options then it returns {@code false}. Otherwise, {@code true} is
151   * returned if all the provided options are present.
152   */
153  @Override
154  public boolean hasAllOptions(Collection<String> options)
155  {
156    return AttributeDescription.containsAllOptions(getOptions(), options);
157  }
158
159  @Override
160  public int hashCode()
161  {
162    int hashCode = getAttributeType().hashCode();
163    for (ByteString value : this)
164    {
165      try
166      {
167        MatchingRule eqRule = getAttributeType().getEqualityMatchingRule();
168        hashCode += eqRule.normalizeAttributeValue(value).hashCode();
169      }
170      catch (DecodeException e)
171      {
172        hashCode += value.hashCode();
173      }
174    }
175    return hashCode;
176  }
177
178  /**
179   * {@inheritDoc}
180   * <p>
181   * This implementation calls {@link #getOptions()} to
182   * retrieve this attribute's set of options and then compares them
183   * one at a time against the provided option. All comparisons are
184   * case insensitive.
185   */
186  @Override
187  public boolean hasOption(String option)
188  {
189    return AttributeDescription.containsOption(getOptions(), option);
190  }
191
192  /**
193   * {@inheritDoc}
194   * <p>
195   * This implementation retrieves the set of options associated with
196   * this attribute and tests to see if it is empty.
197   */
198  @Override
199  public boolean hasOptions()
200  {
201    return !getOptions().isEmpty();
202  }
203
204  /**
205   * {@inheritDoc}
206   * <p>
207   * This implementation returns <code>true</code> if the
208   * {@link #size()} of this attribute is zero.
209   */
210  @Override
211  public boolean isEmpty()
212  {
213    return size() == 0;
214  }
215
216  @Override
217  public boolean isReal()
218  {
219    return !isVirtual();
220  }
221
222  /**
223   * {@inheritDoc}
224   * <p>
225   * This implementation returns !{@link #hasOptions()} if the
226   * provided set of options is <code>null</code>. Otherwise it
227   * checks that the size of the provided set of options is equal to
228   * the size of this attribute's options, return <code>false</code>
229   * if the sizes differ. If the sizes are the same then each option
230   * in the provided set is checked using
231   * {@link #hasOption(String)} and <code>true</code> is
232   * returned if all the provided options are present.
233   */
234  @Override
235  public boolean optionsEqual(Set<String> options)
236  {
237    if (options != null)
238    {
239      return getOptions().size() == options.size()
240          && hasAllOptions(options);
241    }
242    return !hasOptions();
243  }
244
245  @Override
246  public final String toString()
247  {
248    StringBuilder buffer = new StringBuilder();
249    toString(buffer);
250    return buffer.toString();
251  }
252}