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-2009 Sun Microsystems, Inc.
015 * Portions Copyright 2015-2016 ForgeRock AS.
016 */
017
018package org.forgerock.opendj.config;
019
020import org.forgerock.util.Reject;
021
022import java.util.EnumSet;
023import java.util.Locale;
024import java.util.MissingResourceException;
025import java.util.Set;
026
027import org.forgerock.i18n.LocalizableMessage;
028
029/**
030 * Relation definitions define relationships between types of managed objects.
031 * In addition they define the ownership model:
032 * <ul>
033 * <li>composition - referenced managed objects are owned by the parent managed
034 * object and are deleted when the parent is deleted
035 * <li>aggregation - referenced managed objects are not owned by the parent
036 * managed object. Instead they are shared by other managed objects.
037 * </ul>
038 * Relations define how clients interact with the configuration. For example,
039 * clients manage aggregated managed objects in a shared location and attach
040 * them to parent managed objects. Composed managed objects, on the other hand,
041 * would be created directly beneath the parent managed object and destroyed
042 * with it too.
043 * <p>
044 * Within the server, listeners can choose to request notification of managed
045 * objects being added or removed from relations.
046 * <p>
047 * In LDAP, compositions are represented as follows:
048 * <ul>
049 * <li>singleton relations (one to one): a referenced managed object is
050 * represented using a child entry directly beneath the parent
051 * <li>optional relations (one to zero or one): a referenced managed object is
052 * represented using a child entry directly beneath the parent
053 * <li>instantiable relations (one to many): the relation is represented using a
054 * child entry directly beneath the parent. Referenced managed objects are
055 * represented using child entries of this "relation entry" and are named by the
056 * user
057 * <li>set relations (one to many): the relation is represented using a child
058 * entry directly beneath the parent. Referenced managed objects are represented
059 * using child entries of this "relation entry" whose name is the type of the
060 * managed object.
061 * </ul>
062 * Whereas, aggregations are represented by storing the DNs of the referenced
063 * managed objects in an attribute of the aggregating managed object.
064 *
065 * @param <C>
066 *            The type of client managed object configuration that this relation
067 *            definition refers to.
068 * @param <S>
069 *            The type of server managed object configuration that this relation
070 *            definition refers to.
071 */
072public abstract class RelationDefinition<C extends ConfigurationClient, S extends Configuration> {
073
074    /**
075     * An interface for incrementally constructing relation definitions.
076     *
077     * @param <C>
078     *            The type of client managed object configuration that this
079     *            relation definition refers to.
080     * @param <S>
081     *            The type of server managed object configuration that this
082     *            relation definition refers to.
083     * @param <D>
084     *            The type of relation definition constructed by this builder.
085     */
086    protected static abstract class AbstractBuilder<C extends ConfigurationClient, S extends Configuration,
087        D extends RelationDefinition<C, S>> {
088
089        /** Common fields. */
090        private final Common<C, S> common;
091
092        /**
093         * Create a property definition builder.
094         *
095         * @param pd
096         *            The parent managed object definition.
097         * @param name
098         *            The name of the relation.
099         * @param cd
100         *            The child managed object definition.
101         */
102        protected AbstractBuilder(AbstractManagedObjectDefinition<?, ?> pd, String name,
103            AbstractManagedObjectDefinition<C, S> cd) {
104            this.common = new Common<>(pd, name, cd);
105        }
106
107        /**
108         * Construct a relation definition based on the properties of this
109         * builder.
110         *
111         * @return The new relation definition.
112         */
113        public final D getInstance() {
114            return buildInstance(common);
115        }
116
117        /**
118         * Add a relation definition option.
119         *
120         * @param option
121         *            The relation option.
122         */
123        public final void setOption(RelationOption option) {
124            Reject.ifNull(option);
125            common.options.add(option);
126        }
127
128        /**
129         * Build a relation definition based on the properties of this builder.
130         *
131         * @param common
132         *            The common fields of the new relation definition.
133         * @return The new relation definition.
134         */
135        protected abstract D buildInstance(Common<C, S> common);
136    }
137
138    /**
139     * Opaque structure containing fields common to all relation definition
140     * types.
141     *
142     * @param <C>
143     *            The type of client managed object configuration that this
144     *            relation definition refers to.
145     * @param <S>
146     *            The type of server managed object configuration that this
147     *            relation definition refers to.
148     */
149    protected static final class Common<C extends ConfigurationClient, S extends Configuration> {
150
151        /** The definition of the child managed object. */
152        private final AbstractManagedObjectDefinition<C, S> cd;
153
154        /** The name of the relation. */
155        private final String name;
156
157        /** Options applicable to this definition. */
158        private final Set<RelationOption> options;
159
160        /** The definition of the parent managed object. */
161        private final AbstractManagedObjectDefinition<?, ?> pd;
162
163        /** Private constructor. */
164        private Common(AbstractManagedObjectDefinition<?, ?> pd, String name,
165            AbstractManagedObjectDefinition<C, S> cd) {
166            this.name = name;
167            this.pd = pd;
168            this.cd = cd;
169            this.options = EnumSet.noneOf(RelationOption.class);
170        }
171    }
172
173    /** Common fields. */
174    private final Common<C, S> common;
175
176    /**
177     * Create a new managed object relation definition with the specified common
178     * fields.
179     *
180     * @param common
181     *            The common fields of the new relation definition.
182     */
183    protected RelationDefinition(Common<C, S> common) {
184        this.common = common;
185    }
186
187    /**
188     * Apply a visitor to this relation definition.
189     *
190     * @param <R>
191     *            The return type of the visitor's methods.
192     * @param <P>
193     *            The type of the additional parameters to the visitor's
194     *            methods.
195     * @param v
196     *            The relation definition visitor.
197     * @param p
198     *            Optional additional visitor parameter.
199     * @return Returns a result as specified by the visitor.
200     */
201    public abstract <R, P> R accept(RelationDefinitionVisitor<R, P> v, P p);
202
203    /**
204     * Get the definition of the child managed object.
205     *
206     * @return Returns the definition of the child managed object.
207     */
208    public final AbstractManagedObjectDefinition<C, S> getChildDefinition() {
209        return common.cd;
210    }
211
212    /**
213     * Gets the optional description of this relation definition in the default
214     * locale.
215     *
216     * @return Returns the description of this relation definition in the
217     *         default locale, or <code>null</code> if there is no description.
218     */
219    public final LocalizableMessage getDescription() {
220        return getDescription(Locale.getDefault());
221    }
222
223    /**
224     * Gets the optional description of this relation definition in the
225     * specified locale.
226     *
227     * @param locale
228     *            The locale.
229     * @return Returns the description of this relation definition in the
230     *         specified locale, or <code>null</code> if there is no
231     *         description.
232     */
233    public final LocalizableMessage getDescription(Locale locale) {
234        try {
235            String property = "relation." + common.name + ".description";
236            return ManagedObjectDefinitionI18NResource.getInstance().getMessage(getParentDefinition(), property,
237                locale);
238        } catch (MissingResourceException e) {
239            return null;
240        }
241    }
242
243    /**
244     * Get the name of the relation.
245     *
246     * @return Returns the name of the relation.
247     */
248    public final String getName() {
249        return common.name;
250    }
251
252    /**
253     * Get the definition of the parent managed object.
254     *
255     * @return Returns the definition of the parent managed object.
256     */
257    public final AbstractManagedObjectDefinition<?, ?> getParentDefinition() {
258        return common.pd;
259    }
260
261    /**
262     * Gets the synopsis of this relation definition in the default locale.
263     *
264     * @return Returns the synopsis of this relation definition in the default
265     *         locale.
266     */
267    public final LocalizableMessage getSynopsis() {
268        return getSynopsis(Locale.getDefault());
269    }
270
271    /**
272     * Gets the synopsis of this relation definition in the specified locale.
273     *
274     * @param locale
275     *            The locale.
276     * @return Returns the synopsis of this relation definition in the specified
277     *         locale.
278     */
279    public final LocalizableMessage getSynopsis(Locale locale) {
280        String property = "relation." + common.name + ".synopsis";
281        return ManagedObjectDefinitionI18NResource.getInstance().getMessage(getParentDefinition(), property, locale);
282    }
283
284    /**
285     * Gets the user friendly name of this relation definition in the default
286     * locale.
287     *
288     * @return Returns the user friendly name of this relation definition in the
289     *         default locale.
290     */
291    public final LocalizableMessage getUserFriendlyName() {
292        return getUserFriendlyName(Locale.getDefault());
293    }
294
295    /**
296     * Gets the user friendly name of this relation definition in the specified
297     * locale.
298     *
299     * @param locale
300     *            The locale.
301     * @return Returns the user friendly name of this relation definition in the
302     *         specified locale.
303     */
304    public final LocalizableMessage getUserFriendlyName(Locale locale) {
305        String property = "relation." + common.name + ".user-friendly-name";
306        return ManagedObjectDefinitionI18NResource.getInstance().getMessage(getParentDefinition(), property, locale);
307    }
308
309    /**
310     * Check if the specified option is set for this relation definition.
311     *
312     * @param option
313     *            The option to test.
314     * @return Returns <code>true</code> if the option is set, or
315     *         <code>false</code> otherwise.
316     */
317    public final boolean hasOption(RelationOption option) {
318        return common.options.contains(option);
319    }
320
321    @Override
322    public final String toString() {
323        StringBuilder builder = new StringBuilder();
324        toString(builder);
325        return builder.toString();
326    }
327
328    /**
329     * Append a string representation of the managed object relation to the
330     * provided string builder.
331     *
332     * @param builder
333     *            The string builder where the string representation should be
334     *            appended.
335     */
336    public abstract void toString(StringBuilder builder);
337
338    /**
339     * Performs any run-time initialization required by this relation
340     * definition. This may include resolving managed object paths and property
341     * names.
342     *
343     * @throws Exception
344     *             If this relation definition could not be initialized.
345     */
346    protected void initialize() throws Exception {
347        // No implementation required.
348    }
349}