mirror of https://github.com/OpenIdentityPlatform/OpenDJ.git

Nicolas Capponi
26.31.2013 efa949b25f472d7e4c39733678d8f0e5229f8201
opendj-sdk/opendj-admin/src/main/java/org/opends/server/admin/client/spi/PropertySet.java
@@ -26,8 +26,6 @@
package org.opends.server.admin.client.spi;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
@@ -41,330 +39,285 @@
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.
 * 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> {
    /**
     * 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 active set of values.
        private final SortedSet<T> activeValues;
    // The definition associated with this property.
    private final PropertyDefinition<T> d;
        // The definition associated with this property.
        private final PropertyDefinition<T> d;
    // The default set of values (read-only).
    private final SortedSet<T> defaultValues;
        // The default set of values (read-only).
        private final SortedSet<T> defaultValues;
    // The pending set of values.
    private final SortedSet<T> pendingValues;
        // 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}
         */
        @Override
        public SortedSet<T> getActiveValues() {
            return Collections.unmodifiableSortedSet(activeValues);
        }
        /**
         * {@inheritDoc}
         */
        @Override
        public SortedSet<T> getDefaultValues() {
            return defaultValues;
        }
        /**
         * {@inheritDoc}
         */
        @Override
        public SortedSet<T> getEffectiveValues() {
            SortedSet<T> values = getPendingValues();
            if (values.isEmpty()) {
                values = getDefaultValues();
            }
            return values;
        }
        /**
         * {@inheritDoc}
         */
        @Override
        public SortedSet<T> getPendingValues() {
            return Collections.unmodifiableSortedSet(pendingValues);
        }
        /**
         * {@inheritDoc}
         */
        @Override
        public PropertyDefinition<T> 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<T> 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<PropertyDefinition<?>, MyProperty<?>> properties;
    /**
     * Create a property with the provided sets of pre-validated
     * default and active values.
     * 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.
     *            The property definition.
     * @param defaultValues
     *          The set of default values for the property.
     *            The set of default values for the property.
     * @param activeValues
     *          The set of active values for the property.
     *            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);
    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);
    }
    /**
     * 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.
     * Get the property associated with the specified property definition.
     *
     * @param c
     *          The new set of pending property values.
     * @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.
     */
    public void setPendingValues(Collection<T> c) {
      pendingValues.clear();
      pendingValues.addAll(c);
    @SuppressWarnings("unchecked")
    public <T> Property<T> getProperty(PropertyDefinition<T> d) {
        if (!properties.containsKey(d)) {
            throw new IllegalArgumentException("Unknown property " + d.getName());
        }
        return (Property<T>) properties.get(d);
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public String toString() {
      return getEffectiveValues().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();
    }
    /**
     * {@inheritDoc}
     * Makes all pending values active.
     */
    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());
    void commit() {
        for (MyProperty<?> p : properties.values()) {
            p.commit();
        }
    }
    return (Property<T>) properties.get(d);
  }
    /**
     * 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) {
        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);
            }
        }
  /**
   * {@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(' ');
        // Validate each value.
        for (T e : values) {
            if (e == null) {
                throw new NullPointerException();
            }
            d.validateValue(e);
        }
        // Update the property.
        property.setPendingValues(values);
    }
    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);
  }
}