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