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.valueOfUtf8(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, String valueString)
186  {
187    return create(getAttributeTypeOrDefault(attributeName), attributeName, valueString);
188  }
189
190  /**
191   * Creates a new multi-valued attribute with the specified attribute
192   * name and attribute values.
193   * <p>
194   * If the attribute name cannot be found in the schema, a new
195   * attribute type is created using the default attribute syntax.
196   * <p>
197   * <b>NOTE:</b> this method is provided as a convenience and should
198   * typically be reserved for use in unit tests and places where
199   * performance is not an issue. In particular, this method will
200   * construct a temporary array containing the attribute's values.
201   * For performance critical purposes, incrementally construct an
202   * attribute using an {@link AttributeBuilder}.
203   *
204   * @param attributeName
205   *          The name or OID of the attribute type for this attribute
206   *          (can be mixed case).
207   * @param valueStrings
208   *          The string representation of the attribute values.
209   * @return A new attribute with the specified name and values.
210   */
211  public static Attribute create(String attributeName, String... valueStrings)
212  {
213    if (valueStrings.length == 0) {
214      return empty(attributeName);
215    }
216    AttributeBuilder builder = new AttributeBuilder(attributeName);
217    builder.addAllStrings(Arrays.asList(valueStrings));
218    return builder.toAttribute();
219  }
220
221  /**
222   * Creates a new attribute which has the same attribute type and
223   * attribute options as the provided attribute but no attribute
224   * values.
225   *
226   * @param attribute
227   *          The attribute to be copied.
228   * @return A new attribute which has the same attribute type and
229   *         attribute options as the provided attribute but no
230   *         attribute values.
231   */
232  public static Attribute empty(Attribute attribute)
233  {
234    return new AttributeBuilder(attribute, true).toAttribute();
235  }
236
237
238
239  /**
240   * Creates a new attribute with the provided attribute type and no
241   * values.
242   *
243   * @param attributeType
244   *          The attribute type to use.
245   * @return A new attribute with the provided attribute type and no
246   *         values.
247   */
248  public static Attribute empty(AttributeType attributeType)
249  {
250    return empty(attributeType, attributeType.getNameOrOID());
251  }
252
253
254
255  /**
256   * Creates a new attribute with the provided attribute type and no
257   * values.
258   *
259   * @param attributeType
260   *          The attribute type to use.
261   * @param name
262   *          The user-provided name for this attribute.
263   * @return A new attribute with the provided attribute type and no
264   *         values.
265   */
266  public static Attribute empty(AttributeType attributeType,
267      String name)
268  {
269    return AttributeBuilder.create(attributeType, name, Collections
270        .<ByteString> emptySet());
271  }
272
273
274
275  /**
276   * Creates a new attribute with the specified attribute name and no
277   * attribute values.
278   * <p>
279   * If the attribute name cannot be found in the schema, a new
280   * attribute type is created using the default attribute syntax.
281   *
282   * @param attributeName
283   *          The name or OID of the attribute type for this attribute
284   *          (can be mixed case).
285   * @return A new attribute with the specified name and no values.
286   */
287  public static Attribute empty(String attributeName)
288  {
289    return empty(getAttributeTypeOrDefault(attributeName), attributeName);
290  }
291
292
293
294  /**
295   * Creates a new attribute containing all the values from the two
296   * provided attributes. The returned attribute will use the name and
297   * options taken from the first attribute.
298   * <p>
299   * This method is logically equivalent to:
300   *
301   * <pre>
302   * merge(a1, a2, null);
303   * </pre>
304   *
305   * @param a1
306   *          The first attribute.
307   * @param a2
308   *          The second attribute.
309   * @return A new attribute containing all the values from the two
310   *         provided attributes.
311   */
312  public static Attribute merge(Attribute a1, Attribute a2)
313  {
314    return merge(a1, a2, null);
315  }
316
317
318
319  /**
320   * Creates a new attribute containing all the values from the two
321   * provided attributes and put any duplicate values into the
322   * provided collection. The returned attribute will use the name
323   * and options taken from the first attribute.
324   *
325   * @param a1
326   *          The first attribute.
327   * @param a2
328   *          The second attribute.
329   * @param duplicateValues
330   *          A collection which will be used to store any duplicate
331   *          values, or <code>null</code> if duplicate values should
332   *          not be stored.
333   * @return A new attribute containing all the values from the two
334   *         provided attributes.
335   */
336  public static Attribute merge(Attribute a1, Attribute a2,
337      Collection<ByteString> duplicateValues)
338  {
339    AttributeBuilder builder = new AttributeBuilder(a1);
340    for (ByteString av : a2)
341    {
342      if (!builder.add(av) && duplicateValues != null)
343      {
344        duplicateValues.add(av);
345      }
346    }
347    return builder.toAttribute();
348  }
349
350
351
352  /**
353   * Creates a new attribute containing the values from the first
354   * attribute which are not in the second attribute. The returned
355   * attribute will use the name and options taken from the first
356   * attribute.
357   * <p>
358   * This method is logically equivalent to:
359   *
360   * <pre>
361   * subtract(a1, a2, null);
362   * </pre>
363   *
364   * @param a1
365   *          The first attribute.
366   * @param a2
367   *          The second attribute.
368   * @return A new attribute containing the values from the first
369   *         attribute which are not in the second attribute.
370   */
371  public static Attribute subtract(Attribute a1, Attribute a2)
372  {
373    return subtract(a1, a2, null);
374  }
375
376
377
378  /**
379   * Creates a new attribute containing the values from the first
380   * attribute which are not in the second attribute. Any values which
381   * were present in the second attribute but which were not present
382   * in the first attribute will be put into the provided collection.
383   * The returned attribute will use the name and options taken from
384   * the first attribute.
385   *
386   * @param a1
387   *          The first attribute.
388   * @param a2
389   *          The second attribute.
390   * @param missingValues
391   *          A collection which will be used to store any missing
392   *          values, or <code>null</code> if missing values should
393   *          not be stored.
394   * @return A new attribute containing the values from the first
395   *         attribute which are not in the second attribute.
396   */
397  public static Attribute subtract(Attribute a1, Attribute a2,
398      Collection<ByteString> missingValues)
399  {
400    AttributeBuilder builder = new AttributeBuilder(a1);
401    for (ByteString av : a2)
402    {
403      if (!builder.remove(av) && missingValues != null)
404      {
405        missingValues.add(av);
406      }
407    }
408    return builder.toAttribute();
409  }
410
411  private static AttributeType getAttributeTypeOrDefault(String attributeName)
412  {
413    return DirectoryServer.getAttributeTypeOrDefault(toLowerCase(attributeName), attributeName);
414  }
415}