/* * 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 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.PropertyDefinitionsOptions; 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 * The type of the property. */ private static final class MyProperty implements Property { // The active set of values. private final SortedSet activeValues; // The definition associated with this property. private final PropertyDefinition d; // The default set of values (read-only). private final SortedSet defaultValues; // The pending set of values. private final SortedSet 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 pd, Collection defaultValues, Collection activeValues) { this.d = pd; SortedSet sortedDefaultValues = new TreeSet(pd); sortedDefaultValues.addAll(defaultValues); this.defaultValues = Collections.unmodifiableSortedSet(sortedDefaultValues); this.activeValues = new TreeSet(pd); this.activeValues.addAll(activeValues); // Initially the pending values is the same as the active // values. this.pendingValues = new TreeSet(this.activeValues); } /** * Makes the pending values active. */ public void commit() { activeValues.clear(); activeValues.addAll(pendingValues); } /** * {@inheritDoc} */ @Override public SortedSet getActiveValues() { return Collections.unmodifiableSortedSet(activeValues); } /** * {@inheritDoc} */ @Override public SortedSet getDefaultValues() { return defaultValues; } /** * {@inheritDoc} */ @Override public SortedSet getEffectiveValues() { SortedSet values = getPendingValues(); if (values.isEmpty()) { values = getDefaultValues(); } return values; } /** * {@inheritDoc} */ @Override public SortedSet getPendingValues() { return Collections.unmodifiableSortedSet(pendingValues); } /** * {@inheritDoc} */ @Override public PropertyDefinition getPropertyDefinition() { return d; } /** * {@inheritDoc} */ @Override public boolean isEmpty() { return pendingValues.isEmpty(); } /** * {@inheritDoc} */ @Override 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 c) { pendingValues.clear(); pendingValues.addAll(c); } /** * {@inheritDoc} */ @Override public String toString() { return getEffectiveValues().toString(); } /** * {@inheritDoc} */ @Override public boolean wasEmpty() { return activeValues.isEmpty(); } } // The properties. private final Map, MyProperty> properties; /** * Creates a new empty property set. */ public PropertySet() { this.properties = new HashMap, MyProperty>(); } /** * Creates a property with the provided sets of pre-validated default and * active values. * * @param * 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 void addProperty(PropertyDefinition pd, Collection defaultValues, Collection activeValues) { MyProperty p = new MyProperty(pd, defaultValues, activeValues); properties.put(pd, p); } /** * Get the property associated with the specified property definition. * * @param * 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 Property getProperty(PropertyDefinition d) { if (!properties.containsKey(d)) { throw new IllegalArgumentException("Unknown property " + d.getName()); } return (Property) properties.get(d); } /** * {@inheritDoc} */ @Override public String toString() { StringBuilder builder = new StringBuilder(); builder.append('{'); for (Map.Entry, 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. *

* See the class description for more information regarding pending values. * * @param * The type of the property to be modified. * @param d * The property to be modified. * @param values * A non-null 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. * @param options * Options to validate property definitions values. * @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. */ void setPropertyValues(PropertyDefinition d, Collection values, PropertyDefinitionsOptions options) { MyProperty property = (MyProperty) 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, options); } // Update the property. property.setPendingValues(values); } }