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    @SafeVarargs
362    @SuppressWarnings("varargs")
363    public final <T> Set<T> asSetOf(final Function<ByteString, ? extends T, NeverThrowsException> f,
364            final T... defaultValues) {
365        return asSetOf(f, Arrays.asList(defaultValues));
366    }
367
368    /**
369     * Returns the values decoded as a set of {@code AttributeDescription}s
370     * using the schema associated with this parser, or an empty set if the
371     * attribute does not contain any values.
372     *
373     * @return The values decoded as a set of {@code AttributeDescription}s.
374     */
375    public Set<AttributeDescription> asSetOfAttributeDescription() {
376        return asSetOfAttributeDescription(Collections.<AttributeDescription> emptySet());
377    }
378
379    /**
380     * Returns the values decoded as a set of {@code AttributeDescription}s
381     * using the schema associated with this parser, or {@code defaultValues} if
382     * 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 AttributeDescription}s.
387     */
388    public Set<AttributeDescription> asSetOfAttributeDescription(
389            final AttributeDescription... defaultValues) {
390        return asSetOfAttributeDescription(Arrays.asList(defaultValues));
391    }
392
393    /**
394     * Returns the values decoded as a set of {@code AttributeDescription}s
395     * using the schema associated with this parser, or {@code defaultValues} if
396     * the attribute does not contain any values.
397     *
398     * @param defaultValues
399     *            The default values to return if the attribute is empty.
400     * @return The values decoded as a set of {@code AttributeDescription}s.
401     */
402    public Set<AttributeDescription> asSetOfAttributeDescription(
403            final Collection<AttributeDescription> defaultValues) {
404        return asSetOf(Functions.byteStringToAttributeDescription(), defaultValues);
405    }
406
407    /**
408     * Returns the values decoded as a set of {@code AttributeDescription}s
409     * using the schema associated with this parser, or {@code defaultValues} if
410     * the attribute does not contain any values.
411     *
412     * @param defaultValues
413     *            The default values to return if the attribute is empty.
414     * @return The values decoded as a set of {@code AttributeDescription}s.
415     */
416    public Set<AttributeDescription> asSetOfAttributeDescription(final String... defaultValues) {
417        return asSetOfAttributeDescription(transformedCollection(Arrays.asList(defaultValues),
418                Functions.stringToAttributeDescription(getSchema()), null));
419    }
420
421    /**
422     * Returns the values decoded as a set of {@code Boolean}s, or
423     * {@code defaultValues} if the attribute does not contain any values.
424     *
425     * @param defaultValues
426     *            The default values to return if the attribute is empty.
427     * @return The values decoded as a set of {@code Boolean}s.
428     */
429    public Set<Boolean> asSetOfBoolean(final Boolean... defaultValues) {
430        return asSetOfBoolean(Arrays.asList(defaultValues));
431    }
432
433    /**
434     * Returns the values decoded as a set of {@code Boolean}s, or
435     * {@code defaultValues} if the attribute does not contain any values.
436     *
437     * @param defaultValues
438     *            The default values to return if the attribute is empty.
439     * @return The values decoded as a set of {@code Boolean}s.
440     */
441    public Set<Boolean> asSetOfBoolean(final Collection<Boolean> defaultValues) {
442        return asSetOf(Functions.byteStringToBoolean(), defaultValues);
443    }
444
445    /**
446     * Returns the values contained in the attribute, or {@code defaultValues}
447     * if the attribute does not contain any values.
448     *
449     * @param defaultValues
450     *            The default values to return if the attribute is empty.
451     * @return The values contained in the attribute.
452     */
453    public Set<ByteString> asSetOfByteString(final ByteString... defaultValues) {
454        return asSetOfByteString(Arrays.asList(defaultValues));
455    }
456
457    /**
458     * Returns the values contained in the attribute, or {@code defaultValues}
459     * if the attribute does not contain any values.
460     *
461     * @param defaultValues
462     *            The default values to return if the attribute is empty.
463     * @return The values contained in the attribute.
464     */
465    public Set<ByteString> asSetOfByteString(final Collection<ByteString> defaultValues) {
466        return asSetOf(Functions.<ByteString> identityFunction(), defaultValues);
467    }
468
469    /**
470     * Returns the values decoded as a set of {@code DN}s using the schema
471     * associated with this parser, or an empty set if the attribute does not
472     * contain any values.
473     *
474     * @return The values decoded as a set of {@code DN}s.
475     */
476    public Set<DN> asSetOfDN() {
477        return asSetOfDN(Collections.<DN> emptySet());
478    }
479
480    /**
481     * Returns the values decoded as a set of {@code DN}s using the schema
482     * associated with this parser, or {@code defaultValues} if the attribute
483     * does not contain any values.
484     *
485     * @param defaultValues
486     *            The default values to return if the attribute is empty.
487     * @return The values decoded as a set of {@code DN}s.
488     */
489    public Set<DN> asSetOfDN(final Collection<DN> defaultValues) {
490        return asSetOf(Functions.byteStringToDN(), defaultValues);
491    }
492
493    /**
494     * Returns the values decoded as a set of {@code DN}s using the schema
495     * associated with this parser, or {@code defaultValues} if the attribute
496     * does not contain any values.
497     *
498     * @param defaultValues
499     *            The default values to return if the attribute is empty.
500     * @return The values decoded as a set of {@code DN}s.
501     */
502    public Set<DN> asSetOfDN(final DN... defaultValues) {
503        return asSetOfDN(Arrays.asList(defaultValues));
504    }
505
506    /**
507     * Returns the values decoded as a set of {@code DN}s using the schema
508     * associated with this parser, or {@code defaultValues} if the attribute
509     * does not contain any values.
510     *
511     * @param defaultValues
512     *            The default values to return if the attribute is empty.
513     * @return The values decoded as a set of {@code DN}s.
514     */
515    public Set<DN> asSetOfDN(final String... defaultValues) {
516        return asSetOfDN(transformedCollection(Arrays.asList(defaultValues), Functions
517                .stringToDN(getSchema()), null));
518    }
519
520    /**
521     * Returns the values decoded as a set of {@code GeneralizedTime}s using the
522     * generalized time syntax, or {@code defaultValues} if the attribute does
523     * not contain any values.
524     *
525     * @param defaultValues
526     *            The default values to return if the attribute is empty.
527     * @return The values decoded as a set of {@code GeneralizedTime}s.
528     */
529    public Set<GeneralizedTime> asSetOfGeneralizedTime(
530            final Collection<GeneralizedTime> defaultValues) {
531        return asSetOf(Functions.byteStringToGeneralizedTime(), defaultValues);
532    }
533
534    /**
535     * Returns the values decoded as a set of {@code GeneralizedTime}s using the
536     * generalized time syntax, or {@code defaultValues} if the attribute does
537     * not contain any values.
538     *
539     * @param defaultValues
540     *            The default values to return if the attribute is empty.
541     * @return The values decoded as a set of {@code GeneralizedTime}s.
542     */
543    public Set<GeneralizedTime> asSetOfGeneralizedTime(final GeneralizedTime... defaultValues) {
544        return asSetOfGeneralizedTime(Arrays.asList(defaultValues));
545    }
546
547    /**
548     * Returns the values decoded as a set of {@code Integer}s, or
549     * {@code defaultValues} if the attribute does not contain any values.
550     *
551     * @param defaultValues
552     *            The default values to return if the attribute is empty.
553     * @return The values decoded as a set of {@code Integer}s.
554     */
555    public Set<Integer> asSetOfInteger(final Collection<Integer> defaultValues) {
556        return asSetOf(Functions.byteStringToInteger(), defaultValues);
557    }
558
559    /**
560     * Returns the values decoded as a set of {@code Integer}s, or
561     * {@code defaultValues} if the attribute does not contain any values.
562     *
563     * @param defaultValues
564     *            The default values to return if the attribute is empty.
565     * @return The values decoded as a set of {@code Integer}s.
566     */
567    public Set<Integer> asSetOfInteger(final Integer... defaultValues) {
568        return asSetOfInteger(Arrays.asList(defaultValues));
569    }
570
571    /**
572     * Returns the values decoded as a set of {@code Long}s, or
573     * {@code defaultValues} if the attribute does not contain any values.
574     *
575     * @param defaultValues
576     *            The default values to return if the attribute is empty.
577     * @return The values decoded as a set of {@code Long}s.
578     */
579    public Set<Long> asSetOfLong(final Collection<Long> defaultValues) {
580        return asSetOf(Functions.byteStringToLong(), defaultValues);
581    }
582
583    /**
584     * Returns the values decoded as a set of {@code Long}s, or
585     * {@code defaultValues} if the attribute does not contain any values.
586     *
587     * @param defaultValues
588     *            The default values to return if the attribute is empty.
589     * @return The values decoded as a set of {@code Long}s.
590     */
591    public Set<Long> asSetOfLong(final Long... defaultValues) {
592        return asSetOfLong(Arrays.asList(defaultValues));
593    }
594
595    /**
596     * Returns the values decoded as a set of {@code String}s, or
597     * {@code defaultValues} if the attribute does not contain any values.
598     *
599     * @param defaultValues
600     *            The default values to return if the attribute is empty.
601     * @return The values decoded as a set of {@code String}s.
602     */
603    public Set<String> asSetOfString(final Collection<String> defaultValues) {
604        return asSetOf(Functions.byteStringToString(), defaultValues);
605    }
606
607    /**
608     * Returns the values decoded as a set of {@code String}s, or
609     * {@code defaultValues} if the attribute does not contain any values.
610     *
611     * @param defaultValues
612     *            The default values to return if the attribute is empty.
613     * @return The values decoded as a set of {@code String}s.
614     */
615    public Set<String> asSetOfString(final String... defaultValues) {
616        return asSetOfString(Arrays.asList(defaultValues));
617    }
618
619    /**
620     * Returns the first value decoded as a {@code String}, or {@code null} if
621     * the attribute does not contain any values.
622     *
623     * @return The first value decoded as a {@code String}.
624     */
625    public String asString() {
626        return asString(null);
627    }
628
629    /**
630     * Returns the first value decoded as a {@code String}, or
631     * {@code defaultValue} if the attribute does not contain any values.
632     *
633     * @param defaultValue
634     *            The default value to return if the attribute is empty.
635     * @return The first value decoded as a {@code String}.
636     */
637    public String asString(final String defaultValue) {
638        return as(Functions.byteStringToString(), defaultValue);
639    }
640
641    /**
642     * Throws a {@code NoSuchElementException} if the attribute referenced by
643     * this parser is {@code null} or empty.
644     *
645     * @return A reference to this attribute parser.
646     * @throws NoSuchElementException
647     *             If the attribute referenced by this parser is {@code null} or
648     *             empty.
649     */
650    public AttributeParser requireValue() {
651        if (isEmpty(attribute)) {
652            throw new NoSuchElementException();
653        } else {
654            return this;
655        }
656    }
657
658    /**
659     * Sets the {@code Schema} which will be used when parsing schema sensitive
660     * values such as DNs and attribute descriptions.
661     *
662     * @param schema
663     *            The {@code Schema} which will be used when parsing schema
664     *            sensitive values.
665     * @return This attribute parser.
666     */
667    public AttributeParser usingSchema(final Schema schema) {
668        // Avoid modifying the null instance: a schema will not be needed
669        // anyway.
670        if (this != NULL_INSTANCE) {
671            this.schema = schema;
672        }
673        return this;
674    }
675
676    private Schema getSchema() {
677        return schema == null ? Schema.getDefaultSchema() : schema;
678    }
679}