/* * 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); } }