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