From 45359adc09ac1d9e48206c549e667ed6965c7cd3 Mon Sep 17 00:00:00 2001
From: matthew_swift <matthew_swift@localhost>
Date: Mon, 28 May 2007 15:31:13 +0000
Subject: [PATCH] Fix the following issues:

---
 opends/src/server/org/opends/server/admin/client/PropertySet.java |  584 ++++++++++++----------------------------------------------
 1 files changed, 124 insertions(+), 460 deletions(-)

diff --git a/opends/src/server/org/opends/server/admin/client/PropertySet.java b/opends/src/server/org/opends/server/admin/client/PropertySet.java
index 155ad0b..963b125 100644
--- a/opends/src/server/org/opends/server/admin/client/PropertySet.java
+++ b/opends/src/server/org/opends/server/admin/client/PropertySet.java
@@ -32,41 +32,23 @@
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.SortedSet;
 import java.util.TreeSet;
 
-import org.opends.server.admin.AbsoluteInheritedDefaultBehaviorProvider;
-import org.opends.server.admin.AliasDefaultBehaviorProvider;
-import org.opends.server.admin.DefaultBehaviorPropertyValueException;
-import org.opends.server.admin.DefaultBehaviorProviderVisitor;
-import org.opends.server.admin.DefinedDefaultBehaviorProvider;
 import org.opends.server.admin.IllegalPropertyValueException;
-import org.opends.server.admin.IllegalPropertyValueStringException;
-import org.opends.server.admin.InheritedDefaultValueException;
-import org.opends.server.admin.InheritedDefaultValueProvider;
-import org.opends.server.admin.ManagedObjectDefinition;
-import org.opends.server.admin.ManagedObjectPath;
-import org.opends.server.admin.OperationsException;
 import org.opends.server.admin.PropertyDefinition;
-import org.opends.server.admin.PropertyException;
 import org.opends.server.admin.PropertyIsMandatoryException;
-import org.opends.server.admin.PropertyIsReadOnlyException;
 import org.opends.server.admin.PropertyIsSingleValuedException;
 import org.opends.server.admin.PropertyOption;
 import org.opends.server.admin.PropertyProvider;
-import org.opends.server.admin.RelativeInheritedDefaultBehaviorProvider;
-import org.opends.server.admin.StringPropertyProvider;
-import org.opends.server.admin.UndefinedDefaultBehaviorProvider;
 
 
 
 /**
- * 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 implements PropertyProvider {
 
@@ -78,50 +60,65 @@
    */
   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 active set of values (read-only).
-    private final SortedSet<T> activeValues;
-
     // The pending set of values.
     private final SortedSet<T> pendingValues;
 
 
 
     /**
-     * Create a property with the provided sets of pre-validated default and
-     * active values.
-     * <p>
-     * This constructor takes ownership of the provided value sets.
+     * Create a property with the provided sets of pre-validated
+     * default and active values.
      *
-     * @param d
+     * @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> d, SortedSet<T> defaultValues,
-        SortedSet<T> activeValues) {
-      this.d = d;
-      this.defaultValues = Collections.unmodifiableSortedSet(defaultValues);
-      this.activeValues = Collections.unmodifiableSortedSet(activeValues);
+    public MyProperty(PropertyDefinition<T> pd, Collection<T> defaultValues,
+        Collection<T> activeValues) {
+      this.d = pd;
 
-      // Initially the pending values is the same as the active values.
+      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 activeValues;
+      return Collections.unmodifiableSortedSet(activeValues);
     }
 
 
@@ -181,21 +178,18 @@
      * {@inheritDoc}
      */
     public boolean isModified() {
-      if (activeValues == pendingValues) {
+      if (activeValues.size() == pendingValues.size()
+          && activeValues.containsAll(pendingValues)) {
         return false;
-      } else if (activeValues.size() != pendingValues.size()) {
-        return true;
-      } else if (activeValues.containsAll(pendingValues)) {
-        return false;
-      } else {
-        return true;
       }
+      return true;
     }
 
 
 
     /**
-     * Replace all pending values of this property with the provided values.
+     * Replace all pending values of this property with the provided
+     * values.
      *
      * @param c
      *          The new set of pending property values.
@@ -210,376 +204,19 @@
     /**
      * {@inheritDoc}
      */
-    public boolean wasEmpty() {
-      return activeValues.isEmpty();
-    }
-
-
-
-    /**
-     * {@inheritDoc}
-     */
     @Override
     public String toString() {
       return getEffectiveValues().toString();
     }
-  }
-
-
-
-  /**
-   * Internal default behavior visitor implementation.
-   *
-   * @param <T>
-   *          The type of the default property values.
-   */
-  private static final class DefaultVisitor<T> implements
-      DefaultBehaviorProviderVisitor<T, SortedSet<T>,
-      Collection<PropertyException>> {
-
-    // The property definition.
-    private final PropertyDefinition<T> pd;
-
-    // Used to retrieve inherited properties.
-    private final InheritedDefaultValueProvider provider;
-
-
-
-    // Private constructor.
-    private DefaultVisitor(PropertyDefinition<T> pd,
-        InheritedDefaultValueProvider provider) {
-      this.pd = pd;
-      this.provider = provider;
-    }
-
-
-
-    // Cast a set of objects to the required type.
-    private Collection<T> castValues(Collection<?> values,
-        Collection<PropertyException> exceptions) {
-      List<T> castValues = new LinkedList<T>();
-      for (Object value : values) {
-        try {
-          castValues.add(pd.castValue(value));
-        } catch (ClassCastException e) {
-          exceptions.add(new IllegalPropertyValueException(pd, value));
-        }
-      }
-      return castValues;
-    }
-
-
-
-    // Build set of default values and validate them.
-    private SortedSet<T> validateStrings(Collection<String> values,
-        Collection<PropertyException> exceptions) {
-      TreeSet<T> defaultValues = new TreeSet<T>(pd);
-      for (String value : values) {
-        try {
-          defaultValues.add(pd.decodeValue(value));
-        } catch (IllegalPropertyValueStringException e) {
-          exceptions.add(new DefaultBehaviorPropertyValueException(pd, e));
-        }
-      }
-
-      if (!pd.hasOption(PropertyOption.MULTI_VALUED)) {
-        if (defaultValues.size() > 1) {
-          PropertyException e = new PropertyIsSingleValuedException(pd);
-          exceptions.add(new DefaultBehaviorPropertyValueException(pd, e));
-        }
-      }
-
-      return defaultValues;
-    }
-
-
-
-    // Build set of default values and validate them.
-    private SortedSet<T> validate(Collection<T> values,
-        Collection<PropertyException> exceptions) {
-      TreeSet<T> defaultValues = new TreeSet<T>(pd);
-      for (T value : values) {
-        try {
-          pd.validateValue(value);
-          defaultValues.add(value);
-        } catch (IllegalPropertyValueException e) {
-          exceptions.add(new DefaultBehaviorPropertyValueException(pd, e));
-        }
-      }
-
-      if (!pd.hasOption(PropertyOption.MULTI_VALUED)) {
-        if (defaultValues.size() > 1) {
-          PropertyException e = new PropertyIsSingleValuedException(pd);
-          exceptions.add(new DefaultBehaviorPropertyValueException(pd, e));
-        }
-      }
-
-      return defaultValues;
-    }
 
 
 
     /**
      * {@inheritDoc}
      */
-    public SortedSet<T> visitAbsoluteInherited(
-        AbsoluteInheritedDefaultBehaviorProvider<T> d,
-        Collection<PropertyException> p) {
-      // Get the values from the managed object at the specified path.
-      try {
-        // Get the property values/defaults.
-        ManagedObjectPath path = d.getManagedObjectPath();
-        Collection<?> values = provider.getDefaultPropertyValues(path, d
-            .getPropertyName());
-        return validate(castValues(values, p), p);
-      } catch (OperationsException e) {
-        p.add(new InheritedDefaultValueException(pd, e));
-        return new TreeSet<T>(pd);
-      }
+    public boolean wasEmpty() {
+      return activeValues.isEmpty();
     }
-
-
-
-    /**
-     * {@inheritDoc}
-     */
-    public SortedSet<T> visitAlias(AliasDefaultBehaviorProvider<T> d,
-        Collection<PropertyException> p) {
-      // No values applicable - just return the empty set.
-      return new TreeSet<T>(pd);
-    }
-
-
-
-    /**
-     * {@inheritDoc}
-     */
-    public SortedSet<T> visitDefined(DefinedDefaultBehaviorProvider<T> d,
-        Collection<PropertyException> p) {
-      return validateStrings(d.getDefaultValues(), p);
-    }
-
-
-
-    /**
-     * {@inheritDoc}
-     */
-    public SortedSet<T> visitRelativeInherited(
-        RelativeInheritedDefaultBehaviorProvider<T> d,
-        Collection<PropertyException> p) {
-      if (d.getRelativeOffset() == 0) {
-        // TODO: we're inheriting default values from another property in this
-        // property set. Logging is a good use-case: there is a general logging
-        // level for all categories and then category specific levels which can
-        // override. Should the default values be determined dynamically every
-        // time they are accessed? If dynamically, how will decoding errors be
-        // handled? Dynamically: we could return a SortedSet<T> which is lazily
-        // computed.
-        return new TreeSet<T>(pd);
-      } else {
-        // Inheriting default values from a parent managed object.
-        try {
-          ManagedObjectPath base = provider.getManagedObjectPath();
-          ManagedObjectPath path = d.getManagedObjectPath(base);
-          Collection<?> values = provider.getDefaultPropertyValues(path, d
-              .getPropertyName());
-          return validate(castValues(values, p), p);
-        } catch (OperationsException e) {
-          p.add(new InheritedDefaultValueException(pd, e));
-          return new TreeSet<T>(pd);
-        }
-      }
-    }
-
-
-
-    /**
-     * {@inheritDoc}
-     */
-    public SortedSet<T> visitUndefined(UndefinedDefaultBehaviorProvider<T> d,
-        Collection<PropertyException> p) {
-      // No values applicable - just return the empty set.
-      return new TreeSet<T>(pd);
-    }
-  }
-
-
-
-  /**
-   * Create a new property set using a property provider to supply the active
-   * property values. This constructor takes care of validation of the property
-   * values and retrieval of any default values.
-   * <p>
-   * Any exceptions that occurred whilst processing the properties will be
-   * placed in the provided exception collection. Properties that caused the
-   * exceptions will be created with an empty set of values (note that this
-   * could mean that the resulting property set might contain empty mandatory
-   * properties).
-   *
-   * @param d
-   *          The managed object definition.
-   * @param p
-   *          The property provider.
-   * @param i
-   *          An inherited managed object provider for retrieving inherited
-   *          properties.
-   * @param exceptions
-   *          A collection in which any property exceptions can be placed.
-   * @return Returns the new property set.
-   */
-  public static PropertySet create(ManagedObjectDefinition<?, ?> d,
-      PropertyProvider p, InheritedDefaultValueProvider i,
-      Collection<PropertyException> exceptions) {
-    Map<PropertyDefinition, MyProperty> properties =
-      new HashMap<PropertyDefinition, MyProperty>();
-
-    // Copy the properties from the provider.
-    for (PropertyDefinition<?> pd : d.getAllPropertyDefinitions()) {
-      createProperty(pd, p, i, properties, exceptions);
-    }
-
-    return new PropertySet(properties);
-  }
-
-
-
-  /**
-   * Create a new property set using a string property provider to supply the
-   * active property values. This constructor takes care of validation of the
-   * property values and retrieval of any default values.
-   * <p>
-   * Any exceptions that occurred whilst processing the properties will be
-   * placed in the provided exception collection. Properties that caused the
-   * exceptions will be created with an empty set of values (note that this
-   * could mean that the resulting property set might contain empty mandatory
-   * properties).
-   *
-   * @param d
-   *          The managed object definition.
-   * @param p
-   *          The string property provider.
-   * @param i
-   *          An inherited managed object provider for retrieving inherited
-   *          properties.
-   * @param exceptions
-   *          A collection in which any property exceptions can be placed.
-   * @return Returns the new property set.
-   */
-  public static PropertySet create(ManagedObjectDefinition<?, ?> d,
-      StringPropertyProvider p, InheritedDefaultValueProvider i,
-      Collection<PropertyException> exceptions) {
-    Map<PropertyDefinition, MyProperty> properties =
-      new HashMap<PropertyDefinition, MyProperty>();
-
-    // Copy the properties from the provider.
-    for (PropertyDefinition<?> pd : d.getAllPropertyDefinitions()) {
-      createProperty(pd, p, i, properties, exceptions);
-    }
-
-    return new PropertySet(properties);
-  }
-
-
-
-  // Create new property using string values taken from a property provider.
-  private static <T> void createProperty(PropertyDefinition<T> pd,
-      StringPropertyProvider p, InheritedDefaultValueProvider i,
-      Map<PropertyDefinition, MyProperty> properties,
-      Collection<PropertyException> exceptions) {
-
-    // Get the active values for this property.
-    Collection<String> activeStringValues;
-
-    try {
-      activeStringValues = p.getPropertyValues(pd);
-    } catch (IllegalArgumentException e) {
-      // Default to empty set of values.
-      activeStringValues = Collections.<String> emptySet();
-    }
-
-    SortedSet<T> activeValues = new TreeSet<T>(pd);
-    boolean gotException = false;
-    for (String stringValue : activeStringValues) {
-      try {
-        activeValues.add(pd.decodeValue(stringValue));
-      } catch (IllegalPropertyValueStringException e) {
-        exceptions.add(e);
-        gotException = true;
-      }
-    }
-
-    if (gotException == false) {
-      if (pd.hasOption(PropertyOption.MANDATORY)) {
-        if (activeValues.isEmpty()) {
-          exceptions.add(new PropertyIsMandatoryException(pd));
-        }
-      }
-    }
-
-    createProperty(pd, activeValues, i, properties, exceptions);
-  }
-
-
-
-  // Create new property using values taken from a property provider.
-  private static <T> void createProperty(PropertyDefinition<T> pd,
-      PropertyProvider p, InheritedDefaultValueProvider i,
-      Map<PropertyDefinition, MyProperty> properties,
-      Collection<PropertyException> exceptions) {
-    // Get the active values for this property.
-    Collection<T> activeValues;
-
-    try {
-      activeValues = p.getPropertyValues(pd);
-    } catch (IllegalArgumentException e) {
-      // Default to empty set of values.
-      activeValues = Collections.<T> emptySet();
-    }
-
-    SortedSet<T> validActiveValues = new TreeSet<T>(pd);
-    boolean gotException = false;
-    for (T value : activeValues) {
-      try {
-        pd.validateValue(value);
-        validActiveValues.add(value);
-      } catch (IllegalPropertyValueException e) {
-        exceptions.add(e);
-        gotException = true;
-      }
-    }
-
-    if (gotException == false) {
-      if (pd.hasOption(PropertyOption.MANDATORY)) {
-        if (validActiveValues.isEmpty()) {
-          exceptions.add(new PropertyIsMandatoryException(pd));
-        }
-      }
-    }
-
-    createProperty(pd, validActiveValues, i, properties, exceptions);
-  }
-
-
-
-  // Create new property using the provided validated values.
-  private static <T> void createProperty(PropertyDefinition<T> pd,
-      SortedSet<T> activeValues, InheritedDefaultValueProvider i,
-      Map<PropertyDefinition, MyProperty> properties,
-      Collection<PropertyException> exceptions) {
-    // Do remaining validation of active values.
-    if (!pd.hasOption(PropertyOption.MULTI_VALUED)) {
-      if (activeValues.size() > 1) {
-        exceptions.add(new PropertyIsSingleValuedException(pd));
-      }
-    }
-
-    // Get the default values for this property.
-    DefaultVisitor<T> visitor = new DefaultVisitor<T>(pd, i);
-    SortedSet<T> defaultValues = pd.getDefaultBehaviorProvider().accept(
-        visitor, exceptions);
-
-    // Create the property.
-    properties.put(pd, new MyProperty<T>(pd, defaultValues, activeValues));
   }
 
   // The properties.
@@ -587,25 +224,60 @@
 
 
 
-  // Private constructor.
-  private PropertySet(Map<PropertyDefinition, MyProperty> properties) {
-    this.properties = properties;
+  /**
+   * Creates a new empty property set.
+   */
+  public PropertySet() {
+    this.properties = new HashMap<PropertyDefinition, MyProperty>();
   }
 
 
 
   /**
-   * Get the property associated with the specified property definition.
+   * 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);
+  }
+
+
+
+  /**
+   * Makes all pending values active.
+   */
+  public void commit() {
+    for (MyProperty<?> p : properties.values()) {
+      p.commit();
+    }
+  }
+
+
+
+  /**
+   * 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.
+   * @return Returns the property associated with the specified
+   *         property definition.
    * @throws IllegalArgumentException
-   *           If this property provider does not recognise the requested
-   *           property definition.
+   *           If this property provider does not recognise the
+   *           requested property definition.
    */
   @SuppressWarnings("unchecked")
   public <T> Property<T> getProperty(PropertyDefinition<T> d)
@@ -622,18 +294,19 @@
   /**
    * Get the effective value of the specified property.
    * <p>
-   * See the class description for more information about how the effective
-   * property value is derived.
+   * See the class description for more information about how the
+   * effective property value is derived.
    *
    * @param <T>
    *          The type of the property to be retrieved.
    * @param d
    *          The property to be retrieved.
-   * @return Returns the property's effective value, or <code>null</code> if
-   *         there is no effective value defined.
+   * @return Returns the property's effective value, or
+   *         <code>null</code> if there is no effective value
+   *         defined.
    * @throws IllegalArgumentException
-   *           If the property definition is not associated with this managed
-   *           object's definition.
+   *           If the property definition is not associated with this
+   *           managed object's definition.
    */
   public <T> T getPropertyValue(PropertyDefinition<T> d)
       throws IllegalArgumentException {
@@ -650,18 +323,18 @@
   /**
    * Get the effective values of the specified property.
    * <p>
-   * See the class description for more information about how the effective
-   * property values are derived.
+   * See the class description for more information about how the
+   * effective property values are derived.
    *
    * @param <T>
    *          The type of the property to be retrieved.
    * @param d
    *          The property to be retrieved.
-   * @return Returns the property's effective values, or an empty set if there
-   *         are no effective values defined.
+   * @return Returns the property's effective values, or an empty set
+   *         if there are no effective values defined.
    * @throws IllegalArgumentException
-   *           If the property definition is not associated with this managed
-   *           object's definition.
+   *           If the property definition is not associated with this
+   *           managed object's definition.
    */
   public <T> SortedSet<T> getPropertyValues(PropertyDefinition<T> d)
       throws IllegalArgumentException {
@@ -674,29 +347,29 @@
   /**
    * Set a new pending value for the specified property.
    * <p>
-   * See the class description for more information regarding pending values.
+   * 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 value
-   *          The new pending value for the property, or <code>null</code> if
-   *          the property should be reset to its default behavior.
+   *          The new pending value for the property, or
+   *          <code>null</code> if the property should be reset to
+   *          its default behavior.
    * @throws IllegalPropertyValueException
-   *           If the new pending value is deemed to be invalid according to the
-   *           property definition.
-   * @throws PropertyIsReadOnlyException
-   *           If an attempt was made to modify a read-only property.
+   *           If the new pending value is deemed to be invalid
+   *           according to the property definition.
    * @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.
+   *           If the specified property definition is not associated
+   *           with this managed object.
    */
   public <T> void setPropertyValue(PropertyDefinition<T> d, T value)
-      throws IllegalPropertyValueException, PropertyIsReadOnlyException,
-      PropertyIsMandatoryException, IllegalArgumentException {
+      throws IllegalPropertyValueException, PropertyIsMandatoryException,
+      IllegalArgumentException {
     if (value == null) {
       setPropertyValues(d, Collections.<T> emptySet());
     } else {
@@ -709,51 +382,42 @@
   /**
    * Set a new pending values for the specified property.
    * <p>
-   * See the class description for more information regarding pending values.
+   * 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.
+   *          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.
+   *           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 PropertyIsReadOnlyException
-   *           If an attempt was made to modify a read-only property.
+   *           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.
+   *           If the specified property definition is not associated
+   *           with this managed object.
    */
   public <T> void setPropertyValues(PropertyDefinition<T> d,
       Collection<T> values) throws IllegalPropertyValueException,
-      PropertyIsSingleValuedException, PropertyIsReadOnlyException,
-      PropertyIsMandatoryException, IllegalArgumentException {
+      PropertyIsSingleValuedException, PropertyIsMandatoryException,
+      IllegalArgumentException {
     MyProperty<T> property = (MyProperty<T>) getProperty(d);
 
-    if (d.hasOption(PropertyOption.READ_ONLY)) {
-      throw new PropertyIsReadOnlyException(d);
+    if (values.size() > 1 && !d.hasOption(PropertyOption.MULTI_VALUED)) {
+      throw new PropertyIsSingleValuedException(d);
     }
 
-    if (!d.hasOption(PropertyOption.MULTI_VALUED)) {
-      if (values.size() > 1) {
-        throw new PropertyIsSingleValuedException(d);
-      }
-    }
-
-    if (d.hasOption(PropertyOption.MANDATORY)) {
-      if (values.isEmpty()) {
-        throw new PropertyIsMandatoryException(d);
-      }
+    if (values.isEmpty() && d.hasOption(PropertyOption.MANDATORY)) {
+      throw new PropertyIsMandatoryException(d);
     }
 
     // Validate each value.

--
Gitblit v1.10.0