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 2012-2015 ForgeRock AS.
025 */
026package org.opends.server.types;
027
028import java.util.Arrays;
029import java.util.Collection;
030import java.util.LinkedHashSet;
031import java.util.NoSuchElementException;
032import java.util.Set;
033
034import org.forgerock.opendj.ldap.ByteString;
035import org.forgerock.opendj.ldap.Functions;
036import org.forgerock.opendj.ldap.GeneralizedTime;
037import org.forgerock.opendj.ldap.schema.Schema;
038import org.forgerock.util.Function;
039import org.forgerock.util.promise.NeverThrowsException;
040
041
042/**
043 * A fluent API for parsing attributes as different types of object. An
044 * attribute parser is obtained from an entry using the method
045 * {@link Entry#parseAttribute} or from an attribute using
046 * {@link Attribute#parse}.
047 * <p>
048 * Methods throw an {@code IllegalArgumentException} when a value cannot be
049 * parsed (e.g. because its syntax is invalid). Methods which return a
050 * {@code Set} always return a modifiable non-{@code null} result, even if the
051 * attribute is {@code null} or empty.
052 * <p>
053 * Examples:
054 *
055 * <pre>
056 * Entry entry = ...;
057 *
058 * Calendar timestamp = entry.parseAttribute("createTimestamp").asCalendar();
059 * boolean isEnabled = entry.parseAttribute("enabled").asBoolean(false);
060 *
061 * Entry group = ...;
062 * Schema schema = ...;
063 *
064 * Set&lt;DN&gt; members = group.parseAttribute("member").usingSchema(schema).asSetOfDN();
065 * </pre>
066 *
067 * @see Entry#parseAttribute
068 * @see Attribute#parse
069 */
070public final class AttributeParser {
071    // TODO: enums, filters, rdns?
072
073    private static final AttributeParser NULL_INSTANCE = new AttributeParser(null);
074
075    /**
076     * Returns an attribute parser for the provided attribute. {@code null}
077     * attributes are permitted and will be treated as if an empty attribute was
078     * provided.
079     *
080     * @param attribute
081     *            The attribute to be parsed, which may be {@code null}.
082     * @return The attribute parser.
083     */
084    public static AttributeParser parseAttribute(final Attribute attribute) {
085        return isEmpty(attribute) ? NULL_INSTANCE : new AttributeParser(attribute);
086    }
087
088    private static boolean isEmpty(final Attribute attribute) {
089        return attribute == null || attribute.isEmpty();
090    }
091
092    private final Attribute attribute;
093    private Schema schema;
094
095    private AttributeParser(final Attribute attribute) {
096        this.attribute = attribute;
097    }
098
099    /**
100     * Returns the first value decoded as a {@code T} using the provided
101     * {@link Function}, or {@code null} if the attribute does not contain any
102     * values.
103     *
104     * @param <T>
105     *            The type of the value to be decoded.
106     * @param f
107     *            The function which should be used to decode the value.
108     * @return The first value decoded as a {@code T}.
109     */
110    public <T> T as(final Function<ByteString, ? extends T, NeverThrowsException> f) {
111        return as(f, null);
112    }
113
114    /**
115     * Returns the first value decoded as a {@code T} using the provided
116     * {@link Function}, or {@code defaultValue} if the attribute does not
117     * contain any values.
118     *
119     * @param <T>
120     *            The type of the value to be decoded.
121     * @param f
122     *            The function which should be used to decode the value.
123     * @param defaultValue
124     *            The default value to return if the attribute is empty.
125     * @return The first value decoded as a {@code T}.
126     */
127    public <T> T as(final Function<ByteString, ? extends T, NeverThrowsException> f, final T defaultValue) {
128        if (!isEmpty(attribute)) {
129            return f.apply(attribute.iterator().next());
130        } else {
131            return defaultValue;
132        }
133    }
134
135    /**
136     * Returns the first value decoded as a boolean, or {@code null} if the
137     * attribute does not contain any values.
138     *
139     * @return The first value decoded as a boolean.
140     */
141    public Boolean asBoolean() {
142        return isEmpty(attribute) ? null : asBoolean(false /* ignored */);
143    }
144
145    /**
146     * Returns the first value decoded as an {@code Boolean}, or
147     * {@code defaultValue} if the attribute does not contain any values.
148     *
149     * @param defaultValue
150     *            The default value to return if the attribute is empty.
151     * @return The first value decoded as an {@code Boolean}.
152     */
153    public boolean asBoolean(final boolean defaultValue) {
154        return as(Functions.byteStringToBoolean(), defaultValue);
155    }
156
157    /**
158     * Returns the first value, or {@code null} if the attribute does not
159     * contain any values.
160     *
161     * @return The first value.
162     */
163    public ByteString asByteString() {
164        return asByteString(null);
165    }
166
167    /**
168     * Returns the first value, or {@code defaultValue} if the attribute does
169     * not contain any values.
170     *
171     * @param defaultValue
172     *            The default value to return if the attribute is empty.
173     * @return The first value.
174     */
175    public ByteString asByteString(final ByteString defaultValue) {
176        return as(Functions.<ByteString> identityFunction(), defaultValue);
177    }
178
179    /**
180     * Returns the first value decoded as a {@code GeneralizedTime} using the
181     * generalized time syntax, or {@code null} if the attribute does not
182     * contain any values.
183     *
184     * @return The first value decoded as a {@code GeneralizedTime}.
185     */
186    public GeneralizedTime asGeneralizedTime() {
187        return asGeneralizedTime(null);
188    }
189
190    /**
191     * Returns the first value decoded as an {@code GeneralizedTime} using the
192     * generalized time syntax, or {@code defaultValue} if the attribute does
193     * not contain any values.
194     *
195     * @param defaultValue
196     *            The default value to return if the attribute is empty.
197     * @return The first value decoded as an {@code GeneralizedTime}.
198     */
199    public GeneralizedTime asGeneralizedTime(final GeneralizedTime defaultValue) {
200        return as(Functions.byteStringToGeneralizedTime(), defaultValue);
201    }
202
203    /**
204     * Returns the first value decoded as an {@code Integer}, or {@code null} if
205     * the attribute does not contain any values.
206     *
207     * @return The first value decoded as an {@code Integer}.
208     */
209    public Integer asInteger() {
210        return isEmpty(attribute) ? null : asInteger(0 /* ignored */);
211    }
212
213    /**
214     * Returns the first value decoded as an {@code Integer}, or
215     * {@code defaultValue} if the attribute does not contain any values.
216     *
217     * @param defaultValue
218     *            The default value to return if the attribute is empty.
219     * @return The first value decoded as an {@code Integer}.
220     */
221    public int asInteger(final int defaultValue) {
222        return as(Functions.byteStringToInteger(), defaultValue);
223    }
224
225    /**
226     * Returns the first value decoded as a {@code Long}, or {@code null} if the
227     * attribute does not contain any values.
228     *
229     * @return The first value decoded as a {@code Long}.
230     */
231    public Long asLong() {
232        return isEmpty(attribute) ? null : asLong(0L /* ignored */);
233    }
234
235    /**
236     * Returns the first value decoded as a {@code Long}, or
237     * {@code defaultValue} if the attribute does not contain any values.
238     *
239     * @param defaultValue
240     *            The default value to return if the attribute is empty.
241     * @return The first value decoded as a {@code Long}.
242     */
243    public long asLong(final long defaultValue) {
244        return as(Functions.byteStringToLong(), defaultValue);
245    }
246
247    /**
248     * Returns the values decoded as a set of {@code T}s using the provided
249     * {@link Function}, or {@code defaultValues} if the attribute does not
250     * contain any values.
251     *
252     * @param <T>
253     *            The type of the values to be decoded.
254     * @param f
255     *            The function which should be used to decode values.
256     * @param defaultValues
257     *            The default values to return if the attribute is empty.
258     * @return The values decoded as a set of {@code T}s.
259     */
260    public <T> Set<T> asSetOf(final Function<ByteString, ? extends T, NeverThrowsException> f,
261            final Collection<? extends T> defaultValues) {
262        if (!isEmpty(attribute)) {
263            final LinkedHashSet<T> result = new LinkedHashSet<>(attribute.size());
264            for (final ByteString v : attribute) {
265                result.add(f.apply(v));
266            }
267            return result;
268        } else if (defaultValues != null) {
269            return new LinkedHashSet<>(defaultValues);
270        } else {
271            return new LinkedHashSet<>(0);
272        }
273    }
274
275    /**
276     * Returns the values decoded as a set of {@code T}s using the provided
277     * {@link Function}, or {@code defaultValues} if the attribute does not
278     * contain any values.
279     *
280     * @param <T>
281     *            The type of the values to be decoded.
282     * @param f
283     *            The function which should be used to decode values.
284     * @param defaultValues
285     *            The default values to return if the attribute is empty.
286     * @return The values decoded as a set of {@code T}s.
287     */
288    public <T> Set<T> asSetOf(final Function<ByteString, ? extends T, NeverThrowsException> f,
289            final T... defaultValues) {
290        return asSetOf(f, 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 Boolean... defaultValues) {
302        return asSetOfBoolean(Arrays.asList(defaultValues));
303    }
304
305    /**
306     * Returns the values decoded as a set of {@code Boolean}s, or
307     * {@code defaultValues} 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 decoded as a set of {@code Boolean}s.
312     */
313    public Set<Boolean> asSetOfBoolean(final Collection<Boolean> defaultValues) {
314        return asSetOf(Functions.byteStringToBoolean(), 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 ByteString... defaultValues) {
326        return asSetOfByteString(Arrays.asList(defaultValues));
327    }
328
329    /**
330     * Returns the values contained in the attribute, or {@code defaultValues}
331     * if the attribute does not contain any values.
332     *
333     * @param defaultValues
334     *            The default values to return if the attribute is empty.
335     * @return The values contained in the attribute.
336     */
337    public Set<ByteString> asSetOfByteString(final Collection<ByteString> defaultValues) {
338        return asSetOf(Functions.<ByteString> identityFunction(), defaultValues);
339    }
340
341    /**
342     * Returns the values decoded as a set of {@code GeneralizedTime}s using the
343     * generalized time syntax, or {@code defaultValues} if the attribute does
344     * not contain any values.
345     *
346     * @param defaultValues
347     *            The default values to return if the attribute is empty.
348     * @return The values decoded as a set of {@code GeneralizedTime}s.
349     */
350    public Set<GeneralizedTime> asSetOfGeneralizedTime(
351            final Collection<GeneralizedTime> defaultValues) {
352        return asSetOf(Functions.byteStringToGeneralizedTime(), defaultValues);
353    }
354
355    /**
356     * Returns the values decoded as a set of {@code GeneralizedTime}s using the
357     * generalized time syntax, or {@code defaultValues} if the attribute does
358     * 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 GeneralizedTime}s.
363     */
364    public Set<GeneralizedTime> asSetOfGeneralizedTime(final GeneralizedTime... defaultValues) {
365        return asSetOfGeneralizedTime(Arrays.asList(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 Collection<Integer> defaultValues) {
377        return asSetOf(Functions.byteStringToInteger(), defaultValues);
378    }
379
380    /**
381     * Returns the values decoded as a set of {@code Integer}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 Integer}s.
387     */
388    public Set<Integer> asSetOfInteger(final Integer... defaultValues) {
389        return asSetOfInteger(Arrays.asList(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 Collection<Long> defaultValues) {
401        return asSetOf(Functions.byteStringToLong(), defaultValues);
402    }
403
404    /**
405     * Returns the values decoded as a set of {@code Long}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 Long}s.
411     */
412    public Set<Long> asSetOfLong(final Long... defaultValues) {
413        return asSetOfLong(Arrays.asList(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 Collection<String> defaultValues) {
425        return asSetOf(Functions.byteStringToString(), defaultValues);
426    }
427
428    /**
429     * Returns the values decoded as a set of {@code String}s, or
430     * {@code defaultValues} if the attribute does not contain any values.
431     *
432     * @param defaultValues
433     *            The default values to return if the attribute is empty.
434     * @return The values decoded as a set of {@code String}s.
435     */
436    public Set<String> asSetOfString(final String... defaultValues) {
437        return asSetOfString(Arrays.asList(defaultValues));
438    }
439
440    /**
441     * Returns the first value decoded as a {@code String}, or {@code null} if
442     * the attribute does not contain any values.
443     *
444     * @return The first value decoded as a {@code String}.
445     */
446    public String asString() {
447        return asString(null);
448    }
449
450    /**
451     * Returns the first value decoded as a {@code String}, or
452     * {@code defaultValue} if the attribute does not contain any values.
453     *
454     * @param defaultValue
455     *            The default value to return if the attribute is empty.
456     * @return The first value decoded as a {@code String}.
457     */
458    public String asString(final String defaultValue) {
459        return as(Functions.byteStringToString(), defaultValue);
460    }
461
462    /**
463     * Throws a {@code NoSuchElementException} if the attribute referenced by
464     * this parser is {@code null} or empty.
465     *
466     * @return A reference to this attribute parser.
467     * @throws NoSuchElementException
468     *             If the attribute referenced by this parser is {@code null} or
469     *             empty.
470     */
471    public AttributeParser requireValue() throws NoSuchElementException {
472        if (isEmpty(attribute)) {
473            throw new NoSuchElementException();
474        } else {
475            return this;
476        }
477    }
478
479    /**
480     * Sets the {@code Schema} which will be used when parsing schema sensitive
481     * values such as DNs and attribute descriptions.
482     *
483     * @param schema
484     *            The {@code Schema} which will be used when parsing schema
485     *            sensitive values.
486     * @return This attribute parser.
487     */
488    public AttributeParser usingSchema(final Schema schema) {
489        // Avoid modifying the null instance: a schema will not be needed
490        // anyway.
491        if (this != NULL_INSTANCE) {
492            this.schema = schema;
493        }
494        return this;
495    }
496
497    private Schema getSchema() {
498        return schema == null ? Schema.getDefaultSchema() : schema;
499    }
500}