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