Fix FELIX-2711 The event admin handler should provides a Handler Description


git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1044393 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/ipojo/handler/eventadmin/src/main/java/org/apache/felix/ipojo/handlers/event/subscriber/EventAdminSubscriberHandler.java b/ipojo/handler/eventadmin/src/main/java/org/apache/felix/ipojo/handlers/event/subscriber/EventAdminSubscriberHandler.java
index 993934c..3ce2eb5 100644
--- a/ipojo/handler/eventadmin/src/main/java/org/apache/felix/ipojo/handlers/event/subscriber/EventAdminSubscriberHandler.java
+++ b/ipojo/handler/eventadmin/src/main/java/org/apache/felix/ipojo/handlers/event/subscriber/EventAdminSubscriberHandler.java
@@ -1,4 +1,4 @@
-/* 
+/*
  * 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
@@ -18,6 +18,7 @@
  */
 package org.apache.felix.ipojo.handlers.event.subscriber;
 
+import java.lang.reflect.InvocationTargetException;
 import java.util.Collection;
 import java.util.Dictionary;
 import java.util.HashMap;
@@ -45,7 +46,7 @@
 
 /**
  * Event Subscriber Handler.
- * 
+ *
  * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
  */
 public class EventAdminSubscriberHandler extends PrimitiveHandler implements
@@ -81,15 +82,16 @@
     /**
      * The list of subscriber accessible by name.
      */
-    private Map m_subscribersByName = new HashMap();
+    private final Map m_subscribersByName = new HashMap();
 
     /**
      * The list of callbacks accessible by subscribers' names.
      */
-    private Map m_callbacksByName = new Hashtable();
+    private final Map m_callbacksByName = new Hashtable();
 
     /**
      * The iPOJO properties representing all the topics.
+     * Immutable.
      */
     private String[] m_topics;
 
@@ -100,7 +102,7 @@
 
     /**
      * Initializes the component type.
-     * 
+     *
      * @param cd component type description to populate.
      * @param metadata component type metadata.
      * @throws ConfigurationException if the metadata are incorrect.
@@ -182,7 +184,7 @@
 
     /**
      * Constructor.
-     * 
+     *
      * @param metadata the omponent type metadata
      * @param conf the instance configuration
      * @throws ConfigurationException if one event subscription is not correct
@@ -218,17 +220,13 @@
                 info(LOG_PREFIX + "Configuring subscriber " + name);
 
                 // Get the topics instance configuration if redefined
-                String topicsString = (instanceTopics != null) ? (String) instanceTopics
-                        .get(name)
-                        : null;
+                String topicsString = (instanceTopics != null) ? (String) instanceTopics.get(name) : null;
                 if (topicsString != null) {
                     subscriberMetadata.setTopics(topicsString);
                 }
 
                 // Get the filter instance configuration if redefined
-                String filterString = (instanceFilter != null) ? (String) instanceFilter
-                        .get(name)
-                        : null;
+                String filterString = (instanceFilter != null) ? (String) instanceFilter.get(name) : null;
                 if (filterString != null) {
                     subscriberMetadata.setFilter(filterString);
                 }
@@ -277,7 +275,7 @@
 
     /**
      * Handler start method.
-     * 
+     *
      * @see org.apache.felix.ipojo.Handler#start()
      */
     // @Override
@@ -287,7 +285,7 @@
 
     /**
      * Handler stop method.
-     * 
+     *
      * @see org.apache.felix.ipojo.Handler#stop()
      */
     // @Override
@@ -301,102 +299,117 @@
 
     /**
      * Receives 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) {
-
+    public void handleEvent(final Event event) {
+    	EventAdminSubscriberMetadata subscriberMetadata = null;
         // Retrieve the event's topic
         String topic = event.getTopic();
 
         // For each subscribers
         Collection subscribers = m_subscribersByName.values();
         for (Iterator i = subscribers.iterator(); i.hasNext();) {
-            EventAdminSubscriberMetadata subscriberMetadata = (EventAdminSubscriberMetadata) i
-                    .next();
+            subscriberMetadata = (EventAdminSubscriberMetadata) i.next();
+
+            // Stack confinement
+            boolean isListening = false;
+
+            Object callbackParam = null;
+            Callback callback = null;
 
             synchronized (this) {
-                // Check if the subscriber's topic and filter match
-                Filter filter = subscriberMetadata.getFilter();
+            	isListening = m_isListening;
+			}
 
-                if (EventUtil.matches(topic, subscriberMetadata.getTopics())
-                        && (filter == null || event.matches(filter))) {
+            // Check if the subscriber's topic and filter match
+            Filter filter = subscriberMetadata.getFilter();
 
-                    String name = subscriberMetadata.getName();
-                    String dataKey = subscriberMetadata.getDataKey();
-                    Callback callback = (Callback) m_callbacksByName.get(name);
-                    Object callbackParam;
+            if (EventUtil.matches(topic, subscriberMetadata.getTopics())
+                    && (filter == null || event.matches(filter))) {
 
-                    try {
-                        // Depending on the subscriber type...
-                        if (dataKey == null) {
+                String name = subscriberMetadata.getName();
+                callback = (Callback) m_callbacksByName.get(name);
 
-                            // Generic event subscriber : pass the event to the
-                            // registered
-                            // callback
-                            callbackParam = event;
-
-                        } else {
-
-                            // Check for a data key in the event
-                            boolean dataKeyPresent = false;
-                            String[] properties = event.getPropertyNames();
-                            for (int j = 0; j < properties.length
-                                    && !dataKeyPresent; j++) {
-                                if (dataKey.equals(properties[j])) {
-                                    dataKeyPresent = true;
-                                }
-                            }
-
-                            if (dataKeyPresent) {
-                                // Data event : check type compatibility and
-                                // pass the given object to the registered
-                                // callback
-                                Object data = event.getProperty(dataKey);
-                                Class dataType = subscriberMetadata
-                                        .getDataType();
-                                Class dataClazz = data.getClass();
-                                if (dataType.isAssignableFrom(dataClazz)) {
-                                    callbackParam = data;
-                                } else {
-                                    throw new ClassCastException(
-                                            "Cannot convert "
-                                                    + dataClazz.getName()
-                                                    + " to "
-                                                    + dataType.getName());
-                                }
-
-                            } else {
-                                throw new java.lang.NoSuchFieldException(
-                                        dataKey);
-                            }
-                        }
-
-                        // Run the callback (final check to avoid
-                        // NullPointerExceptions)
-                        if (m_isListening) {
-                            callback.call(new Object[] { callbackParam });
-                        }
-
-                    } catch (ClassCastException e) {
-                        // Ignore the data event if type doesn't match
-                        warn(
-                                LOG_PREFIX
-                                        + "Ignoring data event : Bad data type",
-                                e);
-                    } catch (NoSuchFieldException e) {
-                        // Ignore events without data field for data events
-                        // subscriber
-                        warn(LOG_PREFIX + "Ignoring data event : No data", e);
-                    } catch (Exception e) {
-                        // Unexpected exception
-                        error(LOG_PREFIX
-                                + "Unexpected exception when calling callback",
-                                e);
-                    }
+                try {
+                    // Depending on the subscriber type...
+                    callbackParam = getCallbackParameter(event,
+							subscriberMetadata);
+                } catch (ClassCastException e) {
+                    // Ignore the data event if type doesn't match
+                    warn(LOG_PREFIX + "Ignoring data event : Bad data type", e);
+                } catch (NoSuchFieldException e) {
+                    // Ignore events without data field for data events
+                    // subscriber
+                    warn(LOG_PREFIX + "Ignoring data event : No data", e);
                 }
             }
+
+
+            // Run the callback (final check to avoid
+            // NullPointerExceptions)
+            if (isListening  && callback != null  && callbackParam != null) {
+                try {
+					callback.call(new Object[] { callbackParam });
+				} catch (InvocationTargetException e) {
+					error(LOG_PREFIX
+                            + "The callback has thrown an exception",
+                            e.getTargetException());
+				} catch (Exception e) {
+					error(LOG_PREFIX
+                            + "Unexpected exception when calling callback",
+                            e);
+				}
+            }
+
         }
     }
+
+	/**
+	 * Computes the callback parameter.
+	 * @param event the event
+	 * @param subscriberMetadata the subscribe metadata
+	 * @param dataKey the data key
+	 * @return the parameter of the callback
+	 * @throws ClassCastException the data class does not match the found value.
+	 * @throws NoSuchFieldException the datakey is not present in the event.
+	 */
+	private Object getCallbackParameter(final Event event,
+			final EventAdminSubscriberMetadata subscriberMetadata
+			) throws ClassCastException,NoSuchFieldException {
+		String dataKey = subscriberMetadata.getDataKey();
+		if (dataKey == null) {
+		    // Generic event subscriber : pass the event to the
+		    // registered callback
+		    return event;
+		} else {
+		    // Check for a data key in the event
+		    boolean dataKeyPresent = false;
+		    String[] properties = event.getPropertyNames();
+		    for (int j = 0; j < properties.length && !dataKeyPresent; j++) {
+		        if (dataKey.equals(properties[j])) {
+		            dataKeyPresent = true;
+		        }
+		    }
+
+		    if (dataKeyPresent) {
+		        // Data event : check type compatibility and
+		        // pass the given object to the registered
+		        // callback
+		        Object data = event.getProperty(dataKey);
+		        Class dataType = subscriberMetadata.getDataType();
+		        Class dataClazz = data.getClass();
+		        if (dataType.isAssignableFrom(dataClazz)) {
+		            return data;
+		        } else {
+		            throw new ClassCastException("Cannot convert " + dataClazz.getName() + " to "
+		                            + dataType.getName());
+		        }
+		    } else {
+		        throw new java.lang.NoSuchFieldException(dataKey);
+		    }
+
+		}
+	}
 }