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