Several improvements in the event admin handler:
- add checking when the factory is initializing instead of during the instance creation
- subscribers are no more ignored when an error occurs
- improve error messages
- fix a mistake (eventadmins instead of eventadmin) in the artifactid
- the handler now requires the event admin as an iPOJO dependency, this avoids tracking the service

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@681144 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/ipojo/handler/eventadmin/metadata.xml b/ipojo/handler/eventadmin/metadata.xml
index db43296..9bf4cb6 100644
--- a/ipojo/handler/eventadmin/metadata.xml
+++ b/ipojo/handler/eventadmin/metadata.xml
@@ -1,15 +1,16 @@
-<ipojo>

-	<handler

-		classname="org.apache.felix.ipojo.handlers.event.subscriber.EventAdminSubscriberHandler"

-		name="subscriber"

-		namespace="org.apache.felix.ipojo.handlers.event.EventAdminHandler">

-		<provides>

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

-		</provides>

-	</handler>

-	

-	<handler classname="org.apache.felix.ipojo.handlers.event.publisher.EventAdminPublisherHandler"

-		name="publisher"

-		namespace="org.apache.felix.ipojo.handlers.event.EventAdminHandler">

-	</handler>

+<ipojo>
+	<handler
+		classname="org.apache.felix.ipojo.handlers.event.subscriber.EventAdminSubscriberHandler"
+		name="subscriber"
+		namespace="org.apache.felix.ipojo.handlers.event.EventAdminHandler">
+		<provides>
+			<property field="m_topics" name="event.topics" value=""/>
+		</provides>
+	</handler>
+	
+	<handler classname="org.apache.felix.ipojo.handlers.event.publisher.EventAdminPublisherHandler"
+		name="publisher"
+		namespace="org.apache.felix.ipojo.handlers.event.EventAdminHandler">
+		<requires field="m_ea"/>
+	</handler>
 </ipojo>
\ No newline at end of file
diff --git a/ipojo/handler/eventadmin/pom.xml b/ipojo/handler/eventadmin/pom.xml
index ca80272..039b1f2 100644
--- a/ipojo/handler/eventadmin/pom.xml
+++ b/ipojo/handler/eventadmin/pom.xml
@@ -20,7 +20,7 @@
 	<modelVersion>4.0.0</modelVersion>

 	<packaging>bundle</packaging>

 	<name>Apache Felix iPOJO Event Admin Handler</name>

-	<artifactId>org.apache.felix.ipojo.handler.eventadmins</artifactId>

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

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

 	<version>0.9.0-SNAPSHOT</version>

 	

diff --git a/ipojo/handler/eventadmin/src/main/java/org/apache/felix/ipojo/handlers/event/publisher/EventAdminPublisherHandler.java b/ipojo/handler/eventadmin/src/main/java/org/apache/felix/ipojo/handlers/event/publisher/EventAdminPublisherHandler.java
index e77924d..8a0f973 100644
--- a/ipojo/handler/eventadmin/src/main/java/org/apache/felix/ipojo/handlers/event/publisher/EventAdminPublisherHandler.java
+++ b/ipojo/handler/eventadmin/src/main/java/org/apache/felix/ipojo/handlers/event/publisher/EventAdminPublisherHandler.java
@@ -1,323 +1,262 @@
-/* 

- * 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.handlers.event.publisher;

-

-import java.util.Dictionary;

-import java.util.Hashtable;

-import java.util.Map;

-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.ComponentTypeDescription;

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

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

-import org.apache.felix.ipojo.parser.FieldMetadata;

-import org.osgi.framework.BundleContext;

-import org.osgi.framework.InvalidSyntaxException;

-import org.osgi.framework.ServiceEvent;

-import org.osgi.framework.ServiceListener;

-import org.osgi.framework.ServiceReference;

-import org.osgi.service.event.EventAdmin;

-

-/**

- * Event Publisher Handler.

- * 

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

- */

-public class EventAdminPublisherHandler extends PrimitiveHandler implements

-        ServiceListener {

-

-    /**

-     * Handler Namespace.

-     */

-    public static final String NAMESPACE = "org.apache.felix.ipojo.handlers.event.EventAdminHandler";

-

-    /**

-     * Names of instance configuration properties.

-     */

-    public static final String TOPICS_PROPERTY = "event.topics";

-

-    /**

-     * Prefix for logged messages.

-     */

-    private static final String LOG_PREFIX = "EVENT ADMIN PUBLISHER HANDLER : ";

-

-    /**

-     * The Instance Manager.

-     */

-    private InstanceManager m_manager;

-

-    /**

-     * The bundle context.

-     */

-    private BundleContext m_context;

-

-    /**

-     * The current Event Admin service reference.

-     */

-    private ServiceReference m_eaReference;

-

-    /**

-     * The current Event Admin service.

-     */

-    private EventAdmin m_ea;

-

-    /**

-     * The publishers accessible by their names.

-     */

-    private Map m_publishersByName = new Hashtable();

-

-    /**

-     * The publishers accessible by their fields.

-     */

-    private Map m_publishersByField = new Hashtable();

-

-    /**

-     * 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)

-     */

-    // @Override

-    public void initializeComponentFactory(ComponentTypeDescription cd,

-            Element metadata)

-        throws ConfigurationException {

-

-        // Update the current component description

-        Dictionary dict = new Properties();

-        cd.addProperty(new PropertyDescription(TOPICS_PROPERTY,

-                Dictionary.class.getName(), dict.toString()));

-    }

-

-    /**

-     * Constructor.

-     * 

-     * @param metadata :

-     *            component type metadata

-     * @param conf :

-     *            instance configuration

-     * @throws ConfigurationException :

-     *             one event publication is not correct

-     * @see org.apache.felix.ipojo.Handler#configure(org.apache.felix.ipojo.InstanceManager,

-     *      org.apache.felix.ipojo.metadata.Element, java.util.Dictionary)

-     */

-    // @Override

-    public void configure(Element metadata, Dictionary conf)

-        throws ConfigurationException {

-

-        // Store the component manager

-        m_manager = getInstanceManager();

-

-        // Get Metadata publishers

-        Element[] publishers = metadata.getElements("publisher", NAMESPACE);

-

-        if (publishers != null) {

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

-            // map

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

-

-                try {

-                    // Extract the publisher configuration

-                    EventAdminPublisherMetadata publisherMetadata = new EventAdminPublisherMetadata(

-                            publishers[i], conf);

-                    String name = publisherMetadata.getName();

-                    info(LOG_PREFIX + "configuring publisher " + name);

-

-                    // Create the associated Publisher

-                    Publisher publisher = new PublisherImpl(this,

-                            publisherMetadata.getTopics(), publisherMetadata

-                                    .isSynchronous(), publisherMetadata

-                                    .getDataKey(), m_manager.getInstanceName());

-

-                    // Check field existence and type

-                    String field = publisherMetadata.getField();

-                    FieldMetadata fieldMetadata = getPojoMetadata().getField(

-                            publisherMetadata.getField(),

-                            Publisher.class.getName());

-                    if (fieldMetadata == null) {

-                        throw new ConfigurationException(

-                                "Field not found in the component : "

-                                        + Publisher.class.getName() + " "

-                                        + field);

-                    }

-

-                    // Insert in the publisher tables.

-                    Object old;

-                    if ((old = m_publishersByName.put(name, publisher)) != null) {

-                        m_publishersByName.put(name, old);

-                        throw new ConfigurationException("The publisher "

-                                + name + "already exists");

-                    }

-                    if ((old = m_publishersByField.put(field, publisher)) != null) {

-                        m_publishersByField.put(field, old);

-                        m_publishersByName.remove(name);

-                        throw new ConfigurationException("The field " + field

-                                + " is already associated to a publisher");

-                    }

-

-                    // Register the callback that return the publisher

-                    // reference when the specified field is read by the

-                    // POJO.

-                    m_manager.register(fieldMetadata, this);

-

-                } catch (Exception e) {

-                    // Ignore invalid publishers

-                    warn(LOG_PREFIX

-                            + "Ignoring publisher : Error in configuration", e);

-                }

-            }

-        } else {

-            info(LOG_PREFIX + "no publisher detected !");

-        }

-    }

-

-    /**

-     * Start the handler instance. This method tries to get an initial reference

-     * of the EventAdmin service.

-     */

-    // @Override

-    public void start() {

-        info(LOG_PREFIX + "STARTING");

-

-        // Look for the EventAdmin service at startup

-        m_context = m_manager.getContext();

-        m_eaReference = m_context.getServiceReference(EventAdmin.class

-                .getName());

-        if (m_eaReference != null) {

-            m_ea = (EventAdmin) m_context.getService(m_eaReference);

-            if (m_ea != null) {

-                info(LOG_PREFIX + "EventAdmin service caught");

-            }

-        }

-

-        // Update handler validity

-        setValidity(m_ea != null);

-

-        // Register service listener for EventAdmin services

-        try {

-            m_context.addServiceListener(this, "(OBJECTCLASS="

-                    + EventAdmin.class.getName() + ")");

-        } catch (InvalidSyntaxException e) {

-            error(LOG_PREFIX + "Cannot register ServiceListener", e);

-        }

-        info(LOG_PREFIX + "STARTED");

-    }

-

-    /**

-     * Stop the handler instance. This method release the used EventAdmin

-     * service (if any).

-     */

-    // @Override

-    public void stop() {

-        info(LOG_PREFIX + "STOPPING");

-

-        // Unregister service

-        if (m_ea != null) {

-            m_ea = null;

-            m_context.ungetService(m_eaReference);

-            info(LOG_PREFIX + "EventAdmin service released");

-        }

-

-        info(LOG_PREFIX + "STOPPED");

-    }

-

-    /***************************************************************************

-     * OSGi ServiceListener callback

-     **************************************************************************/

-

-    /**

-     * Service listener callback. This method check the

-     * registration/unregistration of EventAdmin services and update the

-     * valididy of the handler.

-     * 

-     * @param event

-     *            the concerned service reference

-     */

-    // @Override

-    public void serviceChanged(ServiceEvent event) {

-        warn(LOG_PREFIX + "serviceChanged()");

-

-        if (m_eaReference == null && event.getType() == ServiceEvent.REGISTERED) {

-            // An EventAdmin service appeared and was expected

-            m_eaReference = event.getServiceReference();

-            m_ea = (EventAdmin) m_context.getService(m_eaReference);

-            info(LOG_PREFIX + "EventAdmin service caught");

-        } else if (m_eaReference != null

-                && event.getType() == ServiceEvent.UNREGISTERING

-                && m_eaReference == event.getServiceReference()) {

-            // The used EventAdmin service disappeared

-            m_ea = null;

-            m_context.ungetService(m_eaReference);

-            info(LOG_PREFIX + "EventAdmin service released");

-

-            // Find another EventAdmin service if available

-            m_eaReference = m_context.getServiceReference(EventAdmin.class

-                    .getName());

-            if (m_eaReference != null) {

-                m_ea = (EventAdmin) m_context.getService(m_eaReference);

-                info(LOG_PREFIX + "EventAdmin service caught");

-            }

-        }

-

-        // Update handler validity

-        setValidity(m_ea != null);

-    }

-

-    /**

-     * Field interceptor callback. This method is called when the component

-     * attempt to one of its Publisher field.

-     * 

-     * @param pojo

-     *            the accessed field

-     * @param fieldName

-     *            the name of the accessed field

-     * @param value

-     *            the value of the field (useless here)

-     * 

-     * @return the Publisher associated with the accessed field's name

-     */

-    // @Override

-    public Object onGet(Object pojo, String fieldName, Object value) {

-        // Retrieve the publisher associated to the given field name

-        Publisher pub = (Publisher) m_publishersByField.get(fieldName);

-        if (pub == null) {

-            error(LOG_PREFIX + "No publisher associated to the field "

-                    + fieldName);

-        }

-        return pub;

-    }

-

-    /**

-     * This method is called by managed publishers to obtain the current

-     * EventAdmin service.

-     * 

-     * @return the current EventAdmin service or {@code null} if unavailable.

-     */

-    public EventAdmin getEventAdminService() {

-        return m_ea;

-    }

-}

+/* 
+ * 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.handlers.event.publisher;
+
+import java.util.Dictionary;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+
+import org.apache.felix.ipojo.ConfigurationException;
+import org.apache.felix.ipojo.InstanceManager;
+import org.apache.felix.ipojo.PrimitiveHandler;
+import org.apache.felix.ipojo.architecture.ComponentTypeDescription;
+import org.apache.felix.ipojo.architecture.PropertyDescription;
+import org.apache.felix.ipojo.metadata.Element;
+import org.apache.felix.ipojo.parser.FieldMetadata;
+import org.osgi.service.event.EventAdmin;
+
+/**
+ * Event Publisher Handler.
+ * 
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class EventAdminPublisherHandler extends PrimitiveHandler {
+
+    /**
+     * Handler Namespace.
+     */
+    public static final String NAMESPACE = "org.apache.felix.ipojo.handlers.event.EventAdminHandler";
+
+    /**
+     * Names of instance configuration properties.
+     */
+    public static final String TOPICS_PROPERTY = "event.topics";
+
+    /**
+     * Prefix for logged messages.
+     */
+    private static final String LOG_PREFIX = "EVENT ADMIN PUBLISHER HANDLER : ";
+
+    /**
+     * The Instance Manager.
+     */
+    private InstanceManager m_manager;
+
+    /**
+     * The current Event Admin service.
+     */
+    private EventAdmin m_ea;
+
+    /**
+     * The publishers accessible by their fields.
+     */
+    private Map m_publishersByField = new Hashtable();
+
+    /**
+     * 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)
+     */
+    // @Override
+    public void initializeComponentFactory(ComponentTypeDescription cd,
+            Element metadata)
+        throws ConfigurationException {
+
+        // Update the current component description
+        Dictionary dict = new Properties();
+        cd.addProperty(new PropertyDescription(TOPICS_PROPERTY,
+                Dictionary.class.getName(), dict.toString()));
+
+        // Get Metadata publishers
+        Element[] publishers = metadata.getElements("publisher", NAMESPACE);
+        if (publishers != null) {
+
+            // Maps used to check name and field are unique
+            Set nameSet = new HashSet();
+            Set fieldSet = new HashSet();
+
+            // Check all publishers are well formed
+            for (int i = 0; i < publishers.length; i++) {
+
+                // Check the publisher configuration is correct by creating an
+                // unused publisher metadata
+                EventAdminPublisherMetadata publisherMetadata = new EventAdminPublisherMetadata(
+                        publishers[i]);
+                String name = publisherMetadata.getName();
+                info(LOG_PREFIX + "checking publisher " + name);
+
+                // Check field existence and type
+                String field = publisherMetadata.getField();
+                FieldMetadata fieldMetadata = getPojoMetadata()
+                        .getField(publisherMetadata.getField(),
+                                Publisher.class.getName());
+                if (fieldMetadata == null) {
+                    throw new ConfigurationException(
+                            "Field not found in the component : "
+                                    + Publisher.class.getName() + " " + field);
+                }
+
+                // Check name and field are unique
+                if (nameSet.contains(name)) {
+                    throw new ConfigurationException(
+                            "A publisher with the same name already exists : "
+                                    + name);
+                } else if (fieldSet.contains(field)) {
+                    throw new ConfigurationException("The field " + field
+                            + " is already associated to a publisher");
+                }
+                nameSet.add(name);
+                fieldSet.add(field);
+            }
+        } else {
+            info(LOG_PREFIX + "no publisher to check");
+        }
+    }
+
+    /**
+     * Constructor.
+     * 
+     * @param metadata :
+     *            component type metadata
+     * @param conf :
+     *            instance configuration
+     * @throws ConfigurationException :
+     *             one event publication is not correct
+     * @see org.apache.felix.ipojo.Handler#configure(org.apache.felix.ipojo.InstanceManager,
+     *      org.apache.felix.ipojo.metadata.Element, java.util.Dictionary)
+     */
+    // @Override
+    public void configure(Element metadata, Dictionary conf)
+        throws ConfigurationException {
+
+        // Store the component manager
+        m_manager = getInstanceManager();
+
+        // Get the topics instance configuration
+        Dictionary instanceTopics = (Dictionary) conf.get(TOPICS_PROPERTY);
+
+        // Get Metadata publishers
+        Element[] publishers = metadata.getElements("publisher", NAMESPACE);
+
+        if (publishers != null) {
+            // then check publishers are well formed and fill the publishers'
+            // map
+            for (int i = 0; i < publishers.length; i++) {
+
+                // Extract the publisher configuration
+                EventAdminPublisherMetadata publisherMetadata = new EventAdminPublisherMetadata(
+                        publishers[i]);
+                String name = publisherMetadata.getName();
+                info(LOG_PREFIX + "configuring publisher " + name);
+
+                // Get the topic instance configuration if redefined
+                String topicsString = (instanceTopics != null) ? (String) instanceTopics
+                        .get(name)
+                        : null;
+                if (topicsString != null) {
+                    publisherMetadata.setTopics(topicsString);
+                }
+
+                // Check the publisher is correctly configured
+                publisherMetadata.check();
+
+                // Create the associated Publisher and insert it in the
+                // publisher map
+                Publisher publisher = new PublisherImpl(this, publisherMetadata
+                        .getTopics(), publisherMetadata.isSynchronous(),
+                        publisherMetadata.getDataKey(), m_manager
+                                .getInstanceName());
+                m_publishersByField
+                        .put(publisherMetadata.getField(), publisher);
+
+                // Register the callback that return the publisher
+                // reference when the specified field is read by the
+                // POJO.
+                FieldMetadata fieldMetadata = getPojoMetadata()
+                        .getField(publisherMetadata.getField(),
+                                Publisher.class.getName());
+                m_manager.register(fieldMetadata, this);
+            }
+        } else {
+            info(LOG_PREFIX + "no publisher to configure");
+        }
+    }
+
+    /**
+     * Start the handler instance.
+     * 
+     * This method does nothing.
+     */
+    // @Override
+    public void start() {
+    }
+
+    /**
+     * Stop the handler instance.
+     * 
+     * This method does nothing.
+     */
+    // @Override
+    public void stop() {
+    }
+
+    /**
+     * Field interceptor callback. This method is called when the component
+     * attempt to one of its Publisher field.
+     * 
+     * @param pojo
+     *            the accessed field
+     * @param fieldName
+     *            the name of the accessed field
+     * @param value
+     *            the value of the field (useless here)
+     * 
+     * @return the Publisher associated with the accessed field's name
+     */
+    // @Override
+    public Object onGet(Object pojo, String fieldName, Object value) {
+        // Retrieve the publisher associated to the given field name
+        Publisher pub = (Publisher) m_publishersByField.get(fieldName);
+        if (pub == null) {
+            error(LOG_PREFIX + "No publisher associated to the field "
+                    + fieldName);
+        }
+        return pub;
+    }
+
+    /**
+     * This method is called by managed publishers to obtain the current
+     * EventAdmin service.
+     * 
+     * @return the current EventAdmin service.
+     */
+    public EventAdmin getEventAdminService() {
+        return m_ea;
+    }
+}
diff --git a/ipojo/handler/eventadmin/src/main/java/org/apache/felix/ipojo/handlers/event/publisher/EventAdminPublisherMetadata.java b/ipojo/handler/eventadmin/src/main/java/org/apache/felix/ipojo/handlers/event/publisher/EventAdminPublisherMetadata.java
index 0408abf..620bf20 100644
--- a/ipojo/handler/eventadmin/src/main/java/org/apache/felix/ipojo/handlers/event/publisher/EventAdminPublisherMetadata.java
+++ b/ipojo/handler/eventadmin/src/main/java/org/apache/felix/ipojo/handlers/event/publisher/EventAdminPublisherMetadata.java
@@ -1,225 +1,260 @@
-/* 

- * 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.handlers.event.publisher;

-

-import java.util.Dictionary;

-import java.util.Enumeration;

-

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

-import org.apache.felix.ipojo.handlers.event.subscriber.EventAdminSubscriberHandler;

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

-import org.apache.felix.ipojo.parser.ParseUtils;

-

-/**

- * Represent a publisher.

- * 

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

- */

-class EventAdminPublisherMetadata {

-

-    // Names of metadata attributes

-

-    /**

-     * The name attribute in the component metadata.

-     */

-    public static final String NAME_ATTRIBUTE = "name";

-

-    /**

-     * The field attribute in the component metadata.

-     */

-    public static final String FIELD_ATTRIBUTE = "field";

-

-    /**

-     * The topics attribute in the component metadata.

-     */

-    public static final String TOPICS_ATTRIBUTE = "topics";

-

-    /**

-     * The synchronous attribute in the component metadata.

-     */

-    public static final String SYNCHRONOUS_ATTRIBUTE = "synchronous";

-

-    /**

-     * The data key attribute in the component metadata.

-     */

-    public static final String DATA_KEY_ATTRIBUTE = "data-key";

-

-    // Default values

-

-    /**

-     * The data key attribute's default value.

-     */

-    public static final String DEFAULT_DATA_KEY_VALUE = "user.data";

-

-    /**

-     * The synchronous attribute's default value.

-     */

-    public static final boolean DEFAULT_SYNCHRONOUS_VALUE = false;

-

-    /**

-     * The name which acts as an identifier.

-     */

-    private final String m_name;

-

-    /**

-     * The name of the field representing the publisher in the component.

-     */

-    private final String m_field;

-

-    /**

-     * Topics to which events are sent.

-     */

-    private final String[] m_topics;

-

-    /**

-     * Events sending mode.

-     */

-    private final boolean m_synchronous;

-

-    /**

-     * The key where user data are stored in the event dictionary.

-     */

-    private final String m_dataKey;

-

-    /**

-     * Construct a publisher from its metadata description.

-     * 

-     * @param publisher :

-     *            publisher metadata description.

-     * @param instanceConf :

-     *            the configuration of the component instance

-     * @throws ConfigurationException

-     *             if the configuration of the component or the instance is

-     *             invalid.

-     */

-    public EventAdminPublisherMetadata(Element publisher,

-            Dictionary instanceConf) throws ConfigurationException {

-

-        /**

-         * Setup required attributes

-         */

-

-        // NAME_ATTRIBUTE

-        if (publisher.containsAttribute(NAME_ATTRIBUTE)) {

-            m_name = publisher.getAttribute(NAME_ATTRIBUTE);

-        } else {

-            throw new ConfigurationException(

-                    "Missing required attribute in component configuration : "

-                            + NAME_ATTRIBUTE);

-        }

-

-        // FIELD_ATTRIBUTE

-        if (publisher.containsAttribute(FIELD_ATTRIBUTE)) {

-            m_field = publisher.getAttribute(FIELD_ATTRIBUTE);

-        } else {

-            throw new ConfigurationException(

-                    "Missing required attribute in component configuration : "

-                            + FIELD_ATTRIBUTE);

-        }

-

-        // TOPICS_ATTRIBUTE

-        String topicsString = null;

-        if (publisher.containsAttribute(TOPICS_ATTRIBUTE)) {

-            topicsString = publisher.getAttribute(TOPICS_ATTRIBUTE);

-        }

-        // Check TOPICS_PROPERTY in the instance configuration

-        Dictionary instanceTopics = (Dictionary) instanceConf

-                .get(EventAdminSubscriberHandler.TOPICS_PROPERTY);

-        if (instanceTopics != null) {

-            Enumeration e = instanceTopics.keys();

-            while (e.hasMoreElements()) {

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

-                if (m_name.equals(myName)) {

-                    topicsString = (String) instanceTopics.get(myName);

-                    break;

-                }

-            }

-        }

-        if (topicsString != null) {

-            m_topics = ParseUtils.split(topicsString, ",");

-        } else {

-            throw new ConfigurationException(

-                    "Missing required attribute in component or instance configuration : "

-                            + TOPICS_ATTRIBUTE);

-        }

-

-        /**

-         * Setup optional attributes

-         */

-        // SYNCHRONOUS_ATTRIBUTE

-        if (publisher.containsAttribute(SYNCHRONOUS_ATTRIBUTE)) {

-            m_synchronous = "true".equalsIgnoreCase(publisher

-                    .getAttribute(SYNCHRONOUS_ATTRIBUTE));

-        } else {

-            m_synchronous = DEFAULT_SYNCHRONOUS_VALUE;

-        }

-

-        // DATA_KEY_ATTRIBUTE

-        if (publisher.containsAttribute(DATA_KEY_ATTRIBUTE)) {

-            m_dataKey = publisher.getAttribute(DATA_KEY_ATTRIBUTE);

-        } else {

-            m_dataKey = DEFAULT_DATA_KEY_VALUE;

-        }

-    }

-

-    /**

-     * Get the name attribute of the publisher.

-     * 

-     * @return the name

-     */

-    public String getName() {

-        return m_name;

-    }

-

-    /**

-     * Get the field attribute of the publisher.

-     * 

-     * @return the field

-     */

-    public String getField() {

-        return m_field;

-    }

-

-    /**

-     * Get the topics attribute of the publisher.

-     * 

-     * @return the topics

-     */

-    public String[] getTopics() {

-        return m_topics;

-    }

-

-    /**

-     * Get the synchronous attribute of the publisher.

-     * 

-     * @return the synchronous

-     */

-    public boolean isSynchronous() {

-        return m_synchronous;

-    }

-

-    /**

-     * Get the dataKey attribute of the publisher.

-     * 

-     * @return the dataKey

-     */

-    public String getDataKey() {

-        return m_dataKey;

-    }

-}

+/* 
+ * 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.handlers.event.publisher;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+import org.apache.felix.ipojo.ConfigurationException;
+import org.apache.felix.ipojo.metadata.Element;
+import org.apache.felix.ipojo.parser.ParseUtils;
+import org.osgi.service.event.Event;
+
+/**
+ * Represent a publisher.
+ * 
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+class EventAdminPublisherMetadata {
+
+    // Names of metadata attributes
+
+    /**
+     * The name attribute in the component metadata.
+     */
+    public static final String NAME_ATTRIBUTE = "name";
+
+    /**
+     * The field attribute in the component metadata.
+     */
+    public static final String FIELD_ATTRIBUTE = "field";
+
+    /**
+     * The topics attribute in the component metadata.
+     */
+    public static final String TOPICS_ATTRIBUTE = "topics";
+
+    /**
+     * The synchronous attribute in the component metadata.
+     */
+    public static final String SYNCHRONOUS_ATTRIBUTE = "synchronous";
+
+    /**
+     * The data key attribute in the component metadata.
+     */
+    public static final String DATA_KEY_ATTRIBUTE = "data-key";
+
+    // Default values
+
+    /**
+     * The data key attribute's default value.
+     */
+    public static final String DEFAULT_DATA_KEY_VALUE = "user.data";
+
+    /**
+     * The synchronous attribute's default value.
+     */
+    public static final boolean DEFAULT_SYNCHRONOUS_VALUE = false;
+
+    /**
+     * The name which acts as an identifier.
+     */
+    private final String m_name;
+
+    /**
+     * The name of the field representing the publisher in the component.
+     */
+    private final String m_field;
+
+    /**
+     * Topics to which events are sent.
+     */
+    private String[] m_topics;
+
+    /**
+     * Events sending mode.
+     */
+    private final boolean m_synchronous;
+
+    /**
+     * The key where user data are stored in the event dictionary.
+     */
+    private final String m_dataKey;
+
+    /**
+     * Construct a publisher from its metadata description.
+     * 
+     * @param publisher :
+     *            publisher metadata description.
+     * @throws ConfigurationException
+     *             if the configuration of the component or the instance is
+     *             invalid.
+     */
+    public EventAdminPublisherMetadata(Element publisher)
+        throws ConfigurationException {
+
+        /**
+         * Setup required attributes
+         */
+
+        // NAME_ATTRIBUTE
+        if (publisher.containsAttribute(NAME_ATTRIBUTE)) {
+            m_name = publisher.getAttribute(NAME_ATTRIBUTE);
+        } else {
+            throw new ConfigurationException(
+                    "Missing required attribute in component configuration : "
+                            + NAME_ATTRIBUTE);
+        }
+
+        // FIELD_ATTRIBUTE
+        if (publisher.containsAttribute(FIELD_ATTRIBUTE)) {
+            m_field = publisher.getAttribute(FIELD_ATTRIBUTE);
+        } else {
+            throw new ConfigurationException(
+                    "Missing required attribute in component configuration : "
+                            + FIELD_ATTRIBUTE);
+        }
+
+        // TOPICS_ATTRIBUTE
+        if (publisher.containsAttribute(TOPICS_ATTRIBUTE)) {
+            m_topics = ParseUtils.split(publisher
+                    .getAttribute(TOPICS_ATTRIBUTE), ",");
+            // Check each topic is valid
+            Dictionary empty = new Hashtable();
+            for (int i = 0; i < m_topics.length; i++) {
+                String topic = m_topics[i];
+                try {
+                    new Event(topic, empty);
+                } catch (IllegalArgumentException e) {
+                    throw new ConfigurationException("Malformed topic : "
+                            + topic);
+                }
+            }
+
+        } else {
+            m_topics = null;
+            // Nothing to do if TOPICS_ATTRIBUTE is not present as it can be
+            // overridden in the instance configuration.
+        }
+
+        /**
+         * Setup optional attributes
+         */
+
+        // SYNCHRONOUS_ATTRIBUTE
+        if (publisher.containsAttribute(SYNCHRONOUS_ATTRIBUTE)) {
+            m_synchronous = "true".equalsIgnoreCase(publisher
+                    .getAttribute(SYNCHRONOUS_ATTRIBUTE));
+        } else {
+            m_synchronous = DEFAULT_SYNCHRONOUS_VALUE;
+        }
+
+        // DATA_KEY_ATTRIBUTE
+        if (publisher.containsAttribute(DATA_KEY_ATTRIBUTE)) {
+            m_dataKey = publisher.getAttribute(DATA_KEY_ATTRIBUTE);
+        } else {
+            m_dataKey = DEFAULT_DATA_KEY_VALUE;
+        }
+    }
+
+    /**
+     * Set the topics attribute of the publisher.
+     * 
+     * @param topicsString
+     *            the comma separated list of the topics on which events are
+     *            sent
+     * @throws ConfigurationException
+     *             the specified topic string is malformed
+     */
+    public void setTopics(String topicsString)
+        throws ConfigurationException {
+        m_topics = ParseUtils.split(topicsString, ",");
+        // Check each topic is valid
+        Dictionary empty = new Hashtable();
+        for (int i = 0; i < m_topics.length; i++) {
+            String topic = m_topics[i];
+            try {
+                new Event(topic, empty);
+            } catch (IllegalArgumentException e) {
+                throw new ConfigurationException("Malformed topic : " + topic);
+            }
+        }
+
+    }
+
+    /**
+     * Check that the required instance configurable attributes are all set.
+     * 
+     * @throws ConfigurationException
+     *             if a required attribute is missing
+     */
+    public void check()
+        throws ConfigurationException {
+        if (m_topics == null || m_topics.length == 0) {
+            throw new ConfigurationException(
+                    "Missing required attribute in component or instance configuration : "
+                            + TOPICS_ATTRIBUTE);
+        }
+    }
+
+    /**
+     * Get the name attribute of the publisher.
+     * 
+     * @return the name
+     */
+    public String getName() {
+        return m_name;
+    }
+
+    /**
+     * Get the field attribute of the publisher.
+     * 
+     * @return the field
+     */
+    public String getField() {
+        return m_field;
+    }
+
+    /**
+     * Get the topics attribute of the publisher.
+     * 
+     * @return the topics
+     */
+    public String[] getTopics() {
+        return m_topics;
+    }
+
+    /**
+     * Get the synchronous attribute of the publisher.
+     * 
+     * @return the synchronous
+     */
+    public boolean isSynchronous() {
+        return m_synchronous;
+    }
+
+    /**
+     * Get the dataKey attribute of the publisher.
+     * 
+     * @return the dataKey
+     */
+    public String getDataKey() {
+        return m_dataKey;
+    }
+}
diff --git a/ipojo/handler/eventadmin/src/main/java/org/apache/felix/ipojo/handlers/event/publisher/PublisherImpl.java b/ipojo/handler/eventadmin/src/main/java/org/apache/felix/ipojo/handlers/event/publisher/PublisherImpl.java
index 265c0a5..17c068f 100644
--- a/ipojo/handler/eventadmin/src/main/java/org/apache/felix/ipojo/handlers/event/publisher/PublisherImpl.java
+++ b/ipojo/handler/eventadmin/src/main/java/org/apache/felix/ipojo/handlers/event/publisher/PublisherImpl.java
@@ -1,139 +1,124 @@
-/* 

- * 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.handlers.event.publisher;

-

-import java.util.Dictionary;

-import java.util.Hashtable;

-

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

-

-/**

- * The PublisherImpl class is the implementation of the Publisher object used by

- * components to send events.

- * 

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

- */

-public class PublisherImpl implements Publisher {

-

-    /**

-     * The key where the component instance name is stored.

-     */

-    public static final String INSTANCE_NAME_PROPERTY = "publisher.instance.name";

-

-    /**

-     * The managing handler.

-     */

-    private EventAdminPublisherHandler m_handler;

-

-    /**

-     * The topics of sent events.

-     */

-    private final String[] m_topics;

-

-    /**

-     * The sending mode of events.

-     */

-    private final boolean m_synchronous;

-

-    /**

-     * The key, in the content of the event, where user data are stored.

-     */

-    private final String m_dataKey;

-

-    /**

-     * The name of the component instance using this publisher.

-     */

-    private final String m_instanceName;

-

-    /**

-     * Construct an Publisher with given parameters.

-     * 

-     * @param handler

-     *            the handler that will manage this publisher

-     * @param topics

-     *            the topics on which events are sent

-     * @param synchronous

-     *            the sending mode of events

-     * @param dataKey

-     *            The key, in the content of the event, where user data are

-     *            stored (may be {@code null})

-     * @param instanceName

-     *            the name of the instance creating this publisher.

-     */

-    public PublisherImpl(EventAdminPublisherHandler handler, String[] topics,

-            boolean synchronous, String dataKey, String instanceName) {

-

-        // Check parameters

-        if (topics.length == 0) {

-            throw new IllegalArgumentException(

-                    "At least one topic must be specified");

-        }

-        // Test validity of each topic

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

-            try {

-                new Event(topics[i], null);

-            } catch (IllegalArgumentException e) {

-                throw new IllegalArgumentException("Malformed topic : "

-                        + e.getMessage());

-            }

-        }

-

-        // Initialize the publisher's fields

-        m_handler = handler;

-        m_topics = topics;

-        m_synchronous = synchronous;

-        m_dataKey = dataKey;

-        m_instanceName = instanceName;

-    }

-

-    /**

-     * Send an event with the specified content.

-     * 

-     * @param content

-     *            the content of the event

-     */

-    public void send(Dictionary content) {

-        // Add instance information in the event

-        content.put(INSTANCE_NAME_PROPERTY, m_instanceName);

-        // We sent the event on each topic

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

-            // Create an event with the given topic and content

-            Event e = new Event(m_topics[i], content);

-            // Send the event, depending on the sending mode

-            if (!m_synchronous) {

-                m_handler.getEventAdminService().postEvent(e); // Asynchronous

-            } else {

-                m_handler.getEventAdminService().sendEvent(e); // Synchronous

-            }

-        }

-    }

-

-    /**

-     * Send a data event.

-     * 

-     * @param object

-     *            the data to send

-     */

-    public void sendData(Object object) {

-        // Construct the content of the event with the given object

-        Dictionary content = new Hashtable();

-        content.put(m_dataKey, object);

-        send(content);

-    }

-}

+/* 
+ * 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.handlers.event.publisher;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+import org.osgi.service.event.Event;
+
+/**
+ * The PublisherImpl class is the implementation of the Publisher object used by
+ * components to send events.
+ * 
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class PublisherImpl implements Publisher {
+
+    /**
+     * The key where the component instance name is stored.
+     */
+    public static final String INSTANCE_NAME_PROPERTY = "publisher.instance.name";
+
+    /**
+     * The managing handler.
+     */
+    private EventAdminPublisherHandler m_handler;
+
+    /**
+     * The topics of sent events.
+     */
+    private final String[] m_topics;
+
+    /**
+     * The sending mode of events.
+     */
+    private final boolean m_synchronous;
+
+    /**
+     * The key, in the content of the event, where user data are stored.
+     */
+    private final String m_dataKey;
+
+    /**
+     * The name of the component instance using this publisher.
+     */
+    private final String m_instanceName;
+
+    /**
+     * Construct an Publisher with given parameters.
+     * 
+     * @param handler
+     *            the handler that will manage this publisher
+     * @param topics
+     *            the topics on which events are sent
+     * @param synchronous
+     *            the sending mode of events
+     * @param dataKey
+     *            The key, in the content of the event, where user data are
+     *            stored (may be {@code null})
+     * @param instanceName
+     *            the name of the instance creating this publisher.
+     */
+    public PublisherImpl(EventAdminPublisherHandler handler, String[] topics,
+            boolean synchronous, String dataKey, String instanceName) {
+
+        // Initialize the publisher's fields
+        m_handler = handler;
+        m_topics = topics;
+        m_synchronous = synchronous;
+        m_dataKey = dataKey;
+        m_instanceName = instanceName;
+    }
+
+    /**
+     * Send an event with the specified content.
+     * 
+     * @param content
+     *            the content of the event
+     */
+    public void send(Dictionary content) {
+        // Add instance information in the event
+        content.put(INSTANCE_NAME_PROPERTY, m_instanceName);
+        // We sent the event on each topic
+        for (int i = 0; i < m_topics.length; i++) {
+            // Create an event with the given topic and content
+            Event e = new Event(m_topics[i], content);
+            // Send the event, depending on the sending mode
+            if (!m_synchronous) {
+                m_handler.getEventAdminService().postEvent(e); // Asynchronous
+            } else {
+                m_handler.getEventAdminService().sendEvent(e); // Synchronous
+            }
+        }
+    }
+
+    /**
+     * Send a data event.
+     * 
+     * @param object
+     *            the data to send
+     */
+    public void sendData(Object object) {
+        // Construct the content of the event with the given object
+        Dictionary content = new Hashtable();
+        content.put(m_dataKey, object);
+        send(content);
+    }
+}
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 d9e6cdc..ba81c2a 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,343 +1,409 @@
-/* 

- * 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.handlers.event.subscriber;

-

-import java.util.Collection;

-import java.util.Dictionary;

-import java.util.HashMap;

-import java.util.Hashtable;

-import java.util.Iterator;

-import java.util.Map;

-import java.util.Properties;

-import java.util.Set;

-import java.util.TreeSet;

-

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

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

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

-import org.apache.felix.ipojo.architecture.ComponentTypeDescription;

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

-import org.apache.felix.ipojo.handlers.event.EventUtil;

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

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

-import org.apache.felix.ipojo.parser.PojoMetadata;

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

-import org.osgi.framework.Filter;

-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.handlers.event.EventAdminHandler";

-

-    // Names of instance configuration properties.

-

-    /**

-     * The event's topics instance configuration property.

-     */

-    public static final String TOPICS_PROPERTY = "event.topics";

-

-    /**

-     * The event's filter instance configuration property.

-     */

-    public static final String FILTER_PROPERTY = "event.filter";

-

-    /**

-     * Prefix for logged messages.

-     */

-    private static final String LOG_PREFIX = "EVENT ADMIN SUBSCRIBER HANDLER : ";

-

-    /**

-     * Instance Manager.

-     */

-    private InstanceManager m_manager;

-

-    /**

-     * List of subscriber accessible by name.

-     */

-    private Map m_subscribersByName = new HashMap();

-

-    /**

-     * List of callbacks accessible by subscribers' names.

-     */

-    private Map m_callbacks = new Hashtable();

-

-    /**

-     * 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)

-     */

-    // @Override

-    public void initializeComponentFactory(ComponentTypeDescription cd,

-            Element metadata)

-        throws ConfigurationException {

-

-        // Update the current component description

-        Dictionary dict = new Properties();

-        cd.addProperty(new PropertyDescription(TOPICS_PROPERTY,

-                Dictionary.class.getName(), dict.toString()));

-        dict = new Properties();

-        cd.addProperty(new PropertyDescription(FILTER_PROPERTY,

-                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)

-     */

-    // @Override

-    public void configure(Element metadata, Dictionary conf)

-        throws ConfigurationException {

-

-        // Store the component manager

-        m_manager = getInstanceManager();

-

-        // Get Metadata subscribers

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

-

-        if (subscribers != null) {

-

-            // then check subscribers are well formed and fill the subscriber'

-            // map

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

-

-                try {

-                    // Extract the subscriber configuration

-                    EventAdminSubscriberMetadata subscriberMetadata = new EventAdminSubscriberMetadata(

-                            m_manager, subscribers[i], conf);

-                    String subscriberName = subscriberMetadata.getName();

-                    info(LOG_PREFIX + "configuring subscriber "

-                            + subscriberName);

-

-                    // Determine the callback prototype

-                    PojoMetadata pojoMetadata = getFactory().getPojoMetadata();

-                    String callbackType;

-                    if (subscriberMetadata.getDataKey() == null) {

-                        callbackType = Event.class.getName();

-                    } else {

-                        callbackType = subscriberMetadata.getDataType()

-                                .getName();

-                    }

-

-                    // Find the specified callback

-                    MethodMetadata methodMetadata = pojoMetadata.getMethod(

-                            subscriberMetadata.getCallback(),

-                            new String[] { callbackType });

-                    if (methodMetadata == null) {

-                        throw new ConfigurationException(

-                                "Unable to find callback "

-                                        + subscriberMetadata.getCallback()

-                                        + "(" + callbackType + ")");

-                    }

-                    Callback callback = new Callback(methodMetadata, m_manager);

-

-                    // Add the subscriber to the subscriber list and

-                    // register callback

-                    Object old;

-                    if ((old = m_subscribersByName.put(subscriberName,

-                            subscriberMetadata)) != null) {

-                        m_subscribersByName.put(subscriberName, old);

-                        throw new ConfigurationException("The subscriber "

-                                + subscriberName + "already exists");

-                    }

-                    m_callbacks.put(subscriberName, callback);

-

-                } catch (Exception e) {

-                    // Ignore invalid subscribers

-                    warn(LOG_PREFIX

-                            + "Ignoring subscriber : Error in configuration", e);

-                }

-            }

-        } else {

-            info(LOG_PREFIX + "no subscriber detected !");

-        }

-    }

-

-    /**

-     * Handler start method.

-     * 

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

-     */

-    // @Override

-    public void start() {

-

-        Set topics = new TreeSet();

-

-        // Build the topic to listen

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

-        if (!m_subscribersByName.isEmpty()) {

-            Collection subscribers = m_subscribersByName.values();

-            for (Iterator i = subscribers.iterator(); i.hasNext();) {

-                String[] subTopics = ((EventAdminSubscriberMetadata) i.next())

-                        .getTopics();

-                for (int j = 0; j < subTopics.length; j++) {

-                    topics.add(subTopics[j]);

-                }

-            }

-        }

-

-        m_topics = new String[topics.size()];

-        int i = 0;

-        for (Iterator iterator = topics.iterator(); iterator.hasNext();) {

-            String tmp = (String) iterator.next();

-            m_topics[i++] = tmp;

-        }

-    }

-

-    /**

-     * Handler stop method.

-     * 

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

-     */

-    // @Override

-    public void stop() {

-    }

-

-    /***************************************************************************

-     * OSGi EventHandler callback

-     **************************************************************************/

-

-    /**

-     * 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) {

-

-        // 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();

-

-            synchronized (this) {

-                // Check if the subscriber's topic and filter match

-                Filter filter = subscriberMetadata.getFilter();

-

-                if (EventUtil.matches(topic, subscriberMetadata.getTopics())

-                        && (filter == null || event.matches(filter))) {

-

-                    String name = subscriberMetadata.getName();

-                    String dataKey = subscriberMetadata.getDataKey();

-                    Callback callback = (Callback) m_callbacks.get(name);

-                    Object callbackParam;

-

-                    try {

-                        // Depending on the subscriber type...

-                        if (dataKey == null) {

-

-                            // 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

-                        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);

-                    }

-                }

-            }

-        }

-    }

-}

+/* 
+ * 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.handlers.event.subscriber;
+
+import java.util.Collection;
+import java.util.Dictionary;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import java.util.TreeSet;
+
+import org.apache.felix.ipojo.ConfigurationException;
+import org.apache.felix.ipojo.InstanceManager;
+import org.apache.felix.ipojo.PrimitiveHandler;
+import org.apache.felix.ipojo.architecture.ComponentTypeDescription;
+import org.apache.felix.ipojo.architecture.PropertyDescription;
+import org.apache.felix.ipojo.handlers.event.EventUtil;
+import org.apache.felix.ipojo.metadata.Element;
+import org.apache.felix.ipojo.parser.MethodMetadata;
+import org.apache.felix.ipojo.parser.PojoMetadata;
+import org.apache.felix.ipojo.util.Callback;
+import org.osgi.framework.Filter;
+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.handlers.event.EventAdminHandler";
+
+    // Names of instance configuration properties.
+
+    /**
+     * The event's topics instance configuration property.
+     */
+    public static final String TOPICS_PROPERTY = "event.topics";
+
+    /**
+     * The event's filter instance configuration property.
+     */
+    public static final String FILTER_PROPERTY = "event.filter";
+
+    /**
+     * Prefix for logged messages.
+     */
+    private static final String LOG_PREFIX = "EVENT ADMIN SUBSCRIBER HANDLER : ";
+
+    /**
+     * Instance Manager.
+     */
+    private InstanceManager m_manager;
+
+    /**
+     * List of subscriber accessible by name.
+     */
+    private Map m_subscribersByName = new HashMap();
+
+    /**
+     * List of callbacks accessible by subscribers' names.
+     */
+    private Map m_callbacksByName = new Hashtable();
+
+    /**
+     * iPOJO Properties representing all the topics.
+     */
+    private String[] m_topics;
+
+    /**
+     * Listen received events ?
+     */
+    private boolean m_isListening;
+
+    /**
+     * 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)
+     */
+    // @Override
+    public void initializeComponentFactory(ComponentTypeDescription cd,
+            Element metadata)
+        throws ConfigurationException {
+
+        // Update the current component description
+        Dictionary dict = new Properties();
+        cd.addProperty(new PropertyDescription(TOPICS_PROPERTY,
+                Dictionary.class.getName(), dict.toString()));
+        dict = new Properties();
+        cd.addProperty(new PropertyDescription(FILTER_PROPERTY,
+                Dictionary.class.getName(), dict.toString()));
+
+        // Get Metadata subscribers
+        Element[] subscribers = metadata.getElements("subscriber", NAMESPACE);
+        if (subscribers != null) {
+
+            // Maps used to check name and field are unique
+            Set nameSet = new HashSet();
+            Set callbackSet = new HashSet();
+
+            // Check all subscribers are well formed
+            for (int i = 0; i < subscribers.length; i++) {
+
+                // Check the subscriber configuration is correct by creating an
+                // unused subscriber metadata
+                EventAdminSubscriberMetadata subscriberMetadata = new EventAdminSubscriberMetadata(
+                        getFactory().getBundleContext(), subscribers[i]);
+
+                String name = subscriberMetadata.getName();
+                info(LOG_PREFIX + "checking subscriber " + name);
+
+                // Determine the event callback prototype
+                PojoMetadata pojoMetadata = getPojoMetadata();
+                String callbackType;
+                if (subscriberMetadata.getDataKey() == null) {
+                    callbackType = Event.class.getName();
+                } else {
+                    callbackType = subscriberMetadata.getDataType().getName();
+                }
+
+                // Check the event callback method is present
+                MethodMetadata methodMetadata = pojoMetadata.getMethod(
+                        subscriberMetadata.getCallback(),
+                        new String[] { callbackType });
+                String callbackSignature = subscriberMetadata.getCallback()
+                        + "(" + callbackType + ")";
+                if (methodMetadata == null) {
+                    throw new ConfigurationException(
+                            "Cannot find callback method " + callbackSignature);
+                }
+
+                // Warn if the same callback is used by several subscribers
+                if (callbackSet.contains(callbackSignature)) {
+                    warn("The callback method is already used by another subscriber : "
+                            + callbackSignature);
+                } else {
+                    callbackSet.add(callbackSignature);
+                }
+
+                // Check name is unique
+                if (nameSet.contains(name)) {
+                    throw new ConfigurationException(
+                            "A subscriber with the same name already exists : "
+                                    + name);
+                }
+                nameSet.add(name);
+            }
+        } else {
+            info(LOG_PREFIX + "no subscriber to check");
+        }
+    }
+
+    /**
+     * 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)
+     */
+    // @Override
+    public void configure(Element metadata, Dictionary conf)
+        throws ConfigurationException {
+
+        // Store the component manager
+        m_manager = getInstanceManager();
+
+        // Get the topics and filter instance configuration
+        Dictionary instanceTopics = (Dictionary) conf.get(TOPICS_PROPERTY);
+        Dictionary instanceFilter = (Dictionary) conf.get(FILTER_PROPERTY);
+
+        // Get Metadata subscribers
+        Element[] subscribers = metadata.getElements("subscriber", NAMESPACE);
+
+        // The topics to listen
+        Set topics = new TreeSet();
+
+        if (subscribers != null) {
+
+            // Configure all subscribers
+            for (int i = 0; i < subscribers.length; i++) {
+
+                // Extract the subscriber configuration
+                EventAdminSubscriberMetadata subscriberMetadata = new EventAdminSubscriberMetadata(
+                        m_manager.getContext(), subscribers[i]);
+                String name = subscriberMetadata.getName();
+                info(LOG_PREFIX + "configuring subscriber " + name);
+
+                // Get the topics instance configuration if redefined
+                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;
+                if (filterString != null) {
+                    subscriberMetadata.setFilter(filterString);
+                }
+
+                // Check the publisher is correctly configured
+                subscriberMetadata.check();
+
+                // Add this subscriber's topics to the global list
+                String[] subscriberTopics = subscriberMetadata.getTopics();
+                for (int j = 0; j < subscriberTopics.length; j++) {
+                    topics.add(subscriberTopics[j]);
+                }
+
+                // Determine the event callback prototype
+                PojoMetadata pojoMetadata = getPojoMetadata();
+                String callbackType;
+                if (subscriberMetadata.getDataKey() == null) {
+                    callbackType = Event.class.getName();
+                } else {
+                    callbackType = subscriberMetadata.getDataType().getName();
+                }
+
+                // Create the specified callback and register it
+                MethodMetadata methodMetadata = pojoMetadata.getMethod(
+                        subscriberMetadata.getCallback(),
+                        new String[] { callbackType });
+                Callback callback = new Callback(methodMetadata, m_manager);
+                m_callbacksByName.put(name, callback);
+
+                // Add the subscriber list gloal map
+                m_subscribersByName.put(name, subscriberMetadata);
+            }
+
+            // Construct the global topic list
+            m_topics = new String[topics.size()];
+            int i = 0;
+            for (Iterator iterator = topics.iterator(); iterator.hasNext();) {
+                String tmp = (String) iterator.next();
+                m_topics[i++] = tmp;
+            }
+
+        } else {
+            info(LOG_PREFIX + "no subscriber to configure");
+        }
+    }
+
+    /**
+     * Handler start method.
+     * 
+     * @see org.apache.felix.ipojo.Handler#start()
+     */
+    // @Override
+    public synchronized void start() {
+        m_isListening = true;
+    }
+
+    /**
+     * Handler stop method.
+     * 
+     * @see org.apache.felix.ipojo.Handler#stop()
+     */
+    // @Override
+    public synchronized void stop() {
+        m_isListening = false;
+    }
+
+    /***************************************************************************
+     * OSGi EventHandler callback
+     **************************************************************************/
+
+    /**
+     * 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) {
+
+        // 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();
+
+            synchronized (this) {
+                // Check if the subscriber's topic and filter match
+                Filter filter = subscriberMetadata.getFilter();
+
+                if (EventUtil.matches(topic, subscriberMetadata.getTopics())
+                        && (filter == null || event.matches(filter))) {
+
+                    String name = subscriberMetadata.getName();
+                    String dataKey = subscriberMetadata.getDataKey();
+                    Callback callback = (Callback) m_callbacksByName.get(name);
+                    Object callbackParam;
+
+                    try {
+                        // Depending on the subscriber type...
+                        if (dataKey == null) {
+
+                            // 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);
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/ipojo/handler/eventadmin/src/main/java/org/apache/felix/ipojo/handlers/event/subscriber/EventAdminSubscriberMetadata.java b/ipojo/handler/eventadmin/src/main/java/org/apache/felix/ipojo/handlers/event/subscriber/EventAdminSubscriberMetadata.java
index de221f4..01567e3 100644
--- a/ipojo/handler/eventadmin/src/main/java/org/apache/felix/ipojo/handlers/event/subscriber/EventAdminSubscriberMetadata.java
+++ b/ipojo/handler/eventadmin/src/main/java/org/apache/felix/ipojo/handlers/event/subscriber/EventAdminSubscriberMetadata.java
@@ -1,295 +1,310 @@
-/* 

- * 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.handlers.event.subscriber;

-

-import java.util.Dictionary;

-import java.util.Enumeration;

-

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

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

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

-import org.apache.felix.ipojo.parser.ParseUtils;

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

-import org.osgi.framework.Filter;

-import org.osgi.framework.InvalidSyntaxException;

-

-/**

- * Represent an subscriber.

- * 

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

- */

-class EventAdminSubscriberMetadata {

-

-    // Names of metadata attributes

-

-    /**

-     * The name attribute in the component metadata.

-     */

-    public static final String NAME_ATTRIBUTE = "name";

-

-    /**

-     * The callback attribute in the component metadata.

-     */

-    public static final String CALLBACK_ATTRIBUTE = "callback";

-

-    /**

-     * The topics attribute in the component metadata.

-     */

-    public static final String TOPICS_ATTRIBUTE = "topics";

-

-    /**

-     * The data key attribute in the component metadata.

-     */

-    public static final String DATA_KEY_ATTRIBUTE = "data-key";

-

-    /**

-     * The data type attribute in the component metadata.

-     */

-    public static final String DATA_TYPE_ATTRIBUTE = "data-type";

-

-    /**

-     * The filter attribute in the component metadata.

-     */

-    public static final String FILTER_ATTRIBUTE = "filter";

-

-    // Default values

-

-    /**

-     * The data type atttribute's default value.

-     */

-    public static final Class DEFAULT_DATA_TYPE_VALUE = java.lang.Object.class;

-

-    /**

-     * The name which acts as an identifier.

-     */

-    private final String m_name;

-

-    /**

-     * Name of the callback method.

-     */

-    private final String m_callback;

-

-    /**

-     * Listened topics.

-     */

-    private final String[] m_topics;

-

-    /**

-     * The key where user data are stored in the event dictionary.

-     */

-    private final String m_dataKey;

-

-    /**

-     * The type of received data.

-     */

-    private final Class m_dataType;

-

-    /**

-     * Event filter.

-     */

-    private final Filter m_filter;

-

-    /**

-     * The Instance Manager.

-     */

-    private final InstanceManager m_instanceManager;

-

-    /**

-     * Constructor.

-     * 

-     * @param instanceManager :

-     *            instance manager.

-     * @param subscriber :

-     *            subscriber metadata.

-     * @param instanceConf :

-     *            the configuration of the component instance

-     * @throws ConfigurationException

-     *             if the configuration of the component or the instance is

-     *             invalid.

-     */

-    public EventAdminSubscriberMetadata(InstanceManager instanceManager,

-            Element subscriber, Dictionary instanceConf)

-        throws ConfigurationException {

-

-        m_instanceManager = instanceManager;

-

-        /**

-         * Setup required attributes

-         */

-

-        // NAME_ATTRIBUTE

-        if (subscriber.containsAttribute(NAME_ATTRIBUTE)) {

-            m_name = subscriber.getAttribute(NAME_ATTRIBUTE);

-        } else {

-            throw new ConfigurationException(

-                    "Missing required attribute in component configuration : "

-                            + NAME_ATTRIBUTE);

-        }

-

-        // CALLBACK_ATTRIBUTE

-        if (subscriber.containsAttribute(CALLBACK_ATTRIBUTE)) {

-            m_callback = subscriber.getAttribute(CALLBACK_ATTRIBUTE);

-        } else {

-            throw new ConfigurationException(

-                    "Missing required attribute in component configuration : "

-                            + CALLBACK_ATTRIBUTE);

-        }

-

-        // TOPICS_ATTRIBUTE

-        String topicsString = null;

-        if (subscriber.containsAttribute(TOPICS_ATTRIBUTE)) {

-            topicsString = subscriber.getAttribute(TOPICS_ATTRIBUTE);

-        }

-        // Check TOPICS_PROPERTY in the instance configuration

-        Dictionary instanceTopics = (Dictionary) instanceConf

-                .get(EventAdminSubscriberHandler.TOPICS_PROPERTY);

-        if (instanceTopics != null) {

-            Enumeration e = instanceTopics.keys();

-            while (e.hasMoreElements()) {

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

-                if (m_name.equals(myName)) {

-                    topicsString = (String) instanceTopics.get(myName);

-                    break;

-                }

-            }

-        }

-        if (topicsString != null) {

-            m_topics = ParseUtils.split(topicsString, ",");

-        } else {

-            throw new ConfigurationException(

-                    "Missing required attribute in component or instance configuration : "

-                            + TOPICS_ATTRIBUTE);

-        }

-

-        /**

-         * Setup optional attributes

-         */

-

-        // DATA_KEY_ATTRIBUTE

-        m_dataKey = subscriber.getAttribute(DATA_KEY_ATTRIBUTE);

-        if (subscriber.containsAttribute(DATA_TYPE_ATTRIBUTE)) {

-            Class type;

-            try {

-                type = m_instanceManager.getContext().getBundle().loadClass(

-                        subscriber.getAttribute(DATA_TYPE_ATTRIBUTE));

-            } catch (ClassNotFoundException e) {

-                m_instanceManager

-                        .getFactory()

-                        .getLogger()

-                        .log(

-                                Logger.WARNING,

-                                "Ignoring data-type (using default) : Malformed attribute in metadata",

-                                e);

-                type = DEFAULT_DATA_TYPE_VALUE;

-            }

-            m_dataType = type;

-        } else {

-            m_dataType = DEFAULT_DATA_TYPE_VALUE;

-        }

-

-        // FILTER_ATTRIBUTE

-        String filterString = null;

-        if (subscriber.containsAttribute(FILTER_ATTRIBUTE)) {

-            filterString = subscriber.getAttribute(FILTER_ATTRIBUTE);

-        }

-        // Check FILTER_PROPERTY in the instance configuration

-        Dictionary instanceFilter = (Dictionary) instanceConf

-                .get(EventAdminSubscriberHandler.FILTER_PROPERTY);

-        if (instanceFilter != null) {

-            Enumeration e = instanceFilter.keys();

-            while (e.hasMoreElements()) {

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

-                if (m_name.equals(myName)) {

-                    filterString = (String) instanceFilter.get(myName);

-                    break;

-                }

-            }

-        }

-        Filter filter;

-        if (filterString != null) {

-            try {

-                filter = m_instanceManager.getContext().createFilter(

-                        filterString);

-            } catch (InvalidSyntaxException e) {

-                // Ignore filter if malformed

-                m_instanceManager.getFactory().getLogger().log(Logger.WARNING,

-                        "Ignoring filter : Malformed attribute in metadata", e);

-                filter = null;

-            }

-        } else {

-            filter = null;

-        }

-        m_filter = filter;

-    }

-

-    /**

-     * Get the name attribute of the subscriber.

-     * 

-     * @return the name

-     */

-    public String getName() {

-        return m_name;

-    }

-

-    /**

-     * Get the topics attribute of the subscriber.

-     * 

-     * @return the topics

-     */

-    public String[] getTopics() {

-        return m_topics;

-    }

-

-    /**

-     * Get the callback attribute of the subscriber.

-     * 

-     * @return the callback

-     */

-    public String getCallback() {

-        return m_callback;

-    }

-

-    /**

-     * Get the data key attribute of the subscriber.

-     * 

-     * @return the dataKey

-     */

-    public String getDataKey() {

-        return m_dataKey;

-    }

-

-    /**

-     * Get the data type attribute of the subscriber.

-     * 

-     * @return the dataType

-     */

-    public Class getDataType() {

-        return m_dataType;

-    }

-

-    /**

-     * Get the filter attribute of the subscriber.

-     * 

-     * @return the filter

-     */

-    public Filter getFilter() {

-        return m_filter;

-    }

-

-}

+/* 
+ * 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.handlers.event.subscriber;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+import org.apache.felix.ipojo.ConfigurationException;
+import org.apache.felix.ipojo.metadata.Element;
+import org.apache.felix.ipojo.parser.ParseUtils;
+import org.osgi.framework.BundleContext;
+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 {
+
+    // Names of metadata attributes
+
+    /**
+     * The name attribute in the component metadata.
+     */
+    public static final String NAME_ATTRIBUTE = "name";
+
+    /**
+     * The callback attribute in the component metadata.
+     */
+    public static final String CALLBACK_ATTRIBUTE = "callback";
+
+    /**
+     * The topics attribute in the component metadata.
+     */
+    public static final String TOPICS_ATTRIBUTE = "topics";
+
+    /**
+     * The data key attribute in the component metadata.
+     */
+    public static final String DATA_KEY_ATTRIBUTE = "data-key";
+
+    /**
+     * The data type attribute in the component metadata.
+     */
+    public static final String DATA_TYPE_ATTRIBUTE = "data-type";
+
+    /**
+     * The filter attribute in the component metadata.
+     */
+    public static final String FILTER_ATTRIBUTE = "filter";
+
+    // Default values
+
+    /**
+     * The data type atttribute's default value.
+     */
+    public static final Class DEFAULT_DATA_TYPE_VALUE = java.lang.Object.class;
+
+    /**
+     * The name which acts as an identifier.
+     */
+    private final String m_name;
+
+    /**
+     * Name of the callback method.
+     */
+    private final String m_callback;
+
+    /**
+     * Listened topics.
+     */
+    private String[] m_topics;
+
+    /**
+     * The key where user data are stored in the event dictionary.
+     */
+    private final String m_dataKey;
+
+    /**
+     * The type of received data.
+     */
+    private final Class m_dataType;
+
+    /**
+     * Event filter.
+     */
+    private Filter m_filter;
+
+    /**
+     * The context of the bundle.
+     */
+    private final BundleContext m_bundleContext;
+
+    /**
+     * Constructor.
+     * 
+     * @param bundleContext : bundle context of the managed instance.
+     * @param subscriber : subscriber metadata.
+     * @throws ConfigurationException
+     *             if the configuration of the component or the instance is
+     *             invalid.
+     */
+    public EventAdminSubscriberMetadata(BundleContext bundleContext,
+            Element subscriber)
+        throws ConfigurationException {
+
+        m_bundleContext = bundleContext;
+
+        /**
+         * Setup required attributes
+         */
+
+        // NAME_ATTRIBUTE
+        if (subscriber.containsAttribute(NAME_ATTRIBUTE)) {
+            m_name = subscriber.getAttribute(NAME_ATTRIBUTE);
+        } else {
+            throw new ConfigurationException(
+                    "Missing required attribute in component configuration : "
+                            + NAME_ATTRIBUTE);
+        }
+
+        // CALLBACK_ATTRIBUTE
+        if (subscriber.containsAttribute(CALLBACK_ATTRIBUTE)) {
+            m_callback = subscriber.getAttribute(CALLBACK_ATTRIBUTE);
+        } else {
+            throw new ConfigurationException(
+                    "Missing required attribute in component configuration : "
+                            + CALLBACK_ATTRIBUTE);
+        }
+
+        // TOPICS_ATTRIBUTE
+        if (subscriber.containsAttribute(TOPICS_ATTRIBUTE)) {
+            m_topics = ParseUtils.split(subscriber
+                    .getAttribute(TOPICS_ATTRIBUTE), ",");
+            // Check each topic is valid
+            Dictionary empty = new Hashtable();
+            for (int i = 0; i < m_topics.length; i++) {
+                String topic = m_topics[i];
+                try {
+                    new Event(topic, empty);
+                } catch (IllegalArgumentException e) {
+                    throw new ConfigurationException("Malformed topic : "
+                            + topic);
+                }
+            }
+        } else {
+            m_topics = null;
+            // Nothing to do if TOPICS_ATTRIBUTE is not present as it can be
+            // overridden in the instance configuration.
+        }
+
+        /**
+         * Setup optional attributes
+         */
+
+        // DATA_KEY_ATTRIBUTE
+        m_dataKey = subscriber.getAttribute(DATA_KEY_ATTRIBUTE);
+        if (subscriber.containsAttribute(DATA_TYPE_ATTRIBUTE)) {
+            Class type;
+            String typeName = subscriber.getAttribute(DATA_TYPE_ATTRIBUTE);
+            try {
+                type = m_bundleContext.getBundle().loadClass(typeName);
+            } catch (ClassNotFoundException e) {
+                throw new ConfigurationException("Data type class not found : "
+                        + typeName);
+            }
+            m_dataType = type;
+        } else {
+            m_dataType = DEFAULT_DATA_TYPE_VALUE;
+        }
+
+        // FILTER_ATTRIBUTE
+        if (subscriber.containsAttribute(FILTER_ATTRIBUTE)) {
+            try {
+                m_filter = m_bundleContext.createFilter(subscriber
+                        .getAttribute(FILTER_ATTRIBUTE));
+            } catch (InvalidSyntaxException e) {
+                throw new ConfigurationException("Invalid filter syntax");
+            }
+        }
+    }
+
+    /**
+     * Set the topics attribute of the subscriber.
+     * 
+     * @param topicsString
+     *            the comma separated list of the topics to listen
+     * @throws ConfigurationException
+     *             the specified topic list is malformed
+     */
+    public void setTopics(String topicsString)
+        throws ConfigurationException {
+        m_topics = ParseUtils.split(topicsString, ",");
+        // Check each topic is valid
+        Dictionary empty = new Hashtable();
+        for (int i = 0; i < m_topics.length; i++) {
+            String topic = m_topics[i];
+            try {
+                new Event(topic, empty);
+            } catch (IllegalArgumentException e) {
+                throw new ConfigurationException("Malformed topic : " + topic);
+            }
+        }
+    }
+
+    /**
+     * Set the filter attribute of the subscriber.
+     * 
+     * @param filterString
+     *            the string representation of the event filter
+     * @throws ConfigurationException : the LDAP filter is malformed
+     */
+    public void setFilter(String filterString)
+        throws ConfigurationException {
+        try {
+            m_filter = m_bundleContext.createFilter(filterString);
+        } catch (InvalidSyntaxException e) {
+            throw new ConfigurationException("Invalid filter syntax");
+        }
+    }
+
+    /**
+     * Check that the required instance configurable attributes are all set.
+     * 
+     * @throws ConfigurationException
+     *             if a required attribute is missing
+     */
+    public void check()
+        throws ConfigurationException {
+        if (m_topics == null || m_topics.length == 0) {
+            throw new ConfigurationException(
+                    "Missing required attribute in component or instance configuration : "
+                            + TOPICS_ATTRIBUTE);
+        }
+    }
+
+    /**
+     * Get the name attribute of the subscriber.
+     * 
+     * @return the name
+     */
+    public String getName() {
+        return m_name;
+    }
+
+    /**
+     * Get the topics attribute of the subscriber.
+     * 
+     * @return the topics
+     */
+    public String[] getTopics() {
+        return m_topics;
+    }
+
+    /**
+     * Get the callback attribute of the subscriber.
+     * 
+     * @return the callback
+     */
+    public String getCallback() {
+        return m_callback;
+    }
+
+    /**
+     * Get the data key attribute of the subscriber.
+     * 
+     * @return the dataKey
+     */
+    public String getDataKey() {
+        return m_dataKey;
+    }
+
+    /**
+     * Get the data type attribute of the subscriber.
+     * 
+     * @return the dataType
+     */
+    public Class getDataType() {
+        return m_dataType;
+    }
+
+    /**
+     * Get the filter attribute of the subscriber.
+     * 
+     * @return the filter
+     */
+    public Filter getFilter() {
+        return m_filter;
+    }
+
+}