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