001/*
002 * The contents of this file are subject to the terms of the Common Development and
003 * Distribution License (the License). You may not use this file except in compliance with the
004 * License.
005 *
006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
007 * specific language governing permission and limitations under the License.
008 *
009 * When distributing Covered Software, include this CDDL Header Notice in each file and include
010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
011 * Header, with the fields enclosed by brackets [] replaced by your own identifying
012 * information: "Portions Copyright [year] [name of copyright owner]".
013 *
014 * Copyright 2012-2016 ForgeRock AS.
015 */
016package org.opends.server.types;
017
018import java.util.Arrays;
019import java.util.Collection;
020import java.util.LinkedHashSet;
021import java.util.NoSuchElementException;
022import java.util.Set;
023
024import org.forgerock.opendj.ldap.ByteString;
025import org.forgerock.opendj.ldap.Functions;
026import org.forgerock.opendj.ldap.GeneralizedTime;
027import org.forgerock.opendj.ldap.schema.Schema;
028import org.forgerock.util.Function;
029import org.forgerock.util.promise.NeverThrowsException;
030
031
032/**
033 * A fluent API for parsing attributes as different types of object. An
034 * attribute parser is obtained from an entry using the method
035 * {@link Entry#parseAttribute}.
036 * <p>
037 * Methods throw an {@code IllegalArgumentException} when a value cannot be
038 * parsed (e.g. because its syntax is invalid). Methods which return a
039 * {@code Set} always return a modifiable non-{@code null} result, even if the
040 * attribute is {@code null} or empty.
041 * <p>
042 * Examples:
043 *
044 * <pre>
045 * Entry entry = ...;
046 *
047 * Calendar timestamp = entry.parseAttribute("createTimestamp").asCalendar();
048 * boolean isEnabled = entry.parseAttribute("enabled").asBoolean(false);
049 *
050 * Entry group = ...;
051 * Schema schema = ...;
052 *
053 * Set&lt;DN&gt; members = group.parseAttribute("member").usingSchema(schema).asSetOfDN();
054 * </pre>
055 *
056 * @see Entry#parseAttribute
057 */
058public final class AttributeParser {
059    // TODO: enums, filters, rdns?
060
061    private static final AttributeParser NULL_INSTANCE = new AttributeParser(null);
062
063    /**
064     * Returns an attribute parser for the provided attribute. {@code null}
065     * attributes are permitted and will be treated as if an empty attribute was
066     * provided.
067     *
068     * @param attribute
069     *            The attribute to be parsed, which may be {@code null}.
070     * @return The attribute parser.
071     */
072    public static AttributeParser parseAttribute(final Attribute attribute) {
073        return isEmpty(attribute) ? NULL_INSTANCE : new AttributeParser(attribute);
074    }
075
076    private static boolean isEmpty(final Attribute attribute) {
077        return attribute == null || attribute.isEmpty();
078    }
079
080    private final Attribute attribute;
081    private Schema schema;
082
083    private AttributeParser(final Attribute attribute) {
084        this.attribute = attribute;
085    }
086
087    /**
088     * Returns the first value decoded as a {@code T} using the provided
089     * {@link Function}, or {@code null} if the attribute does not contain any
090     * values.
091     *
092     * @param <T>
093     *            The type of the value to be decoded.
094     * @param f
095     *            The function which should be used to decode the value.
096     * @return The first value decoded as a {@code T}.
097     */
098    public <T> T as(final Function<ByteString, ? extends T, NeverThrowsException> f) {
099        return as(f, null);
100    }
101
102    /**
103     * Returns the first value decoded as a {@code T} using the provided
104     * {@link Function}, or {@code defaultValue} if the attribute does not
105     * contain any values.
106     *
107     * @param <T>
108     *            The type of the value to be decoded.
109     * @param f
110     *            The function which should be used to decode the value.
111     * @param defaultValue
112     *            The default value to return if the attribute is empty.
113     * @return The first value decoded as a {@code T}.
114     */
115    public <T> T as(final Function<ByteString, ? extends T, NeverThrowsException> f, final T defaultValue) {
116        if (!isEmpty(attribute)) {
117            return f.apply(attribute.iterator().next());
118        } else {
119            return defaultValue;
120        }
121    }
122
123    /**
124     * Returns the first value decoded as a boolean, or {@code null} if the
125     * attribute does not contain any values.
126     *
127     * @return The first value decoded as a boolean.
128     */
129    public Boolean asBoolean() {
130        return isEmpty(attribute) ? null : asBoolean(false /* ignored */);
131    }
132
133    /**
134     * Returns the first value decoded as an {@code Boolean}, or
135     * {@code defaultValue} if the attribute does not contain any values.
136     *
137     * @param defaultValue
138     *            The default value to return if the attribute is empty.
139     * @return The first value decoded as an {@code Boolean}.
140     */
141    public boolean asBoolean(final boolean defaultValue) {
142        return as(Functions.byteStringToBoolean(), defaultValue);
143    }
144
145    /**
146     * Returns the first value, or {@code null} if the attribute does not
147     * contain any values.
148     *
149     * @return The first value.
150     */
151    public ByteString asByteString() {
152        return asByteString(null);
153    }
154
155    /**
156     * Returns the first value, or {@code defaultValue} if the attribute does
157     * not contain any values.
158     *
159     * @param defaultValue
160     *            The default value to return if the attribute is empty.
161     * @return The first value.
162     */
163    public ByteString asByteString(final ByteString defaultValue) {
164        return as(Functions.<ByteString> identityFunction(), defaultValue);
165    }
166
167    /**
168     * Returns the first value decoded as a {@code GeneralizedTime} using the
169     * generalized time syntax, or {@code null} if the attribute does not
170     * contain any values.
171     *
172     * @return The first value decoded as a {@code GeneralizedTime}.
173     */
174    public GeneralizedTime asGeneralizedTime() {
175        return asGeneralizedTime(null);
176    }
177
178    /**
179     * Returns the first value decoded as an {@code GeneralizedTime} using the
180     * generalized time syntax, or {@code defaultValue} if the attribute does
181     * not contain any values.
182     *
183     * @param defaultValue
184     *            The default value to return if the attribute is empty.
185     * @return The first value decoded as an {@code GeneralizedTime}.
186     */
187    public GeneralizedTime asGeneralizedTime(final GeneralizedTime defaultValue) {
188        return as(Functions.byteStringToGeneralizedTime(), defaultValue);
189    }
190
191    /**
192     * Returns the first value decoded as an {@code Integer}, or {@code null} if
193     * the attribute does not contain any values.
194     *
195     * @return The first value decoded as an {@code Integer}.
196     */
197    public Integer asInteger() {
198        return isEmpty(attribute) ? null : asInteger(0 /* ignored */);
199    }
200
201    /**
202     * Returns the first value decoded as an {@code Integer}, or
203     * {@code defaultValue} if the attribute does not contain any values.
204     *
205     * @param defaultValue
206     *            The default value to return if the attribute is empty.
207     * @return The first value decoded as an {@code Integer}.
208     */
209    public int asInteger(final int defaultValue) {
210        return as(Functions.byteStringToInteger(), defaultValue);
211    }
212
213    /**
214     * Returns the first value decoded as a {@code Long}, or {@code null} if the
215     * attribute does not contain any values.
216     *
217     * @return The first value decoded as a {@code Long}.
218     */
219    public Long asLong() {
220        return isEmpty(attribute) ? null : asLong(0L /* ignored */);
221    }
222
223    /**
224     * Returns the first value decoded as a {@code Long}, or
225     * {@code defaultValue} if the attribute does not contain any values.
226     *
227     * @param defaultValue
228     *            The default value to return if the attribute is empty.
229     * @return The first value decoded as a {@code Long}.
230     */
231    public long asLong(final long defaultValue) {
232        return as(Functions.byteStringToLong(), defaultValue);
233    }
234
235    /**
236     * Returns the values decoded as a set of {@code T}s using the provided
237     * {@link Function}, or {@code defaultValues} if the attribute does not
238     * contain any values.
239     *
240     * @param <T>
241     *            The type of the values to be decoded.
242     * @param f
243     *            The function which should be used to decode values.
244     * @param defaultValues
245     *            The default values to return if the attribute is empty.
246     * @return The values decoded as a set of {@code T}s.
247     */
248    public <T> Set<T> asSetOf(final Function<ByteString, ? extends T, NeverThrowsException> f,
249            final Collection<? extends T> defaultValues) {
250        if (!isEmpty(attribute)) {
251            final LinkedHashSet<T> result = new LinkedHashSet<>(attribute.size());
252            for (final ByteString v : attribute) {
253                result.add(f.apply(v));
254            }
255            return result;
256        } else if (defaultValues != null) {
257            return new LinkedHashSet<>(defaultValues);
258        } else {
259            return new LinkedHashSet<>(0);
260        }
261    }
262
263    /**
264     * Returns the values decoded as a set of {@code T}s using the provided
265     * {@link Function}, or {@code defaultValues} if the attribute does not
266     * contain any values.
267     *
268     * @param <T>
269     *            The type of the values to be decoded.
270     * @param f
271     *            The function which should be used to decode values.
272     * @param defaultValues
273     *            The default values to return if the attribute is empty.
274     * @return The values decoded as a set of {@code T}s.
275     */
276    public <T> Set<T> asSetOf(final Function<ByteString, ? extends T, NeverThrowsException> f,
277            final T... defaultValues) {
278        return asSetOf(f, Arrays.asList(defaultValues));
279    }
280
281    /**
282     * Returns the values decoded as a set of {@code Boolean}s, or
283     * {@code defaultValues} if the attribute does not contain any values.
284     *
285     * @param defaultValues
286     *            The default values to return if the attribute is empty.
287     * @return The values decoded as a set of {@code Boolean}s.
288     */
289    public Set<Boolean> asSetOfBoolean(final Boolean... defaultValues) {
290        return asSetOfBoolean(Arrays.asList(defaultValues));
291    }
292
293    /**
294     * Returns the values decoded as a set of {@code Boolean}s, or
295     * {@code defaultValues} if the attribute does not contain any values.
296     *
297     * @param defaultValues
298     *            The default values to return if the attribute is empty.
299     * @return The values decoded as a set of {@code Boolean}s.
300     */
301    public Set<Boolean> asSetOfBoolean(final Collection<Boolean> defaultValues) {
302        return asSetOf(Functions.byteStringToBoolean(), defaultValues);
303    }
304
305    /**
306     * Returns the values contained in the attribute, or {@code defaultValues}
307     * if the attribute does not contain any values.
308     *
309     * @param defaultValues
310     *            The default values to return if the attribute is empty.
311     * @return The values contained in the attribute.
312     */
313    public Set<ByteString> asSetOfByteString(final ByteString... defaultValues) {
314        return asSetOfByteString(Arrays.asList(defaultValues));
315    }
316
317    /**
318     * Returns the values contained in the attribute, or {@code defaultValues}
319     * if the attribute does not contain any values.
320     *
321     * @param defaultValues
322     *            The default values to return if the attribute is empty.
323     * @return The values contained in the attribute.
324     */
325    public Set<ByteString> asSetOfByteString(final Collection<ByteString> defaultValues) {
326        return asSetOf(Functions.<ByteString> identityFunction(), defaultValues);
327    }
328
329    /**
330     * Returns the values decoded as a set of {@code GeneralizedTime}s using the
331     * generalized time syntax, or {@code defaultValues} if the attribute does
332     * not contain any values.
333     *
334     * @param defaultValues
335     *            The default values to return if the attribute is empty.
336     * @return The values decoded as a set of {@code GeneralizedTime}s.
337     */
338    public Set<GeneralizedTime> asSetOfGeneralizedTime(
339            final Collection<GeneralizedTime> defaultValues) {
340        return asSetOf(Functions.byteStringToGeneralizedTime(), defaultValues);
341    }
342
343    /**
344     * Returns the values decoded as a set of {@code GeneralizedTime}s using the
345     * generalized time syntax, or {@code defaultValues} if the attribute does
346     * not contain any values.
347     *
348     * @param defaultValues
349     *            The default values to return if the attribute is empty.
350     * @return The values decoded as a set of {@code GeneralizedTime}s.
351     */
352    public Set<GeneralizedTime> asSetOfGeneralizedTime(final GeneralizedTime... defaultValues) {
353        return asSetOfGeneralizedTime(Arrays.asList(defaultValues));
354    }
355
356    /**
357     * Returns the values decoded as a set of {@code Integer}s, or
358     * {@code defaultValues} if the attribute does not contain any values.
359     *
360     * @param defaultValues
361     *            The default values to return if the attribute is empty.
362     * @return The values decoded as a set of {@code Integer}s.
363     */
364    public Set<Integer> asSetOfInteger(final Collection<Integer> defaultValues) {
365        return asSetOf(Functions.byteStringToInteger(), defaultValues);
366    }
367
368    /**
369     * Returns the values decoded as a set of {@code Integer}s, or
370     * {@code defaultValues} if the attribute does not contain any values.
371     *
372     * @param defaultValues
373     *            The default values to return if the attribute is empty.
374     * @return The values decoded as a set of {@code Integer}s.
375     */
376    public Set<Integer> asSetOfInteger(final Integer... defaultValues) {
377        return asSetOfInteger(Arrays.asList(defaultValues));
378    }
379
380    /**
381     * Returns the values decoded as a set of {@code Long}s, or
382     * {@code defaultValues} if the attribute does not contain any values.
383     *
384     * @param defaultValues
385     *            The default values to return if the attribute is empty.
386     * @return The values decoded as a set of {@code Long}s.
387     */
388    public Set<Long> asSetOfLong(final Collection<Long> defaultValues) {
389        return asSetOf(Functions.byteStringToLong(), defaultValues);
390    }
391
392    /**
393     * Returns the values decoded as a set of {@code Long}s, or
394     * {@code defaultValues} if the attribute does not contain any values.
395     *
396     * @param defaultValues
397     *            The default values to return if the attribute is empty.
398     * @return The values decoded as a set of {@code Long}s.
399     */
400    public Set<Long> asSetOfLong(final Long... defaultValues) {
401        return asSetOfLong(Arrays.asList(defaultValues));
402    }
403
404    /**
405     * Returns the values decoded as a set of {@code String}s, or
406     * {@code defaultValues} if the attribute does not contain any values.
407     *
408     * @param defaultValues
409     *            The default values to return if the attribute is empty.
410     * @return The values decoded as a set of {@code String}s.
411     */
412    public Set<String> asSetOfString(final Collection<String> defaultValues) {
413        return asSetOf(Functions.byteStringToString(), defaultValues);
414    }
415
416    /**
417     * Returns the values decoded as a set of {@code String}s, or
418     * {@code defaultValues} if the attribute does not contain any values.
419     *
420     * @param defaultValues
421     *            The default values to return if the attribute is empty.
422     * @return The values decoded as a set of {@code String}s.
423     */
424    public Set<String> asSetOfString(final String... defaultValues) {
425        return asSetOfString(Arrays.asList(defaultValues));
426    }
427
428    /**
429     * Returns the first value decoded as a {@code String}, or {@code null} if
430     * the attribute does not contain any values.
431     *
432     * @return The first value decoded as a {@code String}.
433     */
434    public String asString() {
435        return asString(null);
436    }
437
438    /**
439     * Returns the first value decoded as a {@code String}, or
440     * {@code defaultValue} if the attribute does not contain any values.
441     *
442     * @param defaultValue
443     *            The default value to return if the attribute is empty.
444     * @return The first value decoded as a {@code String}.
445     */
446    public String asString(final String defaultValue) {
447        return as(Functions.byteStringToString(), defaultValue);
448    }
449
450    /**
451     * Throws a {@code NoSuchElementException} if the attribute referenced by
452     * this parser is {@code null} or empty.
453     *
454     * @return A reference to this attribute parser.
455     * @throws NoSuchElementException
456     *             If the attribute referenced by this parser is {@code null} or
457     *             empty.
458     */
459    public AttributeParser requireValue() throws NoSuchElementException {
460        if (isEmpty(attribute)) {
461            throw new NoSuchElementException();
462        }
463        return this;
464    }
465
466    /**
467     * Sets the {@code Schema} which will be used when parsing schema sensitive
468     * values such as DNs and attribute descriptions.
469     *
470     * @param schema
471     *            The {@code Schema} which will be used when parsing schema
472     *            sensitive values.
473     * @return This attribute parser.
474     */
475    public AttributeParser usingSchema(final Schema schema) {
476        // Avoid modifying the null instance: a schema will not be needed anyway
477        if (this != NULL_INSTANCE) {
478            this.schema = schema;
479        }
480        return this;
481    }
482}