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 2009-2010 Sun Microsystems, Inc.
015 * Portions copyright 2012-2016 ForgeRock AS.
016 */
017package org.forgerock.opendj.ldap;
018
019import org.forgerock.i18n.LocalizableMessage;
020import org.forgerock.i18n.LocalizedIllegalArgumentException;
021import org.forgerock.opendj.ldap.schema.Schema;
022import org.forgerock.util.Function;
023import org.forgerock.util.promise.NeverThrowsException;
024
025import com.forgerock.opendj.util.StaticUtils;
026
027import static org.forgerock.opendj.ldap.schema.Schema.*;
028
029import static com.forgerock.opendj.ldap.CoreMessages.*;
030
031/**
032 * Common {@link Function} implementations which may be used when parsing
033 * attributes.
034 *
035 * @see Entry#parseAttribute
036 * @see Attribute#parse
037 * @see AttributeParser
038 */
039public final class Functions {
040
041    private static final Function<ByteString, String, NeverThrowsException> BYTESTRING_TO_STRING =
042            new Function<ByteString, String, NeverThrowsException>() {
043                @Override
044                public String apply(final ByteString value) {
045                    return value.toString();
046                }
047            };
048
049    private static final Function<Object, Object, NeverThrowsException> IDENTITY =
050            new Function<Object, Object, NeverThrowsException>() {
051                @Override
052                public Object apply(final Object value) {
053                    return value;
054                }
055            };
056
057    private static final Function<String, String, NeverThrowsException> NORMALIZE_STRING =
058            new Function<String, String, NeverThrowsException>() {
059                @Override
060                public String apply(final String value) {
061                    return StaticUtils.toLowerCase(value).trim();
062                }
063            };
064
065    private static final Function<Object, ByteString, NeverThrowsException> OBJECT_TO_BYTESTRING =
066            new Function<Object, ByteString, NeverThrowsException>() {
067                @Override
068                public ByteString apply(final Object value) {
069                    return ByteString.valueOfObject(value);
070                }
071            };
072
073    private static final Function<String, Boolean, NeverThrowsException> STRING_TO_BOOLEAN =
074            new Function<String, Boolean, NeverThrowsException>() {
075                @Override
076                public Boolean apply(final String value) {
077                    final String valueString = StaticUtils.toLowerCase(value);
078                    if ("true".equals(valueString) || "yes".equals(valueString)
079                            || "on".equals(valueString) || "1".equals(valueString)) {
080                        return Boolean.TRUE;
081                    } else if ("false".equals(valueString) || "no".equals(valueString)
082                            || "off".equals(valueString) || "0".equals(valueString)) {
083                        return Boolean.FALSE;
084                    } else {
085                        throw new LocalizedIllegalArgumentException(
086                                WARN_ATTR_SYNTAX_ILLEGAL_BOOLEAN.get(valueString));
087                    }
088                }
089            };
090
091    private static final Function<String, GeneralizedTime, NeverThrowsException> STRING_TO_GENERALIZED_TIME =
092            new Function<String, GeneralizedTime, NeverThrowsException>() {
093                @Override
094                public GeneralizedTime apply(final String value) {
095                    return GeneralizedTime.valueOf(value);
096                }
097            };
098
099    private static final Function<String, Integer, NeverThrowsException> STRING_TO_INTEGER =
100            new Function<String, Integer, NeverThrowsException>() {
101                @Override
102                public Integer apply(final String value) {
103                    try {
104                        return Integer.valueOf(value);
105                    } catch (final NumberFormatException e) {
106                        final LocalizableMessage message = FUNCTIONS_TO_INTEGER_FAIL.get(value);
107                        throw new LocalizedIllegalArgumentException(message);
108                    }
109                }
110            };
111
112    private static final Function<String, Long, NeverThrowsException> STRING_TO_LONG =
113            new Function<String, Long, NeverThrowsException>() {
114                @Override
115                public Long apply(final String value) {
116                    try {
117                        return Long.valueOf(value);
118                    } catch (final NumberFormatException e) {
119                        final LocalizableMessage message = FUNCTIONS_TO_LONG_FAIL.get(value);
120                        throw new LocalizedIllegalArgumentException(message);
121                    }
122                }
123            };
124
125    private static final Function<ByteString, Boolean, NeverThrowsException> BYTESTRING_TO_BOOLEAN = compose(
126            byteStringToString(), STRING_TO_BOOLEAN);
127
128    private static final Function<ByteString, GeneralizedTime, NeverThrowsException> BYTESTRING_TO_GENERALIZED_TIME =
129            compose(byteStringToString(), STRING_TO_GENERALIZED_TIME);
130
131    private static final Function<ByteString, Integer, NeverThrowsException> BYTESTRING_TO_INTEGER = compose(
132            byteStringToString(), STRING_TO_INTEGER);
133
134    private static final Function<ByteString, Long, NeverThrowsException> BYTESTRING_TO_LONG = compose(
135            byteStringToString(), STRING_TO_LONG);
136
137    /**
138     * Creates a function that returns constant value for any input.
139     *
140     * @param <M>
141     *            The type of input values transformed by this function.
142     * @param <N>
143     *            The type of output values returned by this function.
144     * @param constant
145     *            The constant value for the function to return
146     * @return A function that always returns constant value.
147     */
148    public static <M, N> Function<M, N, NeverThrowsException> returns(final N constant) {
149        return new Function<M, N, NeverThrowsException>() {
150            @Override
151            public N apply(M value) {
152                return constant;
153            }
154        };
155    }
156
157    /**
158     * Returns the composition of two functions. The result of the first
159     * function will be passed to the second.
160     *
161     * @param <M>
162     *            The type of input values transformed by this function.
163     * @param <N>
164     *            The type of output values returned by this function.
165     * @param <X>
166     *            The type of intermediate values passed between the two
167     *            functions.
168     * @param first
169     *            The first function which will consume the input.
170     * @param second
171     *            The second function which will produce the result.
172     * @return The composition.
173     */
174    public static <M, X, N> Function<M, N, NeverThrowsException> compose(
175            final Function<M, X, NeverThrowsException> first, final Function<X, N, NeverThrowsException> second) {
176        return new Function<M, N, NeverThrowsException>() {
177            @Override
178            public N apply(final M value) {
179                return second.apply(first.apply(value));
180            }
181        };
182    }
183
184    /**
185     * Returns a function which always returns the value that it was provided
186     * with.
187     *
188     * @param <M>
189     *            The type of values transformed by this function.
190     * @return A function which always returns the value that it was provided
191     *         with.
192     */
193    @SuppressWarnings("unchecked")
194    public static <M> Function<M, M, NeverThrowsException> identityFunction() {
195        return (Function<M, M, NeverThrowsException>) IDENTITY;
196    }
197
198    /**
199     * Returns a function which converts a {@code String} to lower case using
200     * {@link StaticUtils#toLowerCase} and then trims it.
201     *
202     * @return A function which converts a {@code String} to lower case using
203     *         {@link StaticUtils#toLowerCase} and then trims it.
204     */
205    public static Function<String, String, NeverThrowsException> normalizeString() {
206        return NORMALIZE_STRING;
207    }
208
209    /**
210     * Returns a function which converts an {@code Object} to a
211     * {@code ByteString} using the {@link ByteString#valueOfObject(Object)} method.
212     *
213     * @return A function which converts an {@code Object} to a
214     *         {@code ByteString} .
215     */
216    public static Function<Object, ByteString, NeverThrowsException> objectToByteString() {
217        return OBJECT_TO_BYTESTRING;
218    }
219
220    /**
221     * Returns a function which parses {@code AttributeDescription}s using the
222     * default schema. Invalid values will result in a
223     * {@code LocalizedIllegalArgumentException}.
224     *
225     * @return A function which parses {@code AttributeDescription}s.
226     */
227    public static Function<String, AttributeDescription, NeverThrowsException> stringToAttributeDescription() {
228        return stringToAttributeDescription(getDefaultSchema());
229    }
230
231    /**
232     * Returns a function which parses {@code AttributeDescription}s using the
233     * provided schema. Invalid values will result in a
234     * {@code LocalizedIllegalArgumentException}.
235     *
236     * @param schema
237     *            The schema to use for decoding attribute descriptions.
238     * @return A function which parses {@code AttributeDescription}s.
239     */
240    public static Function<String, AttributeDescription, NeverThrowsException> stringToAttributeDescription(
241            final Schema schema) {
242        return new Function<String, AttributeDescription, NeverThrowsException>() {
243            @Override
244            public AttributeDescription apply(final String value) {
245                return AttributeDescription.valueOf(value, schema);
246            }
247        };
248    }
249
250    /**
251     * Returns a function which parses {@code Boolean} values. The function will
252     * accept the values {@code 0}, {@code false}, {@code no}, {@code off},
253     * {@code 1}, {@code true}, {@code yes}, {@code on}. All other values will
254     * result in a {@code NumberFormatException}.
255     *
256     * @return A function which parses {@code Boolean} values.
257     */
258    public static Function<String, Boolean, NeverThrowsException> stringToBoolean() {
259        return STRING_TO_BOOLEAN;
260    }
261
262    /**
263     * Returns a function which parses {@code DN}s using the default schema.
264     * Invalid values will result in a {@code LocalizedIllegalArgumentException}
265     * .
266     *
267     * @return A function which parses {@code DN}s.
268     */
269    public static Function<String, DN, NeverThrowsException> stringToDN() {
270        return stringToDN(getDefaultSchema());
271    }
272
273    /**
274     * Returns a function which parses {@code DN}s using the provided schema.
275     * Invalid values will result in a {@code LocalizedIllegalArgumentException}
276     * .
277     *
278     * @param schema
279     *            The schema to use for decoding DNs.
280     * @return A function which parses {@code DN}s.
281     */
282    public static Function<String, DN, NeverThrowsException> stringToDN(final Schema schema) {
283        return new Function<String, DN, NeverThrowsException>() {
284            @Override
285            public DN apply(final String value) {
286                return DN.valueOf(value, schema);
287            }
288        };
289    }
290
291    /**
292     * Returns a function which parses generalized time strings. Invalid values
293     * will result in a {@code LocalizedIllegalArgumentException}.
294     *
295     * @return A function which parses generalized time strings.
296     */
297    public static Function<String, GeneralizedTime, NeverThrowsException> stringToGeneralizedTime() {
298        return STRING_TO_GENERALIZED_TIME;
299    }
300
301    /**
302     * Returns a function which parses {@code Integer} string values. Invalid
303     * values will result in a {@code LocalizedIllegalArgumentException}.
304     *
305     * @return A function which parses {@code Integer} string values.
306     */
307    public static Function<String, Integer, NeverThrowsException> stringToInteger() {
308        return STRING_TO_INTEGER;
309    }
310
311    /**
312     * Returns a function which parses {@code Long} string values. Invalid
313     * values will result in a {@code LocalizedIllegalArgumentException}.
314     *
315     * @return A function which parses {@code Long} string values.
316     */
317    public static Function<String, Long, NeverThrowsException> stringToLong() {
318        return STRING_TO_LONG;
319    }
320
321    /**
322     * Returns a function which parses {@code AttributeDescription}s using the
323     * default schema. Invalid values will result in a
324     * {@code LocalizedIllegalArgumentException}.
325     *
326     * @return A function which parses {@code AttributeDescription}s.
327     */
328    public static Function<ByteString, AttributeDescription, NeverThrowsException> byteStringToAttributeDescription() {
329        return byteStringToAttributeDescription(getDefaultSchema());
330    }
331
332    /**
333     * Returns a function which parses {@code AttributeDescription}s using the
334     * provided schema. Invalid values will result in a
335     * {@code LocalizedIllegalArgumentException}.
336     *
337     * @param schema
338     *            The schema to use for decoding attribute descriptions.
339     * @return A function which parses {@code AttributeDescription}s.
340     */
341    public static Function<ByteString, AttributeDescription, NeverThrowsException> byteStringToAttributeDescription(
342            final Schema schema) {
343        return compose(byteStringToString(), new Function<String, AttributeDescription, NeverThrowsException>() {
344            @Override
345            public AttributeDescription apply(final String value) {
346                return AttributeDescription.valueOf(value, schema);
347            }
348        });
349    }
350
351    /**
352     * Returns a function which parses {@code Boolean} values. The function will
353     * accept the values {@code 0}, {@code false}, {@code no}, {@code off},
354     * {@code 1}, {@code true}, {@code yes}, {@code on}. All other values will
355     * result in a {@code NumberFormatException}.
356     *
357     * @return A function which parses {@code Boolean} values.
358     */
359    public static Function<ByteString, Boolean, NeverThrowsException> byteStringToBoolean() {
360        return BYTESTRING_TO_BOOLEAN;
361    }
362
363    /**
364     * Returns a function which parses {@code DN}s using the default schema.
365     * Invalid values will result in a {@code LocalizedIllegalArgumentException}
366     * .
367     *
368     * @return A function which parses {@code DN}s.
369     */
370    public static Function<ByteString, DN, NeverThrowsException> byteStringToDN() {
371        return byteStringToDN(getDefaultSchema());
372    }
373
374    /**
375     * Returns a function which parses {@code DN}s using the provided schema.
376     * Invalid values will result in a {@code LocalizedIllegalArgumentException}
377     * .
378     *
379     * @param schema
380     *            The schema to use for decoding DNs.
381     * @return A function which parses {@code DN}s.
382     */
383    public static Function<ByteString, DN, NeverThrowsException> byteStringToDN(final Schema schema) {
384        return compose(byteStringToString(), new Function<String, DN, NeverThrowsException>() {
385            @Override
386            public DN apply(final String value) {
387                return DN.valueOf(value, schema);
388            }
389        });
390    }
391
392    /**
393     * Returns a function which parses generalized time strings. Invalid values
394     * will result in a {@code LocalizedIllegalArgumentException}.
395     *
396     * @return A function which parses generalized time strings.
397     */
398    public static Function<ByteString, GeneralizedTime, NeverThrowsException> byteStringToGeneralizedTime() {
399        return BYTESTRING_TO_GENERALIZED_TIME;
400    }
401
402    /**
403     * Returns a function which parses {@code Integer} string values. Invalid
404     * values will result in a {@code LocalizedIllegalArgumentException}.
405     *
406     * @return A function which parses {@code Integer} string values.
407     */
408    public static Function<ByteString, Integer, NeverThrowsException> byteStringToInteger() {
409        return BYTESTRING_TO_INTEGER;
410    }
411
412    /**
413     * Returns a function which parses {@code Long} string values. Invalid
414     * values will result in a {@code LocalizedIllegalArgumentException}.
415     *
416     * @return A function which parses {@code Long} string values.
417     */
418    public static Function<ByteString, Long, NeverThrowsException> byteStringToLong() {
419        return BYTESTRING_TO_LONG;
420    }
421
422    /**
423     * Returns a function which parses a {@code ByteString} as a UTF-8 encoded
424     * {@code String}.
425     *
426     * @return A function which parses the string representation of a
427     *         {@code ByteString} as a UTF-8 encoded {@code String}.
428     */
429    public static Function<ByteString, String, NeverThrowsException> byteStringToString() {
430        return BYTESTRING_TO_STRING;
431    }
432
433    /** Prevent instantiation. */
434    private Functions() {
435        // Do nothing.
436    }
437
438}