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