Fix the Felix-794 issue
The event admin handler now accepts to receive events on topics containing a '*' (at the end). 

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@707659 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/ipojo/core/src/main/java/org/apache/felix/ipojo/util/DependencyModel.java b/ipojo/core/src/main/java/org/apache/felix/ipojo/util/DependencyModel.java
index 364f554..0ed7051 100644
--- a/ipojo/core/src/main/java/org/apache/felix/ipojo/util/DependencyModel.java
+++ b/ipojo/core/src/main/java/org/apache/felix/ipojo/util/DependencyModel.java
@@ -24,7 +24,6 @@
 import java.util.List;

 

 import org.apache.felix.ipojo.ConfigurationException;

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

 import org.apache.felix.ipojo.context.ServiceReferenceImpl;

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

 import org.osgi.framework.BundleContext;

diff --git a/ipojo/handler/eventadmin/src/main/java/org/apache/felix/ipojo/handlers/event/EventUtil.java b/ipojo/handler/eventadmin/src/main/java/org/apache/felix/ipojo/handlers/event/EventUtil.java
index 502a0d7..c67f9cd 100644
--- a/ipojo/handler/eventadmin/src/main/java/org/apache/felix/ipojo/handlers/event/EventUtil.java
+++ b/ipojo/handler/eventadmin/src/main/java/org/apache/felix/ipojo/handlers/event/EventUtil.java
@@ -18,6 +18,8 @@
  */
 package org.apache.felix.ipojo.handlers.event;
 
+import org.apache.felix.ipojo.parser.ParseUtils;
+
 /**
  * Utility methods.
  * 
@@ -25,40 +27,153 @@
  */
 public class EventUtil {
 
-    /**
-     * Tests that the given topic match with the given topic pattern.
-     * 
-     * @param topic the topic to test
-     * @param topicPattern the topic pattern
-     * @return true if it matches.
-     */
-    public static boolean matches(String topic, String topicPattern) {
-        if (topicPattern.equals("*")) {
-            return true;
-        }
-        int star;
-        if ((star = topicPattern.indexOf("*")) > 0) {
-            return topic.startsWith(topicPattern.substring(0, star - 1));
-        } else {
-            return topic.equals(topicPattern);
-        }
-    }
+	/**
+	 * The separator between topics.
+	 */
+	public static final String TOPIC_SEPARATOR = ",";
 
-    /**
-     * Tests that the given topic match with the given topic patterns.
-     * 
-     * @param topic the topic to test
-     * @param topicPatterns the topic patterns
-     * @return true if it matches.
-     */
-    public static boolean matches(String topic, String[] topicPatterns) {
-        int n = topicPatterns.length;
-        for (int i = 0; i < n; i++) {
-            if (matches(topic, topicPatterns[i])) {
-                return true;
-            }
-        }
-        return false;
-    }
+	/**
+	 * The separator between topics.
+	 */
+	public static final String TOPIC_TOKEN_SEPARATOR = "/";
+
+	/**
+	 * The topic token alphabet.
+	 */
+	private static final String tokenAlphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-";
+
+	/**
+	 * Tests that the given topic match with the given topic pattern.
+	 * 
+	 * @param topic
+	 *            the topic to test
+	 * @param topicPattern
+	 *            the topic pattern
+	 * @return true if it matches.
+	 */
+	public static final boolean matches(String topic, String topicPattern) {
+		if (topicPattern.equals("*")) {
+			return true;
+		}
+		int star;
+		if ((star = topicPattern.indexOf("*")) > 0) {
+			return topic.startsWith(topicPattern.substring(0, star - 1));
+		} else {
+			return topic.equals(topicPattern);
+		}
+	}
+
+	/**
+	 * Tests that the given topic match with the given topic patterns.
+	 * 
+	 * @param topic
+	 *            the topic to test
+	 * @param topicPatterns
+	 *            the topic patterns
+	 * @return true if it matches.
+	 */
+	public static final boolean matches(String topic, String[] topicPatterns) {
+		int n = topicPatterns.length;
+		for (int i = 0; i < n; i++) {
+			if (matches(topic, topicPatterns[i])) {
+				return true;
+			}
+		}
+		return false;
+	}
+
+	/**
+	 * Check the given topic scope is valid.
+	 * 
+	 * topicScope ::= "*" | ( topic "/*" ? )
+	 * 
+	 * @param topicScope
+	 *            the topic scope to check.
+	 * 
+	 * @return {@code true} if the given topic scope is valid, {@code false}
+	 *         otherwise.
+	 */
+	public static final boolean isValidTopicScope(String topicScope) {
+		if (topicScope.equals("*")) {
+			// Wildcard character only accepted.
+			return true;
+		}
+		
+		// Remove trailing "/*" if present, to check the topic radix.
+		String topicWithoutWildcard;
+		if (topicScope.endsWith("/*")) {
+			topicWithoutWildcard = topicScope.substring(0, topicScope.length() - 2);
+		} else {
+			topicWithoutWildcard = topicScope;
+		}
+		
+		// Validate the topic radix.
+		return isValidTopic(topicWithoutWildcard);
+	}
+
+	/**
+	 * Check the given topic is valid.
+	 * 
+	 * topic ::= token ( ’/’ token ) *
+	 * 
+	 * @param topic
+	 *            the topic to check.
+	 * 
+	 * @return {@code true} if the given topic is valid, {@code false}
+	 *         otherwise.
+	 */
+	public static final boolean isValidTopic(String topic) {
+		if (topic.startsWith(TOPIC_TOKEN_SEPARATOR)
+				|| topic.endsWith(TOPIC_TOKEN_SEPARATOR)) {
+			// A topic cannot start nor end with '/'.
+			return false;
+		}
+
+		String[] tokens = ParseUtils.split(topic, TOPIC_TOKEN_SEPARATOR);
+		if (tokens.length < 1) {
+			// A topic must contain at least one token.
+			return false;
+		}
+
+		// Check each token is valid.
+		for (int i = 0; i < tokens.length; i++) {
+			String token = tokens[i];
+			if (!isValidToken(token)) {
+				return false;
+			}
+		}
+
+		// The topic is valid.
+		return true;
+	}
+
+	/**
+	 * Check the given token is valid.
+	 * 
+	 * token ::= ( alphanum | "_" | "-" )+
+	 * 
+	 * @param token
+	 *            the token to check.
+	 * 
+	 * @return {@code true} if the given topic token is valid, {@code false}
+	 *         otherwise.
+	 */
+	private static boolean isValidToken(String token) {
+		int length = token.length();
+		if (length < 1) {
+			// Token must contain at least one character.
+			return false;
+		}
+
+		for (int i = 0; i < length; i++) {
+			// Each character in the token must belong to the token alphabet.
+			if (tokenAlphabet.indexOf(token.charAt(i)) == -1) {
+				return false;
+			}
+		}
+
+		// The token is valid.
+		return true;
+	}
 
 }
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 9746d92..0e7431c 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
@@ -18,13 +18,10 @@
  */
 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.handlers.event.EventUtil;
 import org.apache.felix.ipojo.metadata.Element;
 import org.apache.felix.ipojo.parser.ParseUtils;
-import org.osgi.service.event.Event;
 
 /**
  * Represent a publisher.
@@ -33,221 +30,212 @@
  */
 class EventAdminPublisherMetadata {
 
-    // Names of metadata attributes
+	// Names of metadata attributes
 
-    /**
-     * The name attribute in the component metadata.
-     */
-    public static final String NAME_ATTRIBUTE = "name";
+	/**
+	 * 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 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 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 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";
+	/**
+	 * The data key attribute in the component metadata.
+	 */
+	public static final String DATA_KEY_ATTRIBUTE = "data-key";
 
-    // Default values
+	// Default values
 
-    /**
-     * The data key attribute's default value.
-     */
-    public static final String DEFAULT_DATA_KEY_VALUE = "user.data";
+	/**
+	 * 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 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 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;
+	/**
+	 * 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;
+	/**
+	 * Topics to which events are sent.
+	 */
+	private String[] m_topics;
 
-    /**
-     * Events sending mode.
-     */
-    private final boolean m_synchronous;
+	/**
+	 * Events sending mode.
+	 */
+	private final boolean m_synchronous;
 
-    /**
-     * The key where user data are stored in the event dictionary.
-     */
-    private final String m_dataKey;
+	/**
+	 * The key where user data are stored in the event dictionary.
+	 */
+	private final String m_dataKey;
 
-    /**
-     * Constructs a publisher from its metadata description.
-     * 
-     * @param publisher the publisher metadata description.
-     * @throws ConfigurationException if the configuration of the component or the instance is invalid.
-     */
-    public EventAdminPublisherMetadata(Element publisher)
-        throws ConfigurationException {
+	/**
+	 * Constructs a publisher from its metadata description.
+	 * 
+	 * @param publisher
+	 *            the 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
-         */
+		/**
+		 * 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);
-        }
+		// 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);
-        }
+		// 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);
-                }
-            }
+		// TOPICS_ATTRIBUTE
+		if (publisher.containsAttribute(TOPICS_ATTRIBUTE)) {
+			setTopics(publisher.getAttribute(TOPICS_ATTRIBUTE));
+		} else {
+			m_topics = null;
+			// Nothing to do if TOPICS_ATTRIBUTE is not present as it can be
+			// overridden in the instance configuration.
+		}
 
-        } 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
+		 */
 
-        /**
-         * Setup optional attributes
-         */
+		// SYNCHRONOUS_ATTRIBUTE
+		if (publisher.containsAttribute(SYNCHRONOUS_ATTRIBUTE)) {
+			m_synchronous = "true".equalsIgnoreCase(publisher
+					.getAttribute(SYNCHRONOUS_ATTRIBUTE));
+		} else {
+			m_synchronous = DEFAULT_SYNCHRONOUS_VALUE;
+		}
 
-        // 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;
+		}
+	}
 
-        // DATA_KEY_ATTRIBUTE
-        if (publisher.containsAttribute(DATA_KEY_ATTRIBUTE)) {
-            m_dataKey = publisher.getAttribute(DATA_KEY_ATTRIBUTE);
-        } else {
-            m_dataKey = DEFAULT_DATA_KEY_VALUE;
-        }
-    }
+	/**
+	 * Sets 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 {
+		String[] newTopics = ParseUtils.split(topicsString,
+				EventUtil.TOPIC_SEPARATOR);
+		// Check each topic is valid
+		for (int i = 0; i < newTopics.length; i++) {
+			String topic = newTopics[i];
+			if (!EventUtil.isValidTopic(topic)) {
+				throw new ConfigurationException("Invalid topic : \"" + topic
+						+ "\".");
+			}
+		}
+		m_topics = newTopics;
+	}
 
-    /**
-     * Sets 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);
-            }
-        }
+	/**
+	 * Checks 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);
+		}
+	}
 
-    }
+	/**
+	 * Gets the name attribute of the publisher.
+	 * 
+	 * @return the name
+	 */
+	public String getName() {
+		return m_name;
+	}
 
-    /**
-     * Checks 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);
-        }
-    }
+	/**
+	 * Gets the field attribute of the publisher.
+	 * 
+	 * @return the field
+	 */
+	public String getField() {
+		return m_field;
+	}
 
-    /**
-     * Gets the name attribute of the publisher.
-     * 
-     * @return the name
-     */
-    public String getName() {
-        return m_name;
-    }
+	/**
+	 * Gets the topics attribute of the publisher.
+	 * 
+	 * @return the topics
+	 */
+	public String[] getTopics() {
+		return m_topics;
+	}
 
-    /**
-     * Gets the field attribute of the publisher.
-     * 
-     * @return the field
-     */
-    public String getField() {
-        return m_field;
-    }
+	/**
+	 * Gets the synchronous attribute of the publisher.
+	 * 
+	 * @return the synchronous mode
+	 */
+	public boolean isSynchronous() {
+		return m_synchronous;
+	}
 
-    /**
-     * Gets the topics attribute of the publisher.
-     * 
-     * @return the topics
-     */
-    public String[] getTopics() {
-        return m_topics;
-    }
-
-    /**
-     * Gets the synchronous attribute of the publisher.
-     * 
-     * @return the synchronous mode
-     */
-    public boolean isSynchronous() {
-        return m_synchronous;
-    }
-
-    /**
-     * Gets the dataKey attribute of the publisher.
-     * 
-     * @return the data key
-     */
-    public String getDataKey() {
-        return m_dataKey;
-    }
+	/**
+	 * Gets the dataKey attribute of the publisher.
+	 * 
+	 * @return the data key
+	 */
+	public String getDataKey() {
+		return m_dataKey;
+	}
 }
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 c26d227..3883698 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
@@ -18,16 +18,13 @@
  */
 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.handlers.event.EventUtil;
 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.
@@ -36,269 +33,255 @@
  */
 class EventAdminSubscriberMetadata {
 
-    // Names of metadata attributes
+	// Names of metadata attributes
 
-    /**
-     * The name attribute in the component metadata.
-     */
-    public static final String NAME_ATTRIBUTE = "name";
+	/**
+	 * 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 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 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 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 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";
+	/**
+	 * The filter attribute in the component metadata.
+	 */
+	public static final String FILTER_ATTRIBUTE = "filter";
 
-    // Default values
+	// Default values
 
-    /**
-     * The data type atttribute's default value.
-     */
-    public static final Class DEFAULT_DATA_TYPE_VALUE = java.lang.Object.class;
+	/**
+	 * 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;
+	/**
+	 * The name which acts as an identifier.
+	 */
+	private final String m_name;
 
-    /**
-     * Name of the callback method.
-     */
-    private final String m_callback;
+	/**
+	 * Name of the callback method.
+	 */
+	private final String m_callback;
 
-    /**
-     * Listened topics.
-     */
-    private String[] m_topics;
+	/**
+	 * Listened topics.
+	 */
+	private String[] m_topics;
 
-    /**
-     * The key where user data are stored in the event dictionary.
-     */
-    private final String m_dataKey;
+	/**
+	 * 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;
+	/**
+	 * The type of received data.
+	 */
+	private final Class m_dataType;
 
-    /**
-     * Event filter.
-     */
-    private Filter m_filter;
+	/**
+	 * Event filter.
+	 */
+	private Filter m_filter;
 
-    /**
-     * The context of the bundle.
-     */
-    private final BundleContext m_bundleContext;
+	/**
+	 * The context of the bundle.
+	 */
+	private final BundleContext m_bundleContext;
 
-    /**
-     * Constructor.
-     * 
-     * @param bundleContext the bundle context of the managed instance.
-     * @param subscriber the subscriber metadata.
-     * @throws ConfigurationException if the configuration of the component or the instance is invalid.
-     */
-    public EventAdminSubscriberMetadata(BundleContext bundleContext,
-            Element subscriber)
-        throws ConfigurationException {
+	/**
+	 * Constructor.
+	 * 
+	 * @param bundleContext
+	 *            the bundle context of the managed instance.
+	 * @param subscriber
+	 *            the 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;
 
-        m_bundleContext = bundleContext;
+		/**
+		 * Setup required attributes
+		 */
 
-        /**
-         * 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);
+		}
 
-        // 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);
+		}
 
-        // 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)) {
+			setTopics(subscriber.getAttribute(TOPICS_ATTRIBUTE));
+		} else {
+			m_topics = null;
+			// Nothing to do if TOPICS_ATTRIBUTE is not present as it can be
+			// overridden in the instance configuration.
+		}
 
-        // 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
+		 */
 
-        /**
-         * 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;
+		}
 
-        // 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)) {
+			setFilter(subscriber.getAttribute(FILTER_ATTRIBUTE));
+		}
+	}
 
-        // 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");
-            }
-        }
-    }
+	/**
+	 * Sets the topics attribute of the subscriber.
+	 * 
+	 * @param topicsString
+	 *            the comma separated list of the topics to listen
+	 * @throws ConfigurationException
+	 *             if the specified topic list is malformed
+	 */
+	public void setTopics(String topicsString) throws ConfigurationException {
+		String[] newTopics = ParseUtils.split(topicsString,
+				EventUtil.TOPIC_SEPARATOR);
+		// Check each topic is valid
+		for (int i = 0; i < newTopics.length; i++) {
+			String topicScope = newTopics[i];
+			if (!EventUtil.isValidTopicScope(topicScope)) {
+				throw new ConfigurationException("Invalid topic scope : \""
+						+ topicScope + "\".");
+			}
+		}
+		m_topics = newTopics;
+	}
 
-    /**
-     * Sets the topics attribute of the subscriber.
-     * 
-     * @param topicsString the comma separated list of the topics to listen
-     * @throws ConfigurationException if  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);
-            }
-        }
-    }
+	/**
+	 * Sets the filter attribute of the subscriber.
+	 * 
+	 * @param filterString
+	 *            the string representation of the event filter
+	 * @throws ConfigurationException
+	 *             if 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");
+		}
+	}
 
-    /**
-     * Sets the filter attribute of the subscriber.
-     * 
-     * @param filterString the string representation of the event filter
-     * @throws ConfigurationException if 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");
-        }
-    }
+	/**
+	 * Checks 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);
+		}
+	}
 
-    /**
-     * Checks 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);
-        }
-    }
+	/**
+	 * Gets the name attribute of the subscriber.
+	 * 
+	 * @return the name
+	 */
+	public String getName() {
+		return m_name;
+	}
 
-    /**
-     * Gets the name attribute of the subscriber.
-     * 
-     * @return the name
-     */
-    public String getName() {
-        return m_name;
-    }
+	/**
+	 * Gets the topics attribute of the subscriber.
+	 * 
+	 * @return the topics
+	 */
+	public String[] getTopics() {
+		return m_topics;
+	}
 
-    /**
-     * Gets the topics attribute of the subscriber.
-     * 
-     * @return the topics
-     */
-    public String[] getTopics() {
-        return m_topics;
-    }
+	/**
+	 * Gets the callback attribute of the subscriber.
+	 * 
+	 * @return the callback
+	 */
+	public String getCallback() {
+		return m_callback;
+	}
 
-    /**
-     * Gets the callback attribute of the subscriber.
-     * 
-     * @return the callback
-     */
-    public String getCallback() {
-        return m_callback;
-    }
+	/**
+	 * Gets the data key attribute of the subscriber.
+	 * 
+	 * @return the dataKey
+	 */
+	public String getDataKey() {
+		return m_dataKey;
+	}
 
-    /**
-     * Gets the data key attribute of the subscriber.
-     * 
-     * @return the dataKey
-     */
-    public String getDataKey() {
-        return m_dataKey;
-    }
+	/**
+	 * Gets the data type attribute of the subscriber.
+	 * 
+	 * @return the dataType
+	 */
+	public Class getDataType() {
+		return m_dataType;
+	}
 
-    /**
-     * Gets the data type attribute of the subscriber.
-     * 
-     * @return the dataType
-     */
-    public Class getDataType() {
-        return m_dataType;
-    }
-
-    /**
-     * Gets the filter attribute of the subscriber.
-     * 
-     * @return the filter
-     */
-    public Filter getFilter() {
-        return m_filter;
-    }
-
+	/**
+	 * Gets the filter attribute of the subscriber.
+	 * 
+	 * @return the filter
+	 */
+	public Filter getFilter() {
+		return m_filter;
+	}
 }
diff --git a/ipojo/tests/handler/eventadmin/src/main/java/org/apache/felix/ipojo/test/BadTests.java b/ipojo/tests/handler/eventadmin/src/main/java/org/apache/felix/ipojo/test/BadTests.java
index ba0d1d0..07eb675 100644
--- a/ipojo/tests/handler/eventadmin/src/main/java/org/apache/felix/ipojo/test/BadTests.java
+++ b/ipojo/tests/handler/eventadmin/src/main/java/org/apache/felix/ipojo/test/BadTests.java
@@ -1,876 +1,964 @@
-/* 

- * 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.test;

-

-import java.util.Dictionary;

-import java.util.Hashtable;

-

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

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

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

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

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

-import org.apache.felix.ipojo.junit4osgi.OSGiTestCase;

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

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

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

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

-import org.apache.felix.ipojo.test.donut.Donut;

-import org.apache.felix.ipojo.test.donut.DonutConsumer;

-import org.apache.felix.ipojo.test.donut.DonutProvider;

-import org.apache.felix.ipojo.test.util.IPojoTestUtils;

-import org.osgi.framework.ServiceReference;

-

-/**

- * Test the good behaviour of the EventAdminHandler.

- * 

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

- */

-public class BadTests extends OSGiTestCase {

-

-    /**

-     * The namespace of the Event admin handler.

-     */

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

-

-    /**

-     * The available components.

-     */

-    private Element[] m_components;

-

-    /**

-     * The description of a component that uses an event publisher.

-     */

-    private Element m_provider;

-

-    /**

-     * The event publisher description.

-     */

-    private Element m_publisher;

-

-    /**

-     * The name attribute of the event publisher.

-     */

-    private Attribute m_publisherName;

-

-    /**

-     * The field attribute of the event publisher.

-     */

-    private Attribute m_publisherField;

-

-    /**

-     * The topics attribute of the event publisher.

-     */

-    private Attribute m_publisherTopics;

-

-    /**

-     * The data-key attribute of the event publisher.

-     */

-    private Attribute m_publisherDataKey;

-

-    /**

-     * The synchronous attribute of the event publisher.

-     */

-    private Attribute m_publisherSynchronous;

-

-    /**

-     * The description of a component that uses an event subscriber.

-     */

-    private Element m_consumer;

-

-    /**

-     * The event subscriber description.

-     */

-    private Element m_subscriber;

-

-    /**

-     * The name attribute of the event subscriber.

-     */

-    private Attribute m_subscriberName;

-

-    /**

-     * The callback attribute of the event subscriber.

-     */

-    private Attribute m_subscriberCallback;

-

-    /**

-     * The topics attribute of the event subscriber.

-     */

-    private Attribute m_subscriberTopics;

-

-    /**

-     * The data-key attribute of the event subscriber.

-     */

-    private Attribute m_subscriberDataKey;

-

-    /**

-     * The data-type attribute of the event subscriber.

-     */

-    private Attribute m_subscriberDataType;

-

-    private Element getManipulationForComponent(String compName) {

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

-            if (m_components[i].containsAttribute("name")

-                    && m_components[i].getAttribute("name").equals(compName)) {

-                return m_components[i].getElements("manipulation")[0];

-            }

-        }

-        return null;

-    }

-

-    /**

-     * Initialization before test cases.

-     * 

-     * Create all the instances

-     * 

-     */

-    public void setUp() {

-

-        /**

-         * Get the list of available components.

-         */

-        try {

-            String header = (String) context.getBundle().getHeaders().get(

-                    "iPOJO-Components");

-            m_components = ManifestMetadataParser.parseHeaderMetadata(header)

-                    .getElements("component");

-        } catch (ParseException e) {

-            fail("Parse Exception when parsing iPOJO-Component");

-        }

-

-        /**

-         * Initialize the standard publishing component (based on the

-         * asynchronous donut provider).

-         */

-        m_provider = new Element("component", "");

-        m_provider.addAttribute(new Attribute("className",

-                "org.apache.felix.ipojo.test.donut.DonutProviderImpl"));

-        m_provider.addAttribute(new Attribute("name",

-                "standard donut provider for bad tests"));

-

-        // The provided service of the publisher

-        Element providesDonutProvider = new Element("provides", "");

-        providesDonutProvider.addAttribute(new Attribute("interface",

-                "org.apache.felix.ipojo.test.donut.DonutProvider"));

-        Element providesDonutProviderProperty = new Element("property", "");

-        providesDonutProviderProperty

-                .addAttribute(new Attribute("name", "name"));

-        providesDonutProviderProperty.addAttribute(new Attribute("field",

-                "m_name"));

-        providesDonutProviderProperty.addAttribute(new Attribute("value",

-                "Unknown donut vendor"));

-        providesDonutProvider.addElement(providesDonutProviderProperty);

-        m_provider.addElement(providesDonutProvider);

-

-        // The event publisher, corresponding to the following description :

-        // <ev:publisher name="donut-publisher" field="m_publisher"

-        // topics="food/donuts" data-key="food" synchronous="false"/>

-        m_publisher = new Element("publisher", NAMESPACE);

-        m_publisherName = new Attribute("name", "donut-publisher");

-        m_publisherField = new Attribute("field", "m_publisher");

-        m_publisherTopics = new Attribute("topics", "food/donuts");

-        m_publisherDataKey = new Attribute("data-key", "food");

-        m_publisherSynchronous = new Attribute("synchronous", "false");

-        m_publisher.addAttribute(m_publisherName);

-        m_publisher.addAttribute(m_publisherField);

-        m_publisher.addAttribute(m_publisherTopics);

-        m_publisher.addAttribute(m_publisherDataKey);

-        m_publisher.addAttribute(m_publisherSynchronous);

-        m_provider.addElement(m_publisher);

-

-        m_provider.addElement(getManipulationForComponent("donut-provider"));

-

-        /**

-         * Initialize the standard subscribing component (based on the donut

-         * consumer).

-         */

-        m_consumer = new Element("component", "");

-        m_consumer.addAttribute(new Attribute("className",

-                "org.apache.felix.ipojo.test.donut.DonutConsumerImpl"));

-        m_consumer.addAttribute(new Attribute("name",

-                "standard donut consumer for bad tests"));

-

-        // The provided service of the publisher

-        Element providesDonutConsumer = new Element("provides", "");

-        providesDonutConsumer.addAttribute(new Attribute("interface",

-                "org.apache.felix.ipojo.test.donut.DonutConsumer"));

-        Element providesDonutConsumerNameProperty = new Element("property", "");

-        providesDonutConsumerNameProperty.addAttribute(new Attribute("name",

-                "name"));

-        providesDonutConsumerNameProperty.addAttribute(new Attribute("field",

-                "m_name"));

-        providesDonutConsumerNameProperty.addAttribute(new Attribute("value",

-                "Unknown donut consumer"));

-        providesDonutConsumer.addElement(providesDonutConsumerNameProperty);

-        Element providesDonutConsumerSlowProperty = new Element("property", "");

-        providesDonutConsumerSlowProperty.addAttribute(new Attribute("name",

-                "slow"));

-        providesDonutConsumerSlowProperty.addAttribute(new Attribute("field",

-                "m_isSlow"));

-        providesDonutConsumerSlowProperty.addAttribute(new Attribute("value",

-                "false"));

-        providesDonutConsumer.addElement(providesDonutConsumerSlowProperty);

-        m_consumer.addElement(providesDonutConsumer);

-

-        // The event publisher, corresponding to the following description :

-        // <ev:subscriber name="donut-subscriber" callback="receiveDonut"

-        // topics="food/donuts" data-key="food"

-        // data-type="org.apache.felix.ipojo.test.donut.Donut"/>

-        m_subscriber = new Element("subscriber", NAMESPACE);

-        m_subscriberName = new Attribute("name", "donut-subscriber");

-        m_subscriberCallback = new Attribute("callback", "receiveDonut");

-        m_subscriberTopics = new Attribute("topics", "food/donuts");

-        m_subscriberDataKey = new Attribute("data-key", "food");

-        m_subscriberDataType = new Attribute("data-type",

-                "org.apache.felix.ipojo.test.donut.Donut");

-        m_subscriber.addAttribute(m_subscriberName);

-        m_subscriber.addAttribute(m_subscriberCallback);

-        m_subscriber.addAttribute(m_subscriberTopics);

-        m_subscriber.addAttribute(m_subscriberDataKey);

-        m_subscriber.addAttribute(m_subscriberDataType);

-        m_consumer.addElement(m_subscriber);

-

-        m_consumer.addElement(getManipulationForComponent("donut-consumer"));

-    }

-

-    /**

-     * Test the base configuration is correct to be sure the bad tests will fail

-     * because of they are really bad, and not because of an other application

-     * error.

-     * 

-     * This test simply create a provider and a consumer instance, send one

-     * event and check it is received.

-     * 

-     * @throws ConfigurationException

-     *             something bad happened

-     * @throws MissingHandlerException

-     *             something bad happened

-     * @throws UnacceptableConfiguration

-     *             something bad happened

-     */

-    public void testGoodConfig()

-        throws ConfigurationException, UnacceptableConfiguration,

-        MissingHandlerException {

-        /**

-         * Create the provider and the consumer instances.

-         */

-        Dictionary properties = new Hashtable();

-

-        // Provider

-        ComponentFactory providerFactory = new ComponentFactory(context,

-                m_provider);

-        providerFactory.start();

-        properties.put("instance.name","Emperor of donuts");

-        ComponentInstance providerInstance = providerFactory

-                .createComponentInstance(properties);

-        ServiceReference providerService = IPojoTestUtils

-                .getServiceReferenceByName(context, DonutProvider.class

-                        .getName(), providerInstance.getInstanceName());

-        DonutProvider provider = (DonutProvider) context

-                .getService(providerService);

-

-        // The consumer

-        properties = new Hashtable();

-        ComponentFactory consumerFactory = new ComponentFactory(context,

-                m_consumer);

-        consumerFactory.start();

-        properties.put("instance.name","Homer Simpson");

-        properties.put("slow", "false");

-        ComponentInstance consumerInstance = consumerFactory

-                .createComponentInstance(properties);

-        ServiceReference consumerService = IPojoTestUtils

-                .getServiceReferenceByName(context, DonutConsumer.class

-                        .getName(), consumerInstance.getInstanceName());

-        DonutConsumer consumer = (DonutConsumer) context

-                .getService(consumerService);

-

-        /**

-         * Test the normal behaviour of the instances.

-         */

-        consumer.clearDonuts();

-        Donut sentDonut = provider.sellDonut();

-        Donut receivedDonut = consumer.waitForDonut();

-        assertEquals("The received donut must be the same as the sent one.",

-                sentDonut, receivedDonut);

-

-        /**

-         * Destroy component's instances.

-         */

-        context.ungetService(providerService);

-        providerInstance.dispose();

-        context.ungetService(consumerService);

-        consumerInstance.dispose();

-        providerFactory.stop();

-        consumerFactory.stop();

-    }

-

-    /**

-     * Try to create a publisher with no name.

-     * 

-     * @throws ConfigurationException

-     *             something bad happened

-     * @throws MissingHandlerException

-     *             something bad happened

-     * @throws UnacceptableConfiguration

-     *             something bad happened

-     */

-    public void testPublisherWithoutName()

-        throws ConfigurationException, MissingHandlerException,

-        UnacceptableConfiguration {

-

-        // Remove the name attribute of the publisher

-        m_publisher.removeAttribute(m_publisherName);

-

-        // Create and try to start the factory

-        ComponentFactory fact = new ComponentFactory(context, m_provider);

-        try {

-            fact.start();

-            // Should not be executed

-            fact.stop();

-            fail("The factory must not start when no name is specified.");

-        } catch (IllegalStateException e) {

-            // OK

-        } finally {

-            // Restore the original state of the publisher

-            m_publisher.addAttribute(m_publisherName);

-        }

-    }

-

-    /**

-     * Try to create a publisher with no field.

-     * 

-     * @throws ConfigurationException

-     *             something bad happened

-     * @throws MissingHandlerException

-     *             something bad happened

-     * @throws UnacceptableConfiguration

-     *             something bad happened

-     */

-    public void testPublisherWithoutField()

-        throws ConfigurationException, MissingHandlerException,

-        UnacceptableConfiguration {

-

-        // Remove the name attribute of the publisher

-        m_publisher.removeAttribute(m_publisherField);

-

-        // Create and try to start the factory

-        ComponentFactory fact = new ComponentFactory(context, m_provider);

-        try {

-            fact.start();

-            // Should not be executed

-            fact.stop();

-            fail("The factory must not start when no field is specified.");

-        } catch (IllegalStateException e) {

-            // OK

-        } finally {

-            // Restore the original state of the publisher

-            m_publisher.addAttribute(m_publisherField);

-        }

-    }

-

-    /**

-     * Try to create a publisher with an unexisting field.

-     * 

-     * @throws ConfigurationException

-     *             something bad happened

-     * @throws MissingHandlerException

-     *             something bad happened

-     * @throws UnacceptableConfiguration

-     *             something bad happened

-     */

-    public void testPublisherWithUnexistingField()

-        throws ConfigurationException, MissingHandlerException,

-        UnacceptableConfiguration {

-

-        // Remove the name attribute of the publisher and replace with an

-        // unexisting field name

-        m_publisher.removeAttribute(m_publisherField);

-        Attribute unexistingField = new Attribute("field", "m_unexistingField");

-        m_publisher.addAttribute(unexistingField);

-

-        // Create and try to start the factory

-        ComponentFactory fact = new ComponentFactory(context, m_provider);

-        try {

-            fact.start();

-            // Should not be executed

-            fact.stop();

-            fail("The factory must not start when an unexisting field is specified.");

-        } catch (IllegalStateException e) {

-            // OK

-        } finally {

-            // Restore the original state of the publisher

-            m_publisher.removeAttribute(unexistingField);

-            m_publisher.addAttribute(m_publisherField);

-        }

-    }

-

-    /**

-     * Try to create a publisher with a bad typed field.

-     * 

-     * @throws ConfigurationException

-     *             something bad happened

-     * @throws MissingHandlerException

-     *             something bad happened

-     * @throws UnacceptableConfiguration

-     *             something bad happened

-     */

-    public void testPublisherWithBadTypedField()

-        throws ConfigurationException, MissingHandlerException,

-        UnacceptableConfiguration {

-

-        // Remove the name attribute of the publisher and replace with an

-        // bad typed field name

-        m_publisher.removeAttribute(m_publisherField);

-        Attribute badTypedField = new Attribute("field", "m_name");

-        m_publisher.addAttribute(badTypedField);

-

-        // Create and try to start the factory

-        ComponentFactory fact = new ComponentFactory(context, m_provider);

-        try {

-            fact.start();

-            // Should not be executed

-            fact.stop();

-            fail("The factory must not start when an bad typed field is specified.");

-        } catch (IllegalStateException e) {

-            // OK

-        } finally {

-            // Restore the original state of the publisher

-            m_publisher.removeAttribute(badTypedField);

-            m_publisher.addAttribute(m_publisherField);

-        }

-    }

-

-    /**

-     * Try to create a publisher instance without topics.

-     * 

-     * @throws ConfigurationException

-     *             something bad happened

-     * @throws MissingHandlerException

-     *             something bad happened

-     * @throws UnacceptableConfiguration

-     *             something bad happened

-     */

-    public void testPublisherWithoutTopics()

-        throws ConfigurationException, MissingHandlerException,

-        UnacceptableConfiguration {

-

-        // Remove the topics attribute of the publisher

-        m_publisher.removeAttribute(m_publisherTopics);

-        ComponentFactory fact = new ComponentFactory(context, m_provider);

-        fact.start();

-

-        // Try to create an instance without specified topics

-        Dictionary conf = new Hashtable();

-        conf.put("instance.name","provider without topics");

-

-        ComponentInstance instance;

-        try {

-            instance = fact.createComponentInstance(conf);

-            // Should not be executed

-            instance.dispose();

-            fail("The factory must not create instance without specified topics.");

-        } catch (ConfigurationException e) {

-            // OK

-        } finally {

-            fact.stop();

-            // Restore the original state of the publisher

-            m_publisher.addAttribute(m_publisherTopics);

-        }

-    }

-

-    /**

-     * Try to create a publisher with malformed topics.

-     * 

-     * @throws ConfigurationException

-     *             something bad happened

-     * @throws MissingHandlerException

-     *             something bad happened

-     * @throws UnacceptableConfiguration

-     *             something bad happened

-     */

-    public void testPublisherWithMalformedTopics()

-        throws ConfigurationException, MissingHandlerException,

-        UnacceptableConfiguration {

-

-        // Remove the topics attribute of the publisher and replace with a

-        // malformed one

-        m_publisher.removeAttribute(m_publisherTopics);

-        Attribute malformedTopics = new Attribute("topics",

-                "| |\\| \\/ /-\\ |_ | |)");

-        m_publisher.addAttribute(malformedTopics);

-

-        // Create and try to start the factory

-        ComponentFactory fact = new ComponentFactory(context, m_provider);

-        try {

-            fact.start();

-            // Should not be executed

-            fact.stop();

-            fail("The factory must not start when invalid topics are specified.");

-        } catch (IllegalStateException e) {

-            // OK

-        } finally {

-            // Restore the original state of the publisher

-            m_publisher.removeAttribute(malformedTopics);

-            m_publisher.addAttribute(m_publisherTopics);

-        }

-    }

-

-    /**

-     * Try to create a publisher with malformed instance topics.

-     * 

-     * @throws ConfigurationException

-     *             something bad happened

-     * @throws MissingHandlerException

-     *             something bad happened

-     * @throws UnacceptableConfiguration

-     *             something bad happened

-     */

-    public void testPublisherWithMalformedInstanceTopics()

-        throws ConfigurationException, MissingHandlerException,

-        UnacceptableConfiguration {

-

-        // Remove the topics attribute of the publisher and replace with a

-        // malformed one

-        m_publisher.removeAttribute(m_publisherTopics);

-        ComponentFactory fact = new ComponentFactory(context, m_provider);

-        fact.start();

-

-        // Try to create an instance with malformed specified topics

-        Dictionary conf = new Hashtable();

-        conf.put("instance.name","provider with malformed topics");

-        Dictionary topics = new Hashtable();

-        topics.put("donut-publisher", "| |\\| \\/ /-\\ |_ | |)");

-        conf.put("event.topics", topics);

-

-        ComponentInstance instance;

-        try {

-            instance = fact.createComponentInstance(conf);

-            // Should not be executed

-            instance.dispose();

-            fail("The factory must not create instance with invalid specified topics.");

-        } catch (ConfigurationException e) {

-            // OK

-        } finally {

-            fact.stop();

-            // Restore the original state of the publisher

-            m_publisher.addAttribute(m_publisherTopics);

-        }

-    }

-

-    /**

-     * Try to create a subscriber with no name.

-     * 

-     * @throws ConfigurationException

-     *             something bad happened

-     * @throws MissingHandlerException

-     *             something bad happened

-     * @throws UnacceptableConfiguration

-     *             something bad happened

-     */

-    public void testSubscriberWithoutName()

-        throws ConfigurationException, MissingHandlerException,

-        UnacceptableConfiguration {

-

-        // Remove the name attribute of the publisher

-        m_subscriber.removeAttribute(m_subscriberName);

-

-        // Create and try to start the factory

-        ComponentFactory fact = new ComponentFactory(context, m_consumer);

-        try {

-            fact.start();

-            // Should not be executed

-            fact.stop();

-            fail("The factory must not start when no name is specified.");

-        } catch (IllegalStateException e) {

-            // OK

-        } finally {

-            // Restore the original state of the publisher

-            m_subscriber.addAttribute(m_subscriberName);

-        }

-    }

-

-    /**

-     * Try to create a subscriber with no callback.

-     * 

-     * @throws ConfigurationException

-     *             something bad happened

-     * @throws MissingHandlerException

-     *             something bad happened

-     * @throws UnacceptableConfiguration

-     *             something bad happened

-     */

-    public void testSubscriberWithoutCallback()

-        throws ConfigurationException, MissingHandlerException,

-        UnacceptableConfiguration {

-

-        // Remove the name attribute of the publisher

-        m_subscriber.removeAttribute(m_subscriberCallback);

-

-        // Create and try to start the factory

-        ComponentFactory fact = new ComponentFactory(context, m_consumer);

-        try {

-            fact.start();

-            // Should not be executed

-            fact.stop();

-            fail("The factory must not start when no callback is specified.");

-        } catch (IllegalStateException e) {

-            // OK

-        } finally {

-            // Restore the original state of the publisher

-            m_subscriber.addAttribute(m_subscriberCallback);

-        }

-    }

-

-    /**

-     * Try to create a subscriber instance without topics.

-     * 

-     * @throws ConfigurationException

-     *             something bad happened

-     * @throws MissingHandlerException

-     *             something bad happened

-     * @throws UnacceptableConfiguration

-     *             something bad happened

-     */

-    public void testSubscriberWithoutTopics()

-        throws ConfigurationException, MissingHandlerException,

-        UnacceptableConfiguration {

-

-        // Remove the topics attribute of the subscriber

-        m_subscriber.removeAttribute(m_subscriberTopics);

-        ComponentFactory fact = new ComponentFactory(context, m_consumer);

-        fact.start();

-

-        // Try to create an instance without specified topics

-        Dictionary conf = new Hashtable();

-        conf.put("instance.name","consumer without topics");

-        conf.put("slow", "false");

-

-        ComponentInstance instance;

-        try {

-            instance = fact.createComponentInstance(conf);

-            // Should not be executed

-            instance.dispose();

-            fail("The factory must not create instance without specified topics.");

-        } catch (ConfigurationException e) {

-            // OK

-        } finally {

-            fact.stop();

-            // Restore the original state of the subscriber

-            m_subscriber.addAttribute(m_subscriberTopics);

-        }

-    }

-

-    /**

-     * Try to create a subscriber with malformed topics.

-     * 

-     * @throws ConfigurationException

-     *             something bad happened

-     * @throws MissingHandlerException

-     *             something bad happened

-     * @throws UnacceptableConfiguration

-     *             something bad happened

-     */

-    public void testSubscriberWithMalformedTopics()

-        throws ConfigurationException, MissingHandlerException,

-        UnacceptableConfiguration {

-

-        // Remove the topics attribute of the subscriber and replace with a

-        // malformed one

-        m_subscriber.removeAttribute(m_subscriberTopics);

-        Attribute malformedTopics = new Attribute("topics",

-                "| |\\| \\/ /-\\ |_ | |)");

-        m_subscriber.addAttribute(malformedTopics);

-

-        // Create and try to start the factory

-        ComponentFactory fact = new ComponentFactory(context, m_consumer);

-        try {

-            fact.start();

-            // Should not be executed

-            fact.stop();

-            fail("The factory must not start when invalid topics are specified.");

-        } catch (IllegalStateException e) {

-            // OK

-        } finally {

-            // Restore the original state of the subscriber

-            m_subscriber.removeAttribute(malformedTopics);

-            m_subscriber.addAttribute(m_subscriberTopics);

-        }

-    }

-

-    /**

-     * Try to create a subscriber with malformed instance topics.

-     * 

-     * @throws ConfigurationException

-     *             something bad happened

-     * @throws MissingHandlerException

-     *             something bad happened

-     * @throws UnacceptableConfiguration

-     *             something bad happened

-     */

-    public void testSubscriberWithMalformedInstanceTopics()

-        throws ConfigurationException, MissingHandlerException,

-        UnacceptableConfiguration {

-

-        // Remove the topics attribute of the subscriber and replace with a

-        // malformed one

-        m_subscriber.removeAttribute(m_subscriberTopics);

-        ComponentFactory fact = new ComponentFactory(context, m_consumer);

-        fact.start();

-

-        // Try to create an instance with malformed specified topics

-        Dictionary conf = new Hashtable();

-        conf.put("instance.name","consumer with malformed topics");

-        Dictionary topics = new Hashtable();

-        topics.put("donut-subscriber", "| |\\| \\/ /-\\ |_ | |)");

-        conf.put("event.topics", topics);

-

-        ComponentInstance instance;

-        try {

-            instance = fact.createComponentInstance(conf);

-            // Should not be executed

-            instance.dispose();

-            fail("The factory must not create instance with invalid specified topics.");

-        } catch (ConfigurationException e) {

-            // OK

-        } finally {

-            fact.stop();

-            // Restore the original state of the subscriber

-            m_subscriber.addAttribute(m_subscriberTopics);

-        }

-    }

-

-    /**

-     * Try to create a subscriber with unknown data type.

-     * 

-     * @throws ConfigurationException

-     *             something bad happened

-     * @throws MissingHandlerException

-     *             something bad happened

-     * @throws UnacceptableConfiguration

-     *             something bad happened

-     */

-    public void testSubscriberWithUnknownDataType()

-        throws ConfigurationException, MissingHandlerException,

-        UnacceptableConfiguration {

-

-        // Remove the data-type attribute of the subscriber and replace with a

-        // malformed one

-        m_subscriber.removeAttribute(m_subscriberDataType);

-        Attribute unknownType = new Attribute("data-type", "org.unknown.Clazz");

-        m_subscriber.addAttribute(unknownType);

-

-        // Create and try to start the factory

-        ComponentFactory fact = new ComponentFactory(context, m_consumer);

-        try {

-            fact.start();

-            // Should not be executed

-            fact.stop();

-            fail("The factory must not start when unknown data type is specified.");

-        } catch (IllegalStateException e) {

-            // OK

-        } finally {

-            // Restore the original state of the subscriber

-            m_subscriber.removeAttribute(unknownType);

-            m_subscriber.addAttribute(m_subscriberDataType);

-        }

-    }

-

-    /**

-     * Try to create a subscriber with a data type that does not match with the

-     * callback parameter type.

-     * 

-     * @throws ConfigurationException

-     *             something bad happened

-     * @throws MissingHandlerException

-     *             something bad happened

-     * @throws UnacceptableConfiguration

-     *             something bad happened

-     */

-    public void testSubscriberWithUnappropriatedDataType()

-        throws ConfigurationException, MissingHandlerException,

-        UnacceptableConfiguration {

-

-        // Remove the data-type attribute of the subscriber and replace with a

-        // malformed one

-        m_subscriber.removeAttribute(m_subscriberDataType);

-        Attribute unknownType = new Attribute("data-type", "java.lang.String");

-        m_subscriber.addAttribute(unknownType);

-

-        // Create and try to start the factory

-        ComponentFactory fact = new ComponentFactory(context, m_consumer);

-        try {

-            fact.start();

-            // Should not be executed

-            fact.stop();

-            fail("The factory must not start when unappropriated data type is specified.");

-        } catch (IllegalStateException e) {

-            // OK

-        } finally {

-            // Restore the original state of the subscriber

-            m_subscriber.removeAttribute(unknownType);

-            m_subscriber.addAttribute(m_subscriberDataType);

-        }

-    }

-

-    /**

-     * Finalization after test cases.

-     * 

-     * Release all services references and destroy instances.

-     */

-    public void tearDown() {

-

-    }

-

-    // DEBUG

-    public void dumpElement(String message, Element root) {

-        System.err.println(message + "\n" + dumpElement(0, root));

-    }

-

-    // DEBUG

-    private String dumpElement(int level, Element element) {

-        StringBuilder sb = new StringBuilder();

-        // Enter tag

-        for (int i = 0; i < level; i++) {

-            sb.append("  ");

-        }

-        sb.append('<');

-        sb.append(element.getName());

-        Attribute[] attributes = element.getAttributes();

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

-            Attribute attribute = attributes[i];

-            sb.append(' ');

-            sb.append(attribute.getName());

-            sb.append('=');

-            sb.append(attribute.getValue());

-        }

-        sb.append(">\n");

-        // Children

-        Element[] elements = element.getElements();

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

-            sb.append(dumpElement(level + 1, elements[i]));

-        }

-        // Exit tag

-        for (int i = 0; i < level; i++) {

-            sb.append("  ");

-        }

-        sb.append("</" + element.getName() + ">\n");

-        return sb.toString();

-    }

-

-}

+/* 
+ * 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.test;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+import org.apache.felix.ipojo.ComponentFactory;
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.ConfigurationException;
+import org.apache.felix.ipojo.MissingHandlerException;
+import org.apache.felix.ipojo.UnacceptableConfiguration;
+import org.apache.felix.ipojo.junit4osgi.OSGiTestCase;
+import org.apache.felix.ipojo.metadata.Attribute;
+import org.apache.felix.ipojo.metadata.Element;
+import org.apache.felix.ipojo.parser.ManifestMetadataParser;
+import org.apache.felix.ipojo.parser.ParseException;
+import org.apache.felix.ipojo.test.donut.Donut;
+import org.apache.felix.ipojo.test.donut.DonutConsumer;
+import org.apache.felix.ipojo.test.donut.DonutProvider;
+import org.apache.felix.ipojo.test.util.EahTestUtils;
+import org.apache.felix.ipojo.test.util.IPojoTestUtils;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * Test the good behaviour of the EventAdminHandler.
+ * 
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class BadTests extends OSGiTestCase {
+	
+	 /**
+     * The utility class instance.
+     */
+    public EahTestUtils m_utils;
+
+    /**
+     * The namespace of the Event admin handler.
+     */
+    private static final String NAMESPACE = "org.apache.felix.ipojo.handlers.event.EventAdminHandler";
+
+    /**
+     * The available components.
+     */
+    private Element[] m_components;
+
+    /**
+     * The description of a component that uses an event publisher.
+     */
+    private Element m_provider;
+
+    /**
+     * The event publisher description.
+     */
+    private Element m_publisher;
+
+    /**
+     * The name attribute of the event publisher.
+     */
+    private Attribute m_publisherName;
+
+    /**
+     * The field attribute of the event publisher.
+     */
+    private Attribute m_publisherField;
+
+    /**
+     * The topics attribute of the event publisher.
+     */
+    private Attribute m_publisherTopics;
+
+    /**
+     * The data-key attribute of the event publisher.
+     */
+    private Attribute m_publisherDataKey;
+
+    /**
+     * The synchronous attribute of the event publisher.
+     */
+    private Attribute m_publisherSynchronous;
+
+    /**
+     * The description of a component that uses an event subscriber.
+     */
+    private Element m_consumer;
+
+    /**
+     * The event subscriber description.
+     */
+    private Element m_subscriber;
+
+    /**
+     * The name attribute of the event subscriber.
+     */
+    private Attribute m_subscriberName;
+
+    /**
+     * The callback attribute of the event subscriber.
+     */
+    private Attribute m_subscriberCallback;
+
+    /**
+     * The topics attribute of the event subscriber.
+     */
+    private Attribute m_subscriberTopics;
+
+    /**
+     * The data-key attribute of the event subscriber.
+     */
+    private Attribute m_subscriberDataKey;
+
+    /**
+     * The data-type attribute of the event subscriber.
+     */
+    private Attribute m_subscriberDataType;
+
+    private Element getManipulationForComponent(String compName) {
+        for (int i = 0; i < m_components.length; i++) {
+            if (m_components[i].containsAttribute("name")
+                    && m_components[i].getAttribute("name").equals(compName)) {
+                return m_components[i].getElements("manipulation")[0];
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Initialization before test cases.
+     * 
+     * Create all the instances
+     * 
+     */
+    public void setUp() {
+    	m_utils = new EahTestUtils(context);
+        /**
+         * Get the list of available components.
+         */
+        try {
+            String header = (String) context.getBundle().getHeaders().get(
+                    "iPOJO-Components");
+            m_components = ManifestMetadataParser.parseHeaderMetadata(header)
+                    .getElements("component");
+        } catch (ParseException e) {
+            fail("Parse Exception when parsing iPOJO-Component");
+        }
+
+        /**
+         * Initialize the standard publishing component (based on the
+         * asynchronous donut provider).
+         */
+        m_provider = new Element("component", "");
+        m_provider.addAttribute(new Attribute("className",
+                "org.apache.felix.ipojo.test.donut.DonutProviderImpl"));
+        m_provider.addAttribute(new Attribute("name",
+                "standard donut provider for bad tests"));
+
+        // The provided service of the publisher
+        Element providesDonutProvider = new Element("provides", "");
+        providesDonutProvider.addAttribute(new Attribute("interface",
+                "org.apache.felix.ipojo.test.donut.DonutProvider"));
+        Element providesDonutProviderProperty = new Element("property", "");
+        providesDonutProviderProperty
+                .addAttribute(new Attribute("name", "name"));
+        providesDonutProviderProperty.addAttribute(new Attribute("field",
+                "m_name"));
+        providesDonutProviderProperty.addAttribute(new Attribute("value",
+                "Unknown donut vendor"));
+        providesDonutProvider.addElement(providesDonutProviderProperty);
+        m_provider.addElement(providesDonutProvider);
+
+        // The event publisher, corresponding to the following description :
+        // <ev:publisher name="donut-publisher" field="m_publisher"
+        // topics="food/donuts" data-key="food" synchronous="false"/>
+        m_publisher = new Element("publisher", NAMESPACE);
+        m_publisherName = new Attribute("name", "donut-publisher");
+        m_publisherField = new Attribute("field", "m_publisher");
+        m_publisherTopics = new Attribute("topics", "food/donuts");
+        m_publisherDataKey = new Attribute("data-key", "food");
+        m_publisherSynchronous = new Attribute("synchronous", "false");
+        m_publisher.addAttribute(m_publisherName);
+        m_publisher.addAttribute(m_publisherField);
+        m_publisher.addAttribute(m_publisherTopics);
+        m_publisher.addAttribute(m_publisherDataKey);
+        m_publisher.addAttribute(m_publisherSynchronous);
+        m_provider.addElement(m_publisher);
+
+        m_provider.addElement(getManipulationForComponent("donut-provider"));
+
+        /**
+         * Initialize the standard subscribing component (based on the donut
+         * consumer).
+         */
+        m_consumer = new Element("component", "");
+        m_consumer.addAttribute(new Attribute("className",
+                "org.apache.felix.ipojo.test.donut.DonutConsumerImpl"));
+        m_consumer.addAttribute(new Attribute("name",
+                "standard donut consumer for bad tests"));
+
+        // The provided service of the publisher
+        Element providesDonutConsumer = new Element("provides", "");
+        providesDonutConsumer.addAttribute(new Attribute("interface",
+                "org.apache.felix.ipojo.test.donut.DonutConsumer"));
+        Element providesDonutConsumerNameProperty = new Element("property", "");
+        providesDonutConsumerNameProperty.addAttribute(new Attribute("name",
+                "name"));
+        providesDonutConsumerNameProperty.addAttribute(new Attribute("field",
+                "m_name"));
+        providesDonutConsumerNameProperty.addAttribute(new Attribute("value",
+                "Unknown donut consumer"));
+        providesDonutConsumer.addElement(providesDonutConsumerNameProperty);
+        Element providesDonutConsumerSlowProperty = new Element("property", "");
+        providesDonutConsumerSlowProperty.addAttribute(new Attribute("name",
+                "slow"));
+        providesDonutConsumerSlowProperty.addAttribute(new Attribute("field",
+                "m_isSlow"));
+        providesDonutConsumerSlowProperty.addAttribute(new Attribute("value",
+                "false"));
+        providesDonutConsumer.addElement(providesDonutConsumerSlowProperty);
+        m_consumer.addElement(providesDonutConsumer);
+
+        // The event publisher, corresponding to the following description :
+        // <ev:subscriber name="donut-subscriber" callback="receiveDonut"
+        // topics="food/donuts" data-key="food"
+        // data-type="org.apache.felix.ipojo.test.donut.Donut"/>
+        m_subscriber = new Element("subscriber", NAMESPACE);
+        m_subscriberName = new Attribute("name", "donut-subscriber");
+        m_subscriberCallback = new Attribute("callback", "receiveDonut");
+        m_subscriberTopics = new Attribute("topics", "food/donuts");
+        m_subscriberDataKey = new Attribute("data-key", "food");
+        m_subscriberDataType = new Attribute("data-type",
+                "org.apache.felix.ipojo.test.donut.Donut");
+        m_subscriber.addAttribute(m_subscriberName);
+        m_subscriber.addAttribute(m_subscriberCallback);
+        m_subscriber.addAttribute(m_subscriberTopics);
+        m_subscriber.addAttribute(m_subscriberDataKey);
+        m_subscriber.addAttribute(m_subscriberDataType);
+        m_consumer.addElement(m_subscriber);
+
+        m_consumer.addElement(getManipulationForComponent("donut-consumer"));
+    }
+
+    /**
+     * Test the base configuration is correct to be sure the bad tests will fail
+     * because of they are really bad, and not because of an other application
+     * error.
+     * 
+     * This test simply create a provider and a consumer instance, send one
+     * event and check it is received.
+     * 
+     * @throws ConfigurationException
+     *             something bad happened
+     * @throws MissingHandlerException
+     *             something bad happened
+     * @throws UnacceptableConfiguration
+     *             something bad happened
+     */
+    public void testGoodConfig()
+        throws ConfigurationException, UnacceptableConfiguration,
+        MissingHandlerException {
+        /**
+         * Create the provider and the consumer instances.
+         */
+        Dictionary properties = new Hashtable();
+
+        // Provider
+        ComponentFactory providerFactory = new ComponentFactory(context,
+                m_provider);
+        providerFactory.start();
+        properties.put("instance.name","Emperor of donuts");
+        ComponentInstance providerInstance = providerFactory
+                .createComponentInstance(properties);
+        ServiceReference providerService = IPojoTestUtils
+                .getServiceReferenceByName(context, DonutProvider.class
+                        .getName(), providerInstance.getInstanceName());
+        DonutProvider provider = (DonutProvider) context
+                .getService(providerService);
+
+        // The consumer
+        properties = new Hashtable();
+        ComponentFactory consumerFactory = new ComponentFactory(context,
+                m_consumer);
+        consumerFactory.start();
+        properties.put("instance.name","Homer Simpson");
+        properties.put("slow", "false");
+        ComponentInstance consumerInstance = consumerFactory
+                .createComponentInstance(properties);
+        ServiceReference consumerService = IPojoTestUtils
+                .getServiceReferenceByName(context, DonutConsumer.class
+                        .getName(), consumerInstance.getInstanceName());
+        DonutConsumer consumer = (DonutConsumer) context
+                .getService(consumerService);
+
+        /**
+         * Test the normal behaviour of the instances.
+         */
+        consumer.clearDonuts();
+        Donut sentDonut = provider.sellDonut();
+        Donut receivedDonut = consumer.waitForDonut();
+        assertEquals("The received donut must be the same as the sent one.",
+                sentDonut, receivedDonut);
+
+        /**
+         * Destroy component's instances.
+         */
+        context.ungetService(providerService);
+        providerInstance.dispose();
+        context.ungetService(consumerService);
+        consumerInstance.dispose();
+        providerFactory.stop();
+        consumerFactory.stop();
+    }
+
+    /**
+     * Try to create a publisher with no name.
+     * 
+     * @throws ConfigurationException
+     *             something bad happened
+     * @throws MissingHandlerException
+     *             something bad happened
+     * @throws UnacceptableConfiguration
+     *             something bad happened
+     */
+    public void testPublisherWithoutName()
+        throws ConfigurationException, MissingHandlerException,
+        UnacceptableConfiguration {
+
+        // Remove the name attribute of the publisher
+        m_publisher.removeAttribute(m_publisherName);
+
+        // Create and try to start the factory
+        ComponentFactory fact = new ComponentFactory(context, m_provider);
+        try {
+            fact.start();
+            // Should not be executed
+            fact.stop();
+            fail("The factory must not start when no name is specified.");
+        } catch (IllegalStateException e) {
+            // OK
+        } finally {
+            // Restore the original state of the publisher
+            m_publisher.addAttribute(m_publisherName);
+        }
+    }
+
+    /**
+     * Try to create a publisher with no field.
+     * 
+     * @throws ConfigurationException
+     *             something bad happened
+     * @throws MissingHandlerException
+     *             something bad happened
+     * @throws UnacceptableConfiguration
+     *             something bad happened
+     */
+    public void testPublisherWithoutField()
+        throws ConfigurationException, MissingHandlerException,
+        UnacceptableConfiguration {
+
+        // Remove the name attribute of the publisher
+        m_publisher.removeAttribute(m_publisherField);
+
+        // Create and try to start the factory
+        ComponentFactory fact = new ComponentFactory(context, m_provider);
+        try {
+            fact.start();
+            // Should not be executed
+            fact.stop();
+            fail("The factory must not start when no field is specified.");
+        } catch (IllegalStateException e) {
+            // OK
+        } finally {
+            // Restore the original state of the publisher
+            m_publisher.addAttribute(m_publisherField);
+        }
+    }
+
+    /**
+     * Try to create a publisher with an unexisting field.
+     * 
+     * @throws ConfigurationException
+     *             something bad happened
+     * @throws MissingHandlerException
+     *             something bad happened
+     * @throws UnacceptableConfiguration
+     *             something bad happened
+     */
+    public void testPublisherWithUnexistingField()
+        throws ConfigurationException, MissingHandlerException,
+        UnacceptableConfiguration {
+
+        // Remove the name attribute of the publisher and replace with an
+        // unexisting field name
+        m_publisher.removeAttribute(m_publisherField);
+        Attribute unexistingField = new Attribute("field", "m_unexistingField");
+        m_publisher.addAttribute(unexistingField);
+
+        // Create and try to start the factory
+        ComponentFactory fact = new ComponentFactory(context, m_provider);
+        try {
+            fact.start();
+            // Should not be executed
+            fact.stop();
+            fail("The factory must not start when an unexisting field is specified.");
+        } catch (IllegalStateException e) {
+            // OK
+        } finally {
+            // Restore the original state of the publisher
+            m_publisher.removeAttribute(unexistingField);
+            m_publisher.addAttribute(m_publisherField);
+        }
+    }
+
+    /**
+     * Try to create a publisher with a bad typed field.
+     * 
+     * @throws ConfigurationException
+     *             something bad happened
+     * @throws MissingHandlerException
+     *             something bad happened
+     * @throws UnacceptableConfiguration
+     *             something bad happened
+     */
+    public void testPublisherWithBadTypedField()
+        throws ConfigurationException, MissingHandlerException,
+        UnacceptableConfiguration {
+
+        // Remove the name attribute of the publisher and replace with an
+        // bad typed field name
+        m_publisher.removeAttribute(m_publisherField);
+        Attribute badTypedField = new Attribute("field", "m_name");
+        m_publisher.addAttribute(badTypedField);
+
+        // Create and try to start the factory
+        ComponentFactory fact = new ComponentFactory(context, m_provider);
+        try {
+            fact.start();
+            // Should not be executed
+            fact.stop();
+            fail("The factory must not start when an bad typed field is specified.");
+        } catch (IllegalStateException e) {
+            // OK
+        } finally {
+            // Restore the original state of the publisher
+            m_publisher.removeAttribute(badTypedField);
+            m_publisher.addAttribute(m_publisherField);
+        }
+    }
+
+    /**
+     * Try to create a publisher instance without topics.
+     * 
+     * @throws ConfigurationException
+     *             something bad happened
+     * @throws MissingHandlerException
+     *             something bad happened
+     * @throws UnacceptableConfiguration
+     *             something bad happened
+     */
+    public void testPublisherWithoutTopics()
+        throws ConfigurationException, MissingHandlerException,
+        UnacceptableConfiguration {
+
+        // Remove the topics attribute of the publisher
+        m_publisher.removeAttribute(m_publisherTopics);
+        ComponentFactory fact = new ComponentFactory(context, m_provider);
+        fact.start();
+
+        // Try to create an instance without specified topics
+        Dictionary conf = new Hashtable();
+        conf.put("instance.name","provider without topics");
+
+        ComponentInstance instance;
+        try {
+            instance = fact.createComponentInstance(conf);
+            // Should not be executed
+            instance.dispose();
+            fail("The factory must not create instance without specified topics.");
+        } catch (ConfigurationException e) {
+            // OK
+        } finally {
+            fact.stop();
+            // Restore the original state of the publisher
+            m_publisher.addAttribute(m_publisherTopics);
+        }
+    }
+
+    /**
+     * Try to create a publisher with malformed topics.
+     * 
+     * @throws ConfigurationException
+     *             something bad happened
+     * @throws MissingHandlerException
+     *             something bad happened
+     * @throws UnacceptableConfiguration
+     *             something bad happened
+     */
+    public void testPublisherWithMalformedTopics()
+        throws ConfigurationException, MissingHandlerException,
+        UnacceptableConfiguration {
+
+        // Remove the topics attribute of the publisher and replace with a
+        // malformed one
+        m_publisher.removeAttribute(m_publisherTopics);
+        Attribute malformedTopics = new Attribute("topics",
+                "| |\\| \\/ /-\\ |_ | |)");
+        m_publisher.addAttribute(malformedTopics);
+
+        // Create and try to start the factory
+        ComponentFactory fact = new ComponentFactory(context, m_provider);
+        try {
+            fact.start();
+            // Should not be executed
+            fact.stop();
+            fail("The factory must not start when invalid topics are specified.");
+        } catch (IllegalStateException e) {
+            // OK
+        } finally {
+            // Restore the original state of the publisher
+            m_publisher.removeAttribute(malformedTopics);
+            m_publisher.addAttribute(m_publisherTopics);
+        }
+    }
+    
+    /**
+     * Try to create a publisher with a pattern topic (ending with '*') instead of a fixed topic.
+     * 
+     * @throws ConfigurationException
+     *             something bad happened
+     * @throws MissingHandlerException
+     *             something bad happened
+     * @throws UnacceptableConfiguration
+     *             something bad happened
+     */
+    public void testPublisherWithPatternTopic()
+        throws ConfigurationException, MissingHandlerException,
+        UnacceptableConfiguration {
+
+        // Remove the topics attribute of the publisher and replace with a
+        // malformed one
+        m_publisher.removeAttribute(m_publisherTopics);
+        Attribute malformedTopics = new Attribute("topics",
+                "a/pattern/topic/*");
+        m_publisher.addAttribute(malformedTopics);
+
+        // Create and try to start the factory
+        ComponentFactory fact = new ComponentFactory(context, m_provider);
+        try {
+            fact.start();
+            // Should not be executed
+            fact.stop();
+            fail("The factory must not start when invalid topics are specified.");
+        } catch (IllegalStateException e) {
+            // OK
+        } finally {
+            // Restore the original state of the publisher
+            m_publisher.removeAttribute(malformedTopics);
+            m_publisher.addAttribute(m_publisherTopics);
+        }
+    }
+
+    /**
+     * Try to create a publisher with malformed instance topics.
+     * 
+     * @throws ConfigurationException
+     *             something bad happened
+     * @throws MissingHandlerException
+     *             something bad happened
+     * @throws UnacceptableConfiguration
+     *             something bad happened
+     */
+    public void testPublisherWithMalformedInstanceTopics()
+        throws ConfigurationException, MissingHandlerException,
+        UnacceptableConfiguration {
+
+        // Remove the topics attribute of the publisher and replace with a
+        // malformed one
+        m_publisher.removeAttribute(m_publisherTopics);
+        ComponentFactory fact = new ComponentFactory(context, m_provider);
+        fact.start();
+
+        // Try to create an instance with malformed specified topics
+        Dictionary conf = new Hashtable();
+        conf.put("instance.name","provider with malformed topics");
+        Dictionary topics = new Hashtable();
+        topics.put("donut-publisher", "| |\\| \\/ /-\\ |_ | |)");
+        conf.put("event.topics", topics);
+
+        ComponentInstance instance;
+        try {
+            instance = fact.createComponentInstance(conf);
+            // Should not be executed
+            instance.dispose();
+            fail("The factory must not create instance with invalid specified topics.");
+        } catch (ConfigurationException e) {
+            // OK
+        } finally {
+            fact.stop();
+            // Restore the original state of the publisher
+            m_publisher.addAttribute(m_publisherTopics);
+        }
+    }
+
+    /**
+     * Try to create a subscriber with no name.
+     * 
+     * @throws ConfigurationException
+     *             something bad happened
+     * @throws MissingHandlerException
+     *             something bad happened
+     * @throws UnacceptableConfiguration
+     *             something bad happened
+     */
+    public void testSubscriberWithoutName()
+        throws ConfigurationException, MissingHandlerException,
+        UnacceptableConfiguration {
+
+        // Remove the name attribute of the publisher
+        m_subscriber.removeAttribute(m_subscriberName);
+
+        // Create and try to start the factory
+        ComponentFactory fact = new ComponentFactory(context, m_consumer);
+        try {
+            fact.start();
+            // Should not be executed
+            fact.stop();
+            fail("The factory must not start when no name is specified.");
+        } catch (IllegalStateException e) {
+            // OK
+        } finally {
+            // Restore the original state of the publisher
+            m_subscriber.addAttribute(m_subscriberName);
+        }
+    }
+
+    /**
+     * Try to create a subscriber with no callback.
+     * 
+     * @throws ConfigurationException
+     *             something bad happened
+     * @throws MissingHandlerException
+     *             something bad happened
+     * @throws UnacceptableConfiguration
+     *             something bad happened
+     */
+    public void testSubscriberWithoutCallback()
+        throws ConfigurationException, MissingHandlerException,
+        UnacceptableConfiguration {
+
+        // Remove the name attribute of the publisher
+        m_subscriber.removeAttribute(m_subscriberCallback);
+
+        // Create and try to start the factory
+        ComponentFactory fact = new ComponentFactory(context, m_consumer);
+        try {
+            fact.start();
+            // Should not be executed
+            fact.stop();
+            fail("The factory must not start when no callback is specified.");
+        } catch (IllegalStateException e) {
+            // OK
+        } finally {
+            // Restore the original state of the publisher
+            m_subscriber.addAttribute(m_subscriberCallback);
+        }
+    }
+
+    /**
+     * Try to create a subscriber instance without topics.
+     * 
+     * @throws ConfigurationException
+     *             something bad happened
+     * @throws MissingHandlerException
+     *             something bad happened
+     * @throws UnacceptableConfiguration
+     *             something bad happened
+     */
+    public void testSubscriberWithoutTopics()
+        throws ConfigurationException, MissingHandlerException,
+        UnacceptableConfiguration {
+
+        // Remove the topics attribute of the subscriber
+        m_subscriber.removeAttribute(m_subscriberTopics);
+        ComponentFactory fact = new ComponentFactory(context, m_consumer);
+        fact.start();
+
+        // Try to create an instance without specified topics
+        Dictionary conf = new Hashtable();
+        conf.put("instance.name","consumer without topics");
+        conf.put("slow", "false");
+
+        ComponentInstance instance;
+        try {
+            instance = fact.createComponentInstance(conf);
+            // Should not be executed
+            instance.dispose();
+            fail("The factory must not create instance without specified topics.");
+        } catch (ConfigurationException e) {
+            // OK
+        } finally {
+            fact.stop();
+            // Restore the original state of the subscriber
+            m_subscriber.addAttribute(m_subscriberTopics);
+        }
+    }
+
+    /**
+     * Try to create a subscriber with malformed topics.
+     * 
+     * @throws ConfigurationException
+     *             something bad happened
+     * @throws MissingHandlerException
+     *             something bad happened
+     * @throws UnacceptableConfiguration
+     *             something bad happened
+     */
+    public void testSubscriberWithMalformedTopics()
+        throws ConfigurationException, MissingHandlerException,
+        UnacceptableConfiguration {
+
+        // Remove the topics attribute of the subscriber and replace with a
+        // malformed one
+        m_subscriber.removeAttribute(m_subscriberTopics);
+        Attribute malformedTopics = new Attribute("topics",
+                "| |\\| \\/ /-\\ |_ | |)");
+        m_subscriber.addAttribute(malformedTopics);
+
+        // Create and try to start the factory
+        ComponentFactory fact = new ComponentFactory(context, m_consumer);
+        try {
+            fact.start();
+            // Should not be executed
+            fact.stop();
+            fail("The factory must not start when invalid topics are specified.");
+        } catch (IllegalStateException e) {
+            // OK
+        } finally {
+            // Restore the original state of the subscriber
+            m_subscriber.removeAttribute(malformedTopics);
+            m_subscriber.addAttribute(m_subscriberTopics);
+        }
+    }
+
+    /**
+     * Try to create a subscriber with malformed instance topics.
+     * 
+     * @throws ConfigurationException
+     *             something bad happened
+     * @throws MissingHandlerException
+     *             something bad happened
+     * @throws UnacceptableConfiguration
+     *             something bad happened
+     */
+    public void testSubscriberWithMalformedInstanceTopics()
+        throws ConfigurationException, MissingHandlerException,
+        UnacceptableConfiguration {
+
+        // Remove the topics attribute of the subscriber and replace with a
+        // malformed one
+        m_subscriber.removeAttribute(m_subscriberTopics);
+        ComponentFactory fact = new ComponentFactory(context, m_consumer);
+        fact.start();
+
+        // Try to create an instance with malformed specified topics
+        Dictionary conf = new Hashtable();
+        conf.put("instance.name","consumer with malformed topics");
+        Dictionary topics = new Hashtable();
+        topics.put("donut-subscriber", "| |\\| \\/ /-\\ |_ | |)");
+        conf.put("event.topics", topics);
+
+        ComponentInstance instance;
+        try {
+            instance = fact.createComponentInstance(conf);
+            // Should not be executed
+            instance.dispose();
+            fail("The factory must not create instance with invalid specified topics.");
+        } catch (ConfigurationException e) {
+            // OK
+        } finally {
+            fact.stop();
+            // Restore the original state of the subscriber
+            m_subscriber.addAttribute(m_subscriberTopics);
+        }
+    }
+
+    /**
+     * Try to create a subscriber with unknown data type.
+     * 
+     * @throws ConfigurationException
+     *             something bad happened
+     * @throws MissingHandlerException
+     *             something bad happened
+     * @throws UnacceptableConfiguration
+     *             something bad happened
+     */
+    public void testSubscriberWithUnknownDataType()
+        throws ConfigurationException, MissingHandlerException,
+        UnacceptableConfiguration {
+
+        // Remove the data-type attribute of the subscriber and replace with a
+        // malformed one
+        m_subscriber.removeAttribute(m_subscriberDataType);
+        Attribute unknownType = new Attribute("data-type", "org.unknown.Clazz");
+        m_subscriber.addAttribute(unknownType);
+
+        // Create and try to start the factory
+        ComponentFactory fact = new ComponentFactory(context, m_consumer);
+        try {
+            fact.start();
+            // Should not be executed
+            fact.stop();
+            fail("The factory must not start when unknown data type is specified.");
+        } catch (IllegalStateException e) {
+            // OK
+        } finally {
+            // Restore the original state of the subscriber
+            m_subscriber.removeAttribute(unknownType);
+            m_subscriber.addAttribute(m_subscriberDataType);
+        }
+    }
+
+    /**
+     * Try to create a subscriber with a data type that does not match with the
+     * callback parameter type.
+     * 
+     * @throws ConfigurationException
+     *             something bad happened
+     * @throws MissingHandlerException
+     *             something bad happened
+     * @throws UnacceptableConfiguration
+     *             something bad happened
+     */
+    public void testSubscriberWithUnappropriatedDataType()
+        throws ConfigurationException, MissingHandlerException,
+        UnacceptableConfiguration {
+
+        // Remove the data-type attribute of the subscriber and replace with a
+        // malformed one
+        m_subscriber.removeAttribute(m_subscriberDataType);
+        Attribute unknownType = new Attribute("data-type", "java.lang.String");
+        m_subscriber.addAttribute(unknownType);
+
+        // Create and try to start the factory
+        ComponentFactory fact = new ComponentFactory(context, m_consumer);
+        try {
+            fact.start();
+            // Should not be executed
+            fact.stop();
+            fail("The factory must not start when unappropriated data type is specified.");
+        } catch (IllegalStateException e) {
+            // OK
+        } finally {
+            // Restore the original state of the subscriber
+            m_subscriber.removeAttribute(unknownType);
+            m_subscriber.addAttribute(m_subscriberDataType);
+        }
+    }
+
+    /**
+     * Finalization after test cases.
+     * 
+     * Release all services references and destroy instances.
+     */
+    public void tearDown() {
+
+    }
+
+    // DEBUG
+    public void dumpElement(String message, Element root) {
+        System.err.println(message + "\n" + dumpElement(0, root));
+    }
+
+    // DEBUG
+    private String dumpElement(int level, Element element) {
+        StringBuilder sb = new StringBuilder();
+        // Enter tag
+        for (int i = 0; i < level; i++) {
+            sb.append("  ");
+        }
+        sb.append('<');
+        sb.append(element.getName());
+        Attribute[] attributes = element.getAttributes();
+        for (int i = 0; i < attributes.length; i++) {
+            Attribute attribute = attributes[i];
+            sb.append(' ');
+            sb.append(attribute.getName());
+            sb.append('=');
+            sb.append(attribute.getValue());
+        }
+        sb.append(">\n");
+        // Children
+        Element[] elements = element.getElements();
+        for (int i = 0; i < elements.length; i++) {
+            sb.append(dumpElement(level + 1, elements[i]));
+        }
+        // Exit tag
+        for (int i = 0; i < level; i++) {
+            sb.append("  ");
+        }
+        sb.append("</" + element.getName() + ">\n");
+        return sb.toString();
+    }
+    
+    /**
+     * Creates a subscriber listening on a pattern topic (ending with '*').
+     * @throws ConfigurationException something bad happened.
+     * @throws MissingHandlerException something bad happened.
+     * @throws UnacceptableConfiguration something bad happened.
+     */
+    public void testSubscriberWithPatternTopic() throws UnacceptableConfiguration, MissingHandlerException, ConfigurationException {
+    	Dictionary properties = new Hashtable();
+    	Dictionary topics = new Hashtable();
+
+        // Create the donut consumer instance, listening on a pattern topic
+        properties.put("instance.name","subscriber with pattern topic");
+        topics.put("donut-subscriber", "a/pattern/topic/*rf");
+        properties.put("event.topics", topics);
+        ComponentInstance instance = null;
+        try {
+        	instance = m_utils.getDonutConsumerFactory()
+            .createComponentInstance(properties);
+        	
+        	// Should not been executed
+        	instance.dispose();
+        	 fail("An invalid topic scope was accepted)");
+        	 
+        } catch (ConfigurationException e) {
+        	// Nothing to do
+        }
+        
+    	properties = new Hashtable();
+    	topics = new Hashtable();
+
+        // Create the donut consumer instance, listening on a pattern topic
+        properties.put("instance.name","subscriber with pattern topic");
+        topics.put("donut-subscriber", "a/pattern/*topic/rf");
+        properties.put("event.topics", topics);
+        
+        try {
+        	instance = m_utils.getDonutConsumerFactory()
+            .createComponentInstance(properties);
+        	instance.dispose();
+        	fail("An invalid topic scope was accepted (2)");
+        } catch (ConfigurationException e) {
+        	// Nothing to do
+        }
+    }
+
+}
diff --git a/ipojo/tests/handler/eventadmin/src/main/java/org/apache/felix/ipojo/test/GoodTests.java b/ipojo/tests/handler/eventadmin/src/main/java/org/apache/felix/ipojo/test/GoodTests.java
index 2b944e7..42e6272 100644
--- a/ipojo/tests/handler/eventadmin/src/main/java/org/apache/felix/ipojo/test/GoodTests.java
+++ b/ipojo/tests/handler/eventadmin/src/main/java/org/apache/felix/ipojo/test/GoodTests.java
@@ -1,726 +1,746 @@
-/* 

- * 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.test;

-

-import java.util.ArrayList;

-import java.util.Arrays;

-import java.util.Dictionary;

-import java.util.Hashtable;

-import java.util.List;

-

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

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

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

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

-import org.apache.felix.ipojo.junit4osgi.OSGiTestCase;

-import org.apache.felix.ipojo.test.donut.Donut;

-import org.apache.felix.ipojo.test.donut.DonutConsumer;

-import org.apache.felix.ipojo.test.donut.DonutProvider;

-import org.apache.felix.ipojo.test.donut.EventTracker;

-import org.apache.felix.ipojo.test.util.EahTestUtils;

-import org.apache.felix.ipojo.test.util.IPojoTestUtils;

-import org.osgi.framework.ServiceReference;

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

-

-/**

- * Test the good behaviour of the EventAdminHandler.

- * 

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

- */

-public class GoodTests extends OSGiTestCase {

-

-    /**

-     * The number of providers to test.

-     */

-    private static final int NUMBER_OF_PROVIDERS = 6;

-

-    /**

-     * The number of providers using the event admin handler to test.

-     */

-    private static final int NUMBER_OF_EAH_PROVIDERS = 4;

-

-    /**

-     * The number of consumers to test.

-     */

-    private static final int NUMBER_OF_CONSUMERS = 6;

-

-    /**

-     * The number of synchronous providers to test.

-     */

-    private static final int NUMBER_OF_SYNCHRONOUS_PROVIDERS = 3;

-

-    /**

-     * The number of slow consumers to test.

-     */

-    private static final int NUMBER_OF_QUICK_CONSUMERS = 3;

-

-    /**

-     * The list of topics to test.

-     */

-    private static final String[] TOPICS_LIST = { "foo", "bar", "nut",

-        "foo,bar", "bar,nut", "foo,nut", "foo,bar,nut" };

-

-    /**

-     * The utility class instance.

-     */

-    public EahTestUtils m_utils;

-

-    /**

-     * The providers' instances.

-     */

-    private ComponentInstance[] m_providersInstances;

-

-    /**

-     * The providers' service references.

-     */

-    private ServiceReference[] m_providersServices;

-

-    /**

-     * The providers' services.

-     */

-    private DonutProvider[] m_providers;

-

-    /**

-     * The synchronous providers' services.

-     */

-    private DonutProvider[] m_synchronousProviders;

-

-    /**

-     * The instances of providers that uses the event admin handler.

-     */

-    private ComponentInstance[] m_eahProvidersInstances;

-

-    /**

-     * The services of the providers that uses the event admin handler.

-     */

-    private DonutProvider[] m_eahProviders;

-

-    /**

-     * The synchronous donut event provider service.

-     */

-    private DonutProvider m_synchronousDonutEventProvider;

-

-    /**

-     * The consumers' instances.

-     */

-    private ComponentInstance[] m_consumersInstances;

-

-    /**

-     * The consumers' service references.

-     */

-    private ServiceReference[] m_consumersServices;

-

-    /**

-     * The consumers' services.

-     */

-    private DonutConsumer[] m_consumers;

-

-    /**

-     * The slow consumers' services.

-     */

-    private DonutConsumer[] m_quickConsumers;

-

-    /**

-     * The event tracker' instances.

-     */

-    private ComponentInstance m_eventTrackerInstance;

-

-    /**

-     * The event tracker' service references.

-     */

-    private ServiceReference m_eventTrackerService;

-

-    /**

-     * The event tracker service.

-     */

-    private EventTracker m_eventTracker;

-

-    /**

-     * The filtered consumers' instances.

-     */

-    private ComponentInstance[] m_filteredConsumersInstances;

-

-    /**

-     * The filtered consumers' service references.

-     */

-    private ServiceReference[] m_filteredConsumersServices;

-

-    /**

-     * The filtered consumers' services.

-     */

-    private DonutConsumer[] m_filteredConsumers;

-

-    /**

-     * The providers' instances with specified topics.

-     */

-    private ComponentInstance[] m_topicsProvidersInstances;

-

-    /**

-     * The providers' service references with specified topics.

-     */

-    private ServiceReference[] m_topicsProvidersServices;

-

-    /**

-     * The providers' service with specified topics.

-     */

-    private DonutProvider[] m_topicsProviders;

-

-    /**

-     * The provider that send donuts on the "foo" topic.

-     */

-    private DonutProvider m_fooProvider;

-

-    /**

-     * The provider that send donuts on the "bar" topic.

-     */

-    private DonutProvider m_barProvider;

-

-    /**

-     * The provider that send donuts on the "nut" topic.

-     */

-    private DonutProvider m_nutProvider;

-

-    /**

-     * The provider that send donuts on the "foo,bar" topics.

-     */

-    private DonutProvider m_fooBarProvider;

-

-    /**

-     * The provider that send donuts on the "bar,nut" topics.

-     */

-    private DonutProvider m_barNutProvider;

-

-    /**

-     * The provider that send donuts on the "foo,nut" topics.

-     */

-    private DonutProvider m_fooNutProvider;

-

-    /**

-     * The provider that send donuts on the "foo,bar,nut" topics.

-     */

-    private DonutProvider m_fooBarNutProvider;

-

-    /**

-     * The consumers' instances with specified topics.

-     */

-    private ComponentInstance[] m_topicsConsumersInstances;

-

-    /**

-     * The consumers' service references with specified topics.

-     */

-    private ServiceReference[] m_topicsConsumersServices;

-

-    /**

-     * The consumers' service references with specified topics.

-     */

-    private DonutConsumer[] m_topicsConsumers;

-

-    /**

-     * The consumer that receive donuts on the "foo" topic.

-     */

-    private DonutConsumer m_fooConsumer;

-

-    /**

-     * The consumer that receive donuts on the "bar" topic.

-     */

-    private DonutConsumer m_barConsumer;

-

-    /**

-     * The consumer that receive donuts on the "nut" topic.

-     */

-    private DonutConsumer m_nutConsumer;

-

-    /**

-     * The consumer that receive donuts on the "foo,bar" topics.

-     */

-    private DonutConsumer m_fooBarConsumer;

-

-    /**

-     * The consumer that receive donuts on the "bar,nut" topics.

-     */

-    private DonutConsumer m_barNutConsumer;

-

-    /**

-     * The consumer that receive donuts on the "foo,nut" topics.

-     */

-    private DonutConsumer m_fooNutConsumer;

-

-    /**

-     * The consumer that receive donuts on the "foo,bar,nut" topics.

-     */

-    private DonutConsumer m_fooBarNutConsumer;

-

-    /**

-     * Initialization before test cases.

-     * 

-     * Create all the instances

-     * 

-     * @throws UnacceptableConfiguration

-     *             something bad happened

-     * @throws MissingHandlerException

-     *             something bad happened

-     * @throws ConfigurationException

-     *             something bad happened

-     * 

-     */

-    public void setUp()

-        throws UnacceptableConfiguration, MissingHandlerException,

-        ConfigurationException {

-

-        m_utils = new EahTestUtils(context);

-        Dictionary properties = new Hashtable();

-

-        // All the providers

-        m_providersInstances = new ComponentInstance[NUMBER_OF_PROVIDERS];

-        m_providersServices = new ServiceReference[NUMBER_OF_PROVIDERS];

-        m_providers = new DonutProvider[NUMBER_OF_PROVIDERS];

-        m_synchronousProviders = new DonutProvider[NUMBER_OF_SYNCHRONOUS_PROVIDERS];

-        m_eahProviders = new DonutProvider[NUMBER_OF_EAH_PROVIDERS];

-        m_eahProvidersInstances = new ComponentInstance[NUMBER_OF_EAH_PROVIDERS];

-        m_topicsProvidersInstances = new ComponentInstance[TOPICS_LIST.length];

-        m_topicsProvidersServices = new ServiceReference[TOPICS_LIST.length];

-        m_topicsProviders = new DonutProvider[TOPICS_LIST.length];

-

-        // Create the (asynchronous) donut provider

-        properties.put("instance.name","asynchronous donut provider");

-        m_providersInstances[0] = m_utils.getDonutProviderFactory()

-                .createComponentInstance(properties);

-

-        // Create the synchronous donut provider

-        properties = new Hashtable();

-        properties.put("instance.name","synchronous donut provider");

-        m_providersInstances[1] = m_utils.getSynchronousDonutProviderFactory()

-                .createComponentInstance(properties);

-

-        // Create the (asynchronous) donut event provider

-        properties = new Hashtable();

-        properties.put("instance.name","asynchronous donut event provider");

-        m_providersInstances[2] = m_utils.getDonutEventProviderFactory()

-                .createComponentInstance(properties);

-

-        // Create the synchronous donut event provider

-        properties = new Hashtable();

-        properties.put("instance.name","synchronous donut event provider");

-        m_providersInstances[3] = m_utils

-                .getSynchronousDonutEventProviderFactory()

-                .createComponentInstance(properties);

-

-        // Create the (asynchronous) event provider

-        properties = new Hashtable();

-        properties.put("instance.name","asynchronous event provider");

-        m_providersInstances[4] = m_utils.getEventProviderFactory()

-                .createComponentInstance(properties);

-

-        // Create the synchronous event provider

-        properties = new Hashtable();

-        properties.put("instance.name","synchronous event provider");

-        m_providersInstances[5] = m_utils.getSynchronousEventProviderFactory()

-                .createComponentInstance(properties);

-

-        // Get all the services references

-        for (int i = 0; i < NUMBER_OF_PROVIDERS; i++) {

-            m_providersServices[i] = IPojoTestUtils.getServiceReferenceByName(

-                    context, DonutProvider.class.getName(),

-                    m_providersInstances[i].getInstanceName());

-            m_providers[i] = (DonutProvider) context

-                    .getService(m_providersServices[i]);

-        }

-        m_synchronousProviders[0] = m_providers[1];

-        m_synchronousProviders[1] = m_providers[3];

-        m_synchronousProviders[2] = m_providers[5];

-        m_eahProviders[0] = m_providers[0];

-        m_eahProviders[1] = m_providers[1];

-        m_eahProviders[2] = m_providers[2];

-        m_eahProviders[3] = m_providers[3];

-        m_eahProvidersInstances[0] = m_providersInstances[0];

-        m_eahProvidersInstances[1] = m_providersInstances[1];

-        m_eahProvidersInstances[2] = m_providersInstances[2];

-        m_eahProvidersInstances[3] = m_providersInstances[3];

-        m_synchronousDonutEventProvider = m_providers[3];

-

-        // All the consumers

-        m_consumersInstances = new ComponentInstance[NUMBER_OF_CONSUMERS];

-        m_consumersServices = new ServiceReference[NUMBER_OF_CONSUMERS];

-        m_consumers = new DonutConsumer[NUMBER_OF_CONSUMERS];

-        m_quickConsumers = new DonutConsumer[NUMBER_OF_QUICK_CONSUMERS];

-        m_filteredConsumersInstances = new ComponentInstance[Donut.FLAVOURS.length];

-        m_filteredConsumersServices = new ServiceReference[Donut.FLAVOURS.length];

-        m_filteredConsumers = new DonutConsumer[Donut.FLAVOURS.length];

-        m_topicsConsumersInstances = new ComponentInstance[TOPICS_LIST.length];

-        m_topicsConsumersServices = new ServiceReference[TOPICS_LIST.length];

-        m_topicsConsumers = new DonutConsumer[TOPICS_LIST.length];

-

-        // Create the (quick) donut consumer

-        properties = new Hashtable();

-        properties.put("instance.name","quick donut consumer");

-        m_consumersInstances[0] = m_utils.getDonutConsumerFactory()

-                .createComponentInstance(properties);

-

-        // Create the (quick) donut event consumer

-        properties = new Hashtable();

-        properties.put("instance.name","quick donut event consumer");

-        m_consumersInstances[1] = m_utils.getDonutEventConsumerFactory()

-                .createComponentInstance(properties);

-

-        // Create the (quick) event consumer

-        properties = new Hashtable();

-        properties.put("instance.name","quick event consumer");

-        m_consumersInstances[2] = m_utils.getEventConsumerFactory()

-                .createComponentInstance(properties);

-

-        // Create the slow donut consumer

-        properties = new Hashtable();

-        properties.put("slow", Boolean.TRUE);

-        properties.put("instance.name","slow donut consumer");

-        m_consumersInstances[3] = m_utils.getDonutConsumerFactory()

-                .createComponentInstance(properties);

-

-        // Create the slow donut event consumer

-        properties = new Hashtable();

-        properties.put("instance.name","slow donut event consumer");

-        properties.put("slow", Boolean.TRUE);

-        m_consumersInstances[4] = m_utils.getDonutEventConsumerFactory()

-                .createComponentInstance(properties);

-

-        // Create the slow event consumer

-        properties = new Hashtable();

-        properties.put("instance.name","slow event consumer");

-        properties.put("slow", Boolean.TRUE);

-        m_consumersInstances[5] = m_utils.getEventConsumerFactory()

-                .createComponentInstance(properties);

-

-        // Get all the services references

-        for (int i = 0; i < NUMBER_OF_CONSUMERS; i++) {

-            m_consumersServices[i] = IPojoTestUtils.getServiceReferenceByName(

-                    context, DonutConsumer.class.getName(),

-                    m_consumersInstances[i].getInstanceName());

-            m_consumers[i] = (DonutConsumer) context

-                    .getService(m_consumersServices[i]);

-        }

-        m_quickConsumers[0] = m_consumers[0];

-        m_quickConsumers[1] = m_consumers[1];

-        m_quickConsumers[2] = m_consumers[2];

-

-        // Create the event tracker

-        properties = new Hashtable();

-        properties.put("instance.name","event tracker");

-        m_eventTrackerInstance = m_utils.getEventTrackerFactory()

-                .createComponentInstance(properties);

-        m_eventTrackerService = IPojoTestUtils.getServiceReferenceByName(

-                context, EventTracker.class.getName(), m_eventTrackerInstance

-                        .getInstanceName());

-        m_eventTracker = (EventTracker) context

-                .getService(m_eventTrackerService);

-

-        // Create the filtered consumer

-        Dictionary filter = new Hashtable();

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

-            String flavour = Donut.FLAVOURS[i];

-            properties = new Hashtable();

-            filter.put("donut-event-subscriber", "(flavour=" + flavour + ")");

-            properties.put("instance.name",flavour + " donut consumer");

-            properties.put("event.filter", filter);

-            m_filteredConsumersInstances[i] = m_utils

-                    .getDonutEventConsumerFactory().createComponentInstance(

-                            properties);

-            m_filteredConsumersServices[i] = IPojoTestUtils

-                    .getServiceReferenceByName(context, DonutConsumer.class

-                            .getName(), m_filteredConsumersInstances[i]

-                            .getInstanceName());

-            m_filteredConsumers[i] = (DonutConsumer) context

-                    .getService(m_filteredConsumersServices[i]);

-        }

-

-        // Create the providers and consumers selling and receiving donuts on

-        // specific topics

-        Dictionary topics = new Hashtable();

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

-            String topicsString = TOPICS_LIST[i];

-            properties = new Hashtable();

-            // Create provider

-            topics.put("donut-publisher", topicsString);

-            properties.put("event.topics", topics);

-            properties.put("instance.name",topicsString + " donut provider");

-            m_topicsProvidersInstances[i] = m_utils

-                    .getSynchronousDonutProviderFactory()

-                    .createComponentInstance(properties);

-            m_topicsProvidersServices[i] = IPojoTestUtils

-                    .getServiceReferenceByName(context, DonutProvider.class

-                            .getName(), m_topicsProvidersInstances[i]

-                            .getInstanceName());

-            m_topicsProviders[i] = (DonutProvider) context

-                    .getService(m_topicsProvidersServices[i]);

-

-            // Create consumer

-            properties = new Hashtable();

-            topics.put("donut-subscriber", topicsString);

-            properties.put("event.topics", topics);

-            properties.put("instance.name",topicsString + " donut consumer");

-

-            m_topicsConsumersInstances[i] = m_utils.getDonutConsumerFactory()

-                    .createComponentInstance(properties);

-            m_topicsConsumersServices[i] = IPojoTestUtils

-                    .getServiceReferenceByName(context, DonutConsumer.class

-                            .getName(), m_topicsConsumersInstances[i]

-                            .getInstanceName());

-            m_topicsConsumers[i] = (DonutConsumer) context

-                    .getService(m_topicsConsumersServices[i]);

-            topics.remove("donut-subscriber");

-        }

-

-        m_fooProvider = m_topicsProviders[0];

-        m_barProvider = m_topicsProviders[1];

-        m_nutProvider = m_topicsProviders[2];

-        m_fooBarProvider = m_topicsProviders[3];

-        m_barNutProvider = m_topicsProviders[4];

-        m_fooNutProvider = m_topicsProviders[5];

-        m_fooBarNutProvider = m_topicsProviders[6];

-        m_fooConsumer = m_topicsConsumers[0];

-        m_barConsumer = m_topicsConsumers[1];

-        m_nutConsumer = m_topicsConsumers[2];

-        m_fooBarConsumer = m_topicsConsumers[3];

-        m_barNutConsumer = m_topicsConsumers[4];

-        m_fooNutConsumer = m_topicsConsumers[5];

-        m_fooBarNutConsumer = m_topicsConsumers[6];

-

-    }

-

-    /**

-     * Test the event handler reliability by sending events with all kinds of

-     * publisher and check they are received by all kinds of subscriber.

-     */

-    public void testReliability() {

-

-        // Flush donut list for each consumer

-        for (int i = 0; i < NUMBER_OF_CONSUMERS; i++) {

-            m_consumers[i].clearDonuts();

-        }

-

-        // Send a lot of donut with each provider

-        List sentDonuts = new ArrayList(NUMBER_OF_PROVIDERS

-                * EahTestUtils.NUMBER_OF_TESTS);

-        for (int i = 0; i < NUMBER_OF_PROVIDERS; i++) {

-            for (int j = 0; j < EahTestUtils.NUMBER_OF_TESTS; j++) {

-                sentDonuts.add(m_providers[i].sellDonut());

-            }

-        }

-

-        // Wait a respectable amount of time

-        EahTestUtils.sleep(EahTestUtils.BLACK_LIST_TIME

-                + EahTestUtils.A_LONG_TIME);

-

-        // Collect all received donuts for each consumer

-        for (int i = 0; i < NUMBER_OF_CONSUMERS; i++) {

-            List receivedDonuts = Arrays.asList(m_consumers[i].getAllDonuts());

-            assertEquals(

-                    "The number of received donuts must be the same as the number of sent donuts.",

-                    sentDonuts.size(), receivedDonuts.size());

-            assertTrue("The receiver must have eaten all sent donuts.",

-                    receivedDonuts.containsAll(sentDonuts));

-        }

-    }

-

-    /**

-     * Test the synchronism of event sending for the component.

-     * 

-     * This test consists to send synchronously a big amount of donuts and to

-     * check immediately if it has been received (by all quick consumers).

-     */

-    public void testSynchronism() {

-

-        // Flush donut list for quick consumers

-        for (int i = 0; i < NUMBER_OF_QUICK_CONSUMERS; i++) {

-            m_quickConsumers[i].clearDonuts();

-        }

-

-        // Send a lot of donuts and check they are immediately received.

-        Donut sentDonut;

-        Donut receivedDonut;

-        for (int i = 0; i < EahTestUtils.NUMBER_OF_TESTS; i++) {

-            for (int j = 0; j < NUMBER_OF_SYNCHRONOUS_PROVIDERS; j++) {

-                sentDonut = m_synchronousProviders[j].sellDonut();

-                for (int k = 0; k < NUMBER_OF_QUICK_CONSUMERS; k++) {

-                    receivedDonut = m_quickConsumers[k].getDonut();

-                    assertEquals(

-                            "The donut must have been received immediately and be the be the same as the sent one.",

-                            sentDonut, receivedDonut);

-                }

-            }

-        }

-    }

-

-    /**

-     * Test that the received events contains the instance name of the sender.

-     */

-    public void testInstanceName() {

-

-        // Flush event list of the event tracker

-        m_eventTracker.clearEvents();

-

-        // Send donuts and check the sender instance name

-        Event receivedEvent;

-        for (int i = 0; i < NUMBER_OF_EAH_PROVIDERS; i++) {

-            m_eahProviders[i].sellDonut();

-            receivedEvent = m_eventTracker.waitForEvent();

-            assertEquals(

-                    "The instance name property of the received message must be the same as the sender instance name.",

-                    m_eahProvidersInstances[i].getInstanceName(), receivedEvent

-                            .getProperty("publisher.instance.name"));

-        }

-    }

-

-    /**

-     * Test the event filtering.

-     * 

-     * This test send donuts with different flavours. Each filtered consumer

-     * must receive only a certain kind of donut. Of course, all donuts must

-     * have been received too.

-     */

-    public void testFilters() {

-

-        // The sent donuts, sorted by flavour

-        List[] sentDonuts = new List[Donut.FLAVOURS.length];

-

-        // Flush donut list for each filtered consumer

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

-            m_filteredConsumers[i].clearDonuts();

-            sentDonuts[i] = new ArrayList(EahTestUtils.NUMBER_OF_TESTS

-                    / Donut.FLAVOURS.length);

-        }

-

-        // Send donuts

-        for (int j = 0; j < EahTestUtils.NUMBER_OF_TESTS; j++) {

-            Donut donut = m_synchronousDonutEventProvider.sellDonut();

-            sentDonuts[EahTestUtils.flavourIndex(donut.getFlavour())]

-                    .add(donut);

-        }

-

-        // Check the received donuts

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

-            Donut[] receivedDonuts = m_filteredConsumers[i].getAllDonuts();

-            assertEquals(

-                    "The number of received donuts must be the same as the number of sent donuts with the matching flavour.",

-                    sentDonuts[i].size(), receivedDonuts.length);

-            assertTrue(

-                    "The receiver must have eaten all sent donuts matching the wanted flavour.",

-                    Arrays.asList(receivedDonuts).containsAll(sentDonuts[i]));

-        }

-

-    }

-

-    /**

-     * Test the event topic.

-     * 

-     * This test send donuts on several topics. Each consumer (who listens to

-     * one or several topics) must receive donuts sent on his specifics topics.

-     */

-    public void testTopics() {

-

-        // The sent donuts, sorted by topic

-        int foos = 0;

-        int bars = 0;

-        int nuts = 0;

-

-        // Flush consumers

-        m_fooConsumer.clearDonuts();

-        m_barConsumer.clearDonuts();

-        m_nutConsumer.clearDonuts();

-        m_fooBarConsumer.clearDonuts();

-        m_barNutConsumer.clearDonuts();

-        m_fooNutConsumer.clearDonuts();

-        m_fooBarNutConsumer.clearDonuts();

-

-        // Send donuts

-        for (int i = 0; i < EahTestUtils.NUMBER_OF_TESTS; i++) {

-            m_fooProvider.sellDonut();

-            foos++;

-

-            m_barProvider.sellDonut();

-            bars++;

-

-            m_nutProvider.sellDonut();

-            nuts++;

-

-            m_fooBarProvider.sellDonut();

-            foos++;

-            bars++;

-

-            m_barNutProvider.sellDonut();

-            bars++;

-            nuts++;

-

-            m_fooNutProvider.sellDonut();

-            foos++;

-            nuts++;

-

-            m_fooBarNutProvider.sellDonut();

-            foos++;

-            bars++;

-            nuts++;

-        }

-

-        // Check received donuts

-        assertEquals("The number of received donuts must be correct.", foos,

-                m_fooConsumer.getAllDonuts().length);

-        assertEquals("The number of received donuts must be correct.", bars,

-                m_barConsumer.getAllDonuts().length);

-        assertEquals("The number of received donuts must be correct.", nuts,

-                m_nutConsumer.getAllDonuts().length);

-        assertEquals("The number of received donuts must be correct.", foos

-                + bars, m_fooBarConsumer.getAllDonuts().length);

-        assertEquals("The number of received donuts must be correct.", bars

-                + nuts, m_barNutConsumer.getAllDonuts().length);

-        assertEquals("The number of received donuts must be correct.", foos

-                + nuts, m_fooNutConsumer.getAllDonuts().length);

-        assertEquals("The number of received donuts must be correct.", foos

-                + bars + nuts, m_fooBarNutConsumer.getAllDonuts().length);

-

-    }

-

-    /**

-     * Finalization after test cases.

-     * 

-     * Release all services references and destroy instances.

-     */

-    public void tearDown() {

-        int index;

-        for (index = 0; index < NUMBER_OF_PROVIDERS; index++) {

-            context.ungetService(m_providersServices[index]);

-            m_providersInstances[index].dispose();

-        }

-        for (index = 0; index < NUMBER_OF_CONSUMERS; index++) {

-            context.ungetService(m_consumersServices[index]);

-            m_consumersInstances[index].dispose();

-        }

-        context.ungetService(m_eventTrackerService);

-        m_eventTrackerInstance.dispose();

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

-            context.ungetService(m_filteredConsumersServices[i]);

-            m_filteredConsumersInstances[i].dispose();

-        }

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

-            context.ungetService(m_topicsProvidersServices[i]);

-            m_topicsProvidersInstances[i].dispose();

-            context.ungetService(m_topicsConsumersServices[i]);

-            m_topicsConsumersInstances[i].dispose();

-        }

-

-    }

-

-}

+/* 
+ * 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.test;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.List;
+
+import org.apache.felix.ipojo.ComponentInstance;
+import org.apache.felix.ipojo.ConfigurationException;
+import org.apache.felix.ipojo.MissingHandlerException;
+import org.apache.felix.ipojo.UnacceptableConfiguration;
+import org.apache.felix.ipojo.junit4osgi.OSGiTestCase;
+import org.apache.felix.ipojo.test.donut.Donut;
+import org.apache.felix.ipojo.test.donut.DonutConsumer;
+import org.apache.felix.ipojo.test.donut.DonutProvider;
+import org.apache.felix.ipojo.test.donut.EventTracker;
+import org.apache.felix.ipojo.test.util.EahTestUtils;
+import org.apache.felix.ipojo.test.util.IPojoTestUtils;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.event.Event;
+
+/**
+ * Test the good behaviour of the EventAdminHandler.
+ * 
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class GoodTests extends OSGiTestCase {
+
+    /**
+     * The number of providers to test.
+     */
+    private static final int NUMBER_OF_PROVIDERS = 6;
+
+    /**
+     * The number of providers using the event admin handler to test.
+     */
+    private static final int NUMBER_OF_EAH_PROVIDERS = 4;
+
+    /**
+     * The number of consumers to test.
+     */
+    private static final int NUMBER_OF_CONSUMERS = 6;
+
+    /**
+     * The number of synchronous providers to test.
+     */
+    private static final int NUMBER_OF_SYNCHRONOUS_PROVIDERS = 3;
+
+    /**
+     * The number of slow consumers to test.
+     */
+    private static final int NUMBER_OF_QUICK_CONSUMERS = 3;
+
+    /**
+     * The list of topics to test.
+     */
+    private static final String[] TOPICS_LIST = { "foo", "bar", "nut",
+        "foo,bar", "bar,nut", "foo,nut", "foo,bar,nut" };
+
+    /**
+     * The utility class instance.
+     */
+    public EahTestUtils m_utils;
+
+    /**
+     * The providers' instances.
+     */
+    private ComponentInstance[] m_providersInstances;
+
+    /**
+     * The providers' service references.
+     */
+    private ServiceReference[] m_providersServices;
+
+    /**
+     * The providers' services.
+     */
+    private DonutProvider[] m_providers;
+
+    /**
+     * The synchronous providers' services.
+     */
+    private DonutProvider[] m_synchronousProviders;
+
+    /**
+     * The instances of providers that uses the event admin handler.
+     */
+    private ComponentInstance[] m_eahProvidersInstances;
+
+    /**
+     * The services of the providers that uses the event admin handler.
+     */
+    private DonutProvider[] m_eahProviders;
+
+    /**
+     * The synchronous donut event provider service.
+     */
+    private DonutProvider m_synchronousDonutEventProvider;
+
+    /**
+     * The consumers' instances.
+     */
+    private ComponentInstance[] m_consumersInstances;
+
+    /**
+     * The consumers' service references.
+     */
+    private ServiceReference[] m_consumersServices;
+
+    /**
+     * The consumers' services.
+     */
+    private DonutConsumer[] m_consumers;
+
+    /**
+     * The slow consumers' services.
+     */
+    private DonutConsumer[] m_quickConsumers;
+
+    /**
+     * The event tracker' instances.
+     */
+    private ComponentInstance m_eventTrackerInstance;
+
+    /**
+     * The event tracker' service references.
+     */
+    private ServiceReference m_eventTrackerService;
+
+    /**
+     * The event tracker service.
+     */
+    private EventTracker m_eventTracker;
+
+    /**
+     * The filtered consumers' instances.
+     */
+    private ComponentInstance[] m_filteredConsumersInstances;
+
+    /**
+     * The filtered consumers' service references.
+     */
+    private ServiceReference[] m_filteredConsumersServices;
+
+    /**
+     * The filtered consumers' services.
+     */
+    private DonutConsumer[] m_filteredConsumers;
+
+    /**
+     * The providers' instances with specified topics.
+     */
+    private ComponentInstance[] m_topicsProvidersInstances;
+
+    /**
+     * The providers' service references with specified topics.
+     */
+    private ServiceReference[] m_topicsProvidersServices;
+
+    /**
+     * The providers' service with specified topics.
+     */
+    private DonutProvider[] m_topicsProviders;
+
+    /**
+     * The provider that send donuts on the "foo" topic.
+     */
+    private DonutProvider m_fooProvider;
+
+    /**
+     * The provider that send donuts on the "bar" topic.
+     */
+    private DonutProvider m_barProvider;
+
+    /**
+     * The provider that send donuts on the "nut" topic.
+     */
+    private DonutProvider m_nutProvider;
+
+    /**
+     * The provider that send donuts on the "foo,bar" topics.
+     */
+    private DonutProvider m_fooBarProvider;
+
+    /**
+     * The provider that send donuts on the "bar,nut" topics.
+     */
+    private DonutProvider m_barNutProvider;
+
+    /**
+     * The provider that send donuts on the "foo,nut" topics.
+     */
+    private DonutProvider m_fooNutProvider;
+
+    /**
+     * The provider that send donuts on the "foo,bar,nut" topics.
+     */
+    private DonutProvider m_fooBarNutProvider;
+
+    /**
+     * The consumers' instances with specified topics.
+     */
+    private ComponentInstance[] m_topicsConsumersInstances;
+
+    /**
+     * The consumers' service references with specified topics.
+     */
+    private ServiceReference[] m_topicsConsumersServices;
+
+    /**
+     * The consumers' service references with specified topics.
+     */
+    private DonutConsumer[] m_topicsConsumers;
+
+    /**
+     * The consumer that receive donuts on the "foo" topic.
+     */
+    private DonutConsumer m_fooConsumer;
+
+    /**
+     * The consumer that receive donuts on the "bar" topic.
+     */
+    private DonutConsumer m_barConsumer;
+
+    /**
+     * The consumer that receive donuts on the "nut" topic.
+     */
+    private DonutConsumer m_nutConsumer;
+
+    /**
+     * The consumer that receive donuts on the "foo,bar" topics.
+     */
+    private DonutConsumer m_fooBarConsumer;
+
+    /**
+     * The consumer that receive donuts on the "bar,nut" topics.
+     */
+    private DonutConsumer m_barNutConsumer;
+
+    /**
+     * The consumer that receive donuts on the "foo,nut" topics.
+     */
+    private DonutConsumer m_fooNutConsumer;
+
+    /**
+     * The consumer that receive donuts on the "foo,bar,nut" topics.
+     */
+    private DonutConsumer m_fooBarNutConsumer;
+
+    /**
+     * Initialization before test cases.
+     * 
+     * Create all the instances
+     * 
+     * @throws UnacceptableConfiguration
+     *             something bad happened
+     * @throws MissingHandlerException
+     *             something bad happened
+     * @throws ConfigurationException
+     *             something bad happened
+     * 
+     */
+    public void setUp()
+        throws UnacceptableConfiguration, MissingHandlerException,
+        ConfigurationException {
+
+        m_utils = new EahTestUtils(context);
+        Dictionary properties = new Hashtable();
+
+        // All the providers
+        m_providersInstances = new ComponentInstance[NUMBER_OF_PROVIDERS];
+        m_providersServices = new ServiceReference[NUMBER_OF_PROVIDERS];
+        m_providers = new DonutProvider[NUMBER_OF_PROVIDERS];
+        m_synchronousProviders = new DonutProvider[NUMBER_OF_SYNCHRONOUS_PROVIDERS];
+        m_eahProviders = new DonutProvider[NUMBER_OF_EAH_PROVIDERS];
+        m_eahProvidersInstances = new ComponentInstance[NUMBER_OF_EAH_PROVIDERS];
+        m_topicsProvidersInstances = new ComponentInstance[TOPICS_LIST.length];
+        m_topicsProvidersServices = new ServiceReference[TOPICS_LIST.length];
+        m_topicsProviders = new DonutProvider[TOPICS_LIST.length];
+
+        // Create the (asynchronous) donut provider
+        properties.put("instance.name","asynchronous donut provider");
+        m_providersInstances[0] = m_utils.getDonutProviderFactory()
+                .createComponentInstance(properties);
+
+        // Create the synchronous donut provider
+        properties = new Hashtable();
+        properties.put("instance.name","synchronous donut provider");
+        m_providersInstances[1] = m_utils.getSynchronousDonutProviderFactory()
+                .createComponentInstance(properties);
+
+        // Create the (asynchronous) donut event provider
+        properties = new Hashtable();
+        properties.put("instance.name","asynchronous donut event provider");
+        m_providersInstances[2] = m_utils.getDonutEventProviderFactory()
+                .createComponentInstance(properties);
+
+        // Create the synchronous donut event provider
+        properties = new Hashtable();
+        properties.put("instance.name","synchronous donut event provider");
+        m_providersInstances[3] = m_utils
+                .getSynchronousDonutEventProviderFactory()
+                .createComponentInstance(properties);
+
+        // Create the (asynchronous) event provider
+        properties = new Hashtable();
+        properties.put("instance.name","asynchronous event provider");
+        m_providersInstances[4] = m_utils.getEventProviderFactory()
+                .createComponentInstance(properties);
+
+        // Create the synchronous event provider
+        properties = new Hashtable();
+        properties.put("instance.name","synchronous event provider");
+        m_providersInstances[5] = m_utils.getSynchronousEventProviderFactory()
+                .createComponentInstance(properties);
+
+        // Get all the services references
+        for (int i = 0; i < NUMBER_OF_PROVIDERS; i++) {
+            m_providersServices[i] = IPojoTestUtils.getServiceReferenceByName(
+                    context, DonutProvider.class.getName(),
+                    m_providersInstances[i].getInstanceName());
+            m_providers[i] = (DonutProvider) context
+                    .getService(m_providersServices[i]);
+        }
+        m_synchronousProviders[0] = m_providers[1];
+        m_synchronousProviders[1] = m_providers[3];
+        m_synchronousProviders[2] = m_providers[5];
+        m_eahProviders[0] = m_providers[0];
+        m_eahProviders[1] = m_providers[1];
+        m_eahProviders[2] = m_providers[2];
+        m_eahProviders[3] = m_providers[3];
+        m_eahProvidersInstances[0] = m_providersInstances[0];
+        m_eahProvidersInstances[1] = m_providersInstances[1];
+        m_eahProvidersInstances[2] = m_providersInstances[2];
+        m_eahProvidersInstances[3] = m_providersInstances[3];
+        m_synchronousDonutEventProvider = m_providers[3];
+
+        // All the consumers
+        m_consumersInstances = new ComponentInstance[NUMBER_OF_CONSUMERS];
+        m_consumersServices = new ServiceReference[NUMBER_OF_CONSUMERS];
+        m_consumers = new DonutConsumer[NUMBER_OF_CONSUMERS];
+        m_quickConsumers = new DonutConsumer[NUMBER_OF_QUICK_CONSUMERS];
+        m_filteredConsumersInstances = new ComponentInstance[Donut.FLAVOURS.length];
+        m_filteredConsumersServices = new ServiceReference[Donut.FLAVOURS.length];
+        m_filteredConsumers = new DonutConsumer[Donut.FLAVOURS.length];
+        m_topicsConsumersInstances = new ComponentInstance[TOPICS_LIST.length];
+        m_topicsConsumersServices = new ServiceReference[TOPICS_LIST.length];
+        m_topicsConsumers = new DonutConsumer[TOPICS_LIST.length];
+
+        // Create the (quick) donut consumer
+        properties = new Hashtable();
+        properties.put("instance.name","quick donut consumer");
+        m_consumersInstances[0] = m_utils.getDonutConsumerFactory()
+                .createComponentInstance(properties);
+
+        // Create the (quick) donut event consumer
+        properties = new Hashtable();
+        properties.put("instance.name","quick donut event consumer");
+        m_consumersInstances[1] = m_utils.getDonutEventConsumerFactory()
+                .createComponentInstance(properties);
+
+        // Create the (quick) event consumer
+        properties = new Hashtable();
+        properties.put("instance.name","quick event consumer");
+        m_consumersInstances[2] = m_utils.getEventConsumerFactory()
+                .createComponentInstance(properties);
+
+        // Create the slow donut consumer
+        properties = new Hashtable();
+        properties.put("slow", Boolean.TRUE);
+        properties.put("instance.name","slow donut consumer");
+        m_consumersInstances[3] = m_utils.getDonutConsumerFactory()
+                .createComponentInstance(properties);
+
+        // Create the slow donut event consumer
+        properties = new Hashtable();
+        properties.put("instance.name","slow donut event consumer");
+        properties.put("slow", Boolean.TRUE);
+        m_consumersInstances[4] = m_utils.getDonutEventConsumerFactory()
+                .createComponentInstance(properties);
+
+        // Create the slow event consumer
+        properties = new Hashtable();
+        properties.put("instance.name","slow event consumer");
+        properties.put("slow", Boolean.TRUE);
+        m_consumersInstances[5] = m_utils.getEventConsumerFactory()
+                .createComponentInstance(properties);
+
+        // Get all the services references
+        for (int i = 0; i < NUMBER_OF_CONSUMERS; i++) {
+            m_consumersServices[i] = IPojoTestUtils.getServiceReferenceByName(
+                    context, DonutConsumer.class.getName(),
+                    m_consumersInstances[i].getInstanceName());
+            m_consumers[i] = (DonutConsumer) context
+                    .getService(m_consumersServices[i]);
+        }
+        m_quickConsumers[0] = m_consumers[0];
+        m_quickConsumers[1] = m_consumers[1];
+        m_quickConsumers[2] = m_consumers[2];
+
+        // Create the event tracker
+        properties = new Hashtable();
+        properties.put("instance.name","event tracker");
+        m_eventTrackerInstance = m_utils.getEventTrackerFactory()
+                .createComponentInstance(properties);
+        m_eventTrackerService = IPojoTestUtils.getServiceReferenceByName(
+                context, EventTracker.class.getName(), m_eventTrackerInstance
+                        .getInstanceName());
+        m_eventTracker = (EventTracker) context
+                .getService(m_eventTrackerService);
+
+        // Create the filtered consumer
+        Dictionary filter = new Hashtable();
+        for (int i = 0; i < Donut.FLAVOURS.length; i++) {
+            String flavour = Donut.FLAVOURS[i];
+            properties = new Hashtable();
+            filter.put("donut-event-subscriber", "(flavour=" + flavour + ")");
+            properties.put("instance.name",flavour + " donut consumer");
+            properties.put("event.filter", filter);
+            m_filteredConsumersInstances[i] = m_utils
+                    .getDonutEventConsumerFactory().createComponentInstance(
+                            properties);
+            m_filteredConsumersServices[i] = IPojoTestUtils
+                    .getServiceReferenceByName(context, DonutConsumer.class
+                            .getName(), m_filteredConsumersInstances[i]
+                            .getInstanceName());
+            m_filteredConsumers[i] = (DonutConsumer) context
+                    .getService(m_filteredConsumersServices[i]);
+        }
+
+        // Create the providers and consumers selling and receiving donuts on
+        // specific topics
+        Dictionary topics = new Hashtable();
+        for (int i = 0; i < TOPICS_LIST.length; i++) {
+            String topicsString = TOPICS_LIST[i];
+            properties = new Hashtable();
+            // Create provider
+            topics.put("donut-publisher", topicsString);
+            properties.put("event.topics", topics);
+            properties.put("instance.name",topicsString + " donut provider");
+            m_topicsProvidersInstances[i] = m_utils
+                    .getSynchronousDonutProviderFactory()
+                    .createComponentInstance(properties);
+            m_topicsProvidersServices[i] = IPojoTestUtils
+                    .getServiceReferenceByName(context, DonutProvider.class
+                            .getName(), m_topicsProvidersInstances[i]
+                            .getInstanceName());
+            m_topicsProviders[i] = (DonutProvider) context
+                    .getService(m_topicsProvidersServices[i]);
+
+            // Create consumer
+            properties = new Hashtable();
+            topics.put("donut-subscriber", topicsString);
+            properties.put("event.topics", topics);
+            properties.put("instance.name",topicsString + " donut consumer");
+
+            m_topicsConsumersInstances[i] = m_utils.getDonutConsumerFactory()
+                    .createComponentInstance(properties);
+            m_topicsConsumersServices[i] = IPojoTestUtils
+                    .getServiceReferenceByName(context, DonutConsumer.class
+                            .getName(), m_topicsConsumersInstances[i]
+                            .getInstanceName());
+            m_topicsConsumers[i] = (DonutConsumer) context
+                    .getService(m_topicsConsumersServices[i]);
+            topics.remove("donut-subscriber");
+        }
+
+        m_fooProvider = m_topicsProviders[0];
+        m_barProvider = m_topicsProviders[1];
+        m_nutProvider = m_topicsProviders[2];
+        m_fooBarProvider = m_topicsProviders[3];
+        m_barNutProvider = m_topicsProviders[4];
+        m_fooNutProvider = m_topicsProviders[5];
+        m_fooBarNutProvider = m_topicsProviders[6];
+        m_fooConsumer = m_topicsConsumers[0];
+        m_barConsumer = m_topicsConsumers[1];
+        m_nutConsumer = m_topicsConsumers[2];
+        m_fooBarConsumer = m_topicsConsumers[3];
+        m_barNutConsumer = m_topicsConsumers[4];
+        m_fooNutConsumer = m_topicsConsumers[5];
+        m_fooBarNutConsumer = m_topicsConsumers[6];
+
+    }
+    
+    /**
+     * Creates a subscriber listening on a pattern topic (ending with '*').
+     * @throws ConfigurationException something bad happened.
+     * @throws MissingHandlerException something bad happened.
+     * @throws UnacceptableConfiguration something bad happened.
+     */
+    public void testSubscriberWithPatternTopic() throws UnacceptableConfiguration, MissingHandlerException, ConfigurationException {
+    	Dictionary properties = new Hashtable();
+    	Dictionary topics = new Hashtable();
+
+        // Create the donut consumer instance, listening on a pattern topic
+        properties.put("instance.name","subscriber with pattern topic");
+        topics.put("donut-subscriber", "a/pattern/topic/*");
+        properties.put("event.topics", topics);
+        
+        ComponentInstance instance = m_utils.getDonutConsumerFactory()
+                .createComponentInstance(properties);
+        instance.dispose();
+    }
+
+    /**
+     * Test the event handler reliability by sending events with all kinds of
+     * publisher and check they are received by all kinds of subscriber.
+     */
+    public void testReliability() {
+
+        // Flush donut list for each consumer
+        for (int i = 0; i < NUMBER_OF_CONSUMERS; i++) {
+            m_consumers[i].clearDonuts();
+        }
+
+        // Send a lot of donut with each provider
+        List sentDonuts = new ArrayList(NUMBER_OF_PROVIDERS
+                * EahTestUtils.NUMBER_OF_TESTS);
+        for (int i = 0; i < NUMBER_OF_PROVIDERS; i++) {
+            for (int j = 0; j < EahTestUtils.NUMBER_OF_TESTS; j++) {
+                sentDonuts.add(m_providers[i].sellDonut());
+            }
+        }
+
+        // Wait a respectable amount of time
+        EahTestUtils.sleep(EahTestUtils.BLACK_LIST_TIME
+                + EahTestUtils.A_LONG_TIME);
+
+        // Collect all received donuts for each consumer
+        for (int i = 0; i < NUMBER_OF_CONSUMERS; i++) {
+            List receivedDonuts = Arrays.asList(m_consumers[i].getAllDonuts());
+            assertEquals(
+                    "The number of received donuts must be the same as the number of sent donuts.",
+                    sentDonuts.size(), receivedDonuts.size());
+            assertTrue("The receiver must have eaten all sent donuts.",
+                    receivedDonuts.containsAll(sentDonuts));
+        }
+    }
+
+    /**
+     * Test the synchronism of event sending for the component.
+     * 
+     * This test consists to send synchronously a big amount of donuts and to
+     * check immediately if it has been received (by all quick consumers).
+     */
+    public void testSynchronism() {
+
+        // Flush donut list for quick consumers
+        for (int i = 0; i < NUMBER_OF_QUICK_CONSUMERS; i++) {
+            m_quickConsumers[i].clearDonuts();
+        }
+
+        // Send a lot of donuts and check they are immediately received.
+        Donut sentDonut;
+        Donut receivedDonut;
+        for (int i = 0; i < EahTestUtils.NUMBER_OF_TESTS; i++) {
+            for (int j = 0; j < NUMBER_OF_SYNCHRONOUS_PROVIDERS; j++) {
+                sentDonut = m_synchronousProviders[j].sellDonut();
+                for (int k = 0; k < NUMBER_OF_QUICK_CONSUMERS; k++) {
+                    receivedDonut = m_quickConsumers[k].getDonut();
+                    assertEquals(
+                            "The donut must have been received immediately and be the be the same as the sent one.",
+                            sentDonut, receivedDonut);
+                }
+            }
+        }
+    }
+
+    /**
+     * Test that the received events contains the instance name of the sender.
+     */
+    public void testInstanceName() {
+
+        // Flush event list of the event tracker
+        m_eventTracker.clearEvents();
+
+        // Send donuts and check the sender instance name
+        Event receivedEvent;
+        for (int i = 0; i < NUMBER_OF_EAH_PROVIDERS; i++) {
+            m_eahProviders[i].sellDonut();
+            receivedEvent = m_eventTracker.waitForEvent();
+            assertEquals(
+                    "The instance name property of the received message must be the same as the sender instance name.",
+                    m_eahProvidersInstances[i].getInstanceName(), receivedEvent
+                            .getProperty("publisher.instance.name"));
+        }
+    }
+
+    /**
+     * Test the event filtering.
+     * 
+     * This test send donuts with different flavours. Each filtered consumer
+     * must receive only a certain kind of donut. Of course, all donuts must
+     * have been received too.
+     */
+    public void testFilters() {
+
+        // The sent donuts, sorted by flavour
+        List[] sentDonuts = new List[Donut.FLAVOURS.length];
+
+        // Flush donut list for each filtered consumer
+        for (int i = 0; i < Donut.FLAVOURS.length; i++) {
+            m_filteredConsumers[i].clearDonuts();
+            sentDonuts[i] = new ArrayList(EahTestUtils.NUMBER_OF_TESTS
+                    / Donut.FLAVOURS.length);
+        }
+
+        // Send donuts
+        for (int j = 0; j < EahTestUtils.NUMBER_OF_TESTS; j++) {
+            Donut donut = m_synchronousDonutEventProvider.sellDonut();
+            sentDonuts[EahTestUtils.flavourIndex(donut.getFlavour())]
+                    .add(donut);
+        }
+
+        // Check the received donuts
+        for (int i = 0; i < Donut.FLAVOURS.length; i++) {
+            Donut[] receivedDonuts = m_filteredConsumers[i].getAllDonuts();
+            assertEquals(
+                    "The number of received donuts must be the same as the number of sent donuts with the matching flavour.",
+                    sentDonuts[i].size(), receivedDonuts.length);
+            assertTrue(
+                    "The receiver must have eaten all sent donuts matching the wanted flavour.",
+                    Arrays.asList(receivedDonuts).containsAll(sentDonuts[i]));
+        }
+
+    }
+
+    /**
+     * Test the event topic.
+     * 
+     * This test send donuts on several topics. Each consumer (who listens to
+     * one or several topics) must receive donuts sent on his specifics topics.
+     */
+    public void testTopics() {
+
+        // The sent donuts, sorted by topic
+        int foos = 0;
+        int bars = 0;
+        int nuts = 0;
+
+        // Flush consumers
+        m_fooConsumer.clearDonuts();
+        m_barConsumer.clearDonuts();
+        m_nutConsumer.clearDonuts();
+        m_fooBarConsumer.clearDonuts();
+        m_barNutConsumer.clearDonuts();
+        m_fooNutConsumer.clearDonuts();
+        m_fooBarNutConsumer.clearDonuts();
+
+        // Send donuts
+        for (int i = 0; i < EahTestUtils.NUMBER_OF_TESTS; i++) {
+            m_fooProvider.sellDonut();
+            foos++;
+
+            m_barProvider.sellDonut();
+            bars++;
+
+            m_nutProvider.sellDonut();
+            nuts++;
+
+            m_fooBarProvider.sellDonut();
+            foos++;
+            bars++;
+
+            m_barNutProvider.sellDonut();
+            bars++;
+            nuts++;
+
+            m_fooNutProvider.sellDonut();
+            foos++;
+            nuts++;
+
+            m_fooBarNutProvider.sellDonut();
+            foos++;
+            bars++;
+            nuts++;
+        }
+
+        // Check received donuts
+        assertEquals("The number of received donuts must be correct.", foos,
+                m_fooConsumer.getAllDonuts().length);
+        assertEquals("The number of received donuts must be correct.", bars,
+                m_barConsumer.getAllDonuts().length);
+        assertEquals("The number of received donuts must be correct.", nuts,
+                m_nutConsumer.getAllDonuts().length);
+        assertEquals("The number of received donuts must be correct.", foos
+                + bars, m_fooBarConsumer.getAllDonuts().length);
+        assertEquals("The number of received donuts must be correct.", bars
+                + nuts, m_barNutConsumer.getAllDonuts().length);
+        assertEquals("The number of received donuts must be correct.", foos
+                + nuts, m_fooNutConsumer.getAllDonuts().length);
+        assertEquals("The number of received donuts must be correct.", foos
+                + bars + nuts, m_fooBarNutConsumer.getAllDonuts().length);
+
+    }
+
+    /**
+     * Finalization after test cases.
+     * 
+     * Release all services references and destroy instances.
+     */
+    public void tearDown() {
+        int index;
+        for (index = 0; index < NUMBER_OF_PROVIDERS; index++) {
+            context.ungetService(m_providersServices[index]);
+            m_providersInstances[index].dispose();
+        }
+        for (index = 0; index < NUMBER_OF_CONSUMERS; index++) {
+            context.ungetService(m_consumersServices[index]);
+            m_consumersInstances[index].dispose();
+        }
+        context.ungetService(m_eventTrackerService);
+        m_eventTrackerInstance.dispose();
+        for (int i = 0; i < Donut.FLAVOURS.length; i++) {
+            context.ungetService(m_filteredConsumersServices[i]);
+            m_filteredConsumersInstances[i].dispose();
+        }
+        for (int i = 0; i < TOPICS_LIST.length; i++) {
+            context.ungetService(m_topicsProvidersServices[i]);
+            m_topicsProvidersInstances[i].dispose();
+            context.ungetService(m_topicsConsumersServices[i]);
+            m_topicsConsumersInstances[i].dispose();
+        }
+
+    }
+
+}
diff --git a/ipojo/tests/handler/eventadmin/src/main/resources/metadata.xml b/ipojo/tests/handler/eventadmin/src/main/resources/metadata.xml
index bfe82b3..bb0e571 100644
--- a/ipojo/tests/handler/eventadmin/src/main/resources/metadata.xml
+++ b/ipojo/tests/handler/eventadmin/src/main/resources/metadata.xml
@@ -1,142 +1,142 @@
-<?xml version="1.0" encoding="UTF-8"?>

-<ipojo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

-	xsi:schemaLocation="org.apache.felix.ipojo http://people.apache.org/~clement/ipojo/schemas/core.xsd 

-	    org.apache.felix.ipojo.handlers.event.EventAdminHandler http://people.apache.org/~clement/ipojo/schemas/event-admin.xsd"

-	xmlns="org.apache.felix.ipojo"

-	xmlns:ev="org.apache.felix.ipojo.handlers.event.EventAdminHandler">

-	

-	<!-- The (asynchronous) donut provider -->

-	<component classname="org.apache.felix.ipojo.test.donut.DonutProviderImpl"

-		name="donut-provider">

-		<!-- Expose the donut provider service -->

-		<provides interface="org.apache.felix.ipojo.test.donut.DonutProvider">

-			<property name="name" field="m_name" value="Unknown donut vendor"/>

-		</provides>

-		<!-- Donut publisher -->

-		<ev:publisher name="donut-publisher" field="m_publisher"

-			topics="food/donuts" data-key="food" synchronous="false"/>

-	</component>

-	

-	<!-- The synchronous donut provider -->

-	<component classname="org.apache.felix.ipojo.test.donut.DonutProviderImpl"

-		name="synchronous-donut-provider">

-		<!-- Expose the donut provider service -->

-		<provides interface="org.apache.felix.ipojo.test.donut.DonutProvider">

-			<property name="name" field="m_name" value="Unknown donut vendor"/>

-		</provides>

-		<!-- Donut publisher -->

-		<ev:publisher name="donut-publisher" field="m_publisher"

-			topics="food/donuts" data-key="food" synchronous="true"/>

-	</component>

-	

-	<!-- The (asynchronous) donut event provider -->

-	<component

-		classname="org.apache.felix.ipojo.test.donut.DonutEventProviderImpl"

-		name="donut-event-provider">

-		<!-- Expose the donut provider service -->

-		<provides interface="org.apache.felix.ipojo.test.donut.DonutProvider">

-			<property name="name" field="m_name" value="Unknown donut vendor"/>

-		</provides>

-		<!-- Raw events publisher -->

-		<ev:publisher name="event-publisher" field="m_publisher"

-			topics="food/donuts" synchronous="false"/>

-	</component>

-	

-	<!-- The synchronous donut event provider -->

-	<component

-		classname="org.apache.felix.ipojo.test.donut.DonutEventProviderImpl"

-		name="synchronous-donut-event-provider">

-		<!-- Expose the donut provider service -->

-		<provides interface="org.apache.felix.ipojo.test.donut.DonutProvider">

-			<property name="name" field="m_name" value="Unknown donut vendor"/>

-		</provides>

-		<!-- Raw events publisher -->

-		<ev:publisher name="event-publisher" field="m_publisher"

-			topics="food/donuts" synchronous="true"/>

-	</component>

-	

-	<!-- The (asynchronous) event provider -->

-	<component

-		classname="org.apache.felix.ipojo.test.donut.AsyncEventProviderImpl"

-		name="event-provider">

-		<!-- Expose the donut provider service -->

-		<provides interface="org.apache.felix.ipojo.test.donut.DonutProvider">

-			<property name="name" field="m_name" value="Unknown donut vendor"/>

-		</provides>

-		<!-- Direcly interacts with the Event Admin service -->

-		<requires field="m_ea"/>

-	</component>

-	

-	<!-- The synchronous event provider -->

-	<component

-		classname="org.apache.felix.ipojo.test.donut.SyncEventProviderImpl"

-		name="synchronous-event-provider">

-		<!-- Expose the donut provider service -->

-		<provides interface="org.apache.felix.ipojo.test.donut.DonutProvider">

-			<property name="name" field="m_name" value="Unknown donut vendor"/>

-		</provides>

-		<!-- Direcly interacts with the Event Admin service -->

-		<requires field="m_ea"/>

-	</component>

-	

-	<!-- The donut consumer -->

-	<component classname="org.apache.felix.ipojo.test.donut.DonutConsumerImpl"

-		name="donut-consumer">

-		<!-- Expose the donut consumer service -->

-		<provides interface="org.apache.felix.ipojo.test.donut.DonutConsumer">

-			<property name="name" field="m_name" value="Unknown donut consumer"/>

-			<property name="slow" field="m_isSlow" value="false"/>

-		</provides>

-		<!-- Donut events subscriber -->

-		<ev:subscriber name="donut-subscriber" callback="receiveDonut"

-			topics="food/donuts" data-key="food"

-			data-type="org.apache.felix.ipojo.test.donut.Donut"/>

-	</component>

-	

-	<!-- The donut event consumer -->

-	<component classname="org.apache.felix.ipojo.test.donut.DonutConsumerImpl"

-		name="donut-event-consumer">

-		<!-- Expose the donut consumer service -->

-		<provides interface="org.apache.felix.ipojo.test.donut.DonutConsumer">

-			<property name="name" field="m_name" value="Unknown donut consumer"/>

-			<property name="slow" field="m_isSlow" value="false"/>

-		</provides>

-		<!-- Raw events subscriber -->

-		<ev:subscriber name="donut-event-subscriber" callback="receiveEvent"

-			topics="food/donuts"/>

-	</component>

-	

-	<!-- The event consumer -->

-	<component classname="org.apache.felix.ipojo.test.donut.EventConsumerImpl"

-		name="event-consumer">

-		<!-- Expose the donut consumer service -->

-		<provides

-			interface="{org.apache.felix.ipojo.test.donut.DonutConsumer,org.osgi.service.event.EventHandler}">

-			<property name="name" field="m_name" value="Unknown event consumer"/>

-			<property name="slow" field="m_isSlow" value="false"/>

-			<property name="event.topics" type="String" value="food/donuts"/>

-		</provides>

-	</component>

-	

-	<!-- The event tracker -->

-	<component classname="org.apache.felix.ipojo.test.donut.EventTrackerImpl"

-		name="event-tracker">

-		<!-- Expose the donut consumer service -->

-		<provides

-			interface="{org.apache.felix.ipojo.test.donut.EventTracker,org.osgi.service.event.EventHandler}">

-			<property name="name" field="m_name" value="Unknown event tracker"/>

-			<property name="event.topics" type="String" value="food/donuts"/>

-		</provides>

-	</component>

-	

-	

-	<!-- Example instances -->

-	<instance component="donut-provider" name="zeifhgbzre">

-		<property name="name" value="zeifhgbzre donuts"/>

-	</instance>

-	<instance component="donut-consumer" name="zeifhgbzre simpson">

-		<property name="name" value="zeifhgbzre simpson"/>

-		<property name="slow" value="false"/>

-	</instance>

-	

+<?xml version="1.0" encoding="UTF-8"?>
+<ipojo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="org.apache.felix.ipojo http://people.apache.org/~clement/ipojo/schemas/core.xsd 
+	    org.apache.felix.ipojo.handlers.event.EventAdminHandler http://people.apache.org/~clement/ipojo/schemas/event-admin.xsd"
+	xmlns="org.apache.felix.ipojo"
+	xmlns:ev="org.apache.felix.ipojo.handlers.event.EventAdminHandler">
+	
+	<!-- The (asynchronous) donut provider -->
+	<component classname="org.apache.felix.ipojo.test.donut.DonutProviderImpl"
+		name="donut-provider">
+		<!-- Expose the donut provider service -->
+		<provides interface="org.apache.felix.ipojo.test.donut.DonutProvider">
+			<property name="name" field="m_name" value="Unknown donut vendor"/>
+		</provides>
+		<!-- Donut publisher -->
+		<ev:publisher name="donut-publisher" field="m_publisher"
+			topics="food/donuts" data-key="food" synchronous="false"/>
+	</component>
+	
+	<!-- The synchronous donut provider -->
+	<component classname="org.apache.felix.ipojo.test.donut.DonutProviderImpl"
+		name="synchronous-donut-provider">
+		<!-- Expose the donut provider service -->
+		<provides interface="org.apache.felix.ipojo.test.donut.DonutProvider">
+			<property name="name" field="m_name" value="Unknown donut vendor"/>
+		</provides>
+		<!-- Donut publisher -->
+		<ev:publisher name="donut-publisher" field="m_publisher"
+			topics="food/donuts" data-key="food" synchronous="true"/>
+	</component>
+	
+	<!-- The (asynchronous) donut event provider -->
+	<component
+		classname="org.apache.felix.ipojo.test.donut.DonutEventProviderImpl"
+		name="donut-event-provider">
+		<!-- Expose the donut provider service -->
+		<provides interface="org.apache.felix.ipojo.test.donut.DonutProvider">
+			<property name="name" field="m_name" value="Unknown donut vendor"/>
+		</provides>
+		<!-- Raw events publisher -->
+		<ev:publisher name="event-publisher" field="m_publisher"
+			topics="food/donuts" synchronous="false"/>
+	</component>
+	
+	<!-- The synchronous donut event provider -->
+	<component
+		classname="org.apache.felix.ipojo.test.donut.DonutEventProviderImpl"
+		name="synchronous-donut-event-provider">
+		<!-- Expose the donut provider service -->
+		<provides interface="org.apache.felix.ipojo.test.donut.DonutProvider">
+			<property name="name" field="m_name" value="Unknown donut vendor"/>
+		</provides>
+		<!-- Raw events publisher -->
+		<ev:publisher name="event-publisher" field="m_publisher"
+			topics="food/donuts" synchronous="true"/>
+	</component>
+	
+	<!-- The (asynchronous) event provider -->
+	<component
+		classname="org.apache.felix.ipojo.test.donut.AsyncEventProviderImpl"
+		name="event-provider">
+		<!-- Expose the donut provider service -->
+		<provides interface="org.apache.felix.ipojo.test.donut.DonutProvider">
+			<property name="name" field="m_name" value="Unknown donut vendor"/>
+		</provides>
+		<!-- Direcly interacts with the Event Admin service -->
+		<requires field="m_ea"/>
+	</component>
+	
+	<!-- The synchronous event provider -->
+	<component
+		classname="org.apache.felix.ipojo.test.donut.SyncEventProviderImpl"
+		name="synchronous-event-provider">
+		<!-- Expose the donut provider service -->
+		<provides interface="org.apache.felix.ipojo.test.donut.DonutProvider">
+			<property name="name" field="m_name" value="Unknown donut vendor"/>
+		</provides>
+		<!-- Direcly interacts with the Event Admin service -->
+		<requires field="m_ea"/>
+	</component>
+	
+	<!-- The donut consumer -->
+	<component classname="org.apache.felix.ipojo.test.donut.DonutConsumerImpl"
+		name="donut-consumer">
+		<!-- Expose the donut consumer service -->
+		<provides interface="org.apache.felix.ipojo.test.donut.DonutConsumer">
+			<property name="name" field="m_name" value="Unknown donut consumer"/>
+			<property name="slow" field="m_isSlow" value="false"/>
+		</provides>
+		<!-- Donut events subscriber -->
+		<ev:subscriber name="donut-subscriber" callback="receiveDonut"
+			topics="food/donuts" data-key="food"
+			data-type="org.apache.felix.ipojo.test.donut.Donut"/>
+	</component>
+	
+	<!-- The donut event consumer -->
+	<component classname="org.apache.felix.ipojo.test.donut.DonutConsumerImpl"
+		name="donut-event-consumer">
+		<!-- Expose the donut consumer service -->
+		<provides interface="org.apache.felix.ipojo.test.donut.DonutConsumer">
+			<property name="name" field="m_name" value="Unknown donut consumer"/>
+			<property name="slow" field="m_isSlow" value="false"/>
+		</provides>
+		<!-- Raw events subscriber -->
+		<ev:subscriber name="donut-event-subscriber" callback="receiveEvent"
+			topics="food/donuts"/>
+	</component>
+	
+	<!-- The event consumer -->
+	<component classname="org.apache.felix.ipojo.test.donut.EventConsumerImpl"
+		name="event-consumer">
+		<!-- Expose the donut consumer service -->
+		<provides
+			interface="{org.apache.felix.ipojo.test.donut.DonutConsumer,org.osgi.service.event.EventHandler}">
+			<property name="name" field="m_name" value="Unknown event consumer"/>
+			<property name="slow" field="m_isSlow" value="false"/>
+			<property name="event.topics" type="String" value="food/donuts"/>
+		</provides>
+	</component>
+	
+	<!-- The event tracker -->
+	<component classname="org.apache.felix.ipojo.test.donut.EventTrackerImpl"
+		name="event-tracker">
+		<!-- Expose the donut consumer service -->
+		<provides
+			interface="{org.apache.felix.ipojo.test.donut.EventTracker,org.osgi.service.event.EventHandler}">
+			<property name="name" field="m_name" value="Unknown event tracker"/>
+			<property name="event.topics" type="String" value="food/donuts"/>
+		</provides>
+	</component>
+	
+	
+	<!-- Example instances -->
+	<instance component="donut-provider" name="zeifhgbzre">
+		<property name="name" value="Zeifhgbzre donuts"/>
+	</instance>
+	<instance component="donut-consumer" name="zeifhgbzre simpson">
+		<property name="name" value="Zeifhgbzre simpson"/>
+		<property name="slow" value="false"/>
+	</instance>
+	
 </ipojo>
\ No newline at end of file