001/*
002 * CDDL HEADER START
003 *
004 * The contents of this file are subject to the terms of the
005 * Common Development and Distribution License, Version 1.0 only
006 * (the "License").  You may not use this file except in compliance
007 * with the License.
008 *
009 * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
010 * or http://forgerock.org/license/CDDLv1.0.html.
011 * See the License for the specific language governing permissions
012 * and limitations under the License.
013 *
014 * When distributing Covered Code, include this CDDL HEADER in each
015 * file and include the License file at legal-notices/CDDLv1_0.txt.
016 * If applicable, add the following below this CDDL HEADER, with the
017 * fields enclosed by brackets "[]" replaced with your own identifying
018 * information:
019 *      Portions Copyright [yyyy] [name of copyright owner]
020 *
021 * CDDL HEADER END
022 *
023 *
024 *      Copyright 2014 ForgeRock AS
025 */
026package org.forgerock.opendj.ldap.schema;
027
028import java.util.IdentityHashMap;
029import java.util.Map;
030
031import org.forgerock.opendj.ldap.Option;
032
033import static java.util.Collections.*;
034
035import static org.forgerock.opendj.ldap.schema.SchemaConstants.*;
036
037/**
038 * Common options for LDAP schemas.
039 * <p>
040 * For example you set schema option as you want when using a schema.
041 *
042 * <pre>
043 * // Retrieves options from builder.
044 * SchemaOptions options = new SchemaBuilder().getOptions();
045 * // Creates a new option.
046 * Option myIntegerOption = options.set(Option.of(Integer.class, 0));
047 * // Retrieves option value from SchemaOption
048 * boolean allowMalformedNamesAndOptions = options.get(SchemaOptions.ALLOW_MALFORMED_NAMES_AND_OPTIONS);
049 * </pre>
050 */
051public final class SchemaOptions {
052    /**
053     * Specifies whether the schema should allow certain illegal
054     * characters in OIDs and attribute options. When this compatibility option
055     * is set to {@code true} the following illegal characters will be permitted
056     * in addition to those permitted in section 1.4 of RFC 4512:
057     *
058     * <pre>
059     * USCORE  = %x5F ; underscore ("_")
060     * DOT     = %x2E ; period (".")
061     * </pre>
062     *
063     * By default this compatibility option is set to {@code true} because these
064     * characters are often used for naming purposes (such as collation rules).
065     */
066    public static final Option<Boolean> ALLOW_MALFORMED_NAMES_AND_OPTIONS = Option.withDefault(true);
067
068    /**
069     * Specifies whether the JPEG Photo syntax should allow values which
070     * do not conform to the JFIF or Exif specifications.
071     * <p>
072     * By default this compatibility option is set to {@code true}.
073     */
074    public static final Option<Boolean> ALLOW_MALFORMED_JPEG_PHOTOS = Option.withDefault(true);
075
076    /**
077     * Specifies whether the Certificate syntax should allow values which
078     * do not conform to the X.509 specifications.
079     * <p>
080     * By default this compatibility option is set to {@code true}.
081     */
082    public static final Option<Boolean> ALLOW_MALFORMED_CERTIFICATES = Option.withDefault(true);
083
084    /**
085     * Specifies whether the Telephone Number syntax should allow values
086     * which do not conform to the E.123 international telephone number format.
087     * <p>
088     * By default this compatibility option is set to {@code true}.
089     */
090    public static final Option<Boolean> ALLOW_NON_STANDARD_TELEPHONE_NUMBERS = Option.withDefault(true);
091
092    /**
093     * Specifies whether zero-length values will be allowed by the
094     * Directory String syntax. This is technically forbidden by the LDAP
095     * specification, but it was allowed in earlier versions of the server, and
096     * the discussion of the directory string syntax in RFC 2252 does not
097     * explicitly state that they are not allowed.
098     * <p>
099     * By default this compatibility option is set to {@code false}.
100     */
101    public static final Option<Boolean> ALLOW_ZERO_LENGTH_DIRECTORY_STRINGS = Option.withDefault(false);
102
103    /**
104     * Specifies the OID of the default syntax which will be used when parsing
105     * unrecognized attributes.
106     * <p>
107     * By default the {@link SchemaConstants#SYNTAX_OCTET_STRING_OID OctetString}
108     * syntax will be used.
109     */
110    public static final Option<String> DEFAULT_SYNTAX_OID = Option.of(String.class, SYNTAX_OCTET_STRING_OID);
111
112    /**
113     * Specifies the OID of the default matching rule which will be used when
114     * parsing unrecognized attributes.
115     * <p>
116     * By default the {@link SchemaConstants#EMR_OCTET_STRING_OID OctetString}
117     * matching rule will be used.
118     */
119    public static final Option<String> DEFAULT_MATCHING_RULE_OID = Option.of(String.class, EMR_OCTET_STRING_OID);
120
121    /**
122     * Indicates whether country code values are required to strictly
123     * comply with the standard definition for this syntax.
124     * <p>
125     * When set to false, country codes will not be validated and, as a result
126     * any string containing 2 characters will be acceptable.
127     * By default this compatibility option is set to {@code true}.
128     */
129    public static final Option<Boolean> STRICT_FORMAT_FOR_COUNTRY_STRINGS = Option.withDefault(true);
130
131    /**
132     * Indicates whether the minimum upper bound value should be stripped from
133     * the Attribute Type Syntax Description.
134     * <p>
135     * By default this compatibility option is set to {@code false}.
136     */
137    public static final Option<Boolean> STRIP_UPPER_BOUND_FOR_ATTRIBUTE_TYPE = Option.withDefault(false);
138
139    private final Map<Option<?>, Object> options;
140
141    /**
142     * Creates a new set of schema options with default settings.
143     *
144     * @return A new {@link SchemaOptions} with default settings.
145     */
146    static SchemaOptions defaultSchemaOptions() {
147        return new SchemaOptions(new IdentityHashMap<Option<?>, Object>());
148    }
149
150    /**
151     * Creates a new schema options object by copying the provided schema
152     * options. The options names and values will all be copied.
153     *
154     * @param schemaOptions
155     *            The schema options to be copied.
156     * @return A new schema options object created by copying the provided schema
157     *         options.
158     */
159    static SchemaOptions copyOf(SchemaOptions schemaOptions) {
160        return new SchemaOptions(new IdentityHashMap<Option<?>, Object>(schemaOptions.options));
161    }
162
163    /**
164     * Returns an unmodifiable {@link SchemaOptions} copy of this set of options.
165     *
166     * @param schemaOptions
167     *            The schema options to be copied.
168     * @return An unmodifiable {@link SchemaOptions} view of this set of options.
169     */
170    static SchemaOptions unmodifiable(SchemaOptions schemaOptions) {
171        return new SchemaOptions(unmodifiableMap(new IdentityHashMap<Option<?>, Object>(schemaOptions.options)));
172    }
173
174    private SchemaOptions(Map<Option<?>, Object> optionsMap) {
175        this.options = optionsMap;
176    }
177
178    /**
179     * Returns the value to which the specified {@link Option} is mapped, or
180     * {@code null} if this options set contains no mapping for the {@link Option}.
181     *
182     * @param <T>
183     *            The option type.
184     * @param option
185     *            The option whose associated value is to be returned.
186     * @return The value to which the specified option is mapped, or null if
187     *         this options set contains no mapping for the option.
188     */
189    <T> T get(Option<T> option) {
190        return option.getValue(options.get(option));
191    }
192
193    /**
194     * Associates the specified option value with the specified option in this
195     * set of options. (optional operation). If this set of options previously
196     * contained a mapping for the option, the old value is replaced by the
197     * specified value.
198     *
199     * @param <T>
200     *            The option type.
201     * @param option
202     *            Option with which the specified value is to be associated.
203     * @param value
204     *            Value to be associated with the specified option.
205     * @return A reference to this set of options.
206     * @throws UnsupportedOperationException
207     *         If this set of options is read only.
208     */
209    <T> SchemaOptions set(Option<T> option, T value) {
210        options.put(option, value);
211        return this;
212    }
213
214}