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