/*
|
* 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
|
* trunk/opends/resource/legal-notices/OpenDS.LICENSE
|
* or https://OpenDS.dev.java.net/OpenDS.LICENSE.
|
* 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
|
* trunk/opends/resource/legal-notices/OpenDS.LICENSE. 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 Sun Microsystems, Inc.
|
*/
|
|
package org.opends.server.admin.client.spi;
|
|
|
|
import java.util.Collection;
|
import java.util.Collections;
|
import java.util.HashMap;
|
import java.util.Map;
|
import java.util.SortedSet;
|
import java.util.TreeSet;
|
|
import org.opends.server.admin.IllegalPropertyValueException;
|
import org.opends.server.admin.PropertyDefinition;
|
import org.opends.server.admin.PropertyIsMandatoryException;
|
import org.opends.server.admin.PropertyIsSingleValuedException;
|
import org.opends.server.admin.PropertyOption;
|
|
|
|
/**
|
* A set of properties. Instances of this class can be used as the
|
* core of a managed object implementation.
|
*/
|
public final class PropertySet {
|
|
/**
|
* Internal property implementation.
|
*
|
* @param <T>
|
* The type of the property.
|
*/
|
private static final class MyProperty<T> implements Property<T> {
|
|
// The active set of values.
|
private final SortedSet<T> activeValues;
|
|
// The definition associated with this property.
|
private final PropertyDefinition<T> d;
|
|
// The default set of values (read-only).
|
private final SortedSet<T> defaultValues;
|
|
// The pending set of values.
|
private final SortedSet<T> pendingValues;
|
|
|
|
/**
|
* Create a property with the provided sets of pre-validated
|
* default and active values.
|
*
|
* @param pd
|
* The property definition.
|
* @param defaultValues
|
* The set of default values for the property.
|
* @param activeValues
|
* The set of active values for the property.
|
*/
|
public MyProperty(PropertyDefinition<T> pd, Collection<T> defaultValues,
|
Collection<T> activeValues) {
|
this.d = pd;
|
|
SortedSet<T> sortedDefaultValues = new TreeSet<T>(pd);
|
sortedDefaultValues.addAll(defaultValues);
|
this.defaultValues = Collections
|
.unmodifiableSortedSet(sortedDefaultValues);
|
|
this.activeValues = new TreeSet<T>(pd);
|
this.activeValues.addAll(activeValues);
|
|
// Initially the pending values is the same as the active
|
// values.
|
this.pendingValues = new TreeSet<T>(this.activeValues);
|
}
|
|
|
|
/**
|
* Makes the pending values active.
|
*/
|
public void commit() {
|
activeValues.clear();
|
activeValues.addAll(pendingValues);
|
}
|
|
|
|
/**
|
* {@inheritDoc}
|
*/
|
public SortedSet<T> getActiveValues() {
|
return Collections.unmodifiableSortedSet(activeValues);
|
}
|
|
|
|
/**
|
* {@inheritDoc}
|
*/
|
public SortedSet<T> getDefaultValues() {
|
return defaultValues;
|
}
|
|
|
|
/**
|
* {@inheritDoc}
|
*/
|
public SortedSet<T> getEffectiveValues() {
|
SortedSet<T> values = getPendingValues();
|
|
if (values.isEmpty()) {
|
values = getDefaultValues();
|
}
|
|
return values;
|
}
|
|
|
|
/**
|
* {@inheritDoc}
|
*/
|
public SortedSet<T> getPendingValues() {
|
return Collections.unmodifiableSortedSet(pendingValues);
|
}
|
|
|
|
/**
|
* {@inheritDoc}
|
*/
|
public PropertyDefinition<T> getPropertyDefinition() {
|
return d;
|
}
|
|
|
|
/**
|
* {@inheritDoc}
|
*/
|
public boolean isEmpty() {
|
return pendingValues.isEmpty();
|
}
|
|
|
|
/**
|
* {@inheritDoc}
|
*/
|
public boolean isModified() {
|
if (activeValues.size() == pendingValues.size()
|
&& activeValues.containsAll(pendingValues)) {
|
return false;
|
}
|
return true;
|
}
|
|
|
|
/**
|
* Replace all pending values of this property with the provided
|
* values.
|
*
|
* @param c
|
* The new set of pending property values.
|
*/
|
public void setPendingValues(Collection<T> c) {
|
pendingValues.clear();
|
pendingValues.addAll(c);
|
}
|
|
|
|
/**
|
* {@inheritDoc}
|
*/
|
@Override
|
public String toString() {
|
return getEffectiveValues().toString();
|
}
|
|
|
|
/**
|
* {@inheritDoc}
|
*/
|
public boolean wasEmpty() {
|
return activeValues.isEmpty();
|
}
|
}
|
|
// The properties.
|
private final Map<PropertyDefinition<?>, MyProperty<?>> properties;
|
|
|
|
/**
|
* Creates a new empty property set.
|
*/
|
public PropertySet() {
|
this.properties = new HashMap<PropertyDefinition<?>, MyProperty<?>>();
|
}
|
|
|
|
/**
|
* Creates a property with the provided sets of pre-validated
|
* default and active values.
|
*
|
* @param <T>
|
* The type of the property.
|
* @param pd
|
* The property definition.
|
* @param defaultValues
|
* The set of default values for the property.
|
* @param activeValues
|
* The set of active values for the property.
|
*/
|
public <T> void addProperty(PropertyDefinition<T> pd,
|
Collection<T> defaultValues, Collection<T> activeValues) {
|
MyProperty<T> p = new MyProperty<T>(pd, defaultValues, activeValues);
|
properties.put(pd, p);
|
}
|
|
|
|
/**
|
* Get the property associated with the specified property
|
* definition.
|
*
|
* @param <T>
|
* The underlying type of the property.
|
* @param d
|
* The Property definition.
|
* @return Returns the property associated with the specified
|
* property definition.
|
* @throws IllegalArgumentException
|
* If this property provider does not recognise the
|
* requested property definition.
|
*/
|
@SuppressWarnings("unchecked")
|
public <T> Property<T> getProperty(PropertyDefinition<T> d)
|
throws IllegalArgumentException {
|
if (!properties.containsKey(d)) {
|
throw new IllegalArgumentException("Unknown property " + d.getName());
|
}
|
|
return (Property<T>) properties.get(d);
|
}
|
|
|
|
/**
|
* {@inheritDoc}
|
*/
|
@Override
|
public String toString() {
|
StringBuilder builder = new StringBuilder();
|
builder.append('{');
|
for (Map.Entry<PropertyDefinition<?>, MyProperty<?>> entry : properties
|
.entrySet()) {
|
builder.append(entry.getKey().getName());
|
builder.append('=');
|
builder.append(entry.getValue().toString());
|
builder.append(' ');
|
}
|
builder.append('}');
|
return builder.toString();
|
}
|
|
|
|
|
|
|
/**
|
* Makes all pending values active.
|
*/
|
void commit() {
|
for (MyProperty<?> p : properties.values()) {
|
p.commit();
|
}
|
}
|
|
|
|
/**
|
* Set a new pending values for the specified property.
|
* <p>
|
* See the class description for more information regarding pending
|
* values.
|
*
|
* @param <T>
|
* The type of the property to be modified.
|
* @param d
|
* The property to be modified.
|
* @param values
|
* A non-<code>null</code> set of new pending values for
|
* the property (an empty set indicates that the property
|
* should be reset to its default behavior). The set will
|
* not be referenced by this managed object.
|
* @throws IllegalPropertyValueException
|
* If a new pending value is deemed to be invalid
|
* according to the property definition.
|
* @throws PropertyIsSingleValuedException
|
* If an attempt was made to add multiple pending values
|
* to a single-valued property.
|
* @throws PropertyIsMandatoryException
|
* If an attempt was made to remove a mandatory property.
|
* @throws IllegalArgumentException
|
* If the specified property definition is not associated
|
* with this managed object.
|
*/
|
<T> void setPropertyValues(PropertyDefinition<T> d,
|
Collection<T> values) throws IllegalPropertyValueException,
|
PropertyIsSingleValuedException, PropertyIsMandatoryException,
|
IllegalArgumentException {
|
MyProperty<T> property = (MyProperty<T>) getProperty(d);
|
|
if (values.size() > 1 && !d.hasOption(PropertyOption.MULTI_VALUED)) {
|
throw new PropertyIsSingleValuedException(d);
|
}
|
|
if (values.isEmpty() && d.hasOption(PropertyOption.MANDATORY)) {
|
// But only if there are no default values.
|
if (property.getDefaultValues().isEmpty()) {
|
throw new PropertyIsMandatoryException(d);
|
}
|
}
|
|
// Validate each value.
|
for (T e : values) {
|
if (e == null) {
|
throw new NullPointerException();
|
}
|
|
d.validateValue(e);
|
}
|
|
// Update the property.
|
property.setPendingValues(values);
|
}
|
}
|