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.forgerock.opendj.ldap;
027
028import java.util.Arrays;
029import java.util.Collection;
030import java.util.Collections;
031import java.util.LinkedHashSet;
032import java.util.NoSuchElementException;
033import java.util.Set;
034
035import org.forgerock.opendj.ldap.schema.Schema;
036import org.forgerock.util.Function;
037import org.forgerock.util.promise.NeverThrowsException;
038
039import static com.forgerock.opendj.util.Collections2.*;
040
041/**
042 * A fluent API for parsing attributes as different types of object. An
043 * attribute parser is obtained from an entry using the method
044 * {@link Entry#parseAttribute} or from an attribute using
045 * {@link Attribute#parse}.
046 * <p>
047 * Methods throw an {@code IllegalArgumentException} when a value cannot be
048 * parsed (e.g. because its syntax is invalid). Methods which return a
049 * {@code Set} always return a modifiable non-{@code null} result, even if the
050 * attribute is {@code null} or empty.
051 * <p>
052 * Examples:
053 *
054 * <pre>
055 * Entry entry = ...;
056 *
057 * Calendar timestamp = entry.parseAttribute("createTimestamp").asCalendar();
058 * boolean isEnabled = entry.parseAttribute("enabled").asBoolean(false);
059 *
060 * Entry group = ...;
061 * Schema schema = ...;
062 *
063 * Set&lt;DN&gt; members = group.parseAttribute("member").usingSchema(schema).asSetOfDN();
064 * </pre>
065 *
066 * @see Entry#parseAttribute
067 * @see Attribute#parse
068 */
069public final class AttributeParser {
070    // TODO: enums, filters, rdns?
071
072    private static final AttributeParser NULL_INSTANCE = new AttributeParser(null);
073
074    /**
075     * Returns an attribute parser for the provided attribute. {@code null}
076     * attributes are permitted and will be treated as if an empty attribute was
077     * provided.
078     *
079     * @param attribute
080     *            The attribute to be parsed, which may be {@code null}.
081     * @return The attribute parser.
082     */
083    public static AttributeParser parseAttribute(final Attribute attribute) {
084        return isEmpty(attribute) ? NULL_INSTANCE : new AttributeParser(attribute);
085    }
086
087    private static boolean isEmpty(final Attribute attribute) {
088        return attribute == null || attribute.isEmpty();
089    }
090
091    private final Attribute attribute;
092    private Schema schema;
093
094    private AttributeParser(final Attribute attribute) {
095        this.attribute = attribute;
096    }
097
098    /**
099     * Returns the first value decoded as a {@code T} using the provided
100     * {@link Function}, or {@code null} if the attribute does not contain any
101     * values.
102     *
103     * @param <T>
104     *            The type of the value to be decoded.
105     * @param f
106     *            The function which should be used to decode the value.
107     * @return The first value decoded as a {@code T}.
108     */
109    public <T> T as(final Function<ByteString, ? extends T, NeverThrowsException> f) {
110        return as(f, null);
111    }
112
113    /**
114     * Returns the first value decoded as a {@code T} using the provided
115     * {@link Function}, or {@code defaultValue} if the attribute does not
116     * contain any values.
117     *
118     * @param <T>
119     *            The type of the value to be decoded.
120     * @param f
121     *            The function which should be used to decode the value.
122     * @param defaultValue
123     *            The default value to return if the attribute is empty.
124     * @return The first value decoded as a {@code T}.
125     */
126    public <T> T as(final Function<ByteString, ? extends T, NeverThrowsException> f, final T defaultValue) {
127        if (!isEmpty(attribute)) {
128            return f.apply(attribute.firstValue());
129        } else {
130            return defaultValue;
131        }
132    }
133
134    /**
135     * Returns the first value decoded as an {@code AttributeDescription} using
136     * the schema associated with this parser, or {@code null} if the attribute
137     * does not contain any values.
138     *
139     * @return The first value decoded as an {@code AttributeDescription}.
140     */
141    public AttributeDescription asAttributeDescription() {
142        return asAttributeDescription((AttributeDescription) null);
143    }
144
145    /**
146     * Returns the first value decoded as an {@code AttributeDescription} using
147     * the schema associated with this parser, or {@code defaultValue} if the
148     * attribute does not contain any values.
149     *
150     * @param defaultValue
151     *            The default value to return if the attribute is empty.
152     * @return The first value decoded as an {@code AttributeDescription}.
153     */
154    public AttributeDescription asAttributeDescription(final AttributeDescription defaultValue) {
155        return as(Functions.byteStringToAttributeDescription(getSchema()), defaultValue);
156    }
157
158    /**
159     * Returns the first value decoded as an {@code AttributeDescription} using
160     * the schema associated with this parser, or {@code defaultValue} if the
161     * attribute does not contain any values.
162     *
163     * @param defaultValue
164     *            The default value to return if the attribute is empty.
165     * @return The first value decoded as an {@code AttributeDescription}.
166     */
167    public AttributeDescription asAttributeDescription(final String defaultValue) {
168        return asAttributeDescription(AttributeDescription.valueOf(defaultValue, getSchema()));
169    }
170
171    /**
172     * Returns the first value decoded as a boolean, or {@code null} if the
173     * attribute does not contain any values.
174     *
175     * @return The first value decoded as a boolean.
176     */
177    public Boolean asBoolean() {
178        return isEmpty(attribute) ? null : asBoolean(false /* ignored */);
179    }
180
181    /**
182     * Returns the first value decoded as an {@code Boolean}, or
183     * {@code defaultValue} if the attribute does not contain any values.
184     *
185     * @param defaultValue
186     *            The default value to return if the attribute is empty.
187     * @return The first value decoded as an {@code Boolean}.
188     */
189    public boolean asBoolean(final boolean defaultValue) {
190        return as(Functions.byteStringToBoolean(), defaultValue);
191    }
192
193    /**
194     * Returns the first value, or {@code null} if the attribute does not
195     * contain any values.
196     *
197     * @return The first value.
198     */
199    public ByteString asByteString() {
200        return asByteString(null);
201    }
202
203    /**
204     * Returns the first value, or {@code defaultValue} if the attribute does
205     * not contain any values.
206     *
207     * @param defaultValue
208     *            The default value to return if the attribute is empty.
209     * @return The first value.
210     */
211    public ByteString asByteString(final ByteString defaultValue) {
212        return as(Functions.<ByteString> identityFunction(), defaultValue);
213    }
214
215    /**
216     * Returns the first value decoded as a {@code DN} using the schema
217     * associated with this parser, or {@code null} if the attribute does not
218     * contain any values.
219     *
220     * @return The first value decoded as a {@code DN}.
221     */
222    public DN asDN() {
223        return asDN((DN) null);
224    }
225
226    /**
227     * Returns the first value decoded as a {@code DN} using the schema
228     * associated with this parser, or {@code defaultValue} if the attribute
229     * does not contain any values.
230     *
231     * @param defaultValue
232     *            The default value to return if the attribute is empty.
233     * @return The first value decoded as a {@code DN}.
234     */
235    public DN asDN(final DN defaultValue) {
236        return as(Functions.byteStringToDN(getSchema()), defaultValue);
237    }
238
239    /**
240     * Returns the first value decoded as a {@code DN} using the schema
241     * associated with this parser, or {@code defaultValue} if the attribute
242     * does not contain any values.
243     *
244     * @param defaultValue
245     *            The default value to return if the attribute is empty.
246     * @return The first value decoded as a {@code DN}.
247     */
248    public DN asDN(final String defaultValue) {
249        return asDN(DN.valueOf(defaultValue, getSchema()));
250    }
251
252    /**
253     * Returns the first value decoded as a {@code GeneralizedTime} using the
254     * generalized time syntax, or {@code null} if the attribute does not
255     * contain any values.
256     *
257     * @return The first value decoded as a {@code GeneralizedTime}.
258     */
259    public GeneralizedTime asGeneralizedTime() {
260        return asGeneralizedTime(null);
261    }
262
263    /**
264     * Returns the first value decoded as an {@code GeneralizedTime} using the
265     * generalized time syntax, or {@code defaultValue} if the attribute does
266     * not contain any values.
267     *
268     * @param defaultValue
269     *            The default value to return if the attribute is empty.
270     * @return The first value decoded as an {@code GeneralizedTime}.
271     */
272    public GeneralizedTime asGeneralizedTime(final GeneralizedTime defaultValue) {
273        return as(Functions.byteStringToGeneralizedTime(), defaultValue);
274    }
275
276    /**
277     * Returns the first value decoded as an {@code Integer}, or {@code null} if
278     * the attribute does not contain any values.
279     *
280     * @return The first value decoded as an {@code Integer}.
281     */
282    public Integer asInteger() {
283        return isEmpty(attribute) ? null : asInteger(0 /* ignored */);
284    }
285
286    /**
287     * Returns the first value decoded as an {@code Integer}, or
288     * {@code defaultValue} if the attribute does not contain any values.
289     *
290     * @param defaultValue
291     *            The default value to return if the attribute is empty.
292     * @return The first value decoded as an {@code Integer}.
293     */
294    public int asInteger(final int defaultValue) {
295        return as(Functions.byteStringToInteger(), defaultValue);
296    }
297
298    /**
299     * Returns the first value decoded as a {@code Long}, or {@code null} if the
300     * attribute does not contain any values.
301     *
302     * @return The first value decoded as a {@code Long}.
303     */
304    public Long asLong() {
305        return isEmpty(attribute) ? null : asLong(0L /* ignored */);
306    }
307
308    /**
309     * Returns the first value decoded as a {@code Long}, or
310     * {@code defaultValue} if the attribute does not contain any values.
311     *
312     * @param defaultValue
313     *            The default value to return if the attribute is empty.
314     * @return The first value decoded as a {@code Long}.
315     */
316    public long asLong(final long defaultValue) {
317        return as(Functions.byteStringToLong(), defaultValue);
318    }
319
320    /**
321     * Returns the values decoded as a set of {@code T}s using the provided
322     * {@link Function}, or {@code defaultValues} if the attribute does not
323     * contain any values.
324     *
325     * @param <T>
326     *            The type of the values to be decoded.
327     * @param f
328     *            The function which should be used to decode values.
329     * @param defaultValues
330     *            The default values to return if the attribute is empty.
331     * @return The values decoded as a set of {@code T}s.
332     */
333    public <T> Set<T> asSetOf(final Function<ByteString, ? extends T, NeverThrowsException> f,
334            final Collection<? extends T> defaultValues) {
335        if (!isEmpty(attribute)) {
336            final LinkedHashSet<T> result = new LinkedHashSet<>(attribute.size());
337            for (final ByteString b : attribute) {
338                result.add(f.apply(b));
339            }
340            return result;
341        } else if (defaultValues != null) {
342            return new LinkedHashSet<>(defaultValues);
343        } else {
344            return new LinkedHashSet<>(0);
345        }
346    }
347
348    /**
349     * Returns the values decoded as a set of {@code T}s using the provided
350     * {@link Function}, or {@code defaultValues} if the attribute does not
351     * contain any values.
352     *
353     * @param <T>
354     *            The type of the values to be decoded.
355     * @param f
356     *            The function which should be used to decode values.
357     * @param defaultValues
358     *            The default values to return if the attribute is empty.
359     * @return The values decoded as a set of {@code T}s.
360     */
361    public <T> Set<T> asSetOf(final Function<ByteString, ? extends T, NeverThrowsException> f,
362            final T... defaultValues) {
363        return asSetOf(f, Arrays.asList(defaultValues));
364    }
365
366    /**
367     * Returns the values decoded as a set of {@code AttributeDescription}s
368     * using the schema associated with this parser, or an empty set if the
369     * attribute does not contain any values.
370     *
371     * @return The values decoded as a set of {@code AttributeDescription}s.
372     */
373    public Set<AttributeDescription> asSetOfAttributeDescription() {
374        return asSetOfAttributeDescription(Collections.<AttributeDescription> emptySet());
375    }
376
377    /**
378     * Returns the values decoded as a set of {@code AttributeDescription}s
379     * using the schema associated with this parser, or {@code defaultValues} if
380     * the attribute does not contain any values.
381     *
382     * @param defaultValues
383     *            The default values to return if the attribute is empty.
384     * @return The values decoded as a set of {@code AttributeDescription}s.
385     */
386    public Set<AttributeDescription> asSetOfAttributeDescription(
387            final AttributeDescription... defaultValues) {
388        return asSetOfAttributeDescription(Arrays.asList(defaultValues));
389    }
390
391    /**
392     * Returns the values decoded as a set of {@code AttributeDescription}s
393     * using the schema associated with this parser, or {@code defaultValues} if
394     * 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 AttributeDescription}s.
399     */
400    public Set<AttributeDescription> asSetOfAttributeDescription(
401            final Collection<AttributeDescription> defaultValues) {
402        return asSetOf(Functions.byteStringToAttributeDescription(), defaultValues);
403    }
404
405    /**
406     * Returns the values decoded as a set of {@code AttributeDescription}s
407     * using the schema associated with this parser, or {@code defaultValues} if
408     * the attribute does not contain any values.
409     *
410     * @param defaultValues
411     *            The default values to return if the attribute is empty.
412     * @return The values decoded as a set of {@code AttributeDescription}s.
413     */
414    public Set<AttributeDescription> asSetOfAttributeDescription(final String... defaultValues) {
415        return asSetOfAttributeDescription(transformedCollection(Arrays.asList(defaultValues),
416                Functions.stringToAttributeDescription(getSchema()), null));
417    }
418
419    /**
420     * Returns the values decoded as a set of {@code Boolean}s, or
421     * {@code defaultValues} if the attribute does not contain any values.
422     *
423     * @param defaultValues
424     *            The default values to return if the attribute is empty.
425     * @return The values decoded as a set of {@code Boolean}s.
426     */
427    public Set<Boolean> asSetOfBoolean(final Boolean... defaultValues) {
428        return asSetOfBoolean(Arrays.asList(defaultValues));
429    }
430
431    /**
432     * Returns the values decoded as a set of {@code Boolean}s, or
433     * {@code defaultValues} if the attribute does not contain any values.
434     *
435     * @param defaultValues
436     *            The default values to return if the attribute is empty.
437     * @return The values decoded as a set of {@code Boolean}s.
438     */
439    public Set<Boolean> asSetOfBoolean(final Collection<Boolean> defaultValues) {
440        return asSetOf(Functions.byteStringToBoolean(), defaultValues);
441    }
442
443    /**
444     * Returns the values contained in the attribute, or {@code defaultValues}
445     * if the attribute does not contain any values.
446     *
447     * @param defaultValues
448     *            The default values to return if the attribute is empty.
449     * @return The values contained in the attribute.
450     */
451    public Set<ByteString> asSetOfByteString(final ByteString... defaultValues) {
452        return asSetOfByteString(Arrays.asList(defaultValues));
453    }
454
455    /**
456     * Returns the values contained in the attribute, or {@code defaultValues}
457     * if the attribute does not contain any values.
458     *
459     * @param defaultValues
460     *            The default values to return if the attribute is empty.
461     * @return The values contained in the attribute.
462     */
463    public Set<ByteString> asSetOfByteString(final Collection<ByteString> defaultValues) {
464        return asSetOf(Functions.<ByteString> identityFunction(), defaultValues);
465    }
466
467    /**
468     * Returns the values decoded as a set of {@code DN}s using the schema
469     * associated with this parser, or an empty set if the attribute does not
470     * contain any values.
471     *
472     * @return The values decoded as a set of {@code DN}s.
473     */
474    public Set<DN> asSetOfDN() {
475        return asSetOfDN(Collections.<DN> emptySet());
476    }
477
478    /**
479     * Returns the values decoded as a set of {@code DN}s using the schema
480     * associated with this parser, or {@code defaultValues} if the attribute
481     * does not contain any values.
482     *
483     * @param defaultValues
484     *            The default values to return if the attribute is empty.
485     * @return The values decoded as a set of {@code DN}s.
486     */
487    public Set<DN> asSetOfDN(final Collection<DN> defaultValues) {
488        return asSetOf(Functions.byteStringToDN(), defaultValues);
489    }
490
491    /**
492     * Returns the values decoded as a set of {@code DN}s using the schema
493     * associated with this parser, or {@code defaultValues} if the attribute
494     * does not contain any values.
495     *
496     * @param defaultValues
497     *            The default values to return if the attribute is empty.
498     * @return The values decoded as a set of {@code DN}s.
499     */
500    public Set<DN> asSetOfDN(final DN... defaultValues) {
501        return asSetOfDN(Arrays.asList(defaultValues));
502    }
503
504    /**
505     * Returns the values decoded as a set of {@code DN}s using the schema
506     * associated with this parser, or {@code defaultValues} if the attribute
507     * does not contain any values.
508     *
509     * @param defaultValues
510     *            The default values to return if the attribute is empty.
511     * @return The values decoded as a set of {@code DN}s.
512     */
513    public Set<DN> asSetOfDN(final String... defaultValues) {
514        return asSetOfDN(transformedCollection(Arrays.asList(defaultValues), Functions
515                .stringToDN(getSchema()), null));
516    }
517
518    /**
519     * Returns the values decoded as a set of {@code GeneralizedTime}s using the
520     * generalized time syntax, or {@code defaultValues} if the attribute does
521     * not contain any values.
522     *
523     * @param defaultValues
524     *            The default values to return if the attribute is empty.
525     * @return The values decoded as a set of {@code GeneralizedTime}s.
526     */
527    public Set<GeneralizedTime> asSetOfGeneralizedTime(
528            final Collection<GeneralizedTime> defaultValues) {
529        return asSetOf(Functions.byteStringToGeneralizedTime(), defaultValues);
530    }
531
532    /**
533     * Returns the values decoded as a set of {@code GeneralizedTime}s using the
534     * generalized time syntax, or {@code defaultValues} if the attribute does
535     * not contain any values.
536     *
537     * @param defaultValues
538     *            The default values to return if the attribute is empty.
539     * @return The values decoded as a set of {@code GeneralizedTime}s.
540     */
541    public Set<GeneralizedTime> asSetOfGeneralizedTime(final GeneralizedTime... defaultValues) {
542        return asSetOfGeneralizedTime(Arrays.asList(defaultValues));
543    }
544
545    /**
546     * Returns the values decoded as a set of {@code Integer}s, or
547     * {@code defaultValues} if the attribute does not contain any values.
548     *
549     * @param defaultValues
550     *            The default values to return if the attribute is empty.
551     * @return The values decoded as a set of {@code Integer}s.
552     */
553    public Set<Integer> asSetOfInteger(final Collection<Integer> defaultValues) {
554        return asSetOf(Functions.byteStringToInteger(), defaultValues);
555    }
556
557    /**
558     * Returns the values decoded as a set of {@code Integer}s, or
559     * {@code defaultValues} if the attribute does not contain any values.
560     *
561     * @param defaultValues
562     *            The default values to return if the attribute is empty.
563     * @return The values decoded as a set of {@code Integer}s.
564     */
565    public Set<Integer> asSetOfInteger(final Integer... defaultValues) {
566        return asSetOfInteger(Arrays.asList(defaultValues));
567    }
568
569    /**
570     * Returns the values decoded as a set of {@code Long}s, or
571     * {@code defaultValues} if the attribute does not contain any values.
572     *
573     * @param defaultValues
574     *            The default values to return if the attribute is empty.
575     * @return The values decoded as a set of {@code Long}s.
576     */
577    public Set<Long> asSetOfLong(final Collection<Long> defaultValues) {
578        return asSetOf(Functions.byteStringToLong(), defaultValues);
579    }
580
581    /**
582     * Returns the values decoded as a set of {@code Long}s, or
583     * {@code defaultValues} if the attribute does not contain any values.
584     *
585     * @param defaultValues
586     *            The default values to return if the attribute is empty.
587     * @return The values decoded as a set of {@code Long}s.
588     */
589    public Set<Long> asSetOfLong(final Long... defaultValues) {
590        return asSetOfLong(Arrays.asList(defaultValues));
591    }
592
593    /**
594     * Returns the values decoded as a set of {@code String}s, or
595     * {@code defaultValues} if the attribute does not contain any values.
596     *
597     * @param defaultValues
598     *            The default values to return if the attribute is empty.
599     * @return The values decoded as a set of {@code String}s.
600     */
601    public Set<String> asSetOfString(final Collection<String> defaultValues) {
602        return asSetOf(Functions.byteStringToString(), defaultValues);
603    }
604
605    /**
606     * Returns the values decoded as a set of {@code String}s, or
607     * {@code defaultValues} if the attribute does not contain any values.
608     *
609     * @param defaultValues
610     *            The default values to return if the attribute is empty.
611     * @return The values decoded as a set of {@code String}s.
612     */
613    public Set<String> asSetOfString(final String... defaultValues) {
614        return asSetOfString(Arrays.asList(defaultValues));
615    }
616
617    /**
618     * Returns the first value decoded as a {@code String}, or {@code null} if
619     * the attribute does not contain any values.
620     *
621     * @return The first value decoded as a {@code String}.
622     */
623    public String asString() {
624        return asString(null);
625    }
626
627    /**
628     * Returns the first value decoded as a {@code String}, or
629     * {@code defaultValue} if the attribute does not contain any values.
630     *
631     * @param defaultValue
632     *            The default value to return if the attribute is empty.
633     * @return The first value decoded as a {@code String}.
634     */
635    public String asString(final String defaultValue) {
636        return as(Functions.byteStringToString(), defaultValue);
637    }
638
639    /**
640     * Throws a {@code NoSuchElementException} if the attribute referenced by
641     * this parser is {@code null} or empty.
642     *
643     * @return A reference to this attribute parser.
644     * @throws NoSuchElementException
645     *             If the attribute referenced by this parser is {@code null} or
646     *             empty.
647     */
648    public AttributeParser requireValue() {
649        if (isEmpty(attribute)) {
650            throw new NoSuchElementException();
651        } else {
652            return this;
653        }
654    }
655
656    /**
657     * Sets the {@code Schema} which will be used when parsing schema sensitive
658     * values such as DNs and attribute descriptions.
659     *
660     * @param schema
661     *            The {@code Schema} which will be used when parsing schema
662     *            sensitive values.
663     * @return This attribute parser.
664     */
665    public AttributeParser usingSchema(final Schema schema) {
666        // Avoid modifying the null instance: a schema will not be needed
667        // anyway.
668        if (this != NULL_INSTANCE) {
669            this.schema = schema;
670        }
671        return this;
672    }
673
674    private Schema getSchema() {
675        return schema == null ? Schema.getDefaultSchema() : schema;
676    }
677}