Fix the issue Felix-629
Allows an instance configuration to contain complex types.
Now an instance configuration can contain properties like : 
	<instance component="org.apache.felix.ipojo.test.scenarios.component.ComplexConfiguration" name="complex">
		<property name="array" type="array"> <!-- creates an array -->
			<property value="a"/>
			<property value="b"/>
		</property>

		<property name="list" type="list"> <!-- creates a list -->
			<property value="a"/>
			<property value="b"/>
		</property>

		<property name="dict" type="dictionary"> <!-- creates a dictionary (default case) -->
			<property name="a" value="a"/>
			<property name="b" value="b"/>
		</property>
		
		<property name="map" type="map"> <!-- creates a map -->
			<property name="a" value="a"/>
			<property name="b" value="b"/>
		</property>

		<property name="complex-array" type="array"> <!-- creates an array containing lists -->
			<property type="list">
				<property value="a"/>
				<property value="b"/>
			</property>
			<property type="list">
				<property value="c"/>
				<property value="d"/>
			</property>
		</property>

		<property name="complex-list" type="list"> <!-- creates a list containing lists -->
			<property type="list">
				<property value="a"/>
				<property value="b"/>
			</property>
			<property type="list">
				<property value="c"/>
				<property value="d"/>
			</property>
		</property>

		<property name="complex-map" type="map"> <!-- creates a map containing lists -->
			<property name="a" type="list">
				<property value="a"/>
				<property value="b"/>
			</property>
			<property name="b" type="list">
				<property value="c"/>
				<property value="d"/>
			</property>
		</property>
	</instance>
	
As illustrated, any complex type can contain any complex type (and obviously itself). When no sub-property is declared, an empty structure is returned. 

The patch contains also code allowing to use [...] to describe an array instead of {...}. So it is possible to write something like : <property name="foo" type="String[]" value="[a, b, c]"/>. This is equivalent to the existing syntax : <property name="foo" type="String[]" value="{a, b, c}"/>

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@675569 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/ipojo/core/src/main/java/org/apache/felix/ipojo/parser/ManifestMetadataParser.java b/ipojo/core/src/main/java/org/apache/felix/ipojo/parser/ManifestMetadataParser.java
index e98fff2..81633de 100644
--- a/ipojo/core/src/main/java/org/apache/felix/ipojo/parser/ManifestMetadataParser.java
+++ b/ipojo/core/src/main/java/org/apache/felix/ipojo/parser/ManifestMetadataParser.java
@@ -20,7 +20,9 @@
 
 import java.util.ArrayList;
 import java.util.Dictionary;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.Properties;
 
 import org.apache.felix.ipojo.metadata.Attribute;
@@ -111,27 +113,192 @@
         String name = prop.getAttribute("name");
         String value = prop.getAttribute("value");
         if (name == null) {
-            throw new ParseException("A property does not have the 'name' attribute");
+            throw new ParseException("A property does not have the 'name' attribute: " + prop);
         }
-        //case : the property element has a 'value' attribute
+        //case : the property element has no 'value' attribute
         if (value == null) {
             // Recursive case
-            // Check if there is 'property' element
-            Element[] subProps = prop.getElements("property");
-            if (subProps != null) {
-                Dictionary dict2 = new Properties();
-                for (int i = 0; i < subProps.length; i++) {
-                    parseProperty(subProps[i], dict2);
-                    dict.put(name, dict2);
+            // Get the type of the structure to create
+            String type = prop.getAttribute("type");
+            if (type == null || type.equalsIgnoreCase("dictionary")) {
+                    dict.put(name, parseDictionary(prop));
+            } else if (type.equalsIgnoreCase("map")) {
+                    dict.put(name, parseMap(prop));
+            }  else if (type.equalsIgnoreCase("list")) {
+                    dict.put(name, parseList(prop));
+            } else if (type.equalsIgnoreCase("array")) {
+                List list = parseList(prop);
+                boolean isString = true;
+                for (int i = 0; isString && i < list.size(); i++) {
+                    isString = list.get(i) instanceof String;                                              
                 }
-            } else {
-                // If the no sub-properties, inject an empty dictionary.
-                dict.put(name, new Properties());
+                Object[] obj = null; 
+                if (isString) {
+                    obj = new String[list.size()];    
+                } else {
+                    obj = new Object[list.size()];
+                }
+                dict.put(name, list.toArray(obj)); // Transform the list to array
             }
         } else {
             dict.put(prop.getAttribute("name"), prop.getAttribute("value"));
         }
     }
+    
+    private Dictionary parseDictionary(Element prop) throws ParseException {
+     // Check if there is 'property' elements
+        Element[] subProps = prop.getElements("property");
+        if (subProps != null) {
+            Dictionary dict2 = new Properties();
+            for (int i = 0; i < subProps.length; i++) {
+                parseProperty(subProps[i], dict2);
+            }
+            return dict2;
+        } else {
+            // If the no sub-properties, inject an empty dictionary.
+            return new Properties();
+        }
+    }
+    
+    private Map parseMap(Element prop) throws ParseException {
+        // Check if there is 'property' elements
+        Element[] subProps = prop.getElements("property");
+        if (subProps != null) {
+            Map map = new HashMap(); // Create an hashmap to store elements.
+            for (int i = 0; i < subProps.length; i++) {
+                parseProperty(subProps[i], map);
+            }
+            return map;
+        } else { // if not inject an empty map
+            return new HashMap(0);
+        }
+    }
+    
+    private List parseList(Element prop) throws ParseException {
+        Element[] subProps = prop.getElements("property");
+        if (subProps != null) {
+            List list = new ArrayList(subProps.length); // Create a list to store elements.
+            for (int i = 0; i < subProps.length; i++) {
+                parseAnonymousProperty(subProps[i], list); // Anonymous properties.
+            }
+            return list;
+        } else {
+            // If no sub-properties, inject an empty list.
+            return new ArrayList(0);
+        }
+    }
+    
+    /**
+     * Parse a property.
+     * @param prop : the current element to parse
+     * @param map : the map to populate
+     * @throws ParseException : occurs if the property cannot be parsed correctly
+     */
+    private void parseProperty(Element prop, Map map) throws ParseException {
+        // Check that the property has a name
+        String name = prop.getAttribute("name");
+        String value = prop.getAttribute("value");
+        if (name == null) {
+            throw new ParseException("A property does not have the 'name' attribute");
+        }
+        //case : the property element has no 'value' attribute
+        if (value == null) {
+            // Recursive case
+            // Get the type of the structure to create
+            String type = prop.getAttribute("type");
+            if (type == null || type.equalsIgnoreCase("dictionary")) {
+                    map.put(name, parseDictionary(prop));
+            } else if (type.equalsIgnoreCase("map")) {
+                    map.put(name, parseMap(prop));
+            }  else if (type.equalsIgnoreCase("list")) {
+                    map.put(name, parseList(prop));
+            } else if (type.equalsIgnoreCase("array")) {
+                    List list = parseList(prop);
+                    boolean isString = true;
+                    for (int i = 0; isString && i < list.size(); i++) {
+                        isString = list.get(i) instanceof String;                                              
+                    }
+                    Object[] obj = null; 
+                    if (isString) {
+                        obj = new String[list.size()];    
+                    } else {
+                        obj = new Object[list.size()];
+                    }
+                    map.put(name, list.toArray(obj)); // Transform the list to array
+            }
+        } else {
+            map.put(prop.getAttribute("name"), prop.getAttribute("value"));
+        }
+    }
+
+    private void parseAnonymousProperty(Element prop, List list) throws ParseException {
+        // Check that the property has a name
+        String name = prop.getAttribute("name");
+        String value = prop.getAttribute("value");
+        if (name != null) {
+            throw new ParseException("Anonymous property expected in a list or in an array");
+        }
+        //case : the property element has no 'value' attribute
+        if (value == null) {
+            // Recursive case
+            
+            // Get the type of the structure to create
+            String type = prop.getAttribute("type");
+            if (type == null || type.equalsIgnoreCase("dictionary")) {
+                // Check if there is 'property' elements
+                Element[] subProps = prop.getElements("property");
+                if (subProps != null) {
+                    Dictionary dict2 = new Properties();
+                    for (int i = 0; i < subProps.length; i++) {
+                        parseProperty(subProps[i], dict2);
+                    }
+                    list.add(dict2);
+                } else {
+                    // If the no sub-properties, inject an empty dictionary.
+                    list.add(new Properties());
+                }
+            } else if (type.equalsIgnoreCase("map")) {
+                // Check if there is 'property' elements
+                Element[] subProps = prop.getElements("property");
+                if (subProps != null) {
+                    Map map2 = new HashMap(); // Create an hashmap to store elements.
+                    for (int i = 0; i < subProps.length; i++) {
+                        parseProperty(subProps[i], map2);
+                    }
+                    list.add(map2);
+                } else { // if not inject an empty map
+                    list.add(new HashMap(0));
+                }
+            }  else if (type.equalsIgnoreCase("list")) {
+                    Element[] subProps = prop.getElements("property");
+                    if (subProps != null) {
+                        List list2 = new ArrayList(subProps.length); // Create a list to store elements.
+                        for (int i = 0; i < subProps.length; i++) {
+                            parseAnonymousProperty(subProps[i], list2); // Anonymous properties.
+                        }
+                        list.add(list2);
+                    } else {
+                        // If no sub-properties, inject an empty list.
+                        list.add(new ArrayList(0));
+                    }
+                } else if (type.equalsIgnoreCase("array")) {
+                    // Check sub-props.
+                    Element[] subProps = prop.getElements("property");
+                    if (subProps != null) {
+                        List list2 = new ArrayList(subProps.length); // Use list as pivot type
+                        for (int i = 0; i < subProps.length; i++) {
+                            parseAnonymousProperty(subProps[i], list2);
+                        }
+                        list.add(list.toArray(new Object[list.size()])); // Transform the list to array
+                    } else {
+                        list.add(new Element[0]); // Insert an empty Element array.
+                    }
+                }
+        } else {
+            list.add(prop.getAttribute("value"));
+        }
+        
+    }
 
     /**
      * Add an element to the list.
diff --git a/ipojo/core/src/main/java/org/apache/felix/ipojo/parser/ParseUtils.java b/ipojo/core/src/main/java/org/apache/felix/ipojo/parser/ParseUtils.java
index e8d5bba..2405edc 100644
--- a/ipojo/core/src/main/java/org/apache/felix/ipojo/parser/ParseUtils.java
+++ b/ipojo/core/src/main/java/org/apache/felix/ipojo/parser/ParseUtils.java
@@ -40,8 +40,9 @@
             return new String[0];
         }
         
-        // Remove { and }
-        if (str.charAt(0) == '{' && str.charAt(str.length() - 1) == '}') {
+        // Remove { and } or [ and ]
+        if ((str.charAt(0) == '{' && str.charAt(str.length() - 1) == '}') ||
+                (str.charAt(0) == '[' && str.charAt(str.length() - 1) == ']')  ) {
             String internal = (str.substring(1, str.length() - 1)).trim();
             // Check empty array
             if (internal.length() == 0) {