Applied patch (FELIX-254) to add support for property values in 
<property> element body.


git-svn-id: https://svn.apache.org/repos/asf/incubator/felix/trunk@519016 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/scr/src/main/java/org/apache/felix/scr/PropertyMetadata.java b/scr/src/main/java/org/apache/felix/scr/PropertyMetadata.java
index e67021b..66e4f44 100644
--- a/scr/src/main/java/org/apache/felix/scr/PropertyMetadata.java
+++ b/scr/src/main/java/org/apache/felix/scr/PropertyMetadata.java
@@ -18,6 +18,10 @@
  */
 package org.apache.felix.scr;
 
+import java.util.ArrayList;
+import java.util.List;
+import java.util.StringTokenizer;
+
 import org.osgi.service.component.ComponentException;
 
 /**
@@ -75,40 +79,91 @@
 			return;
 		}
 		
-		// 112.4.5 Parsing of the value is done by the valueOf(String) method (P. 291)
-		// Should the type accept lowercase too?
-		if(m_type.equals("String")) {
-			m_value = String.valueOf(value);
-        }
-		else if(m_type.equals("Long")) {
-			m_value = Long.valueOf(value);
-        }
-		else if(m_type.equals("Double")) {
-			m_value = Double.valueOf(value);
-        }
-		else if(m_type.equals("Float")) {
-			m_value = Float.valueOf(value);
-        }
-		else if(m_type.equals("Integer")) {
-			m_value = Integer.valueOf(value);
-        }
-		else if(m_type.equals("Byte")) {
-			m_value = Byte.valueOf(value);
-        }
-		else if(m_type.equals("Char")) {
-			//TODO: verify if this is adequate for Characters
-			m_value = Byte.valueOf(value);
-        }
-		else if(m_type.equals("Boolean")) {
-			m_value = Boolean.valueOf(value);
-        }
-		else if(m_type.equals("Short")) {
-			m_value = Short.valueOf(value);
-        }
-		else {
-			throw new IllegalArgumentException("Undefined property type '"+m_type+"'");
-		}
+        m_value = toType( value );
 	}
+    
+    /**
+     * Set multiple values as an array, where the values are contained in
+     * the string as one value per line.
+     * 
+     * @param values
+     */
+    public void setValues(String values) {
+        // splite the values and convert to boxed objects
+        List valueList = new ArrayList();
+        StringTokenizer tokener = new StringTokenizer(values, "\r\n");
+        while (tokener.hasMoreTokens()) {
+            String value = tokener.nextToken().trim();
+            if (value.length() > 0) {
+                valueList.add(toType( value ));
+            }
+        }
+        
+        // 112.4.5 Except for String objects, the result will be translated to an array of primitive types.
+        if(m_type.equals("String")) {
+            m_value = valueList.toArray( new String[valueList.size()] );
+        }
+        else if(m_type.equals("Long")) {
+            long[] array = new long[valueList.size()];
+            for (int i=0; i < array.length; i++) {
+                array[i] = ((Long) valueList.get(i)).longValue();
+            }
+            m_value = array;
+        }
+        else if(m_type.equals("Double")) {
+            double[] array = new double[valueList.size()];
+            for (int i=0; i < array.length; i++) {
+                array[i] = ((Double) valueList.get(i)).doubleValue();
+            }
+            m_value = array;
+        }
+        else if(m_type.equals("Float")) {
+            float[] array = new float[valueList.size()];
+            for (int i=0; i < array.length; i++) {
+                array[i] = ((Float) valueList.get(i)).floatValue();
+            }
+            m_value = array;
+        }
+        else if(m_type.equals("Integer")) {
+            int[] array = new int[valueList.size()];
+            for (int i=0; i < array.length; i++) {
+                array[i] = ((Integer) valueList.get(i)).intValue();
+            }
+            m_value = array;
+        }
+        else if(m_type.equals("Byte")) {
+            byte[] array = new byte[valueList.size()];
+            for (int i=0; i < array.length; i++) {
+                array[i] = ((Byte) valueList.get(i)).byteValue();
+            }
+            m_value = array;
+        }
+        else if(m_type.equals("Char")) {
+            //TODO: verify if this is adequate for Characters
+            char[] array = new char[valueList.size()];
+            for (int i=0; i < array.length; i++) {
+                array[i] = ((Character) valueList.get(i)).charValue();
+            }
+            m_value = array;
+        }
+        else if(m_type.equals("Boolean")) {
+            boolean[] array = new boolean[valueList.size()];
+            for (int i=0; i < array.length; i++) {
+                array[i] = ((Boolean) valueList.get(i)).booleanValue();
+            }
+            m_value = array;
+        }
+        else if(m_type.equals("Short")) {
+            short[] array = new short[valueList.size()];
+            for (int i=0; i < array.length; i++) {
+                array[i] = ((Short) valueList.get(i)).shortValue();
+            }
+            m_value = array;
+        }
+        else {
+            throw new IllegalArgumentException("Undefined property type '"+m_type+"'");
+        }
+    }
 
     /**
      * Get the name of the property
@@ -146,4 +201,40 @@
     		throw new ComponentException("Property name attribute is mandatory");
     	}
     }
+    
+    private Object toType(String value) {
+        // 112.4.5 Parsing of the value is done by the valueOf(String) method (P. 291)
+        // Should the type accept lowercase too?
+        if(m_type.equals("String")) {
+            return String.valueOf(value);
+        }
+        else if(m_type.equals("Long")) {
+            return Long.valueOf(value);
+        }
+        else if(m_type.equals("Double")) {
+            return Double.valueOf(value);
+        }
+        else if(m_type.equals("Float")) {
+            return Float.valueOf(value);
+        }
+        else if(m_type.equals("Integer")) {
+            return Integer.valueOf(value);
+        }
+        else if(m_type.equals("Byte")) {
+            return Byte.valueOf(value);
+        }
+        else if(m_type.equals("Char")) {
+            char c = ( value.length() > 0 ) ? value.charAt( 0 ) : 0;
+            return new Character( c );
+        }
+        else if(m_type.equals("Boolean")) {
+            return Boolean.valueOf(value);
+        }
+        else if(m_type.equals("Short")) {
+            return Short.valueOf(value);
+        }
+        else {
+            throw new IllegalArgumentException("Undefined property type '"+m_type+"'");
+        }
+    }
 }
diff --git a/scr/src/main/java/org/apache/felix/scr/XmlHandler.java b/scr/src/main/java/org/apache/felix/scr/XmlHandler.java
index b2e674a..a9b43e7 100644
--- a/scr/src/main/java/org/apache/felix/scr/XmlHandler.java
+++ b/scr/src/main/java/org/apache/felix/scr/XmlHandler.java
@@ -40,6 +40,9 @@
     // A list of component descriptors contained in the file
     private List m_components = new ArrayList();
 
+    // PropertyMetaData whose value attribute is missing, hence has element data
+    private PropertyMetadata m_pendingProperty;
+    
     /**
      * Method called when a tag opens
      *
@@ -89,26 +92,24 @@
 	        }
 	        // 112.4.5 Properties and Property Elements
 	        else if (qName.equals("property")) {
-	        	// 112.4.5: If the value attribute is specified, the body of the element is ignored.
+                PropertyMetadata prop = new PropertyMetadata();
+                
+                // name attribute is mandatory
+                prop.setName(attrib.getProperty("name"));
+                
+                // type attribute is optional
+                if(attrib.getProperty("type") != null) {
+                    prop.setType(attrib.getProperty("type"));
+                }
+
+                // 112.4.5: If the value attribute is specified, the body of the element is ignored.
 	        	if( attrib.getProperty("value") != null) {
-	        		PropertyMetadata prop = new PropertyMetadata();
-	        		
-	        		// name attribute is mandatory
-	        		prop.setName(attrib.getProperty("name"));
-	        		
-	        		// type attribute is optional
-	        		if(attrib.getProperty("type") != null) {
-	        			prop.setType(attrib.getProperty("type"));
-	        		}
-	        		
-	        		// value attribute is optional
-	        		if(attrib.getProperty("value") != null) {
-	        			prop.setValue(attrib.getProperty("value"));
-	        		}
+        			prop.setValue(attrib.getProperty("value"));
 	            	m_currentComponent.addProperty(prop);
 	        	}
 	        	else {
-	        		// TODO: treat the case where property value is not specified (p. 291)
+	        		// hold the metadata pending
+                    m_pendingProperty = prop;
 	        	}
 	        	// TODO: treat the case where a properties file name is provided (p. 292)
 	        }
@@ -175,6 +176,11 @@
         	// When the closing tag for a component is found, the component is validated to check if 
         	// the implementation class has been set
         	m_currentComponent.validate();
+        } else if (qName.equals("property") && m_pendingProperty != null) {
+            // 112.4.5 body expected to contain property value
+            // if so, the m_pendingProperty field would be null
+            // currently, we just ignore this situation
+            m_pendingProperty = null;
         }
     }
 
@@ -188,10 +194,16 @@
         return m_components;
     }
 
-	public void characters(char[] ch, int offset, int length) throws Exception {
-		// Not used
-		
-	}
+	public void characters( char[] ch, int offset, int length ) throws Exception
+    {
+        // 112.4.5 If the value attribute is not specified, the body must contain one or more values
+        if ( m_pendingProperty != null )
+        {
+            m_pendingProperty.setValues( new String( ch, offset, length ) );
+            m_currentComponent.addProperty( m_pendingProperty );
+            m_pendingProperty = null;
+        }
+    }
 
 	public void processingInstruction(String target, String data) throws Exception {
 		// Not used