Applied patch (FELIX-91) to add support for arrays in component metadata.


git-svn-id: https://svn.apache.org/repos/asf/incubator/felix/trunk@420896 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/handlers/architecture/ArchitectureHandler.java b/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/handlers/architecture/ArchitectureHandler.java
index b78a6d1..281ee73 100644
--- a/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/handlers/architecture/ArchitectureHandler.java
+++ b/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/handlers/architecture/ArchitectureHandler.java
@@ -28,7 +28,11 @@
 import org.apache.felix.ipojo.handlers.dependency.Dependency;
 import org.apache.felix.ipojo.handlers.dependency.DependencyHandler;
 import org.apache.felix.ipojo.handlers.dependency.DependencyMetadata;
-import org.apache.felix.ipojo.handlers.providedservice.*;
+import org.apache.felix.ipojo.handlers.providedservice.Property;
+import org.apache.felix.ipojo.handlers.providedservice.PropertyMetadata;
+import org.apache.felix.ipojo.handlers.providedservice.ProvidedService;
+import org.apache.felix.ipojo.handlers.providedservice.ProvidedServiceHandler;
+import org.apache.felix.ipojo.handlers.providedservice.ProvidedServiceMetadata;
 import org.apache.felix.ipojo.metadata.Element;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.Constants;
diff --git a/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/handlers/configuration/ConfigurableProperty.java b/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/handlers/configuration/ConfigurableProperty.java
index 53de8c0..e179ec7 100644
--- a/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/handlers/configuration/ConfigurableProperty.java
+++ b/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/handlers/configuration/ConfigurableProperty.java
@@ -16,6 +16,7 @@
  */
 package org.apache.felix.ipojo.handlers.configuration;
 
+import java.lang.reflect.Array;
 import java.lang.reflect.Constructor;
 import java.lang.reflect.InvocationTargetException;
 import java.util.logging.Level;
@@ -24,7 +25,7 @@
 import org.apache.felix.ipojo.metadata.Element;
 
 /**
- * Configurable Property
+ * Configurable Property.
  * @author <a href="mailto:felix-dev@incubator.apache.org">Felix Project Team</a>
  */
 public class ConfigurableProperty {
@@ -95,6 +96,14 @@
         if (type.equals("long")) { value = new Long(strValue); }
         if (type.equals("float")) { value = new Float(strValue); }
         if (type.equals("double")) { value = new Double(strValue); }
+    	// Array :
+    	if (type.endsWith("[]")) {
+    		String internalType = type.substring(0, type.length() - 2);
+    		strValue = strValue.substring(1, strValue.length() - 1);
+    		String[] values = strValue.split(",");
+    		setArrayValue(internalType, values);
+    		return;
+    	}
 
         if (value == null) {
         	// Else it is a neither a primitive type neither a String -> create the object by calling a constructor with a string in argument.
@@ -134,6 +143,81 @@
 
     }
 
+    private void setArrayValue(String internalType, String[] values) {
+   	 if (internalType.equals("string") || internalType.equals("String")) { m_value = values; return; }
+        if (internalType.equals("boolean")) {
+       	 boolean[] bool = new boolean[values.length];
+       	 for (int i = 0; i < values.length; i++) { bool[i] = new Boolean(values[i]).booleanValue(); }
+       	 m_value = bool;
+       	 return;
+       }
+       if (internalType.equals("byte")) {
+       	byte[] byt = new byte[values.length];
+      	 	for (int i = 0; i < values.length; i++) { byt[i] = new Byte(values[i]).byteValue(); }
+      	 	m_value = byt;
+       	return;
+       }
+        if (internalType.equals("short")) {
+       	 short[] shor = new short[values.length];
+       	 for (int i = 0; i < values.length; i++) { shor[i] = new Short(values[i]).shortValue(); }
+       	 m_value = shor;
+       	 return;
+       }
+        if (internalType.equals("int")) {
+       	 int[] in = new int[values.length];
+       	 for (int i = 0; i < values.length; i++) { in[i] = new Integer(values[i]).intValue(); }
+       	 m_value = in;
+       	 return;
+       }
+        if (internalType.equals("long")) {
+       	 long[] ll = new long[values.length];
+       	 for (int i = 0; i < values.length; i++) { ll[i] = new Long(values[i]).longValue(); }
+       	 m_value = ll;
+       	 return;
+       }
+        if (internalType.equals("float")) {
+       	 float[] fl = new float[values.length];
+       	 for (int i = 0; i < values.length; i++) { fl[i] = new Float(values[i]).floatValue(); }
+       	 m_value = fl;
+       	 return; }
+        if (internalType.equals("double")) {
+       	 double[] dl = new double[values.length];
+       	 for (int i = 0; i < values.length; i++) { dl[i] = new Double(values[i]).doubleValue(); }
+       	 m_value = dl;
+       	 return; }
+
+        // Else it is a neither a primitive type neither a String -> create the object by calling a constructor with a string in argument.
+        try {
+            Class c = m_handler.getComponentManager().getContext().getBundle().loadClass(internalType);
+            Constructor cst = c.getConstructor(new Class[] {String.class});
+            Object[] ob = (Object[]) Array.newInstance(c, values.length);
+            for (int i = 0; i < values.length; i++) {
+           	 ob[i] = cst.newInstance(new Object[] {values[i]});
+            }
+            m_value = ob;
+            return;
+        } catch (ClassNotFoundException e) {
+            System.err.println("Class not found exception in setValue on " + internalType);
+            e.printStackTrace();
+        } catch (SecurityException e) {
+            e.printStackTrace();
+        } catch (NoSuchMethodException e) {
+            System.err.println("Constructor not found exeption in setValue on " + internalType);
+            e.printStackTrace();
+        } catch (IllegalArgumentException e) {
+            System.err.println("Argument problem to call the constructor of the type " + internalType);
+            e.printStackTrace();
+        } catch (InstantiationException e) {
+            System.err.println("Instantiation problem  " + internalType);
+            e.printStackTrace();
+        } catch (IllegalAccessException e) {
+            e.printStackTrace();
+        } catch (InvocationTargetException e) {
+            System.err.println("Invocation problem " + internalType);
+            e.printStackTrace();
+        }
+	}
+
     /**
      * @return the name of the property.
      */
diff --git a/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/handlers/configuration/ConfigurationHandler.java b/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/handlers/configuration/ConfigurationHandler.java
index e9683b1..eb8c332 100644
--- a/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/handlers/configuration/ConfigurationHandler.java
+++ b/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/handlers/configuration/ConfigurationHandler.java
@@ -24,6 +24,7 @@
 import org.apache.felix.ipojo.ComponentManager;
 import org.apache.felix.ipojo.Handler;
 import org.apache.felix.ipojo.Activator;
+import org.apache.felix.ipojo.handlers.providedservice.ProvidedServiceHandler;
 import org.apache.felix.ipojo.metadata.Element;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.Constants;
@@ -48,6 +49,17 @@
 	private ConfigurableProperty[] m_configurableProperties = new ConfigurableProperty[0];
 
 	/**
+	 * ProvidedServiceHandler of the component.
+	 * It is useful to priopagate properties to service registrations.
+	 */
+	private ProvidedServiceHandler m_providedServiceHandler;
+
+	/**
+	 * Properties porpagated at the last "updated".
+	 */
+	private Dictionary m_propagated = new Properties();
+
+	/**
 	 * PID of the component.
 	 */
 	private String m_pid;
@@ -92,6 +104,7 @@
 		// Get the PID :
 		if (metadata.containsAttribute("name")) { m_pid = metadata.getAttribute("name"); }
 		else { m_pid = metadata.getAttribute("className"); }
+		m_providedServiceHandler = (ProvidedServiceHandler) m_manager.getHandler(ProvidedServiceHandler.class.getName());
 	}
 
 	/**
@@ -168,7 +181,7 @@
 	 * @see org.osgi.service.cm.ManagedService#updated(java.util.Dictionary)
 	 */
 	public void updated(Dictionary np) throws ConfigurationException {
-
+		Properties toPropagate = new Properties();
 		if (np != null) {
 			Enumeration keysEnumeration = np.keys();
 			while (keysEnumeration.hasMoreElements()) {
@@ -188,12 +201,22 @@
 					}
 				}
 				if (!find) {
-					Activator.getLogger().log(Level.WARNING, "[" + m_manager.getComponentMetatada().getClassName() + "] The configuration is not valid, the property " + name + " is not a configurable property");
+					//The property is not a configurable property
+					Activator.getLogger().log(Level.INFO, "[" + m_manager.getComponentMetatada().getClassName() + "] The property " + name + " will be propagated to service registrations");
+					toPropagate.put(name, value);
 					}
 				}
 			}
 		else { Activator.getLogger().log(Level.WARNING, "[" + m_manager.getComponentMetatada().getClassName() + "] The pushed configuration is null for " + m_pid); }
 
+		// Propagation of the properties to service registrations :
+		if (m_providedServiceHandler != null && !toPropagate.isEmpty()) {
+			Activator.getLogger().log(Level.INFO, "[" + m_manager.getComponentMetatada().getClassName() + "] Properties will be propagated");
+			m_providedServiceHandler.removeProperties(m_propagated);
+			m_providedServiceHandler.addProperties(toPropagate);
+			m_propagated = toPropagate;
+		}
+
 	}
 
 	/**
diff --git a/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/handlers/providedservice/Property.java b/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/handlers/providedservice/Property.java
index d94ef94..da99dff 100644
--- a/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/handlers/providedservice/Property.java
+++ b/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/handlers/providedservice/Property.java
@@ -16,6 +16,7 @@
  */
 package org.apache.felix.ipojo.handlers.providedservice;
 
+import java.lang.reflect.Array;
 import java.lang.reflect.Constructor;
 import java.lang.reflect.InvocationTargetException;
 import java.util.logging.Level;
@@ -70,7 +71,6 @@
         			break;
         		}
         	}
-
     		pm.setType(type);
     	}
 
@@ -78,6 +78,19 @@
     }
 
     /**
+     * Property constructor.
+     * This constructor is used only for non-field property (property not attached to a field).
+     * @param ps : the provided service
+     * @param name : the name of the property
+     * @param value : the value of the property
+     */
+    public Property(ProvidedService ps, String name, Object value) {
+    	m_providedService = ps;
+    	m_metadata = new PropertyMetadata(name, null, value.getClass().getName(), null);
+    	m_value = value;
+    }
+
+    /**
      * @return the Object value of the property
      */
     protected Object get() {
@@ -130,6 +143,16 @@
     private void setValue(String value) {
     	String type = m_metadata.getType();
 
+    	// Array :
+    	if (type.endsWith("[]")) {
+    		String internalType = type.substring(0, type.length() - 2);
+    		value = value.substring(1, value.length() - 1);
+    		String[] values = value.split(",");
+    		setArrayValue(internalType, values);
+    		return;
+    	}
+
+    	// Simple :
     	Activator.getLogger().log(Level.INFO, "[" + m_providedService.getComponentManager().getComponentMetatada().getClassName() + "] Set the value of the property " + m_metadata.getName() + " [" + m_metadata.getType() + "] " + " with the value : " + value);
 
         if (type.equals("string") || type.equals("String")) { m_value = new String(value); return; }
@@ -169,7 +192,82 @@
         }
     }
 
-    /**
+    private void setArrayValue(String internalType, String[] values) {
+    	 if (internalType.equals("string") || internalType.equals("String")) { m_value = values; return; }
+         if (internalType.equals("boolean")) {
+        	 boolean[] bool = new boolean[values.length];
+        	 for (int i = 0; i < values.length; i++) { bool[i] = new Boolean(values[i]).booleanValue(); }
+        	 m_value = bool;
+        	 return;
+        }
+        if (internalType.equals("byte")) {
+        	byte[] byt = new byte[values.length];
+       	 	for (int i = 0; i < values.length; i++) { byt[i] = new Byte(values[i]).byteValue(); }
+       	 	m_value = byt;
+        	return;
+        }
+         if (internalType.equals("short")) {
+        	 short[] shor = new short[values.length];
+        	 for (int i = 0; i < values.length; i++) { shor[i] = new Short(values[i]).shortValue(); }
+        	 m_value = shor;
+        	 return;
+        }
+         if (internalType.equals("int")) {
+        	 int[] in = new int[values.length];
+        	 for (int i = 0; i < values.length; i++) { in[i] = new Integer(values[i]).intValue(); }
+        	 m_value = in;
+        	 return;
+        }
+         if (internalType.equals("long")) {
+        	 long[] ll = new long[values.length];
+        	 for (int i = 0; i < values.length; i++) { ll[i] = new Long(values[i]).longValue(); }
+        	 m_value = ll;
+        	 return;
+        }
+         if (internalType.equals("float")) {
+        	 float[] fl = new float[values.length];
+        	 for (int i = 0; i < values.length; i++) { fl[i] = new Float(values[i]).floatValue(); }
+        	 m_value = fl;
+        	 return; }
+         if (internalType.equals("double")) {
+        	 double[] dl = new double[values.length];
+        	 for (int i = 0; i < values.length; i++) { dl[i] = new Double(values[i]).doubleValue(); }
+        	 m_value = dl;
+        	 return; }
+
+         // Else it is a neither a primitive type neither a String -> create the object by calling a constructor with a string in argument.
+         try {
+             Class c = m_providedService.getComponentManager().getContext().getBundle().loadClass(internalType);
+             Constructor cst = c.getConstructor(new Class[] {String.class});
+             Object[] ob = (Object[]) Array.newInstance(c, values.length);
+             for (int i = 0; i < values.length; i++) {
+            	 ob[i] = cst.newInstance(new Object[] {values[i]});
+             }
+             m_value = ob;
+             return;
+         } catch (ClassNotFoundException e) {
+             System.err.println("Class not found exception in setValue on " + internalType);
+             e.printStackTrace();
+         } catch (SecurityException e) {
+             e.printStackTrace();
+         } catch (NoSuchMethodException e) {
+             System.err.println("Constructor not found exeption in setValue on " + internalType);
+             e.printStackTrace();
+         } catch (IllegalArgumentException e) {
+             System.err.println("Argument problem to call the constructor of the type " + internalType);
+             e.printStackTrace();
+         } catch (InstantiationException e) {
+             System.err.println("Instantiation problem  " + internalType);
+             e.printStackTrace();
+         } catch (IllegalAccessException e) {
+             e.printStackTrace();
+         } catch (InvocationTargetException e) {
+             System.err.println("Invocation problem " + internalType);
+             e.printStackTrace();
+         }
+	}
+
+	/**
      * @return the value of the property.
      */
     public Object getValue() { return m_value; }
diff --git a/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/handlers/providedservice/ProvidedService.java b/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/handlers/providedservice/ProvidedService.java
index 8c9f0bb..82ce8fb 100644
--- a/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/handlers/providedservice/ProvidedService.java
+++ b/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/handlers/providedservice/ProvidedService.java
@@ -16,6 +16,8 @@
  */
 package org.apache.felix.ipojo.handlers.providedservice;
 
+import java.util.Dictionary;
+import java.util.Enumeration;
 import java.util.Properties;
 import java.util.logging.Level;
 
@@ -106,7 +108,7 @@
      * Add the given property to the property list.
      * @param p : the element to add
      */
-    private void addProperty(Property p) {
+    private synchronized void addProperty(Property p) {
         for (int i = 0; (m_properties != null) && (i < m_properties.length); i++) {
             if (m_properties[i] == p) { return; }
         }
@@ -120,6 +122,24 @@
         else { m_properties = new Property[] {p}; }
     }
 
+    private synchronized void removeProperty(String name) {
+    	 int idx = -1;
+         for (int i = 0; i < m_properties.length; i++) {
+             if (m_properties[i].getMetadata().getName() == name) { idx = i; break; }
+         }
+
+         if (idx >= 0) {
+             if ((m_properties.length - 1) == 0) { m_properties = new Property[0]; }
+             else {
+            	 Property[] newPropertiesList = new Property[m_properties.length - 1];
+                 System.arraycopy(m_properties, 0, newPropertiesList, 0, idx);
+                 if (idx < newPropertiesList.length) {
+                     System.arraycopy(m_properties, idx + 1, newPropertiesList, idx, newPropertiesList.length - idx); }
+                 m_properties = newPropertiesList;
+             }
+         }
+    }
+
     /**
      * @return the service reference of the provided service (null if the service is not published).
      */
@@ -263,7 +283,7 @@
      * Update refresh the service properties.
      * The new list of properties is sended to the service registry.
      */
-    protected void update() {
+    public void update() {
         // Update the service properties
 
         // Contruct the service properties list
@@ -284,4 +304,32 @@
 		return m_metadata;
 	}
 
+	/**
+	 * Add properties to the list.
+	 * @param props : properties to add
+	 */
+	protected void addProperties(Dictionary props) {
+		Enumeration keys = props.keys();
+		while (keys.hasMoreElements()) {
+			String key = (String) keys.nextElement();
+			Object value = props.get(key);
+			Property prop = new Property(this, key, value);
+			addProperty(prop);
+		}
+		update();
+	}
+
+	/**
+	 * Remove properties from the list.
+	 * @param props : properties to remove
+	 */
+	protected void deleteProperties(Dictionary props) {
+		Enumeration keys = props.keys();
+		while (keys.hasMoreElements()) {
+			String key = (String) keys.nextElement();
+			removeProperty(key);
+		}
+		update();
+	}
+
 }
diff --git a/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/handlers/providedservice/ProvidedServiceHandler.java b/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/handlers/providedservice/ProvidedServiceHandler.java
index 2351dcf..1546a3d 100644
--- a/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/handlers/providedservice/ProvidedServiceHandler.java
+++ b/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/handlers/providedservice/ProvidedServiceHandler.java
@@ -16,6 +16,7 @@
  */
 package org.apache.felix.ipojo.handlers.providedservice;
 
+import java.util.Dictionary;
 import java.util.logging.Level;
 
 import org.apache.felix.ipojo.ComponentManager;
@@ -302,4 +303,24 @@
 
 	}
 
+	/**
+	 * Add properties to all provided services.
+	 * @param dict : dictionary fo properties to add
+	 */
+	public void addProperties(Dictionary dict) {
+		for (int i = 0; i < m_providedServices.length; i++) {
+			m_providedServices[i].addProperties(dict);
+		}
+	}
+
+	/**
+	 * Remove properties form all provided services.
+	 * @param dict : dictionary of properties to delete.
+	 */
+	public void removeProperties(Dictionary dict) {
+		for (int i = 0; i < m_providedServices.length; i++) {
+			m_providedServices[i].deleteProperties(dict);
+		}
+	}
+
 }
diff --git a/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/parser/ManifestMetadataParser.java b/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/parser/ManifestMetadataParser.java
index da85147..04a271e 100644
--- a/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/parser/ManifestMetadataParser.java
+++ b/org.apache.felix.ipojo/src/main/java/org/apache/felix/ipojo/parser/ManifestMetadataParser.java
@@ -137,7 +137,7 @@
 					c = string[i];
 				}
 				i++; // skip "
-				c=string[i];
+				c = string[i];
 
 				Attribute att = new Attribute(attName, attNs , attValue);
 				m_elements[m_elements.length - 1].addAttribute(att);