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 2008-2009 Sun Microsystems, Inc.
025 *      Portions Copyright 2014-2015 ForgeRock AS
026 */
027package org.opends.server.types;
028
029import java.util.Arrays;
030import java.util.Collection;
031import java.util.Collections;
032import java.util.List;
033
034import org.forgerock.opendj.ldap.ByteString;
035import org.opends.server.core.DirectoryServer;
036
037import static org.opends.server.util.CollectionUtils.*;
038import static org.opends.server.util.StaticUtils.*;
039
040/**
041 * This class contains various methods for manipulating
042 * {@link Attribute}s as well as static factory methods for
043 * facilitating common {@link Attribute} construction use-cases.
044 * <p>
045 * Of particular interest are the following three factory methods:
046 *
047 * <pre>
048 * empty(String);
049 *
050 * create(String, String);
051 *
052 * create(String, String, String...);
053 * </pre>
054 *
055 * These are provided in order to facilitate construction of empty,
056 * single-valued, and multi-valued attributes respectively, for
057 * example, in unit tests. The last factory method is not designed for
058 * performance critical functionality and, instead, an
059 * {@link AttributeBuilder} should be used in order to incrementally
060 * construct multi-valued attributes.
061 */
062public final class Attributes
063{
064
065  /**
066   * Creates a new single-valued attribute with the specified attribute type and value.
067   *
068   * @param attributeType
069   *          The attribute type to use.
070   * @param value
071   *          The attribute value.
072   * @return A new attribute with the attribute type and value.
073   */
074  public static Attribute create(AttributeType attributeType, ByteString value)
075  {
076    return create(attributeType, attributeType.getNameOrOID(), value);
077  }
078
079  /**
080   * Creates a new List with a single-valued attribute with the specified attribute type and value.
081   *
082   * @param attributeType
083   *          The attribute type to use.
084   * @param value
085   *          The attribute value.
086   * @return A new List with a single-valued attribute with the attribute type and value.
087   */
088  public static List<Attribute> createAsList(AttributeType attributeType, ByteString value)
089  {
090    return newArrayList(create(attributeType, value));
091  }
092
093  /**
094   * Creates a new single-valued attribute with the specified name and value.
095   *
096   * @param attributeType
097   *          The attribute type to use.
098   * @param valueString
099   *          The String representation of the attribute value.
100   * @return A new attribute with the specified name and value.
101   */
102  public static Attribute create(AttributeType attributeType, String valueString)
103  {
104    return create(attributeType, attributeType.getNameOrOID(), valueString);
105  }
106
107  /**
108   * Creates a new List with a single-valued attribute with the specified name and value.
109   *
110   * @param attributeType
111   *          The attribute type to use.
112   * @param valueString
113   *          The String representation of the attribute value.
114   * @return A new List with a attribute with the specified name and value.
115   */
116  public static List<Attribute> createAsList(AttributeType attributeType, String valueString)
117  {
118    return newArrayList(create(attributeType, valueString));
119  }
120
121  /**
122   * Creates a new single-valued attribute with the specified
123   * attribute type and value.
124   *
125   * @param attributeType
126   *          The attribute type to use.
127   * @param name
128   *          The user-provided name for this attribute.
129   * @param value
130   *          The attribute value.
131   * @return A new attribute with the attribute type and value.
132   */
133  public static Attribute create(AttributeType attributeType, String name, ByteString value)
134  {
135    return AttributeBuilder.create(attributeType, name, Collections.singleton(value));
136  }
137
138  /**
139   * Creates a new single-valued attribute with the attribute type and value.
140   *
141   * @param attributeType
142   *          The attribute type to use.
143   * @param name
144   *          The user-provided name for this attribute.
145   * @param valueString
146   *          The String representation of the attribute value.
147   * @return A new attribute with the attribute type and value.
148   */
149  public static Attribute create(AttributeType attributeType, String name, String valueString)
150  {
151    return create(attributeType, name, ByteString.valueOf(valueString));
152  }
153
154  /**
155   * Creates a new List with a single-valued attribute with the attribute type and value.
156   *
157   * @param attributeType
158   *          The attribute type to use.
159   * @param name
160   *          The user-provided name for this attribute.
161   * @param valueString
162   *          The String representation of the attribute value.
163   * @return A new List with a single-valued attribute with the attribute type and value.
164   */
165
166  public static List<Attribute> createAsList(AttributeType attributeType, String name, String valueString)
167  {
168    return newArrayList(create(attributeType, name, valueString));
169  }
170
171  /**
172   * Creates a new single-valued attribute with the specified
173   * attribute name and attribute value.
174   * <p>
175   * If the attribute name cannot be found in the schema, a new
176   * attribute type is created using the default attribute syntax.
177   *
178   * @param attributeName
179   *          The name or OID of the attribute type for this attribute
180   *          (can be mixed case).
181   * @param valueString
182   *          The String representation of the attribute value.
183   * @return A new attribute with the specified name and value.
184   */
185  public static Attribute create(String attributeName,
186      String valueString)
187  {
188    return create(getAttributeType(attributeName), attributeName, valueString);
189  }
190
191  /**
192   * Creates a new multi-valued attribute with the specified attribute
193   * name and attribute values.
194   * <p>
195   * If the attribute name cannot be found in the schema, a new
196   * attribute type is created using the default attribute syntax.
197   * <p>
198   * <b>NOTE:</b> this method is provided as a convenience and should
199   * typically be reserved for use in unit tests and places where
200   * performance is not an issue. In particular, this method will
201   * construct a temporary array containing the attribute's values.
202   * For performance critical purposes, incrementally construct an
203   * attribute using an {@link AttributeBuilder}.
204   *
205   * @param attributeName
206   *          The name or OID of the attribute type for this attribute
207   *          (can be mixed case).
208   * @param valueStrings
209   *          The string representation of the attribute values.
210   * @return A new attribute with the specified name and values.
211   */
212  public static Attribute create(String attributeName, String... valueStrings)
213  {
214    if (valueStrings.length == 0) {
215      return empty(attributeName);
216    }
217    AttributeBuilder builder = new AttributeBuilder(attributeName);
218    builder.addAllStrings(Arrays.asList(valueStrings));
219    return builder.toAttribute();
220  }
221
222  /**
223   * Creates a new attribute which has the same attribute type and
224   * attribute options as the provided attribute but no attribute
225   * values.
226   *
227   * @param attribute
228   *          The attribute to be copied.
229   * @return A new attribute which has the same attribute type and
230   *         attribute options as the provided attribute but no
231   *         attribute values.
232   */
233  public static Attribute empty(Attribute attribute)
234  {
235    return new AttributeBuilder(attribute, true).toAttribute();
236  }
237
238
239
240  /**
241   * Creates a new attribute with the provided attribute type and no
242   * values.
243   *
244   * @param attributeType
245   *          The attribute type to use.
246   * @return A new attribute with the provided attribute type and no
247   *         values.
248   */
249  public static Attribute empty(AttributeType attributeType)
250  {
251    return empty(attributeType, attributeType.getNameOrOID());
252  }
253
254
255
256  /**
257   * Creates a new attribute with the provided attribute type and no
258   * values.
259   *
260   * @param attributeType
261   *          The attribute type to use.
262   * @param name
263   *          The user-provided name for this attribute.
264   * @return A new attribute with the provided attribute type and no
265   *         values.
266   */
267  public static Attribute empty(AttributeType attributeType,
268      String name)
269  {
270    return AttributeBuilder.create(attributeType, name, Collections
271        .<ByteString> emptySet());
272  }
273
274
275
276  /**
277   * Creates a new attribute with the specified attribute name and no
278   * attribute values.
279   * <p>
280   * If the attribute name cannot be found in the schema, a new
281   * attribute type is created using the default attribute syntax.
282   *
283   * @param attributeName
284   *          The name or OID of the attribute type for this attribute
285   *          (can be mixed case).
286   * @return A new attribute with the specified name and no values.
287   */
288  public static Attribute empty(String attributeName)
289  {
290    return empty(getAttributeType(attributeName), attributeName);
291  }
292
293
294
295  /**
296   * Creates a new attribute containing all the values from the two
297   * provided attributes. The returned attribute will use the name and
298   * options taken from the first attribute.
299   * <p>
300   * This method is logically equivalent to:
301   *
302   * <pre>
303   * merge(a1, a2, null);
304   * </pre>
305   *
306   * @param a1
307   *          The first attribute.
308   * @param a2
309   *          The second attribute.
310   * @return A new attribute containing all the values from the two
311   *         provided attributes.
312   */
313  public static Attribute merge(Attribute a1, Attribute a2)
314  {
315    return merge(a1, a2, null);
316  }
317
318
319
320  /**
321   * Creates a new attribute containing all the values from the two
322   * provided attributes and put any duplicate values into the
323   * provided collection. The returned attribute will use the name
324   * and options taken from the first attribute.
325   *
326   * @param a1
327   *          The first attribute.
328   * @param a2
329   *          The second attribute.
330   * @param duplicateValues
331   *          A collection which will be used to store any duplicate
332   *          values, or <code>null</code> if duplicate values should
333   *          not be stored.
334   * @return A new attribute containing all the values from the two
335   *         provided attributes.
336   */
337  public static Attribute merge(Attribute a1, Attribute a2,
338      Collection<ByteString> duplicateValues)
339  {
340    AttributeBuilder builder = new AttributeBuilder(a1);
341    for (ByteString av : a2)
342    {
343      if (!builder.add(av) && duplicateValues != null)
344      {
345        duplicateValues.add(av);
346      }
347    }
348    return builder.toAttribute();
349  }
350
351
352
353  /**
354   * Creates a new attribute containing the values from the first
355   * attribute which are not in the second attribute. The returned
356   * attribute will use the name and options taken from the first
357   * attribute.
358   * <p>
359   * This method is logically equivalent to:
360   *
361   * <pre>
362   * subtract(a1, a2, null);
363   * </pre>
364   *
365   * @param a1
366   *          The first attribute.
367   * @param a2
368   *          The second attribute.
369   * @return A new attribute containing the values from the first
370   *         attribute which are not in the second attribute.
371   */
372  public static Attribute subtract(Attribute a1, Attribute a2)
373  {
374    return subtract(a1, a2, null);
375  }
376
377
378
379  /**
380   * Creates a new attribute containing the values from the first
381   * attribute which are not in the second attribute. Any values which
382   * were present in the second attribute but which were not present
383   * in the first attribute will be put into the provided collection.
384   * The returned attribute will use the name and options taken from
385   * the first attribute.
386   *
387   * @param a1
388   *          The first attribute.
389   * @param a2
390   *          The second attribute.
391   * @param missingValues
392   *          A collection which will be used to store any missing
393   *          values, or <code>null</code> if missing values should
394   *          not be stored.
395   * @return A new attribute containing the values from the first
396   *         attribute which are not in the second attribute.
397   */
398  public static Attribute subtract(Attribute a1, Attribute a2,
399      Collection<ByteString> missingValues)
400  {
401    AttributeBuilder builder = new AttributeBuilder(a1);
402    for (ByteString av : a2)
403    {
404      if (!builder.remove(av) && missingValues != null)
405      {
406        missingValues.add(av);
407      }
408    }
409    return builder.toAttribute();
410  }
411
412  /**
413   * Gets the named attribute type, creating a default attribute if necessary.
414   *
415   * @param attributeName
416   *          The name of the attribute type.
417   * @return The attribute type associated with the provided attribute name.
418   */
419  private static AttributeType getAttributeType(String attributeName)
420  {
421    return DirectoryServer.getAttributeTypeOrDefault(toLowerCase(attributeName), attributeName);
422  }
423}