[FELIX-3757] Processed comments of fmeschbe:

- applied correct code formatting;
- when min/max values were defined for types other than integer, the validation
  failed (possibly with a class cast exception);
- some other small issues fixed regarding the validation of the different types;
- updated the changelog to include the set of changes.



git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1410279 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/metatype/changelog.txt b/metatype/changelog.txt
index af4d409..f6c26b9 100644
--- a/metatype/changelog.txt
+++ b/metatype/changelog.txt
@@ -1,3 +1,11 @@
+Changes from 1.0.6 to 1.0.8
+---------------------------
+
+** Bug
+    * [FELIX-3756] - Optional attributes validated invalid data as correct;
+    * [FELIX-3757] - If an AttributeDefinition did not specify a minimum, maximum or option values, it did not detect missing values;
+    * [FELIX-3758] - AttributeDefinition.validate() did not take non-zero cardinality into consideration.
+
 Changes from 1.0.4 to 1.0.6
 ---------------------------
 
diff --git a/metatype/src/main/java/org/apache/felix/metatype/AD.java b/metatype/src/main/java/org/apache/felix/metatype/AD.java
index a083f68..f2456f2 100644
--- a/metatype/src/main/java/org/apache/felix/metatype/AD.java
+++ b/metatype/src/main/java/org/apache/felix/metatype/AD.java
@@ -18,7 +18,6 @@
  */
 package org.apache.felix.metatype;
 
-
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
@@ -28,7 +27,6 @@
 import org.osgi.service.log.LogService;
 import org.osgi.service.metatype.AttributeDefinition;
 
-
 /**
  * The <code>AD</code> class represents the <code>AD</code> element of the
  * meta type descriptor.
@@ -84,255 +82,221 @@
     private String max;
     private boolean isRequired = true;
 
-
     public String getID()
     {
         return id;
     }
 
-
     public String getName()
     {
         return name;
     }
 
-
     public String getDescription()
     {
         return description;
     }
 
-
     public int getType()
     {
         return type;
     }
 
-
     public int getCardinality()
     {
         return cardinality;
     }
 
-
     public String[] getOptionLabels()
     {
         return optionLabels;
     }
 
-
     public String[] getOptionValues()
     {
         return optionValues;
     }
 
-
     public String[] getDefaultValue()
     {
         return defaultValue;
     }
 
-
     public String getMin()
     {
         return min;
     }
 
-
     public String getMax()
     {
         return max;
     }
 
-
     public boolean isRequired()
     {
         return isRequired;
     }
 
-
     /**
      * Implements validation of the <code>valueString</code> and returns an
-     * indication of the success:
-     * <dl>
-     * <dt><code>null</code>
-     * <dd>If neither a {@link #getMin() minimal value} nor a
-     *      {@link #getMax() maximal value} nor any
-     *      {@link #getOptionValues() optional values} are defined in this
-     *      instance, validation cannot be performed.
-     * <dt>Empty String
-     * <dd>If validation succeeds. This value is also returned if the
-     *      <code>valueString</code> is empty or <code>null</code> or cannot be
-     *      converted into a numeric type.
-     * <dt><b>%</b>message
-     * <dd>If the value falls below the minimum, higher than the maximum or is
-     *      not any of the option values, an explanatory message, which may be
-     *      localized is returned. If any of the minimum, maximum or option
-     *      values is <code>null</code>, the respective value is not checked.
-     * </dl>
+     * indication of the validation result.
      *
-     * @param valueString The string representation of the value to validate.
+     * @param valueString The string representation of the value to validate,
+     *        can be <code>null</code>.
      *
-     * @return As explained above.
+     * @return <code>null</code> if no validation is performed, <tt>""</tt> if
+     *         the value is accepted as valid, or a non-empty string 
+     *         indicating a validation problem was found.
      *
+     * @see ADValidator#validate(AD, String)
      * @see #VALIDATE_GREATER_THAN_MAXIMUM
-     * @see #VALIDATE_LESS_THAN_MINIMUM
      * @see #VALIDATE_NOT_A_VALID_OPTION
+     * @see #VALIDATE_LESS_THAN_MINIMUM
+     * @see #VALIDATE_INVALID_VALUE
+     * @see #VALIDATE_MISSING
      */
-    public String validate( String valueString )
+    public String validate(String valueString)
     {
-    	return ADValidator.validate(this, valueString);
+        return ADValidator.validate(this, valueString);
     }
 
-
     //--------- Setters for setting up this instance --------------------------
 
     /**
      * @param id the id to set
      */
-    public void setID( String id )
+    public void setID(String id)
     {
         this.id = id;
     }
 
-
     /**
      * @param name the name to set
      */
-    public void setName( String name )
+    public void setName(String name)
     {
         this.name = name;
     }
 
-
     /**
      * @param description the description to set
      */
-    public void setDescription( String description )
+    public void setDescription(String description)
     {
         this.description = description;
     }
 
-
     /**
      * @param typeString the type to set
      */
-    public void setType( String typeString )
+    public void setType(String typeString)
     {
-        this.type = toType( typeString );
+        this.type = toType(typeString);
     }
 
-
     /**
      * @param cardinality the cardinality to set
      */
-    public void setCardinality( int cardinality )
+    public void setCardinality(int cardinality)
     {
         this.cardinality = cardinality;
     }
 
-
     /**
      * @param options the options to set
      */
-    public void setOptions( Map options )
+    public void setOptions(Map options)
     {
         optionLabels = new String[options.size()];
         optionValues = new String[options.size()];
         int i = 0;
-        for ( Iterator oi = options.entrySet().iterator(); oi.hasNext(); i++ )
+        for (Iterator oi = options.entrySet().iterator(); oi.hasNext(); i++)
         {
-            Map.Entry entry = ( Map.Entry ) oi.next();
-            optionValues[i] = String.valueOf( entry.getKey() );
-            optionLabels[i] = String.valueOf( entry.getValue() );
+            Map.Entry entry = (Map.Entry) oi.next();
+            optionValues[i] = String.valueOf(entry.getKey());
+            optionLabels[i] = String.valueOf(entry.getValue());
         }
     }
 
-
     /**
      * @param defaultValue the defaultValue to set
      */
-    public void setDefaultValue( String defaultValue )
+    public void setDefaultValue(String defaultValue)
     {
-        this.defaultValue = splitList( defaultValue );
+        this.defaultValue = splitList(defaultValue);
     }
 
-
     /**
      * @param min the min to set
      */
-    public void setMin( String min )
+    public void setMin(String min)
     {
         this.min = min;
     }
 
-
     /**
      * @param max the max to set
      */
-    public void setMax( String max )
+    public void setMax(String max)
     {
         this.max = max;
     }
 
-
     /**
      * @param defaultValue the defaultValue to set
      */
-    public void setDefaultValue( String[] defaultValue )
+    public void setDefaultValue(String[] defaultValue)
     {
-        this.defaultValue = ( String[] ) defaultValue.clone();
+        this.defaultValue = (String[]) defaultValue.clone();
     }
 
-
     /**
      * @param isRequired the isRequired to set
      */
-    public void setRequired( boolean isRequired )
+    public void setRequired(boolean isRequired)
     {
         this.isRequired = isRequired;
     }
 
-
-    public static int toType( String typeString )
+    public static int toType(String typeString)
     {
-        if ( "String".equals( typeString ) )
+        if ("String".equals(typeString))
         {
             return AttributeDefinition.STRING;
         }
-        else if ( "Long".equals( typeString ) )
+        else if ("Long".equals(typeString))
         {
             return AttributeDefinition.LONG;
         }
-        else if ( "Double".equals( typeString ) )
+        else if ("Double".equals(typeString))
         {
             return AttributeDefinition.DOUBLE;
         }
-        else if ( "Float".equals( typeString ) )
+        else if ("Float".equals(typeString))
         {
             return AttributeDefinition.FLOAT;
         }
-        else if ( "Integer".equals( typeString ) )
+        else if ("Integer".equals(typeString))
         {
             return AttributeDefinition.INTEGER;
         }
-        else if ( "Byte".equals( typeString ) )
+        else if ("Byte".equals(typeString))
         {
             return AttributeDefinition.BYTE;
         }
-        else if ( "Char".equals( typeString ) )
+        else if ("Char".equals(typeString))
         {
             return AttributeDefinition.CHARACTER;
         }
-        else if ( "Boolean".equals( typeString ) )
+        else if ("Boolean".equals(typeString))
         {
             return AttributeDefinition.BOOLEAN;
         }
-        else if ( "Short".equals( typeString ) )
+        else if ("Short".equals(typeString))
         {
             return AttributeDefinition.SHORT;
         }
-        else if ( "Password".equals( typeString ) )
+        else if ("Password".equals(typeString))
         {
             return AttributeDefinition.PASSWORD;
         }
@@ -341,90 +305,102 @@
         return AttributeDefinition.STRING;
     }
 
-
-    public static String[] splitList( String listString )
+    public static String[] splitList(String listString)
     {
-		if (listString == null) {
-			return null;
-		} else if (listString.length() == 0) {
-			return new String[] { "" };
-		}
+        if (listString == null)
+        {
+            return null;
+        }
+        else if (listString.length() == 0)
+        {
+            return new String[] { "" };
+        }
 
-		List strings = new ArrayList();
-		StringBuffer sb = new StringBuffer();
+        List strings = new ArrayList();
+        StringBuffer sb = new StringBuffer();
 
-		int length = listString.length();
-		boolean escaped = false;
-		
-		for (int i = 0; i < length; i++) {
-			char ch = listString.charAt(i);
-			if (ch == '\\') {
-				if (!escaped) {
-					escaped = true;
-					continue;
-				}
-			} else if (ch == ',') {
-				if (!escaped) {
-					// unescaped comma, this is a string delimiter...
-					strings.add(sb.toString());
-					sb.setLength(0);
-					continue;
-				}
-			} else if (ch == ' ') {
-				// we should ignore spaces normally, unless they are escaped...
-				if (!escaped) {
-					continue;
-				}
-			} else if (Character.isWhitespace(ch)) {
-				// Other whitespaces are ignored...
-				continue;
-			}
+        int length = listString.length();
+        boolean escaped = false;
 
-			sb.append(ch);
-			escaped = false;
-		}
+        for (int i = 0; i < length; i++)
+        {
+            char ch = listString.charAt(i);
+            if (ch == '\\')
+            {
+                if (!escaped)
+                {
+                    escaped = true;
+                    continue;
+                }
+            }
+            else if (ch == ',')
+            {
+                if (!escaped)
+                {
+                    // unescaped comma, this is a string delimiter...
+                    strings.add(sb.toString());
+                    sb.setLength(0);
+                    continue;
+                }
+            }
+            else if (ch == ' ')
+            {
+                // we should ignore spaces normally, unless they are escaped...
+                if (!escaped)
+                {
+                    continue;
+                }
+            }
+            else if (Character.isWhitespace(ch))
+            {
+                // Other whitespaces are ignored...
+                continue;
+            }
 
-		// Always add the last string, as it contains everything after the last comma...
-		strings.add(sb.toString());
+            sb.append(ch);
+            escaped = false;
+        }
 
-		return (String[]) strings.toArray(new String[strings.size()]);
+        // Always add the last string, as it contains everything after the last comma...
+        strings.add(sb.toString());
+
+        return (String[]) strings.toArray(new String[strings.size()]);
     }
 
-
-    protected Comparable convertToType( final String value )
+    protected Comparable convertToType(final String value)
     {
-        if ( value != null && value.length() > 0 )
+        if (value != null && value.length() > 0)
         {
             try
             {
-                switch ( getType() )
+                switch (getType())
                 {
                     case AttributeDefinition.BOOLEAN:
                         // Boolean is only Comparable starting with Java 5
-                        return new ComparableBoolean( value );
+                        return new ComparableBoolean(value);
                     case AttributeDefinition.CHARACTER:
-                        return new Character( value.charAt( 0 ) );
+                        return new Character(value.charAt(0));
                     case AttributeDefinition.BYTE:
-                        return Byte.valueOf( value );
+                        return Byte.valueOf(value);
                     case AttributeDefinition.SHORT:
-                        return Short.valueOf( value );
+                        return Short.valueOf(value);
                     case AttributeDefinition.INTEGER:
-                        return Integer.valueOf( value );
+                        return Integer.valueOf(value);
                     case AttributeDefinition.LONG:
-                        return Long.valueOf( value );
+                        return Long.valueOf(value);
                     case AttributeDefinition.FLOAT:
-                        return Float.valueOf( value );
+                        return Float.valueOf(value);
                     case AttributeDefinition.DOUBLE:
-                        return Double.valueOf( value );
+                        return Double.valueOf(value);
                     case AttributeDefinition.STRING:
                     case AttributeDefinition.PASSWORD:
                     default:
                         return value;
                 }
             }
-            catch ( NumberFormatException nfe )
+            catch (NumberFormatException nfe)
             {
-                Activator.log( LogService.LOG_INFO, "Cannot convert value '" + value + "'", nfe );
+                Activator.log(LogService.LOG_INFO, "Cannot convert value '" + value + "'", nfe);
             }
         }
 
@@ -435,17 +411,15 @@
     {
         private boolean value;
 
-
-        ComparableBoolean( String boolValue )
+        ComparableBoolean(String boolValue)
         {
-            value = Boolean.valueOf( boolValue ).booleanValue();
+            value = Boolean.valueOf(boolValue).booleanValue();
         }
 
-
-        public int compareTo( Object obj )
+        public int compareTo(Object obj)
         {
-            ComparableBoolean cb = ( ComparableBoolean ) obj;
-            return ( cb.value == value ? 0 : ( value ? 1 : -1 ) );
+            ComparableBoolean cb = (ComparableBoolean) obj;
+            return (cb.value == value ? 0 : (value ? 1 : -1));
         }
     }
 }
diff --git a/metatype/src/main/java/org/apache/felix/metatype/ADValidator.java b/metatype/src/main/java/org/apache/felix/metatype/ADValidator.java
index d82b136..60b35a0 100644
--- a/metatype/src/main/java/org/apache/felix/metatype/ADValidator.java
+++ b/metatype/src/main/java/org/apache/felix/metatype/ADValidator.java
@@ -30,319 +30,407 @@
  * 
  * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
  */
-final class ADValidator {
+final class ADValidator
+{
+    /**
+     * Validates a given input string according to the type specified by the given attribute 
+     * definition.
+     * <p>
+     * The validation is done in the following way:
+     * </p>
+     * <ul>
+     * <li>If the input is undefined (ie. <code>null</code>), and the attribute is mandatory, the 
+     * validation fails due to a missing value. If the attribute is optional, the input is 
+     * accepted;</li>
+     * <li>If the input represents a <em>boolean</em> value, it is tested whether it is defined (in
+     * case of non-zero cardinality) and represents either <tt>"true"</tt> or <tt>"false"</tt>. The
+     * minimum and maximum parameters are <b>not</b> used in this validation;</li>
+     * <li>If the input represents a <em>character</em> value, it is tested whether it is defined 
+     * (in case of non-zero cardinality). The character value must be defined within the character 
+     * range specified by the minimum and maximum parameters (if defined);</li>
+     * <li>If the input represents a <em>numeric</em> value, it is tested whether it is defined (in
+     * case of non-zero cardinality). The numeric value must be defined within the numeric range 
+     * specified by the minimum and maximum parameters (if defined);</li>
+     * <li>If the input represents a <em>string</em> or <em>password</em>, it is tested whether it
+     * is defined (in case of non-zero cardinality). The length of the string value must be in the
+     * range specified by the minimum and maximum parameters (if defined).</li>
+     * </ul>
+     * <p>
+     * For all types of attributes, if it defines option values, the input should be present as one
+     * of the defined option values. 
+     * </p>
+     * 
+     * @param ad
+     *            the attribute definition to use in the validation;
+     * @param rawInput
+     *            the raw input value to validate.
+     * @return <code>null</code> if no validation is available, <tt>""</tt> if
+     *         validation was successful, or any other non-empty string in case
+     *         validation fails.
+     */
+    public static String validate(AD ad, String rawInput)
+    {
+        // Handle the case in which the given input is not defined...
+        if (rawInput == null)
+        {
+            if (ad.isRequired())
+            {
+                return AD.VALIDATE_MISSING;
+            }
 
-	/**
-	 * Validates a given input string according to the type specified by the
-	 * given attribute definition.
-	 * 
-	 * @param ad
-	 *            the attribute definition to use in the validation;
-	 * @param rawInput
-	 *            the raw input value to validate.
-	 * @return <code>null</code> if no validation is available, <tt>""</tt> if
-	 *         validation was successful, or any other non-empty string in case
-	 *         validation fails.
-	 */
-	public static String validate(AD ad, String rawInput) {
-		// Handle the case in which the given input is not defined...
-		if (rawInput == null) {
-			if (ad.isRequired()) {
-				return AD.VALIDATE_MISSING;
-			}
+            return ""; // accept null value...
+        }
 
-			return ""; // accept null value...
-		}
+        // Raw input is defined, validate it further
+        String[] input;
+        if (ad.getCardinality() == 0)
+        {
+            input = new String[] { rawInput.trim() };
+        }
+        else
+        {
+            input = AD.splitList(rawInput);
+        }
 
-		// Raw input is defined, validate it further
-		String[] input;
+        int type = ad.getType();
+        switch (type)
+        {
+            case AttributeDefinition.BOOLEAN:
+                return validateBooleanValue(ad, input);
 
-		if (ad.getCardinality() == 0) {
-			input = new String[] { rawInput.trim() };
-		} else {
-			input = AD.splitList(rawInput);
-		}
+            case AttributeDefinition.CHARACTER:
+                return validateCharacterValue(ad, input);
 
-		int type = ad.getType();
-		switch (type) {
-		case AttributeDefinition.BOOLEAN:
-			return validateBooleanValue(ad, input);
+            case AttributeDefinition.BIGDECIMAL:
+            case AttributeDefinition.BIGINTEGER:
+            case AttributeDefinition.BYTE:
+            case AttributeDefinition.DOUBLE:
+            case AttributeDefinition.FLOAT:
+            case AttributeDefinition.INTEGER:
+            case AttributeDefinition.LONG:
+            case AttributeDefinition.SHORT:
+                return validateNumericValue(ad, input);
 
-		case AttributeDefinition.CHARACTER:
-			return validateCharacterValue(ad, input);
+            case AttributeDefinition.PASSWORD:
+            case AttributeDefinition.STRING:
+                return validateString(ad, input);
 
-		case AttributeDefinition.BIGDECIMAL:
-		case AttributeDefinition.BIGINTEGER:
-		case AttributeDefinition.BYTE:
-		case AttributeDefinition.DOUBLE:
-		case AttributeDefinition.FLOAT:
-		case AttributeDefinition.INTEGER:
-		case AttributeDefinition.LONG:
-		case AttributeDefinition.SHORT:
-			return validateNumericValue(ad, input);
+            default:
+                return null; // no validation present...
+        }
+    }
 
-		case AttributeDefinition.PASSWORD:
-		case AttributeDefinition.STRING:
-			return validateString(ad, input);
+    /**
+     * Searches for a given search value in a given array of options.
+     * 
+     * @param searchValue
+     *            the value to search for;
+     * @param optionValues
+     *            the values to search in.
+     * @return <code>null</code> if the given search value is not found in the
+     *         given options, the searched value if found, or <tt>""</tt> if no
+     *         search value or options were given.
+     */
+    private static String findOptionValue(String searchValue, String[] optionValues)
+    {
+        if ((searchValue == null) || (optionValues == null) || (optionValues.length == 0))
+        {
+            // indicates that we've not searched...
+            return "";
+        }
 
-		default:
-			return null; // no validation present...
-		}
-	}
+        for (int i = 0; i < optionValues.length; i++)
+        {
+            if (optionValues[i].equals(searchValue))
+            {
+                return optionValues[i];
+            }
+        }
 
-	/**
-	 * Searches for a given search value in a given array of options.
-	 * 
-	 * @param searchValue
-	 *            the value to search for;
-	 * @param optionValues
-	 *            the values to search in.
-	 * @return <code>null</code> if the given search value is not found in the
-	 *         given options, the searched value if found, or <tt>""</tt> if no
-	 *         search value or options were given.
-	 */
-	private static String findOptionValue(String searchValue, String[] optionValues) {
-		if ((searchValue == null) || (optionValues == null) || (optionValues.length == 0)) {
-			// indicates that we've not searched
-			return "";
-		}
+        return null;
+    }
 
-		for (int i = 0; i < optionValues.length; i++) {
-			if (optionValues[i].equals(searchValue)) {
-				return optionValues[i];
-			}
-		}
+    /**
+     * Parses a given string value into a numeric type.
+     * 
+     * @param type
+     *            the type to parse;
+     * @param value
+     *            the value to parse.
+     * @return a {@link Number} representation of the given value, or
+     *         <code>null</code> if the input was <code>null</code>, empty, or
+     *         not a numeric type.
+     * @throws NumberFormatException
+     *             in case the given value cannot be parsed as numeric value.
+     */
+    private static Comparable parseNumber(int type, String value) throws NumberFormatException
+    {
+        if ((value != null) && (value.length() > 0))
+        {
+            switch (type)
+            {
+                case AttributeDefinition.BIGDECIMAL:
+                    return new BigDecimal(value);
+                case AttributeDefinition.BIGINTEGER:
+                    return new BigInteger(value);
+                case AttributeDefinition.BYTE:
+                    return Byte.valueOf(value);
+                case AttributeDefinition.SHORT:
+                    return Short.valueOf(value);
+                case AttributeDefinition.INTEGER:
+                    return Integer.valueOf(value);
+                case AttributeDefinition.LONG:
+                    return Long.valueOf(value);
+                case AttributeDefinition.FLOAT:
+                    return Float.valueOf(value);
+                case AttributeDefinition.DOUBLE:
+                    return Double.valueOf(value);
+                default:
+                    return null;
+            }
+        }
+        return null;
+    }
 
-		return null;
-	}
+    /**
+     * Parses a given string value as character, allowing <code>null</code>
+     * -values and empty values to be given as input.
+     * 
+     * @param value
+     *            the value to parse as character, can be <code>null</code> or
+     *            an empty value.
+     * @return the character value if, and only if, the given input was non-
+     *         <code>null</code> and a non-empty string.
+     */
+    private static Character parseOptionalChar(String value)
+    {
+        if ((value != null) && (value.length() > 0))
+        {
+            return Character.valueOf(value.charAt(0));
+        }
+        return null;
+    }
 
-	/**
-	 * Parses a given string value into a numeric type.
-	 * 
-	 * @param type
-	 *            the type to parse;
-	 * @param value
-	 *            the value to parse.
-	 * @return a {@link Number} representation of the given value, or
-	 *         <code>null</code> if the input was <code>null</code>, empty, or
-	 *         not a numeric type.
-	 * @throws NumberFormatException
-	 *             in case the given value cannot be parsed as numeric value.
-	 */
-	private static Comparable parseNumber(int type, String value) throws NumberFormatException {
-		if ((value != null) && (value.length() > 0)) {
-			switch (type) {
-			case AttributeDefinition.BIGDECIMAL:
-				return new BigDecimal(value);
-			case AttributeDefinition.BIGINTEGER:
-				return new BigInteger(value);
-			case AttributeDefinition.BYTE:
-				return Byte.valueOf(value);
-			case AttributeDefinition.SHORT:
-				return Short.valueOf(value);
-			case AttributeDefinition.INTEGER:
-				return Integer.valueOf(value);
-			case AttributeDefinition.LONG:
-				return Long.valueOf(value);
-			case AttributeDefinition.FLOAT:
-				return Float.valueOf(value);
-			case AttributeDefinition.DOUBLE:
-				return Double.valueOf(value);
-			default:
-				return null;
-			}
-		}
-		return null;
-	}
+    /**
+     * Parses a given string value as numeric value, allowing 
+     * <code>null</code>-values and invalid numeric values to be given as 
+     * input.
+     * 
+     * @param type the type of number, should only be a numeric type;
+     * @param value
+     *            the value to parse as integer, can be <code>null</code> or a
+     *            non-numeric value.
+     * @return the integer value if, and only if, the given input was non-
+     *         <code>null</code> and a valid integer representation.
+     */
+    private static Comparable parseOptionalNumber(int type, String value)
+    {
+        if (value != null)
+        {
+            try
+            {
+                return parseNumber(type, value);
+            }
+            catch (NumberFormatException e)
+            {
+                // Ignore; invalid value...
+            }
+        }
+        return null;
+    }
 
-	/**
-	 * Parses a given string value as character, allowing <code>null</code>
-	 * -values and empty values to be given as input.
-	 * 
-	 * @param value
-	 *            the value to parse as character, can be <code>null</code> or
-	 *            an empty value.
-	 * @return the character value if, and only if, the given input was non-
-	 *         <code>null</code> and a non-empty string.
-	 */
-	private static Character parseOptionalChar(String value) {
-		if ((value != null) && (value.length() > 0)) {
-			return Character.valueOf(value.charAt(0));
-		}
-		return null;
-	}
+    /**
+     * Validates a given input string as boolean value.
+     * 
+     * @param ad
+     *            the attribute definition to use in the validation;
+     * @param input
+     *            the array with input values to validate.
+     * @return <code>null</code> if no validation is available, <tt>""</tt> if
+     *         validation was successful, or any other non-empty string in case
+     *         validation fails.
+     */
+    private static String validateBooleanValue(AD ad, String[] input)
+    {
+        for (int i = 0; i < input.length; i++)
+        {
+            String value = input[i];
+            int length = (value == null) ? 0 : value.length();
 
-	/**
-	 * Parses a given string value as integer, allowing <code>null</code>-values
-	 * and invalid numeric values to be given as input.
-	 * 
-	 * @param value
-	 *            the value to parse as integer, can be <code>null</code> or a
-	 *            non-numeric value.
-	 * @return the integer value if, and only if, the given input was non-
-	 *         <code>null</code> and a valid integer representation.
-	 */
-	private static Integer parseOptionalInt(String value) {
-		if (value != null) {
-			try {
-				return Integer.valueOf(value);
-			} catch (NumberFormatException e) {
-				// Ignore; invalid value...
-			}
-		}
-		return null;
-	}
+            if ((length == 0) && ad.isRequired())
+            {
+                return AD.VALIDATE_MISSING;
+            }
+            else if (length > 0 && !"true".equalsIgnoreCase(value) && !"false".equalsIgnoreCase(value))
+            {
+                return AD.VALIDATE_INVALID_VALUE;
+            }
+        }
 
-	/**
-	 * Validates a given input string as boolean value.
-	 * 
-	 * @param ad
-	 *            the attribute definition to use in the validation;
-	 * @param input
-	 *            the array with input values to validate.
-	 * @return <code>null</code> if no validation is available, <tt>""</tt> if
-	 *         validation was successful, or any other non-empty string in case
-	 *         validation fails.
-	 */
-	private static String validateBooleanValue(AD ad, String[] input) {
-		for (int i = 0; i < input.length; i++) {
-			int length = input[i].length();
-			if ((length == 0) && ad.isRequired()) {
-				return AD.VALIDATE_MISSING;
-			} else if (length > 0 && !"true".equalsIgnoreCase(input[i]) && !"false".equalsIgnoreCase(input[i])) {
-				return AD.VALIDATE_INVALID_VALUE;
-			}
-		}
+        String[] optionValues = ad.getOptionValues();
+        if ((optionValues != null) && (optionValues.length > 0))
+        {
+            return null; // no validation possible for this type...
+        }
 
-		String[] optionValues = ad.getOptionValues();
-		if (optionValues != null && optionValues.length > 0) {
-			return null; // no validation possible for this type...
-		}
+        return ""; // accept given value...
+    }
 
-		return ""; // accept given value...
-	}
+    /**
+     * Validates a given input string as character value.
+     * 
+     * @param ad
+     *            the attribute definition to use in the validation;
+     * @param input
+     *            the array with input values to validate.
+     * @return <code>null</code> if no validation is available, <tt>""</tt> if
+     *         validation was successful, or any other non-empty string in case
+     *         validation fails.
+     */
+    private static String validateCharacterValue(AD ad, String[] input)
+    {
+        Character min = parseOptionalChar(ad.getMin());
+        Character max = parseOptionalChar(ad.getMax());
+        String[] optionValues = ad.getOptionValues();
 
-	/**
-	 * Validates a given input string as character value.
-	 * 
-	 * @param ad
-	 *            the attribute definition to use in the validation;
-	 * @param input
-	 *            the array with input values to validate.
-	 * @return <code>null</code> if no validation is available, <tt>""</tt> if
-	 *         validation was successful, or any other non-empty string in case
-	 *         validation fails.
-	 */
-	private static String validateCharacterValue(AD ad, String[] input) {
-		Character min = parseOptionalChar(ad.getMin());
-		Character max = parseOptionalChar(ad.getMax());
-		String[] optionValues = ad.getOptionValues();
+        for (int i = 0; i < input.length; i++)
+        {
+            Character ch = null;
 
-		for (int i = 0; i < input.length; i++) {
-			Character ch = null;
-			int length = input[i].length();
-			if (length > 1) {
-				return AD.VALIDATE_GREATER_THAN_MAXIMUM;
-			} else if ((length == 0) && ad.isRequired()) {
-				return AD.VALIDATE_MISSING;
-			} else if (length == 1) {
-				ch = Character.valueOf(input[i].charAt(0));
-				// Check whether the minimum value is adhered for all values...
-				if ((min != null) && (ch.compareTo(min) < 0)) {
-					return AD.VALIDATE_LESS_THAN_MINIMUM;
-				}
-				// Check whether the maximum value is adhered for all values...
-				if ((max != null) && (ch.compareTo(max) > 0)) {
-					return AD.VALIDATE_GREATER_THAN_MAXIMUM;
-				}
-			}
+            int length = (input[i] == null) ? 0 : input[i].length();
+            if (length > 1)
+            {
+                return AD.VALIDATE_GREATER_THAN_MAXIMUM;
+            }
+            else if ((length == 0) && ad.isRequired())
+            {
+                return AD.VALIDATE_MISSING;
+            }
+            else if (length == 1)
+            {
+                ch = Character.valueOf(input[i].charAt(0));
+                // Check whether the minimum value is adhered for all values...
+                if ((min != null) && (ch.compareTo(min) < 0))
+                {
+                    return AD.VALIDATE_LESS_THAN_MINIMUM;
+                }
+                // Check whether the maximum value is adhered for all values...
+                if ((max != null) && (ch.compareTo(max) > 0))
+                {
+                    return AD.VALIDATE_GREATER_THAN_MAXIMUM;
+                }
+            }
 
-			if (findOptionValue(input[i], optionValues) == null) {
-				return AD.VALIDATE_NOT_A_VALID_OPTION;
-			}
-		}
+            if (findOptionValue(input[i], optionValues) == null)
+            {
+                return AD.VALIDATE_NOT_A_VALID_OPTION;
+            }
+        }
 
-		return ""; // accept given value...
-	}
+        return ""; // accept given value...
+    }
 
-	/**
-	 * Validates a given input string as numeric value.
-	 * 
-	 * @param ad
-	 *            the attribute definition to use in the validation;
-	 * @param input
-	 *            the array with input values to validate.
-	 * @return <code>null</code> if no validation is available, <tt>""</tt> if
-	 *         validation was successful, or any other non-empty string in case
-	 *         validation fails.
-	 */
-	private static String validateNumericValue(AD ad, String[] input) {
-		Integer min = parseOptionalInt(ad.getMin());
-		Integer max = parseOptionalInt(ad.getMax());
-		String[] optionValues = ad.getOptionValues();
+    /**
+     * Validates a given input string as numeric value.
+     * 
+     * @param ad
+     *            the attribute definition to use in the validation;
+     * @param input
+     *            the array with input values to validate.
+     * @return <code>null</code> if no validation is available, <tt>""</tt> if
+     *         validation was successful, or any other non-empty string in case
+     *         validation fails.
+     */
+    private static String validateNumericValue(AD ad, String[] input)
+    {
+        Comparable min = parseOptionalNumber(ad.getType(), ad.getMin());
+        Comparable max = parseOptionalNumber(ad.getType(), ad.getMax());
+        String[] optionValues = ad.getOptionValues();
 
-		for (int i = 0; i < input.length; i++) {
-			Comparable value = null;
-			try {
-				value = parseNumber(ad.getType(), input[i]);
-			} catch (NumberFormatException e) {
-				return AD.VALIDATE_INVALID_VALUE;
-			}
+        for (int i = 0; i < input.length; i++)
+        {
+            Comparable value = null;
+            try
+            {
+                value = parseNumber(ad.getType(), input[i]);
+            }
+            catch (NumberFormatException e)
+            {
+                return AD.VALIDATE_INVALID_VALUE;
+            }
 
-			if ((value == null) && ad.isRequired()) {
-				// Possible if the cardinality != 0 and input was something like
-				// "0,,1"...
-				return AD.VALIDATE_MISSING;
-			}
-			// Check whether the minimum value is adhered for all values...
-			if ((min != null) && (value != null) && (value.compareTo(min) < 0)) {
-				return AD.VALIDATE_LESS_THAN_MINIMUM;
-			}
-			// Check whether the maximum value is adhered for all values...
-			if ((max != null) && (value != null) && (value.compareTo(max) > 0)) {
-				return AD.VALIDATE_GREATER_THAN_MAXIMUM;
-			}
+            if ((value == null) && ad.isRequired())
+            {
+                // Possible if the cardinality != 0 and input was something like
+                // "0,,1"...
+                return AD.VALIDATE_MISSING;
+            }
+            // Check whether the minimum value is adhered for all values...
+            if ((min != null) && (value != null) && (value.compareTo(min) < 0))
+            {
+                return AD.VALIDATE_LESS_THAN_MINIMUM;
+            }
+            // Check whether the maximum value is adhered for all values...
+            if ((max != null) && (value != null) && (value.compareTo(max) > 0))
+            {
+                return AD.VALIDATE_GREATER_THAN_MAXIMUM;
+            }
 
-			if (findOptionValue(input[i], optionValues) == null) {
-				return AD.VALIDATE_NOT_A_VALID_OPTION;
-			}
-		}
+            if (findOptionValue(input[i], optionValues) == null)
+            {
+                return AD.VALIDATE_NOT_A_VALID_OPTION;
+            }
+        }
 
-		return ""; // accept given value...
-	}
+        return ""; // accept given value...
+    }
 
-	/**
-	 * Validates a given input string as string (or password).
-	 * 
-	 * @param ad
-	 *            the attribute definition to use in the validation;
-	 * @param input
-	 *            the array with input values to validate.
-	 * @return <code>null</code> if no validation is available, <tt>""</tt> if
-	 *         validation was successful, or any other non-empty string in case
-	 *         validation fails.
-	 */
-	private static String validateString(AD ad, String[] input) {
-		Integer min = parseOptionalInt(ad.getMin());
-		Integer max = parseOptionalInt(ad.getMax());
-		String[] optionValues = ad.getOptionValues();
+    /**
+     * Validates a given input string as string (or password).
+     * 
+     * @param ad
+     *            the attribute definition to use in the validation;
+     * @param input
+     *            the array with input values to validate.
+     * @return <code>null</code> if no validation is available, <tt>""</tt> if
+     *         validation was successful, or any other non-empty string in case
+     *         validation fails.
+     */
+    private static String validateString(AD ad, String[] input)
+    {
+        // The length() method of a string yields an Integer, so the maximum string length is 2^31-1...
+        Integer min = (Integer) parseOptionalNumber(AttributeDefinition.INTEGER, ad.getMin());
+        Integer max = (Integer) parseOptionalNumber(AttributeDefinition.INTEGER, ad.getMax());
+        String[] optionValues = ad.getOptionValues();
 
-		for (int i = 0; i < input.length; i++) {
-			int length = input[i].length();
-			// Check whether the minimum length is adhered for all values...
-			if ((min != null) && (length < min.intValue())) {
-				return AD.VALIDATE_LESS_THAN_MINIMUM;
-			}
-			// Check whether the maximum length is adhered for all values...
-			if ((max != null) && (length > max.intValue())) {
-				return AD.VALIDATE_GREATER_THAN_MAXIMUM;
-			}
+        for (int i = 0; i < input.length; i++)
+        {
+            String value = input[i];
+            int length = (value == null) ? 0 : value.length();
 
-			if (findOptionValue(input[i], optionValues) == null) {
-				return AD.VALIDATE_NOT_A_VALID_OPTION;
-			}
-		}
+            if (ad.isRequired() && ((value == null) || (length == 0)))
+            {
+                // Possible if the cardinality != 0 and input was something like
+                // "0,,1"...
+                return AD.VALIDATE_MISSING;
+            }
+            // Check whether the minimum length is adhered for all values...
+            if ((min != null) && (length < min.intValue()))
+            {
+                return AD.VALIDATE_LESS_THAN_MINIMUM;
+            }
+            // Check whether the maximum length is adhered for all values...
+            if ((max != null) && (length > max.intValue()))
+            {
+                return AD.VALIDATE_GREATER_THAN_MAXIMUM;
+            }
 
-		return ""; // accept given value...
-	}
+            if (findOptionValue(value, optionValues) == null)
+            {
+                return AD.VALIDATE_NOT_A_VALID_OPTION;
+            }
+        }
+
+        return ""; // accept given value...
+    }
 }
diff --git a/metatype/src/test/java/org/apache/felix/metatype/ADTest.java b/metatype/src/test/java/org/apache/felix/metatype/ADTest.java
index 065f0c9..00cbc27 100644
--- a/metatype/src/test/java/org/apache/felix/metatype/ADTest.java
+++ b/metatype/src/test/java/org/apache/felix/metatype/ADTest.java
@@ -18,12 +18,10 @@
  */
 package org.apache.felix.metatype;
 
-
 import junit.framework.TestCase;
 
 import org.osgi.service.metatype.AttributeDefinition;
 
-
 /**
  * The <code>ADTest</code> class tests the static helper methods of the
  * {@link AD} class.
@@ -35,59 +33,54 @@
 
     private static final String BLANK = "     \r\n   \t";
 
-
     public void testNull()
     {
         String listString = null;
-        String[] list = AD.splitList( listString );
-        assertNull( list );
+        String[] list = AD.splitList(listString);
+        assertNull(list);
     }
 
-
     public void testEmpty()
     {
         String listString = "";
-        String[] list = AD.splitList( listString );
-        assertNotNull( list );
-        assertEquals( 1, list.length );
-        assertEquals( listString, list[0] );
+        String[] list = AD.splitList(listString);
+        assertNotNull(list);
+        assertEquals(1, list.length);
+        assertEquals(listString, list[0]);
     }
 
-
     public void testSingle()
     {
         String value0 = "value";
         String listString = value0;
-        String[] list = AD.splitList( listString );
-        assertNotNull( list );
-        assertEquals( 1, list.length );
-        assertEquals( value0, list[0] );
+        String[] list = AD.splitList(listString);
+        assertNotNull(list);
+        assertEquals(1, list.length);
+        assertEquals(value0, list[0]);
     }
 
-
     public void testTwo()
     {
         String value0 = "value0";
         String value1 = "value1";
         String listString = value0 + "," + value1;
-        String[] list = AD.splitList( listString );
-        assertNotNull( list );
-        assertEquals( 2, list.length );
-        assertEquals( value0, list[0] );
-        assertEquals( value1, list[1] );
+        String[] list = AD.splitList(listString);
+        assertNotNull(list);
+        assertEquals(2, list.length);
+        assertEquals(value0, list[0]);
+        assertEquals(value1, list[1]);
     }
 
-
     public void testEmptySecond()
     {
         String value0 = "value0";
         String value1 = "";
         String listString = value0 + ",";
-        String[] list = AD.splitList( listString );
-        assertNotNull( list );
-        assertEquals( 2, list.length );
-        assertEquals( value0, list[0] );
-        assertEquals( value1, list[1] );
+        String[] list = AD.splitList(listString);
+        assertNotNull(list);
+        assertEquals(2, list.length);
+        assertEquals(value0, list[0]);
+        assertEquals(value1, list[1]);
     }
 
     public void testSpacedSecond()
@@ -95,38 +88,35 @@
         String value0 = "value0";
         String value1 = "";
         String listString = value0 + ", ";
-        String[] list = AD.splitList( listString );
-        assertNotNull( list );
-        assertEquals( 2, list.length );
-        assertEquals( value0, list[0] );
-        assertEquals( value1, list[1] );
+        String[] list = AD.splitList(listString);
+        assertNotNull(list);
+        assertEquals(2, list.length);
+        assertEquals(value0, list[0]);
+        assertEquals(value1, list[1]);
     }
 
-
     public void testSingleBlanks()
     {
         String value0 = "value";
         String listString = BLANK + value0 + BLANK;
-        String[] list = AD.splitList( listString );
-        assertNotNull( list );
-        assertEquals( 1, list.length );
-        assertEquals( value0, list[0] );
+        String[] list = AD.splitList(listString);
+        assertNotNull(list);
+        assertEquals(1, list.length);
+        assertEquals(value0, list[0]);
     }
 
-
     public void testTwoBlanks()
     {
         String value0 = "value0";
         String value1 = "value1";
         String listString = BLANK + value0 + BLANK + "," + BLANK + value1 + BLANK;
-        String[] list = AD.splitList( listString );
-        assertNotNull( list );
-        assertEquals( 2, list.length );
-        assertEquals( value0, list[0] );
-        assertEquals( value1, list[1] );
+        String[] list = AD.splitList(listString);
+        assertNotNull(list);
+        assertEquals(2, list.length);
+        assertEquals(value0, list[0]);
+        assertEquals(value1, list[1]);
     }
 
-
     public void testStandardSample()
     {
         String value0 = "a,b";
@@ -134,66 +124,68 @@
         String value2 = " c\\";
         String value3 = "d";
         String listString = "a\\,b,b\\,c,\\ c\\\\,d";
-        String[] list = AD.splitList( listString );
-        assertNotNull( list );
-        assertEquals( 4, list.length );
-        assertEquals( value0, list[0] );
-        assertEquals( value1, list[1] );
-        assertEquals( value2, list[2] );
-        assertEquals( value3, list[3] );
+        String[] list = AD.splitList(listString);
+        assertNotNull(list);
+        assertEquals(4, list.length);
+        assertEquals(value0, list[0]);
+        assertEquals(value1, list[1]);
+        assertEquals(value2, list[2]);
+        assertEquals(value3, list[3]);
     }
 
-
     public void testToTypeString()
     {
-        assertEquals( AttributeDefinition.STRING, AD.toType( "String" ) );
-        assertEquals( AttributeDefinition.LONG, AD.toType( "Long" ) );
-        assertEquals( AttributeDefinition.DOUBLE, AD.toType( "Double" ) );
-        assertEquals( AttributeDefinition.FLOAT, AD.toType( "Float" ) );
-        assertEquals( AttributeDefinition.INTEGER, AD.toType( "Integer" ) );
-        assertEquals( AttributeDefinition.BYTE, AD.toType( "Byte" ) );
-        assertEquals( AttributeDefinition.CHARACTER, AD.toType( "Char" ) );
-        assertEquals( AttributeDefinition.BOOLEAN, AD.toType( "Boolean" ) );
-        assertEquals( AttributeDefinition.SHORT, AD.toType( "Short" ) );
-        assertEquals( AttributeDefinition.PASSWORD, AD.toType( "Password" ) );
-        assertEquals( AttributeDefinition.STRING, AD.toType( "JohnDoe" ) );
+        assertEquals(AttributeDefinition.STRING, AD.toType("String"));
+        assertEquals(AttributeDefinition.LONG, AD.toType("Long"));
+        assertEquals(AttributeDefinition.DOUBLE, AD.toType("Double"));
+        assertEquals(AttributeDefinition.FLOAT, AD.toType("Float"));
+        assertEquals(AttributeDefinition.INTEGER, AD.toType("Integer"));
+        assertEquals(AttributeDefinition.BYTE, AD.toType("Byte"));
+        assertEquals(AttributeDefinition.CHARACTER, AD.toType("Char"));
+        assertEquals(AttributeDefinition.BOOLEAN, AD.toType("Boolean"));
+        assertEquals(AttributeDefinition.SHORT, AD.toType("Short"));
+        assertEquals(AttributeDefinition.PASSWORD, AD.toType("Password"));
+        assertEquals(AttributeDefinition.STRING, AD.toType("JohnDoe"));
     }
-    
+
     /**
      * FELIX-3757: if an AD has only its 'required' property set, but no 
      * min/max or option values defined, the validation still should detect 
      * empty values. 
      */
-    public void testValidateRequiredValueWithMinimalOptions() {
-    	AD ad = new AD();
-    	ad.setType("Integer");
-    	ad.setRequired(true);
+    public void testValidateRequiredValueWithMinimalOptions()
+    {
+        AD ad = new AD();
+        ad.setType("Integer");
+        ad.setRequired(true);
 
-    	assertEquals(AD.VALIDATE_MISSING, ad.validate(null));
+        assertEquals(AD.VALIDATE_MISSING, ad.validate(null));
     }
-    
+
     /**
      * FELIX-3756: if an AD is optional, but its validate method is called
      * with invalid data, the value is regarded missing.
      */
-    public void testValidateOptionalValueWithInvalidData() {
-    	AD ad = new AD();
-    	ad.setType("Integer");
-    	ad.setRequired(false);
-    	
-    	assertEquals(AD.VALIDATE_INVALID_VALUE, ad.validate("abc"));
+    public void testValidateOptionalValueWithInvalidData()
+    {
+        AD ad = new AD();
+        ad.setType("Integer");
+        ad.setRequired(false);
+
+        assertEquals(AD.VALIDATE_INVALID_VALUE, ad.validate("abc"));
     }
-    
+
     /**
      * FELIX-3758: if an AD has a cardinality != 0, the validation method
      * cannot handle a comma-separated input.
      */
-    public void testValidateValueWithMultiValueCardinality() {
-    	AD ad = new AD();
-    	ad.setType("Integer");
-    	ad.setCardinality(2);
-    	ad.setRequired(true);
-    	
-    	assertEquals("", ad.validate("1,2"));
+    public void testValidateValueWithMultiValueCardinality()
+    {
+        AD ad = new AD();
+        ad.setType("Integer");
+        ad.setCardinality(2);
+        ad.setRequired(true);
+
+        assertEquals("", ad.validate("1,2"));
     }
 }
diff --git a/metatype/src/test/java/org/apache/felix/metatype/ADValidatorTest.java b/metatype/src/test/java/org/apache/felix/metatype/ADValidatorTest.java
index 8640629..33c02c3 100644
--- a/metatype/src/test/java/org/apache/felix/metatype/ADValidatorTest.java
+++ b/metatype/src/test/java/org/apache/felix/metatype/ADValidatorTest.java
@@ -30,240 +30,348 @@
  * 
  * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
  */
-public class ADValidatorTest extends TestCase {
+public class ADValidatorTest extends TestCase
+{
+    /**
+     * Tests the validation of boolean is only done minimally.
+     */
+    public void testValidateBoolean()
+    {
+        AD ad = new AD();
+        ad.setType("Boolean");
+        ad.setRequired(false);
 
-	/**
-	 * Tests the validation of boolean is only done minimally.
-	 */
-	public void testValidateBoolean() {
-		AD ad = new AD();
-		ad.setType("Boolean");
-		ad.setRequired(false);
+        // optional value
+        assertEquals("", ADValidator.validate(ad, null));
+        // adhere minimal value
+        assertEquals("", ADValidator.validate(ad, "true"));
+        // adhere maximal value
+        assertEquals("", ADValidator.validate(ad, "false"));
+        // not a valid value
+        assertEquals(AD.VALIDATE_INVALID_VALUE, ADValidator.validate(ad, "foobar"));
 
-		// optional value
-		assertEquals("", ADValidator.validate(ad, null));
-		// adhere minimal value
-		assertEquals("", ADValidator.validate(ad, "true"));
-		// adhere maximal value
-		assertEquals("", ADValidator.validate(ad, "false"));
-		// not a valid value
-		assertEquals(AD.VALIDATE_INVALID_VALUE, ADValidator.validate(ad, "foobar"));
+        ad.setCardinality(3); // up to three values are allowed...
 
-		ad.setCardinality(3); // up to three values are allowed...
-		
-		// mandatory value
-		assertEquals("", ADValidator.validate(ad, null));
-		// 2nd value is missing
-		assertEquals("", ADValidator.validate(ad, "true,,false"));
+        // optional value
+        assertEquals("", ADValidator.validate(ad, null));
+        // 2nd value is missing, but that's ok...
+        assertEquals("", ADValidator.validate(ad, "true,,false"));
 
-		ad.setRequired(true);
+        ad.setRequired(true);
 
-		// mandatory value
-		assertEquals(AD.VALIDATE_MISSING, ADValidator.validate(ad, null));
-		// 2nd value is missing
-		assertEquals(AD.VALIDATE_MISSING, ADValidator.validate(ad, "false,,true"));
-		assertEquals("", ADValidator.validate(ad, "false, true, false"));
+        // mandatory value
+        assertEquals(AD.VALIDATE_MISSING, ADValidator.validate(ad, null));
+        // 2nd value is missing
+        assertEquals(AD.VALIDATE_MISSING, ADValidator.validate(ad, "false,,true"));
+        // correct values
+        assertEquals("", ADValidator.validate(ad, "false, true, false"));
+        // correct values
+        assertEquals(AD.VALIDATE_INVALID_VALUE, ADValidator.validate(ad, "false, yessir, false"));
 
-		ad.setOptions(Collections.singletonMap("true", "Yes!"));
+        ad.setOptions(Collections.singletonMap("true", "Yes!"));
 
-		assertEquals(null, ADValidator.validate(ad, "false, true, false"));
-	}
+        assertEquals(null, ADValidator.validate(ad, "false, true, false"));
+    }
 
-	/**
-	 * Tests the validation of characters with only limited set of options.
-	 */
-	public void testValidateCharacterOptionValues() {
-		AD ad = new AD();
-		ad.setType("Char");
-		ad.setRequired(false);
+    /**
+     * Tests the validation of bytes works and uses the correct minimum and maximum values.
+     */
+    public void testValidateByte()
+    {
+        AD ad = new AD();
+        ad.setType("Byte");
+        ad.setRequired(false);
 
-		// optional value
-		assertEquals("", ADValidator.validate(ad, null));
-		// option too long
-		assertEquals(AD.VALIDATE_GREATER_THAN_MAXIMUM, ADValidator.validate(ad, "ab"));
-		// adhere first option value
-		assertEquals("", ADValidator.validate(ad, "b"));
-		// adhere last option value
-		assertEquals("", ADValidator.validate(ad, "e"));
+        // optional value
+        assertEquals("", ADValidator.validate(ad, null));
+        assertEquals("", ADValidator.validate(ad, ""));
 
-		ad.setCardinality(3); // up to three values are allowed...
+        ad.setRequired(true);
 
-		// mandatory value
-		assertEquals("", ADValidator.validate(ad, ""));
-		// 2nd value is missing
-		assertEquals("", ADValidator.validate(ad, "b,,c"));
+        // mandatory value
+        assertEquals(AD.VALIDATE_MISSING, ADValidator.validate(ad, ""));
+        // value too small
+        assertEquals(AD.VALIDATE_INVALID_VALUE, ADValidator.validate(ad, "-129"));
+        // value too small
+        assertEquals("", ADValidator.validate(ad, "-128"));
+        // value within bounds
+        assertEquals("", ADValidator.validate(ad, "0"));
+        // value within bounds
+        assertEquals("", ADValidator.validate(ad, "127"));
+        // value is invalid
+        assertEquals(AD.VALIDATE_INVALID_VALUE, ADValidator.validate(ad, "128"));
 
-		ad.setRequired(true);
+        ad.setMin("0");
+        ad.setMax("128"); // !!! this is an invalid value for maximum, this means that we cannot do this validation...
 
-		// mandatory value
-		assertEquals(AD.VALIDATE_MISSING, ADValidator.validate(ad, null));
-		// 2nd value is missing
-		assertEquals(AD.VALIDATE_MISSING, ADValidator.validate(ad, "b,,c"));
-		// adhere minimal values
-		assertEquals("", ADValidator.validate(ad, "b, c, d"));
-		// adhere maximal values
-		assertEquals("", ADValidator.validate(ad, "c, d, e"));
+        // value too small
+        assertEquals(AD.VALIDATE_LESS_THAN_MINIMUM, ADValidator.validate(ad, "-1"));
+        // value within bounds
+        assertEquals("", ADValidator.validate(ad, "0"));
+        // value within bounds
+        assertEquals("", ADValidator.validate(ad, "127"));
+        // value is invalid
+        assertEquals(AD.VALIDATE_INVALID_VALUE, ADValidator.validate(ad, "128"));
+    }
 
-		Map options = new HashMap();
-		options.put("b", "B");
-		options.put("c", "C");
-		options.put("d", "D");
-		options.put("e", "E");
+    /**
+     * Tests the validation of characters with only limited set of options.
+     */
+    public void testValidateCharacter()
+    {
+        AD ad = new AD();
+        ad.setType("Char");
+        ad.setRequired(false);
 
-		ad.setOptions(options);
-		// no option given
-		assertEquals(AD.VALIDATE_MISSING, ADValidator.validate(ad, ""));
-		// invalid option
-		assertEquals(AD.VALIDATE_NOT_A_VALID_OPTION, ADValidator.validate(ad, "a"));
-		// too great
-		assertEquals(AD.VALIDATE_NOT_A_VALID_OPTION, ADValidator.validate(ad, "f"));
-		// 2nd value is too less
-		assertEquals(AD.VALIDATE_NOT_A_VALID_OPTION, ADValidator.validate(ad, "b,a,c"));
-		// 3rd value is too great
-		assertEquals(AD.VALIDATE_NOT_A_VALID_OPTION, ADValidator.validate(ad, "d, e, f"));
+        // optional value
+        assertEquals("", ADValidator.validate(ad, null));
+        // option too long
+        assertEquals(AD.VALIDATE_GREATER_THAN_MAXIMUM, ADValidator.validate(ad, "ab"));
+        // adhere first option value
+        assertEquals("", ADValidator.validate(ad, "b"));
+        // adhere last option value
+        assertEquals("", ADValidator.validate(ad, "e"));
 
-		ad.setMin("b");
-		ad.setMax("c");
-		ad.setOptions(Collections.emptyMap());
+        ad.setCardinality(3); // up to three values are allowed...
 
-		// adhere minimal values
-		assertEquals("", ADValidator.validate(ad, "b, c, b"));
-		// d is too great
-		assertEquals(AD.VALIDATE_GREATER_THAN_MAXIMUM, ADValidator.validate(ad, "b, c, d"));
-		// a is too less
-		assertEquals(AD.VALIDATE_LESS_THAN_MINIMUM, ADValidator.validate(ad, "a, b, c"));
-	}
+        // mandatory value
+        assertEquals("", ADValidator.validate(ad, ""));
+        // 2nd value is missing
+        assertEquals("", ADValidator.validate(ad, "b,,c"));
 
-	/**
-	 * Tests the validation of characters with only limited set of options.
-	 */
-	public void testValidateDoubleOptionValues() {
-		Map options = new HashMap();
-		options.put("1.1", "B");
-		options.put("2.2", "C");
-		options.put("3.3", "D");
-		options.put("4.4", "E");
+        ad.setRequired(true);
 
-		AD ad = new AD();
-		ad.setType("Double");
-		ad.setOptions(options);
-		ad.setRequired(false);
+        // mandatory value
+        assertEquals(AD.VALIDATE_MISSING, ADValidator.validate(ad, null));
+        // 2nd value is missing
+        assertEquals(AD.VALIDATE_MISSING, ADValidator.validate(ad, "b,,c"));
+        // adhere minimal values
+        assertEquals("", ADValidator.validate(ad, "b, c, d"));
+        // adhere maximal values
+        assertEquals("", ADValidator.validate(ad, "c, d, e"));
 
-		// optional value
-		assertEquals("", ADValidator.validate(ad, null));
-		// invalid option
-		assertEquals(AD.VALIDATE_NOT_A_VALID_OPTION, ADValidator.validate(ad, "1.0"));
-		// adhere first option value
-		assertEquals("", ADValidator.validate(ad, "1.1"));
-		// adhere last option value
-		assertEquals("", ADValidator.validate(ad, "4.4"));
-		// too great
-		assertEquals(AD.VALIDATE_NOT_A_VALID_OPTION, ADValidator.validate(ad, "4.5"));
+        Map options = new HashMap();
+        options.put("b", "B");
+        options.put("c", "C");
+        options.put("d", "D");
+        options.put("e", "E");
 
-		ad.setCardinality(3); // up to three values are allowed...
-		ad.setRequired(true);
+        ad.setOptions(options);
+        // no option given
+        assertEquals(AD.VALIDATE_MISSING, ADValidator.validate(ad, ""));
+        // invalid option
+        assertEquals(AD.VALIDATE_NOT_A_VALID_OPTION, ADValidator.validate(ad, "a"));
+        // too great
+        assertEquals(AD.VALIDATE_NOT_A_VALID_OPTION, ADValidator.validate(ad, "f"));
+        // 2nd value is too less
+        assertEquals(AD.VALIDATE_NOT_A_VALID_OPTION, ADValidator.validate(ad, "b,a,c"));
+        // 3rd value is too great
+        assertEquals(AD.VALIDATE_NOT_A_VALID_OPTION, ADValidator.validate(ad, "d, e, f"));
 
-		// mandatory value
-		assertEquals(AD.VALIDATE_MISSING, ADValidator.validate(ad, null));
-		// 2nd value is too less
-		assertEquals(AD.VALIDATE_NOT_A_VALID_OPTION, ADValidator.validate(ad, "1.1,1.0,2.2"));
-		// adhere minimal values
-		assertEquals("", ADValidator.validate(ad, "1.1, 2.2, 3.3"));
-		// adhere maximal values
-		assertEquals("", ADValidator.validate(ad, "2.2, 3.3, 4.4"));
-		// 3rd value is too great
-		assertEquals(AD.VALIDATE_NOT_A_VALID_OPTION, ADValidator.validate(ad, "3.3, 4.4, 5.5"));
-	}
+        ad.setMin("b");
+        ad.setMax("c");
+        ad.setOptions(Collections.emptyMap());
 
-	/**
-	 * Tests the validation of integers is based on the minimum and maximum values.
-	 */
-	public void testValidateInteger() {
-		AD ad = new AD();
-		ad.setType("Integer");
-		ad.setMin("3"); // only values greater than 2
-		ad.setMax("6"); // only values less than 7
-		ad.setRequired(false);
+        // adhere minimal values
+        assertEquals("", ADValidator.validate(ad, "b, c, b"));
+        // d is too great
+        assertEquals(AD.VALIDATE_GREATER_THAN_MAXIMUM, ADValidator.validate(ad, "b, c, d"));
+        // a is too small
+        assertEquals(AD.VALIDATE_LESS_THAN_MINIMUM, ADValidator.validate(ad, "a, b, c"));
+    }
 
-		// optional value
-		assertEquals("", ADValidator.validate(ad, null));
-		// too less
-		assertEquals(AD.VALIDATE_LESS_THAN_MINIMUM, ADValidator.validate(ad, "2"));
-		// adhere minimal value
-		assertEquals("", ADValidator.validate(ad, "3"));
-		// adhere maximal value
-		assertEquals("", ADValidator.validate(ad, "6"));
-		// too great
-		assertEquals(AD.VALIDATE_GREATER_THAN_MAXIMUM, ADValidator.validate(ad, "7"));
+    /**
+     * Tests the validation of double value works as expected.
+     */
+    public void testValidateDouble()
+    {
+        AD ad = new AD();
+        ad.setType("Double");
+        ad.setRequired(false);
 
-		ad.setCardinality(3); // up to three values are allowed...
-		
-		// mandatory value
-		assertEquals("", ADValidator.validate(ad, null));
-		// 2nd value is missing
-		assertEquals("", ADValidator.validate(ad, "3,,3"));
+        ad.setMin("-123.45");
+        ad.setMax("+123.45");
 
-		ad.setRequired(true);
+        // Value is too small...
+        assertEquals(AD.VALIDATE_LESS_THAN_MINIMUM, ADValidator.validate(ad, "-123.4501"));
+        // Value is within range...
+        assertEquals("", ADValidator.validate(ad, "-123.45000"));
+        // Value is within range...
+        assertEquals("", ADValidator.validate(ad, "123.45000"));
+        // Value is too great...
+        assertEquals(AD.VALIDATE_GREATER_THAN_MAXIMUM, ADValidator.validate(ad, "123.4501"));
 
-		// mandatory value
-		assertEquals(AD.VALIDATE_MISSING, ADValidator.validate(ad, null));
-		// 2nd value is missing
-		assertEquals(AD.VALIDATE_MISSING, ADValidator.validate(ad, "3,,3"));
-		// 2nd value is invalid
-		assertEquals(AD.VALIDATE_INVALID_VALUE, ADValidator.validate(ad, "3,a,3"));
-		// 2nd value is too less
-		assertEquals(AD.VALIDATE_LESS_THAN_MINIMUM, ADValidator.validate(ad, "3,2,3"));
-		// adhere minimal values
-		assertEquals("", ADValidator.validate(ad, "3, 4, 5"));
-		// adhere maximal values
-		assertEquals("", ADValidator.validate(ad, "6, 5, 4"));
-		// 3rd value is too great
-		assertEquals(AD.VALIDATE_GREATER_THAN_MAXIMUM, ADValidator.validate(ad, "5, 6, 7"));
-	}
+        Map options = new HashMap();
+        options.put("1.1", "B");
+        options.put("2.2", "C");
+        options.put("3.3", "D");
+        options.put("4.4", "E");
 
-	/**
-	 * Tests the validation of strings is based on the minimum and maximum lengths.
-	 */
-	public void testValidateString() {
-		AD ad = new AD();
-		ad.setType("String");
-		ad.setRequired(false);
+        ad.setOptions(options);
 
-		// optional value
-		assertEquals("", ADValidator.validate(ad, null));
-		// any length of input is accepted
-		assertEquals("", ADValidator.validate(ad, "1234567890"));
+        // optional value
+        assertEquals("", ADValidator.validate(ad, null));
+        // invalid option
+        assertEquals(AD.VALIDATE_NOT_A_VALID_OPTION, ADValidator.validate(ad, "1.0"));
+        // adhere first option value
+        assertEquals("", ADValidator.validate(ad, "1.1"));
+        // adhere last option value
+        assertEquals("", ADValidator.validate(ad, "4.4"));
+        // too great
+        assertEquals(AD.VALIDATE_NOT_A_VALID_OPTION, ADValidator.validate(ad, "4.5"));
 
-		ad.setMin("3"); // minimal length == 3
-		ad.setMax("6"); // maximum length == 6
+        ad.setCardinality(3); // up to three values are allowed...
+        ad.setRequired(true);
 
-		// too short
-		assertEquals(AD.VALIDATE_LESS_THAN_MINIMUM, ADValidator.validate(ad, "12"));
-		// adhere minimum length
-		assertEquals("", ADValidator.validate(ad, "123"));
-		// adhere maximum length
-		assertEquals("", ADValidator.validate(ad, "12356"));
-		// too long
-		assertEquals(AD.VALIDATE_GREATER_THAN_MAXIMUM, ADValidator.validate(ad, "1234567"));
+        // mandatory value
+        assertEquals(AD.VALIDATE_MISSING, ADValidator.validate(ad, null));
+        // 2nd value is too less
+        assertEquals(AD.VALIDATE_NOT_A_VALID_OPTION, ADValidator.validate(ad, "1.1,1.0,2.2"));
+        // adhere minimal values
+        assertEquals("", ADValidator.validate(ad, "1.1, 2.2, 3.3"));
+        // adhere maximal values
+        assertEquals("", ADValidator.validate(ad, "2.2, 3.3, 4.4"));
+        // 3rd value is too great
+        assertEquals(AD.VALIDATE_NOT_A_VALID_OPTION, ADValidator.validate(ad, "3.3, 4.4, 5.5"));
+    }
 
-		ad.setCardinality(3); // up to three values are allowed...
-		ad.setRequired(true);
+    /**
+     * Tests the validation of integers is based on the minimum and maximum values.
+     */
+    public void testValidateInteger()
+    {
+        AD ad = new AD();
+        ad.setType("Integer");
+        ad.setMin("3"); // only values greater than 2
+        ad.setMax("6"); // only values less than 7
+        ad.setRequired(false);
 
-		// mandatory value
-		assertEquals(AD.VALIDATE_MISSING, ADValidator.validate(ad, null));
-		// 2nd value is too short
-		assertEquals(AD.VALIDATE_LESS_THAN_MINIMUM, ADValidator.validate(ad, "321,12,123"));
-		// adhere minimum lengths
-		assertEquals("", ADValidator.validate(ad, "123, 123, 123"));
-		// adhere maximum lengths
-		assertEquals("", ADValidator.validate(ad, "12356, 654321, 123456"));
-		// 3rd value is too long
-		assertEquals(AD.VALIDATE_GREATER_THAN_MAXIMUM, ADValidator.validate(ad, "123, 123, 1234567"));
-		
-		ad.setOptions(Collections.singletonMap("123", "foo"));
+        // optional value
+        assertEquals("", ADValidator.validate(ad, null));
+        assertEquals("", ADValidator.validate(ad, ""));
+        // too less
+        assertEquals(AD.VALIDATE_LESS_THAN_MINIMUM, ADValidator.validate(ad, "2"));
+        // adhere minimal value
+        assertEquals("", ADValidator.validate(ad, "3"));
+        // adhere maximal value
+        assertEquals("", ADValidator.validate(ad, "6"));
+        // too great
+        assertEquals(AD.VALIDATE_GREATER_THAN_MAXIMUM, ADValidator.validate(ad, "7"));
 
-		// adhere minimum lengths
-		assertEquals("", ADValidator.validate(ad, "123, 123, 123"));
-		assertEquals(AD.VALIDATE_NOT_A_VALID_OPTION, ADValidator.validate(ad, "2134"));
-	}
+        ad.setCardinality(3); // up to three values are allowed...
+
+        // mandatory value
+        assertEquals("", ADValidator.validate(ad, null));
+        // 2nd value is missing
+        assertEquals("", ADValidator.validate(ad, "3,,3"));
+
+        ad.setRequired(true);
+
+        // mandatory value
+        assertEquals(AD.VALIDATE_MISSING, ADValidator.validate(ad, null));
+        // 2nd value is missing
+        assertEquals(AD.VALIDATE_MISSING, ADValidator.validate(ad, "3,,3"));
+        // 2nd value is invalid
+        assertEquals(AD.VALIDATE_INVALID_VALUE, ADValidator.validate(ad, "3,a,3"));
+        // 2nd value is too less
+        assertEquals(AD.VALIDATE_LESS_THAN_MINIMUM, ADValidator.validate(ad, "3,2,3"));
+        // adhere minimal values
+        assertEquals("", ADValidator.validate(ad, "3, 4, 5"));
+        // adhere maximal values
+        assertEquals("", ADValidator.validate(ad, "6, 5, 4"));
+        // 3rd value is too great
+        assertEquals(AD.VALIDATE_GREATER_THAN_MAXIMUM, ADValidator.validate(ad, "5, 6, 7"));
+    }
+
+    /**
+     * Tests the validation of long values works as expected.
+     */
+    public void testValidateLong()
+    {
+        AD ad = new AD();
+        ad.setType("Long");
+        ad.setRequired(true);
+
+        ad.setMin("-20");
+        ad.setMax("-15");
+
+        // value too small
+        assertEquals(AD.VALIDATE_LESS_THAN_MINIMUM, ADValidator.validate(ad, "-21"));
+        // value within bounds
+        assertEquals("", ADValidator.validate(ad, "-15"));
+        // value within bounds
+        assertEquals("", ADValidator.validate(ad, "-20"));
+        // value too great
+        assertEquals(AD.VALIDATE_GREATER_THAN_MAXIMUM, ADValidator.validate(ad, "-14"));
+
+        // Set minimum and maximum beyond the range of plain integers...
+        ad.setMin("2147483650");
+        ad.setMax("2147483655");
+
+        // value too small
+        assertEquals(AD.VALIDATE_LESS_THAN_MINIMUM, ADValidator.validate(ad, "2147483649"));
+        // value within bounds
+        assertEquals("", ADValidator.validate(ad, "2147483650"));
+        // value within bounds
+        assertEquals("", ADValidator.validate(ad, "2147483655"));
+        // value too great
+        assertEquals(AD.VALIDATE_GREATER_THAN_MAXIMUM, ADValidator.validate(ad, "2147483656"));
+    }
+
+    /**
+     * Tests the validation of strings is based on the minimum and maximum lengths.
+     */
+    public void testValidateString()
+    {
+        AD ad = new AD();
+        ad.setType("String");
+        ad.setRequired(false);
+
+        // optional value
+        assertEquals("", ADValidator.validate(ad, null));
+        // any length of input is accepted
+        assertEquals("", ADValidator.validate(ad, "1234567890"));
+
+        ad.setMin("3"); // minimal length == 3
+        ad.setMax("6"); // maximum length == 6
+
+        // too short
+        assertEquals(AD.VALIDATE_LESS_THAN_MINIMUM, ADValidator.validate(ad, "12"));
+        // adhere minimum length
+        assertEquals("", ADValidator.validate(ad, "123"));
+        // adhere maximum length
+        assertEquals("", ADValidator.validate(ad, "12356"));
+        // too long
+        assertEquals(AD.VALIDATE_GREATER_THAN_MAXIMUM, ADValidator.validate(ad, "1234567"));
+
+        ad.setCardinality(3); // up to three values are allowed...
+        ad.setMin("");
+
+        // optional value
+        assertEquals("", ADValidator.validate(ad, null));
+        // 2nd value is missing; but that's ok
+        assertEquals("", ADValidator.validate(ad, "321, , 123"));
+
+        ad.setRequired(true);
+        ad.setMin("3");
+
+        // mandatory value
+        assertEquals(AD.VALIDATE_MISSING, ADValidator.validate(ad, null));
+        // 2nd value is missing
+        assertEquals(AD.VALIDATE_MISSING, ADValidator.validate(ad, "321, , 123"));
+        // 2nd value is too short
+        assertEquals(AD.VALIDATE_LESS_THAN_MINIMUM, ADValidator.validate(ad, "321,12,123"));
+        // adhere minimum lengths
+        assertEquals("", ADValidator.validate(ad, "123, 123, 123"));
+        // adhere maximum lengths
+        assertEquals("", ADValidator.validate(ad, "12356, 654321, 123456"));
+        // 3rd value is too long
+        assertEquals(AD.VALIDATE_GREATER_THAN_MAXIMUM, ADValidator.validate(ad, "123, 123, 1234567"));
+
+        ad.setOptions(Collections.singletonMap("123", "foo"));
+
+        // adhere minimum lengths
+        assertEquals("", ADValidator.validate(ad, "123, 123, 123"));
+        assertEquals(AD.VALIDATE_NOT_A_VALID_OPTION, ADValidator.validate(ad, "2134"));
+    }
 }