/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt * or http://forgerock.org/license/CDDLv1.0.html. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at legal-notices/CDDLv1_0.txt. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: * Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * * Copyright 2008-2009 Sun Microsystems, Inc. * Portions Copyright 2015 ForgeRock AS. */ package org.forgerock.opendj.config; import org.forgerock.util.Reject; import java.util.EnumSet; import java.util.Locale; import java.util.MissingResourceException; import java.util.Set; import org.forgerock.i18n.LocalizableMessage; /** * Relation definitions define relationships between types of managed objects. * In addition they define the ownership model: * <ul> * <li>composition - referenced managed objects are owned by the parent managed * object and are deleted when the parent is deleted * <li>aggregation - referenced managed objects are not owned by the parent * managed object. Instead they are shared by other managed objects. * </ul> * Relations define how clients interact with the configuration. For example, * clients manage aggregated managed objects in a shared location and attach * them to parent managed objects. Composed managed objects, on the other hand, * would be created directly beneath the parent managed object and destroyed * with it too. * <p> * Within the server, listeners can choose to request notification of managed * objects being added or removed from relations. * <p> * In LDAP, compositions are represented as follows: * <ul> * <li>singleton relations (one to one): a referenced managed object is * represented using a child entry directly beneath the parent * <li>optional relations (one to zero or one): a referenced managed object is * represented using a child entry directly beneath the parent * <li>instantiable relations (one to many): the relation is represented using a * child entry directly beneath the parent. Referenced managed objects are * represented using child entries of this "relation entry" and are named by the * user * <li>set relations (one to many): the relation is represented using a child * entry directly beneath the parent. Referenced managed objects are represented * using child entries of this "relation entry" whose name is the type of the * managed object. * </ul> * Whereas, aggregations are represented by storing the DNs of the referenced * managed objects in an attribute of the aggregating managed object. * * @param <C> * The type of client managed object configuration that this relation * definition refers to. * @param <S> * The type of server managed object configuration that this relation * definition refers to. */ public abstract class RelationDefinition<C extends ConfigurationClient, S extends Configuration> { /** * An interface for incrementally constructing relation definitions. * * @param <C> * The type of client managed object configuration that this * relation definition refers to. * @param <S> * The type of server managed object configuration that this * relation definition refers to. * @param <D> * The type of relation definition constructed by this builder. */ protected static abstract class AbstractBuilder<C extends ConfigurationClient, S extends Configuration, D extends RelationDefinition<C, S>> { /** Common fields. */ private final Common<C, S> common; /** * Create a property definition builder. * * @param pd * The parent managed object definition. * @param name * The name of the relation. * @param cd * The child managed object definition. */ protected AbstractBuilder(AbstractManagedObjectDefinition<?, ?> pd, String name, AbstractManagedObjectDefinition<C, S> cd) { this.common = new Common<>(pd, name, cd); } /** * Construct a relation definition based on the properties of this * builder. * * @return The new relation definition. */ public final D getInstance() { return buildInstance(common); } /** * Add a relation definition option. * * @param option * The relation option. */ public final void setOption(RelationOption option) { Reject.ifNull(option); common.options.add(option); } /** * Build a relation definition based on the properties of this builder. * * @param common * The common fields of the new relation definition. * @return The new relation definition. */ protected abstract D buildInstance(Common<C, S> common); } /** * Opaque structure containing fields common to all relation definition * types. * * @param <C> * The type of client managed object configuration that this * relation definition refers to. * @param <S> * The type of server managed object configuration that this * relation definition refers to. */ protected static final class Common<C extends ConfigurationClient, S extends Configuration> { /** The definition of the child managed object. */ private final AbstractManagedObjectDefinition<C, S> cd; /** The name of the relation. */ private final String name; /** Options applicable to this definition. */ private final Set<RelationOption> options; /** The definition of the parent managed object. */ private final AbstractManagedObjectDefinition<?, ?> pd; /** Private constructor. */ private Common(AbstractManagedObjectDefinition<?, ?> pd, String name, AbstractManagedObjectDefinition<C, S> cd) { this.name = name; this.pd = pd; this.cd = cd; this.options = EnumSet.noneOf(RelationOption.class); } } /** Common fields. */ private final Common<C, S> common; /** * Create a new managed object relation definition with the specified common * fields. * * @param common * The common fields of the new relation definition. */ protected RelationDefinition(Common<C, S> common) { this.common = common; } /** * Apply a visitor to this relation definition. * * @param <R> * The return type of the visitor's methods. * @param <P> * The type of the additional parameters to the visitor's * methods. * @param v * The relation definition visitor. * @param p * Optional additional visitor parameter. * @return Returns a result as specified by the visitor. */ public abstract <R, P> R accept(RelationDefinitionVisitor<R, P> v, P p); /** * Get the definition of the child managed object. * * @return Returns the definition of the child managed object. */ public final AbstractManagedObjectDefinition<C, S> getChildDefinition() { return common.cd; } /** * Gets the optional description of this relation definition in the default * locale. * * @return Returns the description of this relation definition in the * default locale, or <code>null</code> if there is no description. */ public final LocalizableMessage getDescription() { return getDescription(Locale.getDefault()); } /** * Gets the optional description of this relation definition in the * specified locale. * * @param locale * The locale. * @return Returns the description of this relation definition in the * specified locale, or <code>null</code> if there is no * description. */ public final LocalizableMessage getDescription(Locale locale) { try { String property = "relation." + common.name + ".description"; return ManagedObjectDefinitionI18NResource.getInstance().getMessage(getParentDefinition(), property, locale); } catch (MissingResourceException e) { return null; } } /** * Get the name of the relation. * * @return Returns the name of the relation. */ public final String getName() { return common.name; } /** * Get the definition of the parent managed object. * * @return Returns the definition of the parent managed object. */ public final AbstractManagedObjectDefinition<?, ?> getParentDefinition() { return common.pd; } /** * Gets the synopsis of this relation definition in the default locale. * * @return Returns the synopsis of this relation definition in the default * locale. */ public final LocalizableMessage getSynopsis() { return getSynopsis(Locale.getDefault()); } /** * Gets the synopsis of this relation definition in the specified locale. * * @param locale * The locale. * @return Returns the synopsis of this relation definition in the specified * locale. */ public final LocalizableMessage getSynopsis(Locale locale) { String property = "relation." + common.name + ".synopsis"; return ManagedObjectDefinitionI18NResource.getInstance().getMessage(getParentDefinition(), property, locale); } /** * Gets the user friendly name of this relation definition in the default * locale. * * @return Returns the user friendly name of this relation definition in the * default locale. */ public final LocalizableMessage getUserFriendlyName() { return getUserFriendlyName(Locale.getDefault()); } /** * Gets the user friendly name of this relation definition in the specified * locale. * * @param locale * The locale. * @return Returns the user friendly name of this relation definition in the * specified locale. */ public final LocalizableMessage getUserFriendlyName(Locale locale) { String property = "relation." + common.name + ".user-friendly-name"; return ManagedObjectDefinitionI18NResource.getInstance().getMessage(getParentDefinition(), property, locale); } /** * Check if the specified option is set for this relation definition. * * @param option * The option to test. * @return Returns <code>true</code> if the option is set, or * <code>false</code> otherwise. */ public final boolean hasOption(RelationOption option) { return common.options.contains(option); } /** {@inheritDoc} */ @Override public final String toString() { StringBuilder builder = new StringBuilder(); toString(builder); return builder.toString(); } /** * Append a string representation of the managed object relation to the * provided string builder. * * @param builder * The string builder where the string representation should be * appended. */ public abstract void toString(StringBuilder builder); /** * Performs any run-time initialization required by this relation * definition. This may include resolving managed object paths and property * names. * * @throws Exception * If this relation definition could not be initialized. */ protected void initialize() throws Exception { // No implementation required. } }