AggregationPropertyDefinition.java revision 2f6d798e90520dd1b83ac30e53838ae6fd41a150
/*
* 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
* 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 2007-2008 Sun Microsystems, Inc.
* Portions Copyright 2014-2015 ForgeRock AS
*/
/**
* Aggregation property definition.
* <p>
* An aggregation property names one or more managed objects which are
* required by the managed object associated with this property. An
* aggregation property definition takes care to perform referential
* integrity checks: referenced managed objects cannot be deleted. Nor
* can an aggregation reference non-existent managed objects.
* Referential integrity checks are <b>not</b> performed during value
* validation. Instead they are performed when changes to the managed
* object are committed.
* <p>
* An aggregation property definition can optionally identify two
* properties:
* <ul>
* <li>an <code>enabled</code> property in the aggregated managed
* object - the property must be a {@link BooleanPropertyDefinition}
* and indicate whether the aggregated managed object is enabled or
* not. If specified, the administration framework will prevent the
* aggregated managed object from being disabled while it is
* referenced
* <li>an <code>enabled</code> property in this property's managed
* object - the property must be a {@link BooleanPropertyDefinition}
* and indicate whether this property's managed object is enabled or
* not. If specified, and as long as there is an equivalent
* <code>enabled</code> property defined for the aggregated managed
* object, the <code>enabled</code> property in the aggregated
* managed object will only be checked when this property is true.
* </ul>
* In other words, these properties can be used to make sure that
* referenced managed objects are not disabled while they are
* referenced.
*
* @param <C>
* The type of client managed object configuration that this
* aggregation property definition refers to.
* @param <S>
* The type of server managed object configuration that this
* aggregation property definition refers to.
*/
public final class AggregationPropertyDefinition
<C extends ConfigurationClient, S extends Configuration>
extends PropertyDefinition<String> {
/**
* An interface for incrementally constructing aggregation property
* definitions.
*
* @param <C>
* The type of client managed object configuration that
* this aggregation property definition refers to.
* @param <S>
* The type of server managed object configuration that
* this aggregation property definition refers to.
*/
public static class Builder
<C extends ConfigurationClient, S extends Configuration>
/**
* The string representation of the managed object path specifying
* the parent of the aggregated managed objects.
*/
private String parentPathString;
/**
* The name of a relation in the parent managed object which
* contains the aggregated managed objects.
*/
/**
* The condition which is used to determine if a referenced
* managed object is enabled.
*/
/**
* The condition which is used to determine whether or not
* referenced managed objects need to be enabled.
*/
/** Private constructor. */
private Builder(AbstractManagedObjectDefinition<?, ?> d,
super(d, propertyName);
}
/**
* Sets the name of the managed object which is the parent of the
* aggregated managed objects.
* <p>
* This must be defined before the property definition can be
* built.
*
* @param pathString
* The string representation of the managed object path
* specifying the parent of the aggregated managed
* objects.
*/
this.parentPathString = pathString;
}
/**
* Sets the relation in the parent managed object which contains
* the aggregated managed objects.
* <p>
* This must be defined before the property definition can be
* built.
*
* @param rdName
* The name of a relation in the parent managed object
* which contains the aggregated managed objects.
*/
}
/**
* Sets the condition which is used to determine if a referenced
* managed object is enabled. By default referenced managed
* objects are assumed to always be enabled.
*
* @param condition
* The condition which is used to determine if a
* referenced managed object is enabled.
*/
this.targetIsEnabledCondition = condition;
}
/**
* Sets the condition which is used to determine whether or not
* referenced managed objects need to be enabled. By default
* referenced managed objects must always be enabled.
*
* @param condition
* The condition which is used to determine whether or
* not referenced managed objects need to be enabled.
*/
}
/** {@inheritDoc} */
protected AggregationPropertyDefinition<C, S> buildInstance(
// Make sure that the parent path has been defined.
if (parentPathString == null) {
throw new IllegalStateException("Parent path undefined");
}
// Make sure that the relation definition has been defined.
throw new IllegalStateException("Relation definition undefined");
}
}
}
/**
* A change listener which prevents the named component from being
* disabled.
*/
private class ReferentialIntegrityChangeListener implements
/**
* The error message which should be returned if an attempt is
* made to disable the referenced component.
*/
private final LocalizableMessage message;
/** The path of the referenced component. */
private final ManagedObjectPath<C, S> path;
/** Creates a new referential integrity delete listener. */
}
/** {@inheritDoc} */
ServerManagedObject<? extends S> mo) {
try {
return new ConfigChangeResult();
}
} catch (ConfigException e) {
// This should not happen - ignore it and throw an exception
// anyway below.
}
// This should not happen - the previous call-back should have
// trapped this.
throw new IllegalStateException("Attempting to disable a referenced "
}
/** {@inheritDoc} */
public boolean isConfigurationChangeAcceptable(
ServerManagedObject<? extends S> mo,
// Always prevent the referenced component from being
// disabled.
try {
return false;
} else {
return true;
}
} catch (ConfigException e) {
// The condition could not be evaluated.
logger.traceException(e);
return false;
}
}
/** Gets the path associated with this listener. */
private ManagedObjectPath<C, S> getManagedObjectPath() {
return path;
}
}
/**
* A delete listener which prevents the named component from being
* deleted.
*/
private class ReferentialIntegrityDeleteListener implements
/** The DN of the referenced configuration entry. */
/**
* The error message which should be returned if an attempt is
* made to delete the referenced component.
*/
private final LocalizableMessage message;
/** Creates a new referential integrity delete listener. */
}
/** {@inheritDoc} */
// This should not happen - the
// isConfigurationDeleteAcceptable() call-back should have
// trapped this.
// This should not happen - the
// isConfigurationDeleteAcceptable() call-back should have
// trapped this.
throw new IllegalStateException("Attempting to delete a referenced "
} else {
return new ConfigChangeResult();
}
}
/** {@inheritDoc} */
public boolean isConfigurationDeleteAcceptable(S configuration,
// Always prevent deletion of the referenced component.
return false;
}
return true;
}
}
/**
* The server-side constraint handler implementation.
*/
private class ServerHandler extends ServerConstraintHandler {
/** {@inheritDoc} */
boolean isUsable = true;
boolean needsEnabling = targetNeedsEnablingCondition
isUsable = false;
} else if (needsEnabling) {
// Check that the referenced component is enabled if
// required.
isUsable = false;
}
}
}
return isUsable;
}
/** {@inheritDoc} */
throws ConfigException {
// First make sure existing listeners associated with this
// managed object are removed. This is required in order to
// prevent multiple change listener registrations from
// occurring, for example if this call-back is invoked multiple
// times after the same add event.
// Add change and delete listeners against all referenced
// components.
// Referenced managed objects will only need a change listener
// if they have can be disabled.
// Delete listeners need to be registered against the parent
// entry of the referenced components.
// Create entries in the listener tables.
// Register the delete listener.
// Register the change listener if required.
if (needsChangeListeners) {
}
}
}
/** {@inheritDoc} */
throws ConfigException {
// Remove any registered delete and change listeners.
// Delete listeners need to be deregistered against the parent
// entry of the referenced components.
}
}
// Change listeners need to be deregistered from their
// associated referenced component.
}
}
}
/** {@inheritDoc} */
throws ConfigException {
// Remove all the constraints associated with this managed
// object and then re-register them.
}
}
/**
* The client-side constraint handler implementation which enforces
* referential integrity when aggregating managed objects are added
* or modified.
*/
private class SourceClientHandler extends ClientConstraintHandler {
/** {@inheritDoc} */
throws AuthorizationException, CommunicationException {
// If all of this managed object's "enabled" properties are true
// then any referenced managed objects must also be enabled.
// Check the referenced managed objects exist and, if required,
// are enabled.
boolean isAcceptable = true;
// Retrieve the referenced managed object and make sure it
// exists.
ManagedObject<?> ref;
try {
} catch (DefinitionDecodingException | ManagedObjectDecodingException e) {
getName(), e.getMessageObject());
isAcceptable = false;
continue;
} catch (ManagedObjectNotFoundException e) {
isAcceptable = false;
continue;
}
// Make sure the reference managed object is enabled.
if (needsEnabling
isAcceptable = false;
}
}
return isAcceptable;
}
/** {@inheritDoc} */
throws AuthorizationException, CommunicationException {
// The same constraint applies as for adds.
}
}
/**
* The client-side constraint handler implementation which enforces
* referential integrity when aggregated managed objects are deleted
* or modified.
*/
private class TargetClientHandler extends ClientConstraintHandler {
/** {@inheritDoc} */
throws AuthorizationException, CommunicationException {
// Any references to the deleted managed object should cause a
// constraint violation.
boolean isAcceptable = true;
} else {
}
isAcceptable = false;
}
return isAcceptable;
}
/** {@inheritDoc} */
throws AuthorizationException, CommunicationException {
// If the modified managed object is disabled and there are some
// active references then refuse the change.
return true;
}
// The referenced managed object is disabled. Need to check for
// active references.
boolean isAcceptable = true;
.getName())) {
} else {
}
isAcceptable = false;
}
}
return isAcceptable;
}
/**
* Find all managed objects which reference the named managed
* object using this property.
*/
private <CC extends ConfigurationClient>
while (i.hasNext()) {
boolean hasReference = false;
hasReference = true;
break;
}
}
if (!hasReference) {
i.remove();
}
}
return instances;
}
/** Find all instances of a specific type of managed object. */
@SuppressWarnings("unchecked")
private <CC extends ConfigurationClient>
throws AuthorizationException, CommunicationException {
} else {
.getParentDefinition())) {
try {
if (rd instanceof SingletonRelationDefinition) {
}
} else if (rd instanceof OptionalRelationDefinition) {
}
} else if (rd instanceof InstantiableRelationDefinition) {
}
}
}
} catch (OperationsException e) {
// Ignore all operations exceptions.
}
}
}
}
return instances;
}
}
/**
* Creates an aggregation property definition builder.
*
* @param <C>
* The type of client managed object configuration that
* this aggregation property definition refers to.
* @param <S>
* The type of server managed object configuration that
* this aggregation property definition refers to.
* @param d
* The managed object definition associated with this
* property definition.
* @param propertyName
* The property name.
* @return Returns the new aggregation property definition builder.
*/
public static <C extends ConfigurationClient, S extends Configuration>
Builder<C, S> createBuilder(
return new Builder<C, S>(d, propertyName);
}
/**
* The active server-side referential integrity change listeners
* associated with this property.
*/
/**
* The active server-side referential integrity delete listeners
* associated with this property.
*/
/**
* The name of the managed object which is the parent of the
* aggregated managed objects.
*/
private ManagedObjectPath<?, ?> parentPath;
/**
* The string representation of the managed object path specifying
* the parent of the aggregated managed objects.
*/
private final String parentPathString;
/**
* The name of a relation in the parent managed object which
* contains the aggregated managed objects.
*/
/**
* The relation in the parent managed object which contains the
* aggregated managed objects.
*/
private InstantiableRelationDefinition<C, S> relationDefinition;
/** The source constraint. */
private final Constraint sourceConstraint;
/**
* The condition which is used to determine if a referenced managed
* object is enabled.
*/
private final Condition targetIsEnabledCondition;
/**
* The condition which is used to determine whether or not
* referenced managed objects need to be enabled.
*/
private final Condition targetNeedsEnablingCondition;
/** Private constructor. */
private AggregationPropertyDefinition(
this.parentPathString = parentPathString;
this.sourceConstraint = new Constraint() {
/** {@inheritDoc} */
}
/** {@inheritDoc} */
}
};
}
/** {@inheritDoc} */
public <R, P> R accept(PropertyDefinitionVisitor<R, P> v, P p) {
return v.visitAggregation(this, p);
}
/** {@inheritDoc} */
return v.visitAggregation(this, value, p);
}
/** {@inheritDoc} */
throws PropertyException {
try {
return value;
} catch (PropertyException e) {
}
}
/**
* Constructs a DN for a referenced managed object having the
* provided name. This method is implemented by first calling
* {@link #getChildPath(String)} and then invoking
* {@code ManagedObjectPath.toDN()} on the returned path.
*
* @param name
* The name of the child managed object.
* @return Returns a DN for a referenced managed object having the
* provided name.
*/
}
/**
* Constructs a managed object path for a referenced managed object
* having the provided name.
*
* @param name
* The name of the child managed object.
* @return Returns a managed object path for a referenced managed
* object having the provided name.
*/
}
/**
* Gets the name of the managed object which is the parent of the
* aggregated managed objects.
*
* @return Returns the name of the managed object which is the
* parent of the aggregated managed objects.
*/
public final ManagedObjectPath<?, ?> getParentPath() {
return parentPath;
}
/**
* Gets the relation in the parent managed object which contains the
* aggregated managed objects.
*
* @return Returns the relation in the parent managed object which
* contains the aggregated managed objects.
*/
public final InstantiableRelationDefinition<C, S> getRelationDefinition() {
return relationDefinition;
}
/**
* Gets the constraint which should be enforced on the aggregating
* managed object.
*
* @return Returns the constraint which should be enforced on the
* aggregating managed object.
*/
public final Constraint getSourceConstraint() {
return sourceConstraint;
}
/**
* Gets the optional constraint synopsis of this aggregation
* property definition in the default locale. The constraint
* synopsis describes when and how referenced managed objects must
* be enabled. When there are no constraints between the source
* managed object and the objects it references through this
* aggregation, <code>null</code> is returned.
*
* @return Returns the optional constraint synopsis of this
* aggregation property definition in the default locale, or
* <code>null</code> if there is no constraint synopsis.
*/
public final LocalizableMessage getSourceConstraintSynopsis() {
}
/**
* Gets the optional constraint synopsis of this aggregation
* property definition in the specified locale.The constraint
* synopsis describes when and how referenced managed objects must
* be enabled. When there are no constraints between the source
* managed object and the objects it references through this
* aggregation, <code>null</code> is returned.
*
* @param locale
* The locale.
* @return Returns the optional constraint synopsis of this
* aggregation property definition in the specified locale,
* or <code>null</code> if there is no constraint
* synopsis.
*/
+ ".syntax.aggregation.constraint-synopsis";
try {
return resource
} catch (MissingResourceException e) {
return null;
}
}
/**
* Gets the condition which is used to determine if a referenced
* managed object is enabled.
*
* @return Returns the condition which is used to determine if a
* referenced managed object is enabled.
*/
public final Condition getTargetIsEnabledCondition() {
return targetIsEnabledCondition;
}
/**
* Gets the condition which is used to determine whether or not
* referenced managed objects need to be enabled.
*
* @return Returns the condition which is used to determine whether
* or not referenced managed objects need to be enabled.
*/
public final Condition getTargetNeedsEnablingCondition() {
return targetNeedsEnablingCondition;
}
/** {@inheritDoc} */
throws PropertyException {
try {
return reference.getNormalizedName();
} catch (IllegalArgumentException e) {
}
}
/** {@inheritDoc} */
}
/** {@inheritDoc} */
try {
} catch (IllegalArgumentException e) {
}
}
/** {@inheritDoc} */
@SuppressWarnings("unchecked")
public void initialize() throws Exception {
// Decode the path.
// Decode the relation definition.
// Now decode the conditions.
// Register a client-side constraint with the referenced
// definition. This will be used to enforce referential integrity
// for actions performed against referenced managed objects.
/** {@inheritDoc} */
}
/** {@inheritDoc} */
return Collections.emptyList();
}
};
}
}