The iPOJO API now supports external handlers. To use them, the handler provider has to implements HandlerConfiguration that returns the Element-Attribute structure representing the handler configuration.

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@766037 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/ipojo/api/src/main/java/org/apache/felix/ipojo/api/ComponentType.java b/ipojo/api/src/main/java/org/apache/felix/ipojo/api/ComponentType.java
index b45d0b4..ef4cd06 100644
--- a/ipojo/api/src/main/java/org/apache/felix/ipojo/api/ComponentType.java
+++ b/ipojo/api/src/main/java/org/apache/felix/ipojo/api/ComponentType.java
@@ -43,6 +43,7 @@
      * current component type.
      */
     private List m_instances = new ArrayList();
+   
     
     /**
      * Gets the factory attached to the current
@@ -64,7 +65,7 @@
      * component type.
      */
     public abstract void stop();
-    
+
     
     /**
      * Creates a component instance from the current type 
@@ -189,9 +190,6 @@
             }
         }
     }
-    
-    
-    
 
 
 }
diff --git a/ipojo/api/src/main/java/org/apache/felix/ipojo/api/Dependency.java b/ipojo/api/src/main/java/org/apache/felix/ipojo/api/Dependency.java
index a2dbe29..ba04f09 100644
--- a/ipojo/api/src/main/java/org/apache/felix/ipojo/api/Dependency.java
+++ b/ipojo/api/src/main/java/org/apache/felix/ipojo/api/Dependency.java
@@ -28,7 +28,7 @@
  * Allows configuring a service dependencies.
  * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
  */
-public class Dependency {
+public class Dependency implements HandlerConfiguration {
     
     /**
      * The dynamic binding policy.
diff --git a/ipojo/api/src/main/java/org/apache/felix/ipojo/api/HandlerConfiguration.java b/ipojo/api/src/main/java/org/apache/felix/ipojo/api/HandlerConfiguration.java
new file mode 100644
index 0000000..6e0958c
--- /dev/null
+++ b/ipojo/api/src/main/java/org/apache/felix/ipojo/api/HandlerConfiguration.java
@@ -0,0 +1,36 @@
+/* 
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.ipojo.api;
+
+import org.apache.felix.ipojo.metadata.Element;
+
+/**
+ * Common interfaces for all contributions.
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public interface HandlerConfiguration {
+    
+    /**
+     * Gets the Handler description.
+     * @return the Element-Attribute structure containing the handler
+     * configuration.
+     */
+    public Element getElement();
+
+}
diff --git a/ipojo/api/src/main/java/org/apache/felix/ipojo/api/PrimitiveComponentType.java b/ipojo/api/src/main/java/org/apache/felix/ipojo/api/PrimitiveComponentType.java
index 09d1a93..93bdb54 100644
--- a/ipojo/api/src/main/java/org/apache/felix/ipojo/api/PrimitiveComponentType.java
+++ b/ipojo/api/src/main/java/org/apache/felix/ipojo/api/PrimitiveComponentType.java
@@ -125,6 +125,12 @@
     private ArrayList m_temporals = new ArrayList();
     
     /**
+     * List of Handler representing external
+     * handler configuration
+     */
+    private List m_handlers = new ArrayList();
+    
+    /**
      * Checks that the component type is not already
      * started.
      */
@@ -356,9 +362,28 @@
             element.addElement(properties);
         }
         
+        // External handlers
+        for (int i = 0; i < m_handlers.size(); i++) {
+            HandlerConfiguration hc = (HandlerConfiguration) m_handlers.get(i);
+            element.addElement(hc.getElement());
+        }
+        
         return element;
     }
     
+
+    /**
+     * Adds an HandlerConfiguration to the component type. Each component type
+     * implementation must uses the populated list (m_handlers) when generating
+     * the component metadata.
+     * @param handler the handler configuration to add
+     * @return the current component type
+     */
+    public PrimitiveComponentType addHandler(HandlerConfiguration handler) {
+        m_handlers.add(handler);
+        return this;
+    }
+    
     /**
      * Creates the component factory.
      */
diff --git a/ipojo/api/src/main/java/org/apache/felix/ipojo/api/Service.java b/ipojo/api/src/main/java/org/apache/felix/ipojo/api/Service.java
index b70057f..3ce062e 100644
--- a/ipojo/api/src/main/java/org/apache/felix/ipojo/api/Service.java
+++ b/ipojo/api/src/main/java/org/apache/felix/ipojo/api/Service.java
@@ -33,7 +33,7 @@
  * Allows configuring a provided service.
  * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
  */
-public class Service {
+public class Service implements HandlerConfiguration {
     
     /**
      * Creation strategy : singleton (default).
diff --git a/ipojo/api/src/main/java/org/apache/felix/ipojo/api/TemporalDependency.java b/ipojo/api/src/main/java/org/apache/felix/ipojo/api/TemporalDependency.java
index 4f89295..713bf0a 100644
--- a/ipojo/api/src/main/java/org/apache/felix/ipojo/api/TemporalDependency.java
+++ b/ipojo/api/src/main/java/org/apache/felix/ipojo/api/TemporalDependency.java
@@ -25,7 +25,7 @@
  * Allows configuring a service dependencies.
  * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
  */
-public class TemporalDependency {
+public class TemporalDependency implements HandlerConfiguration {
     
     /**
      * OnTimeout policy: nullable object.
diff --git a/ipojo/api/src/main/java/org/apache/felix/ipojo/api/composite/CompositeComponentType.java b/ipojo/api/src/main/java/org/apache/felix/ipojo/api/composite/CompositeComponentType.java
index 7186f26..3da590e 100644
--- a/ipojo/api/src/main/java/org/apache/felix/ipojo/api/composite/CompositeComponentType.java
+++ b/ipojo/api/src/main/java/org/apache/felix/ipojo/api/composite/CompositeComponentType.java
@@ -25,6 +25,7 @@
 import org.apache.felix.ipojo.ConfigurationException;
 import org.apache.felix.ipojo.Factory;
 import org.apache.felix.ipojo.api.ComponentType;
+import org.apache.felix.ipojo.api.HandlerConfiguration;
 import org.apache.felix.ipojo.composite.CompositeFactory;
 import org.apache.felix.ipojo.metadata.Attribute;
 import org.apache.felix.ipojo.metadata.Element;
@@ -82,7 +83,16 @@
      */
     private boolean m_public = true;
 
+    /**
+     * Component type name.
+     */
     private String m_name;
+    
+    /**
+     * List of Handler representing external
+     * handler configuration
+     */
+    private List m_handlers = new ArrayList();
 
     /**
      * Checks that the component type is not already
@@ -199,6 +209,17 @@
     }
     
     /**
+     * Adds an HandlerConfiguration to the component type. Each component type
+     * implementation must uses the populated list (m_handlers) when generating
+     * the component metadata.
+     * @param handler the handler configuration to add
+     * @return the current component type.
+     */
+    public void CompositeComponentType(HandlerConfiguration handler) {
+        m_handlers.add(handler);
+    }
+    
+    /**
      * Generates the component description.
      * @return the component type description of 
      * the current component type
@@ -231,6 +252,13 @@
             ProvidedService inst = (ProvidedService) m_provided.get(i);
             element.addElement(inst.getElement());
         }
+        
+        // External handlers
+        for (int i = 0; i < m_handlers.size(); i++) {
+            HandlerConfiguration hc = (HandlerConfiguration) m_handlers.get(i);
+            element.addElement(hc.getElement());
+        }
+        
         return element;
     }
     
diff --git a/ipojo/api/src/main/java/org/apache/felix/ipojo/api/composite/ExportedService.java b/ipojo/api/src/main/java/org/apache/felix/ipojo/api/composite/ExportedService.java
index 981fae8..c7cb423 100644
--- a/ipojo/api/src/main/java/org/apache/felix/ipojo/api/composite/ExportedService.java
+++ b/ipojo/api/src/main/java/org/apache/felix/ipojo/api/composite/ExportedService.java
@@ -18,11 +18,12 @@
  */
 package org.apache.felix.ipojo.api.composite;
 
+import org.apache.felix.ipojo.api.HandlerConfiguration;
 import org.apache.felix.ipojo.metadata.Attribute;
 import org.apache.felix.ipojo.metadata.Element;
 import org.apache.felix.ipojo.util.DependencyModel;
 
-public class ExportedService {
+public class ExportedService implements HandlerConfiguration {
     
     /**
      * The required specification.
diff --git a/ipojo/api/src/main/java/org/apache/felix/ipojo/api/composite/ImportedService.java b/ipojo/api/src/main/java/org/apache/felix/ipojo/api/composite/ImportedService.java
index be91287..d7aff45 100644
--- a/ipojo/api/src/main/java/org/apache/felix/ipojo/api/composite/ImportedService.java
+++ b/ipojo/api/src/main/java/org/apache/felix/ipojo/api/composite/ImportedService.java
@@ -18,11 +18,12 @@
  */
 package org.apache.felix.ipojo.api.composite;
 
+import org.apache.felix.ipojo.api.HandlerConfiguration;
 import org.apache.felix.ipojo.metadata.Attribute;
 import org.apache.felix.ipojo.metadata.Element;
 import org.apache.felix.ipojo.util.DependencyModel;
 
-public class ImportedService {
+public class ImportedService implements HandlerConfiguration {
     
     public static final String COMPOSITE_SCOPE = "composite";
     
diff --git a/ipojo/api/src/main/java/org/apache/felix/ipojo/api/composite/Instance.java b/ipojo/api/src/main/java/org/apache/felix/ipojo/api/composite/Instance.java
index 68d0dd6..ae66997 100644
--- a/ipojo/api/src/main/java/org/apache/felix/ipojo/api/composite/Instance.java
+++ b/ipojo/api/src/main/java/org/apache/felix/ipojo/api/composite/Instance.java
@@ -28,10 +28,11 @@
 import java.util.Vector;
 import java.util.Map.Entry;
 
+import org.apache.felix.ipojo.api.HandlerConfiguration;
 import org.apache.felix.ipojo.metadata.Attribute;
 import org.apache.felix.ipojo.metadata.Element;
 
-public class Instance {
+public class Instance implements HandlerConfiguration {
     private String m_type;
     private List m_conf = new ArrayList();
     
diff --git a/ipojo/api/src/main/java/org/apache/felix/ipojo/api/composite/InstantiatedService.java b/ipojo/api/src/main/java/org/apache/felix/ipojo/api/composite/InstantiatedService.java
index 5751cd9..b53c636 100644
--- a/ipojo/api/src/main/java/org/apache/felix/ipojo/api/composite/InstantiatedService.java
+++ b/ipojo/api/src/main/java/org/apache/felix/ipojo/api/composite/InstantiatedService.java
@@ -28,11 +28,12 @@
 import java.util.Vector;
 import java.util.Map.Entry;
 
+import org.apache.felix.ipojo.api.HandlerConfiguration;
 import org.apache.felix.ipojo.metadata.Attribute;
 import org.apache.felix.ipojo.metadata.Element;
 import org.apache.felix.ipojo.util.DependencyModel;
 
-public class InstantiatedService {
+public class InstantiatedService implements HandlerConfiguration {
     
     /**
      * The required specification.
diff --git a/ipojo/api/src/main/java/org/apache/felix/ipojo/api/composite/ProvidedService.java b/ipojo/api/src/main/java/org/apache/felix/ipojo/api/composite/ProvidedService.java
index 1b2bd0c..136419e 100644
--- a/ipojo/api/src/main/java/org/apache/felix/ipojo/api/composite/ProvidedService.java
+++ b/ipojo/api/src/main/java/org/apache/felix/ipojo/api/composite/ProvidedService.java
@@ -21,10 +21,11 @@
 import java.util.ArrayList;
 import java.util.List;
 
+import org.apache.felix.ipojo.api.HandlerConfiguration;
 import org.apache.felix.ipojo.metadata.Attribute;
 import org.apache.felix.ipojo.metadata.Element;
 
-public class ProvidedService {
+public class ProvidedService implements HandlerConfiguration {
     public static final String ALL_POLICY = "all";
     public static final String ONE_POLICY = "one";
     
diff --git a/ipojo/tests/api/pom.xml b/ipojo/tests/api/pom.xml
index 4d8faed..2417d4e 100644
--- a/ipojo/tests/api/pom.xml
+++ b/ipojo/tests/api/pom.xml
@@ -72,6 +72,12 @@
 			<version>1.3.0-SNAPSHOT</version>
 		</dependency>
 		
+		<!-- For external handlermanagement -->
+		<dependency>
+			<groupId>org.apache.felix</groupId>
+			<artifactId>org.apache.felix.ipojo.handler.whiteboard</artifactId>
+			<version>1.3.0-SNAPSHOT</version>
+		</dependency>	
 		
 	<!--
 		Pax Exam API:
@@ -108,7 +114,7 @@
 		<version>4.5</version>
 		<type>jar</type>
 		<scope>test</scope>
-	</dependency>	
+	</dependency>
 	</dependencies>
 	
 	<repositories>
diff --git a/ipojo/tests/api/src/test/java/org/apache/felix/ipojo/tests/api/ExternalHandlerTest.java b/ipojo/tests/api/src/test/java/org/apache/felix/ipojo/tests/api/ExternalHandlerTest.java
new file mode 100644
index 0000000..59f4e0d
--- /dev/null
+++ b/ipojo/tests/api/src/test/java/org/apache/felix/ipojo/tests/api/ExternalHandlerTest.java
@@ -0,0 +1,107 @@
+package org.apache.felix.ipojo.tests.api;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.notNullValue;
+import static org.junit.Assert.assertThat;
+import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
+import static org.ops4j.pax.exam.CoreOptions.options;
+import static org.ops4j.pax.exam.CoreOptions.provision;
+import static org.ops4j.pax.exam.MavenUtils.asInProject;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.api.PrimitiveComponentType;
+import org.apache.felix.ipojo.architecture.HandlerDescription;
+import org.example.service.impl.HostImpl;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.ops4j.pax.exam.Inject;
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.junit.Configuration;
+import org.ops4j.pax.exam.junit.JUnit4TestRunner;
+import org.osgi.framework.BundleContext;
+
+
+
+@RunWith( JUnit4TestRunner.class )
+public class ExternalHandlerTest {
+    
+    @Inject
+    private BundleContext context;
+    
+    private OSGiHelper osgi;
+    
+    private IPOJOHelper ipojo;
+    
+    @Before
+    public void init() {
+        osgi = new OSGiHelper(context);
+        ipojo = new IPOJOHelper(context);
+    }
+    
+    @After
+    public void stop() {
+        ipojo.dispose();
+        osgi.dispose();
+    }
+    
+    @Configuration
+    public static Option[] configure() {    
+        Option[] opt =  options(
+                provision(
+                        mavenBundle().groupId("org.apache.felix").artifactId("org.apache.felix.ipojo").version(asInProject()),
+                        mavenBundle().groupId("org.apache.felix").artifactId("org.apache.felix.ipojo.api").version(asInProject()),
+                        mavenBundle().groupId("org.apache.felix").artifactId("org.apache.felix.ipojo.handler.whiteboard").version(asInProject())
+                    )
+                );
+        return opt;
+    }
+    
+    @Test
+    public void createAHost() throws Exception {
+        PrimitiveComponentType type = createAWhiteboardHost();
+        ComponentInstance ci = type.createInstance();
+        assertThat (ci.getState(), is (ComponentInstance.VALID));
+        HandlerDescription hd = ci.getInstanceDescription().getHandlerDescription(Whiteboard.NAMESPACE + ":" + Whiteboard.NAME);
+        assertThat (hd, is (notNullValue()));
+    }
+    
+    @Test
+    public void createDoubleHost() throws Exception {
+        PrimitiveComponentType type = createASecondWhiteboardHost();
+        ComponentInstance ci = type.createInstance();
+        assertThat (ci.getState(), is (ComponentInstance.VALID));
+        HandlerDescription hd = ci.getInstanceDescription().getHandlerDescription(Whiteboard.NAMESPACE + ":" + Whiteboard.NAME);
+        assertThat (hd, is (notNullValue()));
+    }
+    
+    private PrimitiveComponentType createAWhiteboardHost() {
+        return new PrimitiveComponentType()
+        .setBundleContext(context)
+        .setClassName(HostImpl.class.getName())
+        .addHandler(new Whiteboard()
+            .onArrival("arrival")
+            .onDeparture("departure")
+            .setFilter("(foo=foo)")
+         );
+    }
+    
+    private PrimitiveComponentType createASecondWhiteboardHost() {
+        return new PrimitiveComponentType()
+        .setBundleContext(context)
+        .setClassName(HostImpl.class.getName())
+        .addHandler(new Whiteboard()
+            .onArrival("arrival")
+            .onDeparture("departure")
+            .setFilter("(foo=foo)")
+         )
+         .addHandler(new Whiteboard()
+         .onArrival("arrival")
+         .onDeparture("departure")
+         .setFilter("(foo=bar)")
+         .onModification("modification")
+      );
+    }
+
+}
diff --git a/ipojo/tests/api/src/test/java/org/apache/felix/ipojo/tests/api/Whiteboard.java b/ipojo/tests/api/src/test/java/org/apache/felix/ipojo/tests/api/Whiteboard.java
new file mode 100644
index 0000000..17bce48
--- /dev/null
+++ b/ipojo/tests/api/src/test/java/org/apache/felix/ipojo/tests/api/Whiteboard.java
@@ -0,0 +1,71 @@
+package org.apache.felix.ipojo.tests.api;
+
+import org.apache.felix.ipojo.api.HandlerConfiguration;
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+
+public class Whiteboard implements HandlerConfiguration {
+    
+    public static final String NAME = "wbp";
+    
+    public static final String NAMESPACE = "org.apache.felix.ipojo.whiteboard";
+    
+    private String arrival;
+    
+    private String departure;
+    
+    private String modification;
+    
+    private String filter;
+    
+    public Whiteboard onArrival(String method) {
+        arrival = method;
+        return this;
+    }
+    
+    public Whiteboard onDeparture(String method) {
+        departure = method;
+        return this;
+    }
+    
+    public Whiteboard onModification(String method) {
+        modification = method;
+        return this;
+    }
+    
+    public Whiteboard setFilter(String fil) {
+        filter = fil;
+        return this;
+    }
+
+    public Element getElement() {
+        ensureValidity();
+        // Create the root element.
+        Element element = new Element(NAME, NAMESPACE);
+        // Mandatory attributes
+        element.addAttribute(new Attribute("onArrival", arrival));
+        element.addAttribute(new Attribute("onDeparture", departure));
+        element.addAttribute(new Attribute("filter", filter));
+        
+        // Optional attribute
+        if (modification != null) {
+            element.addAttribute(new Attribute("onModification", modification));
+        }        
+        
+        return element;
+    }
+
+    private void ensureValidity() {
+        if (arrival == null) {
+            throw new IllegalStateException("The whiteboard pattern configuration must have a onArrival method");
+        }
+        if (departure == null) {
+            throw new IllegalStateException("The whiteboard pattern configuration must have a onDeparture method");
+        }
+        if (filter == null) {
+            throw new IllegalStateException("The whiteboard pattern configuration must have a filter");
+        }
+        
+    }
+
+}
diff --git a/ipojo/tests/api/src/test/java/org/example/service/impl/HostImpl.java b/ipojo/tests/api/src/test/java/org/example/service/impl/HostImpl.java
new file mode 100644
index 0000000..1be1a70
--- /dev/null
+++ b/ipojo/tests/api/src/test/java/org/example/service/impl/HostImpl.java
@@ -0,0 +1,19 @@
+package org.example.service.impl;
+
+import org.osgi.framework.ServiceReference;
+
+public class HostImpl {
+    
+    public void arrival(ServiceReference ref) {
+        
+    }
+    
+    public void departure(ServiceReference ref) {
+        
+    }
+    
+    public void modification(ServiceReference ref) {
+        
+    }
+
+}