Commit the Event Admin handler.
This handler automates event admin interactions (both sending and reception).

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@586874 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/ipojo/event.admin.handler/pom.xml b/ipojo/event.admin.handler/pom.xml
new file mode 100644
index 0000000..851b077
--- /dev/null
+++ b/ipojo/event.admin.handler/pom.xml
@@ -0,0 +1,65 @@
+<project>

+  <modelVersion>4.0.0</modelVersion>

+  <packaging>bundle</packaging>

+  <name>iPOJO Event Admin Handler</name>

+  <groupId>org.apache.felix</groupId>

+  <version>0.7.5-SNAPSHOT</version>

+  <artifactId>org.apache.felix.ipojo.handler.event</artifactId>

+	  

+  <dependencies>

+	  <dependency>

+  			<groupId>org.apache.felix</groupId>

+      		<artifactId>org.apache.felix.ipojo</artifactId>

+	        <version>0.7.5-SNAPSHOT</version>

+	  </dependency>

+	  <dependency>

+  			<groupId>org.apache.felix</groupId>

+      		<artifactId>org.apache.felix.ipojo.metadata</artifactId>

+	      	<version>0.7.5-SNAPSHOT</version>

+	  </dependency>

+	  <dependency>

+  			<groupId>org.apache.felix</groupId>

+      		<artifactId>org.osgi.core</artifactId>

+      		<version>1.1.0-SNAPSHOT</version>

+	  </dependency>

+	  <dependency>

+	     <groupId>org.apache.felix</groupId>

+  		 <artifactId>org.osgi.compendium</artifactId>

+         <version>0.9.0-SNAPSHOT</version>

+	</dependency>

+  </dependencies>

+  

+

+  

+  <build>

+    <plugins>

+      <plugin>

+        <groupId>org.apache.felix</groupId>

+        <artifactId>maven-bundle-plugin</artifactId>

+        <extensions>true</extensions>

+        <configuration>

+          <instructions>

+            <Private-Package>org.apache.felix.ipojo.handler.event</Private-Package>

+            <Bundle-Name>${pom.name}</Bundle-Name>

+            <Bundle-SymbolicName>ipojo.event.admin.handler</Bundle-SymbolicName>

+          </instructions>

+        </configuration>

+      </plugin>

+      <plugin>

+	      <groupId>org.apache.felix</groupId>

+	      <artifactId>maven-ipojo-plugin</artifactId>

+          <version>${pom.version}</version>

+		  <executions>

+          	<execution>

+            	<goals>

+	              <goal>ipojo-bundle</goal>

+               </goals>

+            <configuration>

+   				<metadata>metadata.xml</metadata>

+            </configuration>

+          </execution>

+        </executions>

+      </plugin>

+    </plugins>

+  </build>

+</project>

diff --git a/ipojo/event.admin.handler/src/main/java/org/apache/felix/ipojo/handler/event/EventAdminSubscriberHandler.java b/ipojo/event.admin.handler/src/main/java/org/apache/felix/ipojo/handler/event/EventAdminSubscriberHandler.java
new file mode 100644
index 0000000..b2654ca
--- /dev/null
+++ b/ipojo/event.admin.handler/src/main/java/org/apache/felix/ipojo/handler/event/EventAdminSubscriberHandler.java
@@ -0,0 +1,268 @@
+/* 

+ * 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.handler.event;

+

+import java.util.ArrayList;

+import java.util.Dictionary;

+import java.util.Enumeration;

+import java.util.List;

+import java.util.Properties;

+

+import org.apache.felix.ipojo.ConfigurationException;

+import org.apache.felix.ipojo.InstanceManager;

+import org.apache.felix.ipojo.PrimitiveHandler;

+import org.apache.felix.ipojo.architecture.ComponentDescription;

+import org.apache.felix.ipojo.architecture.PropertyDescription;

+import org.apache.felix.ipojo.metadata.Element;

+import org.apache.felix.ipojo.parser.ManipulationMetadata;

+import org.apache.felix.ipojo.parser.MethodMetadata;

+import org.apache.felix.ipojo.util.Callback;

+import org.apache.felix.ipojo.util.Logger;

+import org.osgi.framework.InvalidSyntaxException;

+import org.osgi.service.event.Event;

+import org.osgi.service.event.EventHandler;

+

+/** 

+ * Event Subscriber Handler.

+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>

+ */

+public class EventAdminSubscriberHandler extends PrimitiveHandler implements EventHandler {

+

+    /**

+     * Handler Namespace. 

+     */

+    public static final String NAMESPACE = "org.apache.felix.ipojo.handler.event.EventAdminSubscriberHandler";

+

+    /**

+     * Instance Manager.

+     */

+    private InstanceManager m_manager;

+

+    /**

+     * List of subscriber.

+     */

+    private List m_subEvent = new ArrayList();

+

+    /**

+     * iPOJO Properties representing all the topics.

+     */

+    private String[] m_topics;

+

+    /**

+     * Initialize the component type.

+     * @param cd : component type description to populate.

+     * @param metadata : component type metadata.

+     * @throws ConfigurationException : metadata are incorrect.

+     * @see org.apache.felix.ipojo.Handler#initializeComponentFactory(org.apache.felix.ipojo.architecture.ComponentDescription, org.apache.felix.ipojo.metadata.Element)

+     */

+    public void initializeComponentFactory(ComponentDescription cd, Element metadata) throws ConfigurationException {

+        // Update the current component description

+        Dictionary dict = new Properties();

+        cd.addProperty(new PropertyDescription("event.topics", Dictionary.class.getName(), dict.toString()));

+

+        // Update the current component description

+        dict = new Properties();

+        cd.addProperty(new PropertyDescription("event.filter", Dictionary.class.getName(), dict.toString()));

+

+    }

+

+    /**

+     * Constructor. 

+     * @param metadata : component type metadata

+     * @param conf : instance configuration

+     * @throws ConfigurationException : one event subscription is not correct

+     * @see org.apache.felix.ipojo.Handler#configure(org.apache.felix.ipojo.InstanceManager, org.apache.felix.ipojo.metadata.Element, java.util.Dictionary)

+     */

+    public void configure(Element metadata, Dictionary conf) throws ConfigurationException {

+

+        // Store the component manager

+        m_manager = getInstanceManager();

+        ManipulationMetadata mm = new ManipulationMetadata(metadata);

+

+        // Get Metadata subscribers

+        Element[] subscribers = metadata.getElements("subscriber", NAMESPACE);

+        if (subscribers.length > 0) {

+            // then check publishers are well formed and fill the publishers'

+            // map

+            for (int i = 0; i < subscribers.length; i++) {

+                EventAdminSubscriberMetadata eventAdminSubscriberMetadata = new EventAdminSubscriberMetadata(m_manager, subscribers[i]);

+

+                if (eventAdminSubscriberMetadata.getCallbackStr() != null) {

+                    if (mm.getMethod(eventAdminSubscriberMetadata.getCallbackStr(), new String[] {Event.class.getName()}) != null) {

+                        MethodMetadata methodMetadata = mm.getMethod(eventAdminSubscriberMetadata.getCallbackStr(), new String[] {Event.class.getName()});

+                        Callback cb = new Callback(methodMetadata, m_manager);

+                        eventAdminSubscriberMetadata.setCallback(cb);

+                    } else {

+                        log(Logger.WARNING, " EVENT HANDLER SUBSCRIBERS : malformed subscriber : the method " + eventAdminSubscriberMetadata.getCallbackStr() + "(Event myEvent) is not present in the component");

+                        throw new ConfigurationException("EVENT HANDLER SUBSCRIBERS : malformed subscriber : the method " + eventAdminSubscriberMetadata.getCallbackStr() + "(Event myEvent) is not present in the component");

+                    }

+                    m_subEvent.add(eventAdminSubscriberMetadata);

+                } else {

+                    log(Logger.WARNING, " EVENT HANDLER SUBSCRIBERS : malformed subscriber !");

+                    throw new ConfigurationException("EVENT HANDLER SUBSCRIBERS : malformed subscriber !");

+                }

+            }

+            log(Logger.INFO, " EVENT HANDLER SUBSCRIBERS : Suscribers detected !");

+        } else {

+            log(Logger.ERROR, " EVENT HANDLER SUBSCRIBERS : no Suscribers detected !");

+            throw new ConfigurationException(" EVENT HANDLER SUBSCRIBERS : no Suscribers detected !");

+        }

+

+        // if well formed publishers or subscribers found

+        if (!m_subEvent.isEmpty()) {

+            // register the handler

+            log(Logger.INFO, " EVENT HANDLER SUBSCRIBERS has been configured !");

+        } else {

+            return;

+        }

+

+        // Check if the configuration has a event.topics property and update the

+        // topic if needed

+        if (conf.get("event.topics") != null) {

+            // Map <callbackName, topics>

+            Dictionary d = (Dictionary) conf.get("event.topics");

+            Enumeration e = d.keys();

+            while (e.hasMoreElements()) {

+                String myName = (String) e.nextElement(); // name

+                for (int i = 0; i < m_subEvent.size(); i++) {

+                    EventAdminSubscriberMetadata met = (EventAdminSubscriberMetadata) (m_subEvent.get(i));

+                    if (met.getName().equals(myName)) {

+                        met.setTopics((String) d.get(myName));

+                        break;

+                    }

+                }

+            }

+        }

+        // Check if the configuration has a event.filter property and update the

+        // filter if needed

+        if (conf.get("event.filter") != null) {

+            // Map <callbackName, topics>

+            Dictionary d = (Dictionary) conf.get("event.filter");

+            Enumeration e = d.keys();

+            while (e.hasMoreElements()) {

+                String myName = (String) e.nextElement(); // name

+                for (int i = 0; i < m_subEvent.size(); i++) {

+                    EventAdminSubscriberMetadata met = (EventAdminSubscriberMetadata) (m_subEvent.get(i));

+                    if (met.getName().equals(myName)) {

+                        try {

+                            met.setFilter((String) d.get(myName));

+                        } catch (InvalidSyntaxException e1) {

+                            e1.printStackTrace();

+                        }

+                        break;

+                    }

+                }

+            }

+        }

+    }

+

+    /** 

+     * Handler start method.

+     * Expose the EventHandler service. 

+     * @see org.apache.felix.ipojo.Handler#start()

+     */

+    public void start() {

+        log(Logger.INFO, " EVENT HANDLER SUBSCRIBERS STARTING!!!");

+

+        if (!m_subEvent.isEmpty()) {

+            // build the topic to listen

+            // Topics is a merge of all required topics by subscribers

+            String topics = "";

+

+            // for all subscribers

+            for (int i = 0; i < m_subEvent.size(); i++) {

+                EventAdminSubscriberMetadata sub = (EventAdminSubscriberMetadata) m_subEvent.get(i);

+                String stopics = sub.getTopics();

+                // gets its topic

+                if (topics.length() > 0 && stopics.length() > 0) {

+                    topics += ",";

+                }

+                // concat to the main topic

+                topics += stopics;

+            }

+

+            // Put the m_topics properties to the good value

+            m_topics = topics.split(",");

+

+            log(Logger.INFO, " EVENT HANDLER SUBSCRIBERS : EventHandler registered object: " + this);

+        }

+    }

+

+    /***************************************************************************************************************************************************************************************************

+     * Handler lifecycle management

+     **************************************************************************************************************************************************************************************************/

+

+    /**

+     * Handler state change method.

+     * register or unregister the EventHandler service according to the new state. 

+     * @param state : new state

+     * @see org.apache.felix.ipojo.Handler#stateChanged(int)

+     */

+    public void stateChanged(int state) {

+        if (state == InstanceManager.VALID) {

+            start();

+            return;

+        }

+        if (state == InstanceManager.INVALID) {

+            stop();

+            return;

+        }

+    }

+

+    /***************************************************************************************************************************************************************************************************

+     * OSGi EventHandler management

+     **************************************************************************************************************************************************************************************************/

+

+    /** 

+     * Receive an event.

+     * The event is dispatch to attached subscribers.

+     * @param event : the received event.

+     * @see org.osgi.service.event.EventHandler#handleEvent(org.osgi.service.event.Event)

+     */

+    public void handleEvent(Event event) {

+        // for each subscribers

+        for (int i = 0; i < m_subEvent.size(); i++) {

+            EventAdminSubscriberMetadata eventSubscriberData = (EventAdminSubscriberMetadata) m_subEvent.get(i);

+            synchronized (this) {

+                // check if the subscribers topic match

+

+                if (eventSubscriberData.matchingTopic(event.getTopic()) && event.matches(eventSubscriberData.getFilter()) && m_manager.getState() == InstanceManager.VALID) {

+                    try {

+                        Callback c = eventSubscriberData.getCallback();

+                        if (c != null) {

+                            c.call(new Object[] { event });

+                        }

+                    } catch (Exception e) {

+                        log(Logger.ERROR, "EVENT HANDLER SUBSCRIBERS CALLBACK error : " + eventSubscriberData.getCallbackStr() + " exception :" + e + " Cause : " + e.getCause());

+                        // stop the component :

+                        m_manager.setState(InstanceManager.INVALID);

+                    }

+                }

+            }

+        }

+    }

+

+    /**

+     * The stop method of a handler.

+     * @see org.apache.felix.ipojo.Handler#stop()

+     */

+    public void stop() {

+    }

+

+}

diff --git a/ipojo/event.admin.handler/src/main/java/org/apache/felix/ipojo/handler/event/EventAdminSubscriberMetadata.java b/ipojo/event.admin.handler/src/main/java/org/apache/felix/ipojo/handler/event/EventAdminSubscriberMetadata.java
new file mode 100644
index 0000000..989f633
--- /dev/null
+++ b/ipojo/event.admin.handler/src/main/java/org/apache/felix/ipojo/handler/event/EventAdminSubscriberMetadata.java
@@ -0,0 +1,195 @@
+/* 

+ * 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.handler.event;

+

+import org.apache.felix.ipojo.InstanceManager;

+import org.apache.felix.ipojo.metadata.Element;

+import org.apache.felix.ipojo.util.Callback;

+import org.apache.felix.ipojo.util.Logger;

+import org.osgi.framework.Filter;

+import org.osgi.framework.InvalidSyntaxException;

+import org.osgi.service.event.Event;

+

+/**

+ * Represent an subscriber.

+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>

+ */

+class EventAdminSubscriberMetadata {

+

+    /**

+     * Name of the callback method.

+     */

+    private String m_callbackStr;

+

+    /**

+     * Callback method.

+     */

+    private Callback m_callback;

+

+    /**

+     * Listenned topics.

+     */

+    private String m_topics;

+

+    /**

+     * String form of the event filter.

+     */

+    private String m_filterStr;

+

+    /**

+     * Event filter.

+     */

+    private Filter m_filter;

+

+    /**

+     * Event object.

+     */

+    private Event m_value;

+

+    /**

+     * The name which acts as an identifier.

+     */

+    private String m_name;

+

+    /**

+     * Ths Instance Manager.

+     */

+    private InstanceManager m_instanceManager;

+

+    /**

+     * Constructor.

+     * @param instanceManager : instance manager.

+     * @param subscriber : subscriber metadata.

+     */

+    public EventAdminSubscriberMetadata(InstanceManager instanceManager, Element subscriber) {

+        this.m_callbackStr = null;

+        this.m_topics = null;

+        this.m_filterStr = "";

+        this.m_filter = null;

+        this.m_value = null;

+        this.m_name = null;

+        this.m_instanceManager = instanceManager;

+        if (checkValidity(subscriber)) {

+            try {

+                if (subscriber.containsAttribute("topics")) {

+                    this.m_topics = subscriber.getAttribute("topics");

+                }

+                this.m_callbackStr = subscriber.getAttribute("callback");

+                if (subscriber.containsAttribute("filter")) {

+                    this.m_filterStr = subscriber.getAttribute("filter");

+                } else {

+                    this.m_filterStr = "(event.topics=*)";

+                }

+                this.m_filter = instanceManager.getContext().createFilter(this.m_filterStr);

+

+                this.m_name = subscriber.getAttribute("name");

+            } catch (InvalidSyntaxException e) {

+                instanceManager.getFactory().getLogger().log(Logger.WARNING, "===> EVENT handler : " + e.getMessage());

+            }

+        }

+

+    }

+

+    /**

+     * Does the topic match with the listenned topics ?

+     * @param topic : topic to test.

+     * @return true if the given topic is a listenned topic.

+     */

+    public boolean matchingTopic(String topic) {

+        return EventUtil.matches(topic, m_topics.split(","));

+    }

+

+    /**

+     * Is the subscriber metadata valid ?

+     * This method check only the existence of a callback and a name attribute.

+     * @param subscriber : metadata.

+     * @return true if the metadata is valid.

+     */

+    private boolean checkValidity(Element subscriber) {

+        return subscriber.containsAttribute("callback") && subscriber.containsAttribute("name");

+    }

+

+    /**

+     * Get the callback method name.

+     * @return the callback method name.

+     */

+    public String getCallbackStr() {

+        return m_callbackStr;

+    }

+

+    /**

+     * Get the callback object.

+     * @return the callback object.

+     */

+    public Callback getCallback() {

+        return m_callback;

+    }

+

+    /**

+     * Set the callback object.

+     * @param c : callback.

+     */

+    public void setCallback(Callback c) {

+        this.m_callback = c;

+    }

+

+    /**

+     * Get listened topics.

+     * @return the string form of the listened topics.

+     */

+    public String getTopics() {

+        return m_topics;

+    }

+

+    public Event getValue() {

+        return m_value;

+    }

+

+    public void setValue(Event value) {

+        this.m_value = value;

+    }

+

+    public Filter getFilter() {

+        return m_filter;

+    }

+

+    public void setTopics(String top) {

+        m_topics = top;

+    }

+

+    /**

+     * Create and set the filter.

+     * The filter is create from the given argument.

+     * @param filter : the String form of the LDAP filter.

+     * @throws InvalidSyntaxException : occurs when the given filter is invalid.

+     */

+    public void setFilter(String filter) throws InvalidSyntaxException {

+        this.m_filterStr = filter;

+        this.m_filter = m_instanceManager.getContext().createFilter(this.m_filterStr);

+    }

+

+    public String getName() {

+        return m_name;

+    }

+

+    public void setName(String name) {

+        this.m_name = name;

+    }

+

+}

diff --git a/ipojo/event.admin.handler/src/main/java/org/apache/felix/ipojo/handler/event/EventUtil.java b/ipojo/event.admin.handler/src/main/java/org/apache/felix/ipojo/handler/event/EventUtil.java
new file mode 100644
index 0000000..698e8fb
--- /dev/null
+++ b/ipojo/event.admin.handler/src/main/java/org/apache/felix/ipojo/handler/event/EventUtil.java
@@ -0,0 +1,60 @@
+/* 

+ * 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.handler.event;

+

+

+/**

+ * Utility methods.

+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>

+ */

+public class EventUtil {

+

+    /**

+     * Test that the given topic match with the given topic pattern.

+     * @param topic : topic to test.

+     * @param topicPattern : topic pattern

+     * @return true if it matches.

+     */

+    public static boolean matches(String topic, String topicPattern) {

+        if (topicPattern.equals("*")) { return true; }

+        int star;

+        if ((star = topicPattern.indexOf("*")) > 0) {

+            return topic.startsWith(topicPattern.substring(0, star - 1));

+        } else {

+            return topic.equals(topicPattern);

+        }

+    }

+

+    /**

+     * Test that the given topic match with the given topic patterns.

+     * @param topic : topic to test.

+     * @param topicPatterns : topic patterns

+     * @return true if it matches.

+     */

+    public static boolean matches(String topic, String[] topicPatterns) {

+        int n = topicPatterns.length;

+        for (int i = 0; i < n; i++) {

+            if (matches(topic, topicPatterns[i])) {

+                return true;

+            }

+        }

+        return false;

+    }

+

+}

diff --git a/ipojo/event.admin.handler/src/main/resources/metadata.xml b/ipojo/event.admin.handler/src/main/resources/metadata.xml
new file mode 100644
index 0000000..0c11767
--- /dev/null
+++ b/ipojo/event.admin.handler/src/main/resources/metadata.xml
@@ -0,0 +1,8 @@
+<ipojo>

+<!-- Primitives handler -->

+<handler classname="org.apache.felix.ipojo.handler.event.EventAdminSubscriberHandler" name="subscriber" namespace="org.apache.felix.ipojo.handler.event.EventAdminSubscriberHandler">

+	<provides>

+		<property field="m_topics" name="event.topics" value=""/>

+	</provides>

+</handler>

+</ipojo>
\ No newline at end of file