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 2008 Sun Microsystems, Inc.
025 *      Portions Copyright 2015 ForgeRock AS.
026 */
027package org.forgerock.opendj.config;
028
029import java.util.Arrays;
030import java.util.HashMap;
031import java.util.List;
032import java.util.Map;
033import java.util.SortedSet;
034import java.util.TreeSet;
035
036/**
037 * A default managed object which should be created when a parent managed object
038 * is created. Default managed objects are associated with a
039 * {@link RelationDefinition}.
040 *
041 * @param <C>
042 *            The type of client default managed object configuration.
043 * @param <S>
044 *            The type of server default managed object configuration.
045 */
046public final class DefaultManagedObject<C extends ConfigurationClient, S extends Configuration> implements
047    PropertyProvider {
048
049    /**
050     * An interface for incrementally constructing default managed objects.
051     *
052     * @param <C>
053     *            The type of client default managed object configuration.
054     * @param <S>
055     *            The type of server default managed object configuration.
056     */
057    public static final class Builder<C extends ConfigurationClient, S extends Configuration> {
058
059        /** The default managed object's definition. */
060        private final ManagedObjectDefinition<C, S> definition;
061
062        /** The string encoded default managed object's properties. */
063        private final Map<String, List<String>> propertyStringValues = new HashMap<>();
064
065        /**
066         * Creates a new default managed object builder.
067         *
068         * @param definition
069         *            The default managed object's definition.
070         */
071        public Builder(ManagedObjectDefinition<C, S> definition) {
072            this.definition = definition;
073        }
074
075        /**
076         * Construct a default managed object based on the properties of this
077         * builder.
078         *
079         * @return Returns the new default managed object.
080         */
081        public DefaultManagedObject<C, S> getInstance() {
082            return new DefaultManagedObject<>(definition, propertyStringValues);
083        }
084
085        /**
086         * Defines a property's values for the default managed object.
087         *
088         * @param name
089         *            The name of the property.
090         * @param values
091         *            One or more property values in the string representation.
092         */
093        public void setPropertyValues(String name, String... values) {
094            if (values == null || values.length == 0) {
095                throw new IllegalArgumentException("null or empty values specified for property " + name);
096            }
097
098            propertyStringValues.put(name, Arrays.asList(values));
099        }
100    }
101
102    /** The default managed object's definition. */
103    private final ManagedObjectDefinition<C, S> definition;
104
105    /** The string encoded default managed object's properties. */
106    private final Map<String, List<String>> propertyStringValues;
107
108    /** Private constructor. */
109    private DefaultManagedObject(ManagedObjectDefinition<C, S> definition,
110        Map<String, List<String>> propertyStringValues) {
111        this.definition = definition;
112        this.propertyStringValues = propertyStringValues;
113    }
114
115    /**
116     * Gets the managed object definition associated with this default managed
117     * object.
118     *
119     * @return Returns the managed object definition associated with this
120     *         default managed object.
121     */
122    public ManagedObjectDefinition<C, S> getManagedObjectDefinition() {
123        return definition;
124    }
125
126    /**
127     * Gets a mutable copy of the set of property values for the specified
128     * property.
129     *
130     * @param <T>
131     *            The type of the property to be retrieved.
132     * @param pd
133     *            The property to be retrieved.
134     * @return Returns a newly allocated set containing a copy of the property's
135     *         values. An empty set indicates that the property has no values
136     *         defined and any default behavior is applicable.
137     * @throws IllegalArgumentException
138     *             If the property definition is not associated with this
139     *             managed object's definition.
140     */
141    public <T> SortedSet<T> getPropertyValues(PropertyDefinition<T> pd) {
142        // Validate the property definition.
143        definition.getPropertyDefinition(pd.getName());
144
145        // Do a defensive copy.
146        SortedSet<T> values = new TreeSet<>(pd);
147        List<String> stringValues = propertyStringValues.get(pd.getName());
148        if (stringValues != null) {
149            for (String stringValue : stringValues) {
150                // TODO : is it correct to have no validation ?
151                values.add(pd.decodeValue(stringValue));
152            }
153        }
154        return values;
155    }
156
157    /**
158     * Performs run-time initialization of properties.
159     *
160     * @throws Exception
161     *             If this default managed object could not be initialized.
162     */
163    void initialize() throws Exception {
164        // FIXME: it would be nice if we could decode all property values
165        // at this point. However this is not possible on the server side
166        // since some properties will be determined to be invalid since
167        // the schema is not loaded.
168
169        // Validate provided property names.
170        for (String name : propertyStringValues.keySet()) {
171            definition.getPropertyDefinition(name);
172        }
173    }
174}