/*
* 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.
}
}