FELIX-3903 - Restructuration of the event admin handler project and migration of the tests to pax exam 3
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1450816 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/ipojo-event-admin-integration-test.iml b/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/ipojo-event-admin-integration-test.iml
new file mode 100644
index 0000000..de1441f
--- /dev/null
+++ b/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/ipojo-event-admin-integration-test.iml
@@ -0,0 +1,94 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module org.jetbrains.idea.maven.project.MavenProjectsManager.isMavenModule="true" type="JAVA_MODULE" version="4">
+ <component name="NewModuleRootManager" inherit-compiler-output="false">
+ <output url="file://$MODULE_DIR$/target/classes" />
+ <output-test url="file://$MODULE_DIR$/target/test-classes" />
+ <exclude-output />
+ <content url="file://$MODULE_DIR$">
+ <sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
+ <sourceFolder url="file://$MODULE_DIR$/src/main/resources" isTestSource="false" />
+ <sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
+ <excludeFolder url="file://$MODULE_DIR$/target" />
+ </content>
+ <orderEntry type="inheritedJdk" />
+ <orderEntry type="sourceFolder" forTests="false" />
+ <orderEntry type="library" name="Maven: org.apache.felix:org.apache.felix.ipojo.handler.eventadmin:@project.version@" level="project" />
+ <orderEntry type="library" scope="TEST" name="Maven: org.ops4j.pax.exam:pax-exam-container-native:3.0.0" level="project" />
+ <orderEntry type="library" scope="TEST" name="Maven: org.ops4j.pax.exam:pax-exam:3.0.0" level="project" />
+ <orderEntry type="library" name="Maven: org.ops4j.base:ops4j-base-lang:1.3.0" level="project" />
+ <orderEntry type="library" name="Maven: org.ops4j.base:ops4j-base-store:1.2.3" level="project" />
+ <orderEntry type="library" name="Maven: org.slf4j:slf4j-api:1.5.11" level="project" />
+ <orderEntry type="library" name="Maven: org.ops4j.base:ops4j-base-io:1.2.3" level="project" />
+ <orderEntry type="library" name="Maven: org.ops4j.base:ops4j-base-monitors:1.3.0" level="project" />
+ <orderEntry type="library" name="Maven: org.ops4j.base:ops4j-base-util-property:1.4.0" level="project" />
+ <orderEntry type="library" scope="TEST" name="Maven: org.ops4j.pax.exam:pax-exam-spi:3.0.0" level="project" />
+ <orderEntry type="library" scope="TEST" name="Maven: org.ops4j.base:ops4j-base-spi:1.4.0" level="project" />
+ <orderEntry type="library" scope="TEST" name="Maven: com.google.guava:guava:12.0" level="project" />
+ <orderEntry type="library" scope="TEST" name="Maven: com.google.code.findbugs:jsr305:1.3.9" level="project" />
+ <orderEntry type="library" name="Maven: org.ops4j.pax.tinybundles:tinybundles:1.0.0" level="project" />
+ <orderEntry type="library" name="Maven: biz.aQute:bndlib:1.43.0" level="project" />
+ <orderEntry type="library" scope="TEST" name="Maven: org.glassfish.main.common:scattered-archive-api:3.1.2.2" level="project" />
+ <orderEntry type="library" scope="TEST" name="Maven: org.ops4j.pax.swissbox:pax-swissbox-core:1.6.0" level="project" />
+ <orderEntry type="library" scope="TEST" name="Maven: org.ops4j.pax.swissbox:pax-swissbox-lifecycle:1.6.0" level="project" />
+ <orderEntry type="library" scope="TEST" name="Maven: org.ops4j.pax.swissbox:pax-swissbox-tracker:1.6.0" level="project" />
+ <orderEntry type="library" name="Maven: org.ops4j.base:ops4j-base-net:1.4.0" level="project" />
+ <orderEntry type="library" scope="TEST" name="Maven: org.ops4j.pax.url:pax-url-link:1.5.0" level="project" />
+ <orderEntry type="library" name="Maven: org.ops4j.pax.url:pax-url-commons:1.5.1" level="project" />
+ <orderEntry type="library" name="Maven: org.ops4j.pax.swissbox:pax-swissbox-property:1.5.0" level="project" />
+ <orderEntry type="library" scope="TEST" name="Maven: org.ops4j.pax.url:pax-url-classpath:1.5.0" level="project" />
+ <orderEntry type="library" scope="TEST" name="Maven: org.ops4j.pax.swissbox:pax-swissbox-optional-jcl:1.5.0" level="project" />
+ <orderEntry type="library" scope="TEST" name="Maven: org.ops4j.pax.exam:pax-exam-junit4:3.0.0" level="project" />
+ <orderEntry type="library" scope="TEST" name="Maven: junit:junit:4.9" level="project" />
+ <orderEntry type="library" scope="TEST" name="Maven: org.hamcrest:hamcrest-core:1.1" level="project" />
+ <orderEntry type="library" scope="TEST" name="Maven: org.ops4j.pax.exam:pax-exam-link-mvn:3.0.0" level="project" />
+ <orderEntry type="library" scope="TEST" name="Maven: org.ops4j.pax.url:pax-url-aether:1.5.1" level="project" />
+ <orderEntry type="library" scope="TEST" name="Maven: org.ops4j.pax.url:pax-url-maven-commons:1.5.1" level="project" />
+ <orderEntry type="library" scope="TEST" name="Maven: org.ops4j.base:ops4j-base-util-xml:1.3.0" level="project" />
+ <orderEntry type="library" scope="TEST" name="Maven: org.ops4j.base:ops4j-base-util-collections:1.3.0" level="project" />
+ <orderEntry type="library" scope="TEST" name="Maven: org.sonatype.aether:aether-api:1.13.1" level="project" />
+ <orderEntry type="library" scope="TEST" name="Maven: org.sonatype.aether:aether-spi:1.13.1" level="project" />
+ <orderEntry type="library" scope="TEST" name="Maven: org.sonatype.aether:aether-util:1.13.1" level="project" />
+ <orderEntry type="library" scope="TEST" name="Maven: org.sonatype.aether:aether-impl:1.13.1" level="project" />
+ <orderEntry type="library" scope="TEST" name="Maven: org.sonatype.aether:aether-connector-wagon:1.13.1" level="project" />
+ <orderEntry type="library" scope="TEST" name="Maven: org.apache.maven.wagon:wagon-provider-api:1.0-beta-7" level="project" />
+ <orderEntry type="library" scope="TEST" name="Maven: org.codehaus.plexus:plexus-utils:3.0" level="project" />
+ <orderEntry type="library" scope="TEST" name="Maven: org.codehaus.plexus:plexus-classworlds:2.4" level="project" />
+ <orderEntry type="library" scope="TEST" name="Maven: org.sonatype.sisu:sisu-inject-plexus:2.2.3" level="project" />
+ <orderEntry type="library" scope="TEST" name="Maven: org.codehaus.plexus:plexus-component-annotations:1.5.5" level="project" />
+ <orderEntry type="library" scope="TEST" name="Maven: org.sonatype.sisu:sisu-inject-bean:2.2.3" level="project" />
+ <orderEntry type="library" scope="TEST" name="Maven: org.sonatype.sisu:sisu-guice:no_aop:3.0.3" level="project" />
+ <orderEntry type="library" scope="TEST" name="Maven: org.apache.maven:maven-aether-provider:3.0.4" level="project" />
+ <orderEntry type="library" scope="TEST" name="Maven: org.apache.maven:maven-model:3.0.4" level="project" />
+ <orderEntry type="library" scope="TEST" name="Maven: org.apache.maven:maven-model-builder:3.0.4" level="project" />
+ <orderEntry type="library" scope="TEST" name="Maven: org.codehaus.plexus:plexus-interpolation:1.14" level="project" />
+ <orderEntry type="library" scope="TEST" name="Maven: org.apache.maven:maven-repository-metadata:3.0.4" level="project" />
+ <orderEntry type="library" scope="TEST" name="Maven: org.apache.maven.wagon:wagon-file:1.0-beta-7" level="project" />
+ <orderEntry type="library" scope="TEST" name="Maven: org.apache.maven.wagon:wagon-http-lightweight:1.0-beta-7" level="project" />
+ <orderEntry type="library" scope="TEST" name="Maven: org.apache.maven.wagon:wagon-http-shared:1.0-beta-7" level="project" />
+ <orderEntry type="library" scope="TEST" name="Maven: org.codehaus.plexus:plexus-container-default:1.5.5" level="project" />
+ <orderEntry type="library" scope="TEST" name="Maven: org.apache.xbean:xbean-reflect:3.4" level="project" />
+ <orderEntry type="library" scope="TEST" name="Maven: com.google.collections:google-collections:1.0" level="project" />
+ <orderEntry type="library" scope="TEST" name="Maven: commons-httpclient:commons-httpclient:3.1" level="project" />
+ <orderEntry type="library" scope="TEST" name="Maven: commons-codec:commons-codec:1.2" level="project" />
+ <orderEntry type="library" scope="TEST" name="Maven: commons-logging:commons-logging:1.0.4" level="project" />
+ <orderEntry type="library" scope="TEST" name="Maven: org.apache.felix:org.apache.felix.framework:4.2.0" level="project" />
+ <orderEntry type="library" scope="TEST" name="Maven: ch.qos.logback:logback-core:0.9.6" level="project" />
+ <orderEntry type="library" scope="TEST" name="Maven: ch.qos.logback:logback-classic:0.9.6" level="project" />
+ <orderEntry type="library" name="Maven: org.mockito:mockito-all:1.9.5" level="project" />
+ <orderEntry type="library" name="Maven: org.apache.felix:org.apache.felix.ipojo:1.8.6" level="project" />
+ <orderEntry type="library" name="Maven: org.osgi:org.osgi.core:4.3.1" level="project" />
+ <orderEntry type="library" name="Maven: org.osgi:org.osgi.compendium:4.0.0" level="project" />
+ <orderEntry type="library" name="Maven: org.apache.felix:org.apache.felix.ipojo.metadata:1.6.0" level="project" />
+ <orderEntry type="library" name="Maven: org.apache.felix:org.apache.felix.ipojo.manipulator:1.8.6" level="project" />
+ <orderEntry type="library" name="Maven: asm:asm-all:3.3.1" level="project" />
+ <orderEntry type="library" name="Maven: org.apache.felix:org.apache.felix.ipojo.annotations:1.8.0" level="project" />
+ <orderEntry type="library" scope="TEST" name="Maven: org.apache.felix:org.apache.felix.configadmin:1.6.0" level="project" />
+ <orderEntry type="library" name="Maven: commons-io:commons-io:2.4" level="project" />
+ <orderEntry type="library" scope="TEST" name="Maven: org.ow2.chameleon.testing:osgi-helpers:0.6.0" level="project" />
+ <orderEntry type="library" name="Maven: org.ow2.chameleon.testing:tinybundles-ipojo:0.3.0" level="project" />
+ <orderEntry type="library" name="Maven: xerces:xercesImpl:2.4.0" level="project" />
+ <orderEntry type="library" name="Maven: org.ops4j.pax.url:pax-url-wrap:1.5.2" level="project" />
+ <orderEntry type="library" name="Maven: org.ops4j.pax.swissbox:pax-swissbox-bnd:1.5.0" level="project" />
+ </component>
+</module>
+
diff --git a/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/pom.xml b/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/pom.xml
new file mode 100644
index 0000000..4798e76
--- /dev/null
+++ b/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/pom.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.ipojo.handler.eventadmin-it</artifactId>
+ <version>1.9.0-SNAPSHOT</version>
+ <relativePath>../../../pom.xml</relativePath>
+ </parent>
+
+
+ <artifactId>ipojo-event-admin-integration-test</artifactId>
+ <name>${project.artifactId}</name>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.compendium</artifactId>
+ <version>4.2.0</version>
+ </dependency>
+ </dependencies>
+
+</project>
\ No newline at end of file
diff --git a/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/main/java/org/apache/felix/ipojo/handler/eventadmin/test/donut/AsyncEventProviderImpl.java b/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/main/java/org/apache/felix/ipojo/handler/eventadmin/test/donut/AsyncEventProviderImpl.java
new file mode 100644
index 0000000..bb023f8
--- /dev/null
+++ b/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/main/java/org/apache/felix/ipojo/handler/eventadmin/test/donut/AsyncEventProviderImpl.java
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.ipojo.handler.eventadmin.test.donut;
+
+import org.osgi.service.event.Event;
+import org.osgi.service.event.EventAdmin;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.Random;
+
+/**
+ * Implementation of an event vendor that directly uses the Event Admin service
+ * to post (asynchronously) raw events.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class AsyncEventProviderImpl implements DonutProvider {
+
+ /**
+ * The donut current serial number.
+ */
+ private long m_serial = 0L;
+ /**
+ * The name of the donut vendor.
+ */
+ private String m_name;
+ /**
+ * A random generator.
+ */
+ private Random m_random;
+ /**
+ * The Event Admin service reference.
+ */
+ private EventAdmin m_ea;
+
+ /**
+ * Construct a new donut provider. The initial serial number is randomly
+ * generated.
+ */
+ public AsyncEventProviderImpl() {
+ m_random = new Random(System.currentTimeMillis());
+ }
+
+ /**
+ * Sell a donut with a random flavour.
+ *
+ * @return the sold donut
+ */
+ public Donut sellDonut() {
+ Dictionary rawEvent = new Hashtable();
+ Donut donut = new Donut(m_serial++, m_name, Donut.FLAVOURS[m_random
+ .nextInt(Donut.FLAVOURS.length)]);
+ rawEvent.put("food", donut);
+ m_ea.postEvent(new Event("food/donuts", rawEvent));
+ return donut;
+ }
+}
diff --git a/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/main/java/org/apache/felix/ipojo/handler/eventadmin/test/donut/Donut.java b/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/main/java/org/apache/felix/ipojo/handler/eventadmin/test/donut/Donut.java
new file mode 100644
index 0000000..c848adc
--- /dev/null
+++ b/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/main/java/org/apache/felix/ipojo/handler/eventadmin/test/donut/Donut.java
@@ -0,0 +1,100 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.ipojo.handler.eventadmin.test.donut;
+
+/**
+ * Donut representation.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class Donut {
+
+ /**
+ * All possible donut flavours.
+ */
+ public static final String[] FLAVOURS = { "unflavoured", "icing sugar",
+ "chocolate", "toffee", "strawberry", "apple" };
+
+ /**
+ * The vendor's unique donut identifier.
+ */
+ private final long m_id;
+
+ /**
+ * The name of this donut's vendor.
+ */
+ private final String m_vendorName;
+
+ /**
+ * The m_flavour of this donut.
+ */
+ private final String m_flavour;
+
+ /**
+ * Create a new donut.
+ *
+ * @param id
+ * the vendor's unique donut identifier
+ * @param vendorName
+ * the name of this donut's vendor
+ * @param flavour
+ * the m_flavour of this donut
+ */
+ public Donut(long id, String vendorName, String flavour) {
+ this.m_id = id;
+ this.m_vendorName = vendorName;
+ this.m_flavour = flavour;
+ }
+
+ /**
+ * Get the vendor's unique identifier of this donut.
+ *
+ * @return the id
+ */
+ public long getId() {
+ return m_id;
+ }
+
+ /**
+ * Get the vendor name of this donut.
+ *
+ * @return the name
+ */
+ public String getVendorName() {
+ return m_vendorName;
+ }
+
+ /**
+ * Get the flavour of this donut.
+ *
+ * @return the flavour
+ */
+ public String getFlavour() {
+ return m_flavour;
+ }
+
+ /**
+ * Return the string representation of this donut.
+ *
+ * @return this donut as a String
+ */
+ public String toString() {
+ return m_id + " " + m_flavour + " (" + m_vendorName + ")";
+ }
+}
diff --git a/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/main/java/org/apache/felix/ipojo/handler/eventadmin/test/donut/DonutConsumer.java b/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/main/java/org/apache/felix/ipojo/handler/eventadmin/test/donut/DonutConsumer.java
new file mode 100644
index 0000000..7482ff6
--- /dev/null
+++ b/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/main/java/org/apache/felix/ipojo/handler/eventadmin/test/donut/DonutConsumer.java
@@ -0,0 +1,81 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.ipojo.handler.eventadmin.test.donut;
+
+import org.osgi.service.event.Event;
+
+/**
+ * Specification of a donut consumer.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public interface DonutConsumer {
+
+ /**
+ * Donut receiver callback. This method is called when a donut is received
+ * on the listened topic.
+ *
+ * @param donut
+ * the received donut
+ */
+ void receiveDonut(Donut donut);
+
+ /**
+ * Event donut receiver callback. This method is called when an event is
+ * received on the listened topic.
+ *
+ * @param event
+ * the received event
+ */
+ void receiveEvent(Event event);
+
+ /**
+ * Clear the eaten donuts list. (Useful before tests)
+ */
+ void clearDonuts();
+
+ /**
+ * Get the first received donut and remove it from the eaten donut list.
+ *
+ * @return the first received donut or null if no donut is available
+ */
+ Donut getDonut();
+
+ /**
+ * Get the whole list of eaten donuts.
+ *
+ * @return the array containing all eaten donuts
+ */
+ Donut[] getAllDonuts();
+
+ /**
+ * Get the first donut if available or wait for an incoming donut. The
+ * returned donut is removed from the eaten donut list.
+ *
+ * @return the first available donut.
+ */
+ Donut waitForDonut();
+
+ /**
+ * Return the size of the eaten donut list.
+ *
+ * @return the size of the eaten donut list
+ */
+ int getNumberOfDonuts();
+}
diff --git a/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/main/java/org/apache/felix/ipojo/handler/eventadmin/test/donut/DonutConsumerImpl.java b/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/main/java/org/apache/felix/ipojo/handler/eventadmin/test/donut/DonutConsumerImpl.java
new file mode 100644
index 0000000..fd7116e
--- /dev/null
+++ b/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/main/java/org/apache/felix/ipojo/handler/eventadmin/test/donut/DonutConsumerImpl.java
@@ -0,0 +1,194 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.ipojo.handler.eventadmin.test.donut;
+
+import org.osgi.service.event.Event;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Implementation of a donut consumer.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ * @see Homer Simpson
+ */
+public class DonutConsumerImpl implements DonutConsumer {
+
+
+ /**
+ * The time that is normally necessary to cause a blacklist from the event
+ * admin service.
+ */
+ public static final long BLACK_LIST_TIME = 5000L;
+ /**
+ * The name of the donut consumer.
+ */
+ private String m_name;
+ /**
+ * The list of eaten donuts.
+ */
+ private List m_donuts = new ArrayList();
+ /**
+ * Is this consumer a slow eater ?
+ */
+ private boolean m_isSlow;
+
+ /**
+ * Utility method that causes the current thread to sleep.
+ *
+ * @param millis the number of milliseconds to wait
+ */
+ public static void sleep(long millis) {
+ long past = System.currentTimeMillis();
+ long future = past + millis;
+ long now = past;
+ while (now < future) {
+ try {
+ Thread.sleep(future - now);
+ } catch (Exception e) {
+ }
+ now = System.currentTimeMillis();
+ }
+ }
+
+ /**
+ * Process incoming donuts. This method is called by the receiveDonut
+ * callback.
+ *
+ * @param donut the received donut
+ */
+ private void doReceiveDonut(Donut donut) {
+ synchronized (m_donuts) {
+ m_donuts.add(donut);
+ m_donuts.notify();
+ }
+ }
+
+ /**
+ * Donut receiver callback. This method is called when a donut is received
+ * on the listened topic.
+ *
+ * @param donut the received donut
+ */
+ public void receiveDonut(Donut donut) {
+ final Donut myDonut = donut;
+ if (m_isSlow) {
+ new Thread(new Runnable() {
+ public void run() {
+ sleep(BLACK_LIST_TIME);
+ doReceiveDonut(myDonut);
+ }
+ }, m_name + " eating " + donut).start();
+ } else {
+ doReceiveDonut(donut);
+ }
+ }
+
+ /**
+ * Event donut receiver callback. This method is called when an event is
+ * received on the listened topic.
+ *
+ * @param event the received event
+ */
+ public void receiveEvent(Event event) {
+ Object thing = event.getProperty("food");
+ if (Donut.class.isInstance(thing)) {
+ receiveDonut((Donut) thing);
+ } else {
+ // Nothing.
+ }
+ }
+
+ /**
+ * Clear the eaten donuts list. (Useful before tests)
+ */
+ public void clearDonuts() {
+ synchronized (m_donuts) {
+ m_donuts.clear();
+ }
+ }
+
+ /**
+ * Get the first received donut and remove it from the eaten donut list.
+ *
+ * @return the first received donut or null if no donut is available
+ */
+ public Donut getDonut() {
+ Donut donut = null;
+ synchronized (m_donuts) {
+ if (!m_donuts.isEmpty()) {
+ donut = (Donut) m_donuts.remove(0);
+ }
+ }
+ return donut;
+ }
+
+ /**
+ * Get the whole list of eaten donuts.
+ *
+ * @return the array containing all eaten donuts
+ */
+ public Donut[] getAllDonuts() {
+ Donut[] donuts = new Donut[0];
+ synchronized (m_donuts) {
+ donuts = (Donut[]) m_donuts.toArray(donuts);
+ m_donuts.clear();
+ }
+ return donuts;
+ }
+
+ /**
+ * Get the first donut if available or wait for an incoming donut. The
+ * returned donut is removed from the eaten donut list.
+ *
+ * @return the first available donut.
+ */
+ public Donut waitForDonut() {
+ Donut donut = null;
+ synchronized (m_donuts) {
+ while (donut == null) {
+ if (m_donuts.isEmpty()) {
+ try {
+ m_donuts.wait();
+ } catch (InterruptedException e) {
+ // Thanks Checkstyle to forbid empty catch statements
+ // ;-(
+ }
+ } else {
+ donut = (Donut) m_donuts.remove(0);
+ }
+ }
+ }
+ return donut;
+ }
+
+ /**
+ * Return the size of the eaten donut list.
+ *
+ * @return the size of the eaten donut list
+ */
+ public int getNumberOfDonuts() {
+ int length;
+ synchronized (m_donuts) {
+ length = m_donuts.size();
+ }
+ return length;
+ }
+}
diff --git a/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/main/java/org/apache/felix/ipojo/handler/eventadmin/test/donut/DonutEventProviderImpl.java b/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/main/java/org/apache/felix/ipojo/handler/eventadmin/test/donut/DonutEventProviderImpl.java
new file mode 100644
index 0000000..2684706
--- /dev/null
+++ b/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/main/java/org/apache/felix/ipojo/handler/eventadmin/test/donut/DonutEventProviderImpl.java
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.ipojo.handler.eventadmin.test.donut;
+
+import org.apache.felix.ipojo.handlers.event.publisher.Publisher;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.Random;
+
+/**
+ * Implementation of a donut vendor that send raw events instead of sending
+ * Donut objects.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class DonutEventProviderImpl implements DonutProvider {
+
+ /**
+ * The donut current serial number.
+ */
+ private long m_serial = 0L;
+ /**
+ * The name of the donut vendor.
+ */
+ private String m_name;
+ /**
+ * A random generator.
+ */
+ private Random m_random;
+ /**
+ * The event publisher of the donut vendor.
+ */
+ private Publisher m_publisher;
+
+ /**
+ * Construct a new donut provider. The initial serial number is randomly
+ * generated.
+ */
+ public DonutEventProviderImpl() {
+ m_random = new Random(System.currentTimeMillis());
+ }
+
+ /**
+ * Sell a donut with a random flavour.
+ *
+ * @return the sold donut
+ */
+ public Donut sellDonut() {
+ Dictionary rawEvent = new Hashtable();
+ String flavour = Donut.FLAVOURS[m_random.nextInt(Donut.FLAVOURS.length)];
+ Donut donut = new Donut(m_serial++, m_name, flavour);
+ rawEvent.put("food", donut);
+ rawEvent.put("flavour", flavour);
+ m_publisher.send(rawEvent);
+ return donut;
+ }
+}
diff --git a/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/main/java/org/apache/felix/ipojo/handler/eventadmin/test/donut/DonutProvider.java b/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/main/java/org/apache/felix/ipojo/handler/eventadmin/test/donut/DonutProvider.java
new file mode 100644
index 0000000..748fd10
--- /dev/null
+++ b/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/main/java/org/apache/felix/ipojo/handler/eventadmin/test/donut/DonutProvider.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.ipojo.handler.eventadmin.test.donut;
+
+/**
+ * Specification of a donut vendor.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ *
+ */
+public interface DonutProvider {
+
+ /**
+ * Sell a donut with a random flavour.
+ *
+ * @return the sold donut
+ */
+ Donut sellDonut();
+}
diff --git a/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/main/java/org/apache/felix/ipojo/handler/eventadmin/test/donut/DonutProviderImpl.java b/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/main/java/org/apache/felix/ipojo/handler/eventadmin/test/donut/DonutProviderImpl.java
new file mode 100644
index 0000000..085b9bc
--- /dev/null
+++ b/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/main/java/org/apache/felix/ipojo/handler/eventadmin/test/donut/DonutProviderImpl.java
@@ -0,0 +1,76 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.ipojo.handler.eventadmin.test.donut;
+
+import org.apache.felix.ipojo.handlers.event.publisher.Publisher;
+
+import java.util.Random;
+
+/**
+ * The standard implementation of a donut vendor.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ *
+ */
+public class DonutProviderImpl implements DonutProvider {
+
+
+
+ /**
+ * The donut current serial number.
+ */
+ private long m_serial = 0L;
+
+ /**
+ * The name of the donut vendor.
+ */
+ private String m_name;
+
+ /**
+ * A random generator.
+ */
+ private Random m_random;
+
+ /**
+ * The donut publisher of the vendor.
+ */
+ private Publisher m_publisher;
+
+ /**
+ * Construct a new donut provider. The initial serial number is randomly
+ * generated.
+ */
+ public DonutProviderImpl() {
+ m_random = new Random(System.currentTimeMillis());
+ }
+
+ /**
+ * Sell a donut with a random flavour.
+ *
+ * @return the sold donut
+ */
+ public Donut sellDonut() {
+ Donut donut = new Donut(m_serial++, m_name, Donut.FLAVOURS[m_random
+ .nextInt(Donut.FLAVOURS.length)]);
+ m_publisher.sendData(donut);
+ System.err.println("[" + this.getClass().getSimpleName() + ":"
+ + m_name + "] Selling donut " + donut);
+ return donut;
+ }
+}
diff --git a/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/main/java/org/apache/felix/ipojo/handler/eventadmin/test/donut/EventConsumerImpl.java b/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/main/java/org/apache/felix/ipojo/handler/eventadmin/test/donut/EventConsumerImpl.java
new file mode 100644
index 0000000..3fc27ab
--- /dev/null
+++ b/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/main/java/org/apache/felix/ipojo/handler/eventadmin/test/donut/EventConsumerImpl.java
@@ -0,0 +1,199 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.ipojo.handler.eventadmin.test.donut;
+
+import org.osgi.service.event.Event;
+import org.osgi.service.event.EventHandler;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Implementation of a donut consumer.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ * @see Homer Simpson
+ */
+public class EventConsumerImpl implements DonutConsumer, EventHandler {
+
+ /**
+ * The name of the donut consumer.
+ */
+ private String m_name;
+ /**
+ * The list of eaten donuts.
+ */
+ private List m_donuts = new ArrayList();
+ /**
+ * Is this consumer a slow eater ?
+ */
+ private boolean m_isSlow;
+
+ /**
+ * Utility method that causes the current thread to sleep.
+ *
+ * @param millis the number of milliseconds to wait
+ */
+ public static void sleep(long millis) {
+ long past = System.currentTimeMillis();
+ long future = past + millis;
+ long now = past;
+ while (now < future) {
+ try {
+ Thread.sleep(future - now);
+ } catch (Exception e) {
+ }
+ now = System.currentTimeMillis();
+ }
+ }
+
+ /**
+ * Process incoming donuts. This method is called by the receiveDonut
+ * callback.
+ *
+ * @param donut the received donut
+ */
+ private void doReceiveDonut(Donut donut) {
+ synchronized (m_donuts) {
+ m_donuts.add(donut);
+ m_donuts.notify();
+ }
+ }
+
+ /**
+ * Donut receiver callback. This method is called when a donut is received
+ * on the listened topic.
+ *
+ * @param donut the received donut
+ */
+ public void receiveDonut(Donut donut) {
+ final Donut myDonut = donut;
+ if (m_isSlow) {
+ new Thread(new Runnable() {
+ public void run() {
+ sleep(DonutConsumerImpl.BLACK_LIST_TIME);
+ doReceiveDonut(myDonut);
+ }
+ }, m_name + " eating " + donut).start();
+ } else {
+ doReceiveDonut(donut);
+ }
+ }
+
+ /**
+ * Event donut receiver callback. This method is called when an event is
+ * received on the listened topic.
+ *
+ * @param event the received event
+ */
+ public void receiveEvent(Event event) {
+ Object thing = event.getProperty("food");
+ if (Donut.class.isInstance(thing)) {
+ receiveDonut((Donut) thing);
+ } else {
+ // Nothing to do.
+ }
+ }
+
+ /**
+ * Event receiver callback. This method is called by the event admin service
+ * when a event is received.
+ *
+ * @param event the received event
+ */
+ public void handleEvent(Event event) {
+ receiveEvent(event);
+ }
+
+ /**
+ * Clear the eaten donuts list. (Useful before tests)
+ */
+ public void clearDonuts() {
+ synchronized (m_donuts) {
+ m_donuts.clear();
+ }
+ }
+
+ /**
+ * Get the first received donut and remove it from the eaten donut list.
+ *
+ * @return the first received donut or null if no donut is available
+ */
+ public Donut getDonut() {
+ Donut donut = null;
+ synchronized (m_donuts) {
+ if (!m_donuts.isEmpty()) {
+ donut = (Donut) m_donuts.remove(0);
+ }
+ }
+ return donut;
+ }
+
+ /**
+ * Get the whole list of eaten donuts.
+ *
+ * @return the array containing all eaten donuts
+ */
+ public Donut[] getAllDonuts() {
+ Donut[] donuts = new Donut[0];
+ synchronized (m_donuts) {
+ donuts = (Donut[]) m_donuts.toArray(donuts);
+ m_donuts.clear();
+ }
+ return donuts;
+ }
+
+ /**
+ * Get the first donut if available or wait for an incoming donut. The
+ * returned donut is removed from the eaten donut list.
+ *
+ * @return the first available donut.
+ */
+ public Donut waitForDonut() {
+ Donut donut = null;
+ synchronized (m_donuts) {
+ while (donut == null) {
+ if (m_donuts.isEmpty()) {
+ try {
+ m_donuts.wait();
+ } catch (InterruptedException e) {
+ // Thanks Checkstyle to forbid empty catch statements
+ // ;-(
+ }
+ } else {
+ donut = (Donut) m_donuts.remove(0);
+ }
+ }
+ }
+ return donut;
+ }
+
+ /**
+ * Return the size of the eaten donut list.
+ *
+ * @return the size of the eaten donut list
+ */
+ public int getNumberOfDonuts() {
+ int length;
+ synchronized (m_donuts) {
+ length = m_donuts.size();
+ }
+ return length;
+ }
+}
diff --git a/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/main/java/org/apache/felix/ipojo/handler/eventadmin/test/donut/EventTracker.java b/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/main/java/org/apache/felix/ipojo/handler/eventadmin/test/donut/EventTracker.java
new file mode 100644
index 0000000..df45809
--- /dev/null
+++ b/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/main/java/org/apache/felix/ipojo/handler/eventadmin/test/donut/EventTracker.java
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.ipojo.handler.eventadmin.test.donut;
+
+import org.osgi.service.event.Event;
+
+/**
+ * Specification of an event tracker.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public interface EventTracker {
+
+ /**
+ * Clear the received events list. (Useful before tests)
+ */
+ void clearEvents();
+
+ /**
+ * Get the first received event and remove it from the events list.
+ *
+ * @return the first received event or null if no event is available
+ */
+ Event getEvent();
+
+ /**
+ * Get the whole list of received events.
+ *
+ * @return the array containing all received events
+ */
+ Event[] getAllEvents();
+
+ /**
+ * Get the first event if available or wait for an incoming event. The
+ * returned event is removed from the eaten event list.
+ *
+ * @return the first available event.
+ */
+ Event waitForEvent();
+
+ /**
+ * Return the size of the events list.
+ *
+ * @return the size of the events list
+ */
+ int getNumberOfEvents();
+}
diff --git a/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/main/java/org/apache/felix/ipojo/handler/eventadmin/test/donut/EventTrackerImpl.java b/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/main/java/org/apache/felix/ipojo/handler/eventadmin/test/donut/EventTrackerImpl.java
new file mode 100644
index 0000000..e79d5ff
--- /dev/null
+++ b/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/main/java/org/apache/felix/ipojo/handler/eventadmin/test/donut/EventTrackerImpl.java
@@ -0,0 +1,152 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.ipojo.handler.eventadmin.test.donut;
+
+import org.osgi.service.event.Event;
+import org.osgi.service.event.EventHandler;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Implementation of an event tracker.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class EventTrackerImpl implements EventTracker, EventHandler {
+
+ /**
+ * The name of the event tracker.
+ */
+ private String m_name;
+ /**
+ * The list of received events
+ */
+ private List m_events = new ArrayList();
+
+ /**
+ * Return the string representation of a given event.
+ *
+ * @return the string representation of a given event
+ */
+ public static String eventToString(Event e) {
+ StringBuilder buf = new StringBuilder();
+ buf.append("[" + e.getTopic() + "] {");
+
+ String[] properties = e.getPropertyNames();
+ int n = properties.length - 1;
+ for (int i = 0; i <= n; i++) {
+ String name = properties[i];
+ buf.append(name + "=" + e.getProperty(name));
+ if (i != n)
+ buf.append(", ");
+ }
+ buf.append("}");
+ return buf.toString();
+ }
+
+ /**
+ * Event receiver callback. This method is called by the event admin service
+ * when a event is received.
+ *
+ * @param event the received event
+ */
+ public void handleEvent(Event event) {
+ synchronized (m_events) {
+ m_events.add(event);
+ m_events.notify();
+ }
+ }
+
+ /**
+ * Clear the received events list. (Useful before tests)
+ */
+ public void clearEvents() {
+ synchronized (m_events) {
+ m_events.clear();
+ }
+ }
+
+ /**
+ * Get the first received event and remove it from the events list.
+ *
+ * @return the first received event or null if no event is available
+ */
+ public Event getEvent() {
+ Event event = null;
+ synchronized (m_events) {
+ if (!m_events.isEmpty()) {
+ event = (Event) m_events.remove(0);
+ }
+ }
+ return event;
+ }
+
+ /**
+ * Get the whole list of received events.
+ *
+ * @return the array containing all received events
+ */
+ public Event[] getAllEvents() {
+ Event[] events = new Event[0];
+ synchronized (m_events) {
+ events = (Event[]) m_events.toArray(events);
+ m_events.clear();
+ }
+ return events;
+ }
+
+ /**
+ * Get the first event if available or wait for an incoming event. The
+ * returned event is removed from the eaten event list.
+ *
+ * @return the first available event.
+ */
+ public Event waitForEvent() {
+ Event event = null;
+ synchronized (m_events) {
+ while (event == null) {
+ if (m_events.isEmpty()) {
+ try {
+ m_events.wait();
+ } catch (InterruptedException e) {
+ // Thanks Checkstyle to forbid empty catch statements
+ // ;-(
+ }
+ } else {
+ event = (Event) m_events.remove(0);
+ }
+ }
+ }
+ return event;
+ }
+
+ /**
+ * Return the size of the events list.
+ *
+ * @return the size of the events list
+ */
+ public int getNumberOfEvents() {
+ int length;
+ synchronized (m_events) {
+ length = m_events.size();
+ }
+ return length;
+ }
+}
diff --git a/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/main/java/org/apache/felix/ipojo/handler/eventadmin/test/donut/SyncEventProviderImpl.java b/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/main/java/org/apache/felix/ipojo/handler/eventadmin/test/donut/SyncEventProviderImpl.java
new file mode 100644
index 0000000..332ccc7
--- /dev/null
+++ b/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/main/java/org/apache/felix/ipojo/handler/eventadmin/test/donut/SyncEventProviderImpl.java
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.ipojo.handler.eventadmin.test.donut;
+
+import org.osgi.service.event.Event;
+import org.osgi.service.event.EventAdmin;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.Random;
+
+/**
+ * Implementation of an event vendor that directly uses the Event Admin service
+ * to send (synchronously) raw events.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class SyncEventProviderImpl implements DonutProvider {
+
+ /**
+ * The donut current serial number.
+ */
+ private long m_serial = 0L;
+ /**
+ * The name of the donut vendor.
+ */
+ private String m_name;
+ /**
+ * A random generator.
+ */
+ private Random m_random;
+ /**
+ * The Event Admin service reference.
+ */
+ private EventAdmin m_ea;
+
+ /**
+ * Construct a new donut provider. The initial serial number is randomly
+ * generated.
+ */
+ public SyncEventProviderImpl() {
+ m_random = new Random(System.currentTimeMillis());
+ }
+
+ /**
+ * Sell a donut with a random flavour.
+ *
+ * @return the sold donut
+ */
+ public Donut sellDonut() {
+ Dictionary rawEvent = new Hashtable();
+ Donut donut = new Donut(m_serial++, m_name, Donut.FLAVOURS[m_random
+ .nextInt(Donut.FLAVOURS.length)]);
+ rawEvent.put("food", donut);
+ m_ea.sendEvent(new Event("food/donuts", rawEvent));
+ return donut;
+ }
+}
diff --git a/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/main/resources/metadata.xml b/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/main/resources/metadata.xml
new file mode 100644
index 0000000..00b59c9
--- /dev/null
+++ b/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/main/resources/metadata.xml
@@ -0,0 +1,180 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ipojo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="org.apache.felix.ipojo http://felix.apache.org/ipojo/schemas/SNAPSHOT/core.xsd"
+ xmlns="org.apache.felix.ipojo"
+ xmlns:ev="org.apache.felix.ipojo.handlers.event">
+
+ <!-- The (asynchronous) donut provider -->
+ <component classname="org.apache.felix.ipojo.handler.eventadmin.test.donut.DonutProviderImpl"
+ name="donut-provider">
+ <!-- Expose the donut provider service -->
+ <provides specifications="org.apache.felix.ipojo.handler.eventadmin.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 (asynchronous) donut provider using publishes -->
+ <component classname="org.apache.felix.ipojo.handler.eventadmin.test.donut.DonutProviderImpl"
+ name="donut-provider-publishes">
+ <!-- Expose the donut provider service -->
+ <provides specifications="org.apache.felix.ipojo.handler.eventadmin.test.donut.DonutProvider">
+ <property name="name" field="m_name" value="Unknown donut vendor"/>
+ </provides>
+ <!-- Donut publisher -->
+ <ev:publishes name="donut-publisher" field="m_publisher"
+ topics="food/donuts" dataKey="food" synchronous="false"/>
+ </component>
+
+ <!-- The synchronous donut provider -->
+ <component classname="org.apache.felix.ipojo.handler.eventadmin.test.donut.DonutProviderImpl"
+ name="synchronous-donut-provider">
+ <!-- Expose the donut provider service -->
+ <provides specifications="org.apache.felix.ipojo.handler.eventadmin.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 synchronous donut provider using dataKey -->
+ <component classname="org.apache.felix.ipojo.handler.eventadmin.test.donut.DonutProviderImpl"
+ name="synchronous-donut-provider-2">
+ <!-- Expose the donut provider service -->
+ <provides specifications="org.apache.felix.ipojo.handler.eventadmin.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" dataKey="food" synchronous="true"/>
+ </component>
+
+ <!-- The (asynchronous) donut event provider -->
+ <component
+ classname="org.apache.felix.ipojo.handler.eventadmin.test.donut.DonutEventProviderImpl"
+ name="donut-event-provider">
+ <!-- Expose the donut provider service -->
+ <provides specifications="org.apache.felix.ipojo.handler.eventadmin.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.handler.eventadmin.test.donut.DonutEventProviderImpl"
+ name="synchronous-donut-event-provider">
+ <!-- Expose the donut provider service -->
+ <provides specifications="org.apache.felix.ipojo.handler.eventadmin.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.handler.eventadmin.test.donut.AsyncEventProviderImpl"
+ name="event-provider">
+ <!-- Expose the donut provider service -->
+ <provides specifications="org.apache.felix.ipojo.handler.eventadmin.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.handler.eventadmin.test.donut.SyncEventProviderImpl"
+ name="synchronous-event-provider">
+ <!-- Expose the donut provider service -->
+ <provides specifications="org.apache.felix.ipojo.handler.eventadmin.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.handler.eventadmin.test.donut.DonutConsumerImpl"
+ name="donut-consumer">
+ <!-- Expose the donut consumer service -->
+ <provides specifications="org.apache.felix.ipojo.handler.eventadmin.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.handler.eventadmin.test.donut.Donut"/>
+ </component>
+
+ <!-- The donut consumer using dataKey and dataType -->
+ <component classname="org.apache.felix.ipojo.handler.eventadmin.test.donut.DonutConsumerImpl"
+ name="donut-consumer-2">
+ <!-- Expose the donut consumer service -->
+ <provides specifications="org.apache.felix.ipojo.handler.eventadmin.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" dataKey="food"
+ dataType="org.apache.felix.ipojo.handler.eventadmin.test.donut.Donut"/>
+ </component>
+
+
+ <!-- The donut event consumer -->
+ <component classname="org.apache.felix.ipojo.handler.eventadmin.test.donut.DonutConsumerImpl"
+ name="donut-event-consumer">
+ <!-- Expose the donut consumer service -->
+ <provides specifications="org.apache.felix.ipojo.handler.eventadmin.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.handler.eventadmin.test.donut.EventConsumerImpl"
+ name="event-consumer">
+ <!-- Expose the donut consumer service -->
+ <provides
+ specifications="{org.apache.felix.ipojo.handler.eventadmin.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.handler.eventadmin.test.donut.EventTrackerImpl"
+ name="event-tracker">
+ <!-- Expose the donut consumer service -->
+ <provides
+ specifications="{org.apache.felix.ipojo.handler.eventadmin.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
diff --git a/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/test/java/org/apache/felix/ipojo/handler/eventadmin/test/Common.java b/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/test/java/org/apache/felix/ipojo/handler/eventadmin/test/Common.java
new file mode 100644
index 0000000..4275b5f
--- /dev/null
+++ b/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/test/java/org/apache/felix/ipojo/handler/eventadmin/test/Common.java
@@ -0,0 +1,203 @@
+package org.apache.felix.ipojo.handler.eventadmin.test;
+
+import ch.qos.logback.classic.Level;
+import ch.qos.logback.classic.Logger;
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.filefilter.TrueFileFilter;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.runner.RunWith;
+import org.ops4j.pax.exam.Configuration;
+import org.ops4j.pax.exam.CoreOptions;
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.junit.PaxExam;
+import org.ops4j.pax.exam.options.CompositeOption;
+import org.ops4j.pax.exam.options.DefaultCompositeOption;
+import org.ops4j.pax.exam.options.libraries.JUnitBundlesOption;
+import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy;
+import org.ops4j.pax.exam.spi.reactors.PerClass;
+import org.ops4j.pax.tinybundles.core.TinyBundle;
+import org.ops4j.pax.tinybundles.core.TinyBundles;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.ow2.chameleon.testing.helpers.IPOJOHelper;
+import org.ow2.chameleon.testing.helpers.OSGiHelper;
+import org.ow2.chameleon.testing.tinybundles.ipojo.IPOJOStrategy;
+import org.slf4j.LoggerFactory;
+
+import javax.inject.Inject;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import static junit.framework.Assert.fail;
+import static org.ops4j.pax.exam.CoreOptions.*;
+
+/**
+ * Bootstrap the test from this project
+ */
+@RunWith(PaxExam.class)
+@ExamReactorStrategy(PerClass.class)
+public class Common {
+
+ @Inject
+ BundleContext bc;
+
+ OSGiHelper osgiHelper;
+ IPOJOHelper ipojoHelper;
+
+ Bundle testedBundle;
+
+ @Configuration
+ public Option[] config() throws IOException {
+ Logger root = (Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
+ root.setLevel(Level.DEBUG);
+
+ return options(
+ cleanCaches(),
+ ipojoBundles(),
+ junitBundles(),
+ eventadmin(),
+ testedBundle(),
+ systemProperty("org.ops4j.pax.logging.DefaultServiceLog.level").value("WARN")
+ );
+ }
+
+ public CompositeOption eventadmin() {
+ return new DefaultCompositeOption(
+ mavenBundle("org.apache.felix", "org.apache.felix.eventadmin", "1.3.0"),
+ mavenBundle("org.apache.felix", "org.apache.felix.ipojo.handler.eventadmin").versionAsInProject());
+ }
+
+ public static Option junitAndMockitoBundles() {
+ return new DefaultCompositeOption(
+ // Repository required to load harmcrest (OSGi-fied version).
+ repository("http://repository.springsource.com/maven/bundles/external").id(
+ "com.springsource.repository.bundles.external"),
+
+ // Hamcrest with a version matching the range expected by Mockito
+ mavenBundle("org.hamcrest", "com.springsource.org.hamcrest.core", "1.1.0"),
+
+ // Mockito core does not includes Hamcrest
+ mavenBundle("org.mockito", "mockito-core", "1.9.5"),
+
+ // Objenesis with a version matching the range expected by Mockito
+ wrappedBundle(mavenBundle("org.objenesis", "objenesis", "1.2"))
+ .exports("*;version=1.2"),
+
+ // The default JUnit bundle also exports Hamcrest, but with an (incorrect) version of
+ // 4.9 which does not match the Mockito import. When deployed after the hamcrest bundles, it gets
+ // resolved correctly.
+ CoreOptions.junitBundles(),
+
+ /*
+ * Felix has implicit boot delegation enabled by default. It conflicts with Mockito:
+ * java.lang.LinkageError: loader constraint violation in interface itable initialization:
+ * when resolving method "org.osgi.service.useradmin.User$$EnhancerByMockitoWithCGLIB$$dd2f81dc
+ * .newInstance(Lorg/mockito/cglib/proxy/Callback;)Ljava/lang/Object;" the class loader
+ * (instance of org/mockito/internal/creation/jmock/SearchingClassLoader) of the current class,
+ * org/osgi/service/useradmin/User$$EnhancerByMockitoWithCGLIB$$dd2f81dc, and the class loader
+ * (instance of org/apache/felix/framework/BundleWiringImpl$BundleClassLoaderJava5) for interface
+ * org/mockito/cglib/proxy/Factory have different Class objects for the type org/mockito/cglib/
+ * proxy/Callback used in the signature
+ *
+ * So we disable the bootdelegation. this property has no effect on the other OSGi implementation.
+ */
+ frameworkProperty("felix.bootdelegation.implicit").value("false")
+ );
+ }
+
+ @Before
+ public void commonSetUp() {
+ osgiHelper = new OSGiHelper(bc);
+ ipojoHelper = new IPOJOHelper(bc);
+
+ testedBundle = osgiHelper.getBundle("test.bundle");
+
+ // Dump OSGi Framework information
+ String vendor = (String) osgiHelper.getBundle(0).getHeaders().get(Constants.BUNDLE_VENDOR);
+ if (vendor == null) {
+ vendor = (String) osgiHelper.getBundle(0).getHeaders().get(Constants.BUNDLE_SYMBOLICNAME);
+ }
+ String version = (String) osgiHelper.getBundle(0).getHeaders().get(Constants.BUNDLE_VERSION);
+ System.out.println("OSGi Framework : " + vendor + " - " + version);
+ }
+
+ @After
+ public void commonTearDown() {
+ ipojoHelper.dispose();
+ osgiHelper.dispose();
+ }
+
+ public static CompositeOption ipojoBundles() {
+ return new DefaultCompositeOption(
+ mavenBundle("org.apache.felix", "org.apache.felix.ipojo").versionAsInProject(),
+ mavenBundle("org.ow2.chameleon.testing", "osgi-helpers").versionAsInProject()
+ );
+ }
+
+ public Option testedBundle() throws MalformedURLException {
+ File out = new File("target/tested/bundle.jar");
+
+ TinyBundle tested = TinyBundles.bundle();
+
+ // We look inside target/classes to find the class and resources
+ File classes = new File("target/classes");
+ Collection<File> files = FileUtils.listFilesAndDirs(classes, TrueFileFilter.INSTANCE, TrueFileFilter.INSTANCE);
+ List<File> services = new ArrayList<File>();
+ for (File file : files) {
+ if (file.isDirectory()) {
+ // By convention we export of .services and .service package
+ if (file.getName().endsWith("services") || file.getName().endsWith("service")) {
+ services.add(file);
+ }
+ } else {
+ // We need to compute the path
+ String path = file.getAbsolutePath().substring(classes.getAbsolutePath().length() +1);
+ tested.add(path, file.toURI().toURL());
+ System.out.println(file.getName() + " added to " + path);
+ }
+ }
+
+ String export = "org.apache.felix.ipojo.handler.eventadmin.test.donut";
+ for (File file : services) {
+ if (export.length() > 0) { export += ", "; }
+ String path = file.getAbsolutePath().substring(classes.getAbsolutePath().length() +1);
+ String packageName = path.replace('/', '.');
+ export += packageName;
+ }
+
+ System.out.println("Exported packages : " + export);
+
+ InputStream inputStream = tested
+ .set(Constants.BUNDLE_SYMBOLICNAME, "test.bundle")
+ .set(Constants.IMPORT_PACKAGE, "*")
+ .set(Constants.EXPORT_PACKAGE, export)
+ .build(IPOJOStrategy.withiPOJO(new File("src/main/resources")));
+
+ try {
+ FileUtils.copyInputStreamToFile(inputStream, out);
+ return bundle(out.toURI().toURL().toExternalForm());
+ } catch (MalformedURLException e) {
+ throw new RuntimeException("Cannot compute the url of the manipulated bundle");
+ } catch (IOException e) {
+ throw new RuntimeException("Cannot write of the manipulated bundle");
+ }
+ }
+
+ public void assertContains(String s, String[] arrays, String object) {
+ for (String suspect : arrays) {
+ if (object.equals(suspect)) {
+ return;
+ }
+ }
+ fail("Assertion failed : " + s);
+ }
+
+
+}
diff --git a/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/test/java/org/apache/felix/ipojo/handler/eventadmin/test/EahTestUtils.java b/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/test/java/org/apache/felix/ipojo/handler/eventadmin/test/EahTestUtils.java
new file mode 100644
index 0000000..47786db
--- /dev/null
+++ b/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/test/java/org/apache/felix/ipojo/handler/eventadmin/test/EahTestUtils.java
@@ -0,0 +1,225 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.ipojo.handler.eventadmin.test;
+
+import org.apache.felix.ipojo.Factory;
+import org.apache.felix.ipojo.handler.eventadmin.test.donut.Donut;
+import org.osgi.framework.BundleContext;
+import org.ow2.chameleon.testing.helpers.IPOJOHelper;
+
+/**
+ * Useful variables used for the tests of the Event Admin Handler.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class EahTestUtils {
+
+ /**
+ * Enable debug messages ?
+ */
+ public static final boolean TRACE = false;
+ /**
+ * The number of tests to execute.
+ */
+ public static final int NUMBER_OF_TESTS = 50;
+ /**
+ * The time that is normally necessary to cause a blacklist from the event
+ * admin service.
+ */
+ public static final long BLACK_LIST_TIME = 5000L;
+ /**
+ * The long amount of time.
+ */
+ public static final long A_LONG_TIME = 1000L;
+ /**
+ * The bundle context.
+ */
+ private BundleContext m_context;
+ /**
+ * The iPOJO Helper.
+ */
+ private IPOJOHelper m_ipojoHelper;
+
+ /**
+ * Construct a new Event Admin Handler Tests utility instance.
+ */
+ public EahTestUtils(BundleContext context, IPOJOHelper ipojoHelper) {
+ m_ipojoHelper = ipojoHelper;
+ m_context = context;
+ }
+
+ /**
+ * Utility method that causes the current thread to sleep.
+ *
+ * @param millis the number of milliseconds to wait
+ */
+ public static void sleep(long millis) {
+ long past = System.currentTimeMillis();
+ long future = past + millis;
+ long now = past;
+ if (TRACE) {
+ System.err.println("Sleeping for " + millis + "ms");
+ }
+ while (now < future) {
+ try {
+ Thread.sleep(future - now);
+ } catch (Exception e) {
+ }
+ now = System.currentTimeMillis();
+ }
+ }
+
+ /**
+ * Return the index of the given donut flavour in the flavour array.
+ *
+ * @return the index of the given flavour or -1 if not found
+ */
+ public static int flavourIndex(String flavour) {
+ for (int i = 0; i < Donut.FLAVOURS.length; i++) {
+ if (Donut.FLAVOURS[i].equals(flavour))
+ return i;
+ }
+ return -1;
+ }
+
+ /**
+ * Return the (asynchronous) donut provider factory.
+ *
+ * @return the (asynchronous) donut provider factory
+ */
+ public Factory getDonutProviderFactory() {
+ return m_ipojoHelper.getFactory("donut-provider");
+ }
+
+ /**
+ * Return the (asynchronous) donut provider using publishes factory.
+ *
+ * @return the (asynchronous) donut provider using publishes factory
+ */
+ public Factory getDonutProviderUsingPublishesFactory() {
+ return m_ipojoHelper.getFactory("donut-provider-publishes");
+ }
+
+ /**
+ * Return the synchronous donut provider factory.
+ *
+ * @return the synchronous donut provider factory
+ */
+ public Factory getSynchronousDonutProviderFactory() {
+ return m_ipojoHelper.getFactory(
+ "synchronous-donut-provider");
+ }
+
+ /**
+ * Return the synchronous donut provider factory using
+ * dataKey
+ *
+ * @return the synchronous donut provider factory
+ */
+ public Factory getSynchronousDonutProvider2Factory() {
+ return m_ipojoHelper.getFactory(
+ "synchronous-donut-provider-2");
+ }
+
+ /**
+ * Return the (asynchronous) donut event provider factory.
+ *
+ * @return the (asynchronous) donut event provider factory
+ */
+ public Factory getDonutEventProviderFactory() {
+ return m_ipojoHelper.getFactory(
+ "donut-event-provider");
+ }
+
+ /**
+ * Return the synchronous donut event provider factory.
+ *
+ * @return the synchronous donut event provider factory
+ */
+ public Factory getSynchronousDonutEventProviderFactory() {
+ return m_ipojoHelper.getFactory(
+ "synchronous-donut-event-provider");
+ }
+
+ /**
+ * Return the event provider factory.
+ *
+ * @return the event provider factory
+ */
+ public Factory getEventProviderFactory() {
+ return m_ipojoHelper.getFactory("event-provider");
+ }
+
+ /**
+ * Return the synchronous event provider factory.
+ *
+ * @return the synchronous event provider factory
+ */
+ public Factory getSynchronousEventProviderFactory() {
+ return m_ipojoHelper.getFactory(
+ "synchronous-event-provider");
+ }
+
+ /**
+ * Return the donut consumer factory.
+ *
+ * @return the donut consumer factory
+ */
+ public Factory getDonutConsumerFactory() {
+ return m_ipojoHelper.getFactory("donut-consumer");
+ }
+
+ /**
+ * Return the donut consumer factory using dataKey
+ * and dataType.
+ *
+ * @return the donut consumer factory
+ */
+ public Factory getDonutConsumer2Factory() {
+ return m_ipojoHelper.getFactory("donut-consumer-2");
+ }
+
+ /**
+ * Return the donut event consumer factory.
+ *
+ * @return the donut event consumer factory
+ */
+ public Factory getDonutEventConsumerFactory() {
+ return m_ipojoHelper.getFactory(
+ "donut-event-consumer");
+ }
+
+ /**
+ * Return the event consumer factory.
+ *
+ * @return the event consumer factory
+ */
+ public Factory getEventConsumerFactory() {
+ return m_ipojoHelper.getFactory("event-consumer");
+ }
+
+ /**
+ * Return the event tracker.
+ *
+ * @return the event consumer factory
+ */
+ public Factory getEventTrackerFactory() {
+ return m_ipojoHelper.getFactory("event-tracker");
+ }
+}
diff --git a/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/test/java/org/apache/felix/ipojo/handler/eventadmin/test/SimpleTest.java b/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/test/java/org/apache/felix/ipojo/handler/eventadmin/test/SimpleTest.java
new file mode 100644
index 0000000..3323701
--- /dev/null
+++ b/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/test/java/org/apache/felix/ipojo/handler/eventadmin/test/SimpleTest.java
@@ -0,0 +1,22 @@
+package org.apache.felix.ipojo.handler.eventadmin.test;
+
+import org.junit.Test;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+
+import javax.inject.Inject;
+
+
+public class SimpleTest extends Common {
+
+ @Inject
+ BundleContext bc;
+
+ @Test
+ public void testSomethingStupid() {
+ System.out.println("This is fucking weird");
+ for (Bundle bundle : bc.getBundles()) {
+ System.out.println(bundle.getSymbolicName() + " " + bundle.getState());
+ }
+ }
+}
diff --git a/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/test/java/org/apache/felix/ipojo/handler/eventadmin/test/TestBadConfigurations.java b/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/test/java/org/apache/felix/ipojo/handler/eventadmin/test/TestBadConfigurations.java
new file mode 100644
index 0000000..6da354e
--- /dev/null
+++ b/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/test/java/org/apache/felix/ipojo/handler/eventadmin/test/TestBadConfigurations.java
@@ -0,0 +1,958 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.ipojo.handler.eventadmin.test;
+
+import org.apache.felix.ipojo.*;
+import org.apache.felix.ipojo.handler.eventadmin.test.donut.Donut;
+import org.apache.felix.ipojo.handler.eventadmin.test.donut.DonutConsumer;
+import org.apache.felix.ipojo.handler.eventadmin.test.donut.DonutProvider;
+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.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+import static junit.framework.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+/**
+ * Test the good behaviour of the EventAdminHandler.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class TestBadConfigurations extends Common {
+
+ /**
+ * The namespace of the Event admin handler.
+ */
+ private static final String NAMESPACE = "org.apache.felix.ipojo.handlers.event";
+ /**
+ * The utility class instance.
+ */
+ public EahTestUtils m_utils;
+ /**
+ * 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.
+ * <p/>
+ * Create all the instances
+ */
+ @Before
+ public void setUp() {
+ m_utils = new EahTestUtils(bc, ipojoHelper);
+ /**
+ * Get the list of available components.
+ */
+ try {
+ String header = (String) testedBundle.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.handler.eventadmin.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.handler.eventadmin.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.handler.eventadmin.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.handler.eventadmin.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.handler.eventadmin.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.handler.eventadmin.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.
+ * <p/>
+ * This test simply create a provider and a consumer instance, send one
+ * event and check it is received.
+ *
+ * @throws org.apache.felix.ipojo.ConfigurationException
+ * something bad happened
+ * @throws org.apache.felix.ipojo.MissingHandlerException
+ * something bad happened
+ * @throws org.apache.felix.ipojo.UnacceptableConfiguration
+ * something bad happened
+ */
+ @Test
+ public void testGoodConfig()
+ throws ConfigurationException, UnacceptableConfiguration,
+ MissingHandlerException {
+ /**
+ * Create the provider and the consumer instances.
+ */
+ Dictionary properties = new Hashtable();
+
+ // Provider
+ ComponentFactory providerFactory = new ComponentFactory(bc,
+ m_provider);
+ providerFactory.start();
+ properties.put("instance.name", "Emperor of donuts");
+ ComponentInstance providerInstance = providerFactory
+ .createComponentInstance(properties);
+ ServiceReference providerService = ipojoHelper
+ .getServiceReferenceByName(DonutProvider.class
+ .getName(), providerInstance.getInstanceName());
+ DonutProvider provider = (DonutProvider) bc
+ .getService(providerService);
+
+ // The consumer
+ properties = new Hashtable();
+ ComponentFactory consumerFactory = new ComponentFactory(bc,
+ m_consumer);
+ consumerFactory.start();
+ properties.put("instance.name", "Homer Simpson");
+ properties.put("slow", "false");
+ ComponentInstance consumerInstance = consumerFactory
+ .createComponentInstance(properties);
+ ServiceReference consumerService = ipojoHelper
+ .getServiceReferenceByName(DonutConsumer.class
+ .getName(), consumerInstance.getInstanceName());
+ DonutConsumer consumer = (DonutConsumer) bc
+ .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.
+ */
+ bc.ungetService(providerService);
+ providerInstance.dispose();
+ bc.ungetService(consumerService);
+ consumerInstance.dispose();
+ providerFactory.stop();
+ consumerFactory.stop();
+ }
+
+ /**
+ * Try to create a publisher with no name.
+ *
+ * @throws org.apache.felix.ipojo.ConfigurationException
+ * something bad happened
+ * @throws org.apache.felix.ipojo.MissingHandlerException
+ * something bad happened
+ * @throws org.apache.felix.ipojo.UnacceptableConfiguration
+ * something bad happened
+ */
+ @Test
+ 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(bc, 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 org.apache.felix.ipojo.ConfigurationException
+ * something bad happened
+ * @throws org.apache.felix.ipojo.MissingHandlerException
+ * something bad happened
+ * @throws org.apache.felix.ipojo.UnacceptableConfiguration
+ * something bad happened
+ */
+ @Test
+ 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(bc, 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 org.apache.felix.ipojo.ConfigurationException
+ * something bad happened
+ * @throws org.apache.felix.ipojo.MissingHandlerException
+ * something bad happened
+ * @throws org.apache.felix.ipojo.UnacceptableConfiguration
+ * something bad happened
+ */
+ @Test
+ 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(bc, 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 org.apache.felix.ipojo.ConfigurationException
+ * something bad happened
+ * @throws org.apache.felix.ipojo.MissingHandlerException
+ * something bad happened
+ * @throws org.apache.felix.ipojo.UnacceptableConfiguration
+ * something bad happened
+ */
+ @Test
+ 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(bc, 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 org.apache.felix.ipojo.ConfigurationException
+ * something bad happened
+ * @throws org.apache.felix.ipojo.MissingHandlerException
+ * something bad happened
+ * @throws org.apache.felix.ipojo.UnacceptableConfiguration
+ * something bad happened
+ */
+ @Test
+ public void testPublisherWithoutTopics()
+ throws ConfigurationException, MissingHandlerException,
+ UnacceptableConfiguration {
+
+ // Remove the topics attribute of the publisher
+ m_publisher.removeAttribute(m_publisherTopics);
+ ComponentFactory fact = new ComponentFactory(bc, 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 org.apache.felix.ipojo.ConfigurationException
+ * something bad happened
+ * @throws org.apache.felix.ipojo.MissingHandlerException
+ * something bad happened
+ * @throws org.apache.felix.ipojo.UnacceptableConfiguration
+ * something bad happened
+ */
+ @Test
+ 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(bc, 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 org.apache.felix.ipojo.ConfigurationException
+ * something bad happened
+ * @throws org.apache.felix.ipojo.MissingHandlerException
+ * something bad happened
+ * @throws org.apache.felix.ipojo.UnacceptableConfiguration
+ * something bad happened
+ */
+ @Test
+ 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(bc, 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 org.apache.felix.ipojo.ConfigurationException
+ * something bad happened
+ * @throws org.apache.felix.ipojo.MissingHandlerException
+ * something bad happened
+ * @throws org.apache.felix.ipojo.UnacceptableConfiguration
+ * something bad happened
+ */
+ @Test
+ 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(bc, 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 org.apache.felix.ipojo.ConfigurationException
+ * something bad happened
+ * @throws org.apache.felix.ipojo.MissingHandlerException
+ * something bad happened
+ * @throws org.apache.felix.ipojo.UnacceptableConfiguration
+ * something bad happened
+ */
+ @Test
+ 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(bc, 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 org.apache.felix.ipojo.ConfigurationException
+ * something bad happened
+ * @throws org.apache.felix.ipojo.MissingHandlerException
+ * something bad happened
+ * @throws org.apache.felix.ipojo.UnacceptableConfiguration
+ * something bad happened
+ */
+ @Test
+ 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(bc, 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 org.apache.felix.ipojo.ConfigurationException
+ * something bad happened
+ * @throws org.apache.felix.ipojo.MissingHandlerException
+ * something bad happened
+ * @throws org.apache.felix.ipojo.UnacceptableConfiguration
+ * something bad happened
+ */
+ @Test
+ public void testSubscriberWithoutTopics()
+ throws ConfigurationException, MissingHandlerException,
+ UnacceptableConfiguration {
+
+ // Remove the topics attribute of the subscriber
+ m_subscriber.removeAttribute(m_subscriberTopics);
+ ComponentFactory fact = new ComponentFactory(bc, 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 org.apache.felix.ipojo.ConfigurationException
+ * something bad happened
+ * @throws org.apache.felix.ipojo.MissingHandlerException
+ * something bad happened
+ * @throws org.apache.felix.ipojo.UnacceptableConfiguration
+ * something bad happened
+ */
+ @Test
+ 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(bc, 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 org.apache.felix.ipojo.ConfigurationException
+ * something bad happened
+ * @throws org.apache.felix.ipojo.MissingHandlerException
+ * something bad happened
+ * @throws org.apache.felix.ipojo.UnacceptableConfiguration
+ * something bad happened
+ */
+ @Test
+ 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(bc, 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 org.apache.felix.ipojo.ConfigurationException
+ * something bad happened
+ * @throws org.apache.felix.ipojo.MissingHandlerException
+ * something bad happened
+ * @throws org.apache.felix.ipojo.UnacceptableConfiguration
+ * something bad happened
+ */
+ @Test
+ 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(bc, 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 org.apache.felix.ipojo.ConfigurationException
+ * something bad happened
+ * @throws org.apache.felix.ipojo.MissingHandlerException
+ * something bad happened
+ * @throws org.apache.felix.ipojo.UnacceptableConfiguration
+ * something bad happened
+ */
+ @Test
+ 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(bc, 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);
+ }
+ }
+
+ // 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 org.apache.felix.ipojo.ConfigurationException
+ * something bad happened.
+ * @throws org.apache.felix.ipojo.MissingHandlerException
+ * something bad happened.
+ * @throws org.apache.felix.ipojo.UnacceptableConfiguration
+ * something bad happened.
+ */
+ @Test
+ 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/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/test/java/org/apache/felix/ipojo/handler/eventadmin/test/TestEventAdminHandler.java b/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/test/java/org/apache/felix/ipojo/handler/eventadmin/test/TestEventAdminHandler.java
new file mode 100644
index 0000000..3814c1a
--- /dev/null
+++ b/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/test/java/org/apache/felix/ipojo/handler/eventadmin/test/TestEventAdminHandler.java
@@ -0,0 +1,714 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.ipojo.handler.eventadmin.test;
+
+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.handler.eventadmin.test.donut.Donut;
+import org.apache.felix.ipojo.handler.eventadmin.test.donut.DonutConsumer;
+import org.apache.felix.ipojo.handler.eventadmin.test.donut.DonutProvider;
+import org.apache.felix.ipojo.handler.eventadmin.test.donut.EventTracker;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.event.Event;
+
+import java.util.*;
+
+import static junit.framework.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Test the good behaviour of the EventAdminHandler.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class TestEventAdminHandler extends Common {
+
+ /**
+ * 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.
+ * <p/>
+ * Create all the instances
+ *
+ * @throws org.apache.felix.ipojo.UnacceptableConfiguration
+ * something bad happened
+ * @throws org.apache.felix.ipojo.MissingHandlerException
+ * something bad happened
+ * @throws org.apache.felix.ipojo.ConfigurationException
+ * something bad happened
+ */
+ @Before
+ public void setUp()
+ throws UnacceptableConfiguration, MissingHandlerException,
+ ConfigurationException {
+
+ m_utils = new EahTestUtils(bc, ipojoHelper);
+ 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] = ipojoHelper.getServiceReferenceByName(
+ DonutProvider.class.getName(),
+ m_providersInstances[i].getInstanceName());
+ m_providers[i] = (DonutProvider) bc
+ .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] = ipojoHelper.getServiceReferenceByName(
+ DonutConsumer.class.getName(),
+ m_consumersInstances[i].getInstanceName());
+ m_consumers[i] = (DonutConsumer) bc
+ .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 = ipojoHelper.getServiceReferenceByName(
+ EventTracker.class.getName(), m_eventTrackerInstance
+ .getInstanceName());
+ m_eventTracker = (EventTracker) bc
+ .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] = ipojoHelper
+ .getServiceReferenceByName(
+ DonutConsumer.class
+ .getName(), m_filteredConsumersInstances[i]
+ .getInstanceName());
+ m_filteredConsumers[i] = (DonutConsumer) bc
+ .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] = ipojoHelper
+ .getServiceReferenceByName(DonutProvider.class
+ .getName(), m_topicsProvidersInstances[i]
+ .getInstanceName());
+ m_topicsProviders[i] = (DonutProvider) bc
+ .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] = ipojoHelper
+ .getServiceReferenceByName(DonutConsumer.class
+ .getName(), m_topicsConsumersInstances[i]
+ .getInstanceName());
+ m_topicsConsumers[i] = (DonutConsumer) bc
+ .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 org.apache.felix.ipojo.ConfigurationException
+ * something bad happened.
+ * @throws org.apache.felix.ipojo.MissingHandlerException
+ * something bad happened.
+ * @throws org.apache.felix.ipojo.UnacceptableConfiguration
+ * something bad happened.
+ */
+ @Test
+ 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.
+ */
+ @Test
+ 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.
+ * <p/>
+ * This test consists to send synchronously a big amount of donuts and to
+ * check immediately if it has been received (by all quick consumers).
+ */
+ @Test
+ 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.
+ */
+ @Test
+ 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.
+ * <p/>
+ * 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.
+ */
+ @Test
+ 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.
+ * <p/>
+ * This test send donuts on several topics. Each consumer (who listens to
+ * one or several topics) must receive donuts sent on his specifics topics.
+ */
+ @Test
+ 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.
+ * <p/>
+ * Release all services references and destroy instances.
+ */
+ @After
+ public void tearDown() {
+ int index;
+ for (index = 0; index < NUMBER_OF_PROVIDERS; index++) {
+ bc.ungetService(m_providersServices[index]);
+ m_providersInstances[index].dispose();
+ }
+ for (index = 0; index < NUMBER_OF_CONSUMERS; index++) {
+ bc.ungetService(m_consumersServices[index]);
+ m_consumersInstances[index].dispose();
+ }
+ bc.ungetService(m_eventTrackerService);
+ m_eventTrackerInstance.dispose();
+ for (int i = 0; i < Donut.FLAVOURS.length; i++) {
+ bc.ungetService(m_filteredConsumersServices[i]);
+ m_filteredConsumersInstances[i].dispose();
+ }
+ for (int i = 0; i < TOPICS_LIST.length; i++) {
+ bc.ungetService(m_topicsProvidersServices[i]);
+ m_topicsProvidersInstances[i].dispose();
+ bc.ungetService(m_topicsConsumersServices[i]);
+ m_topicsConsumersInstances[i].dispose();
+ }
+
+ }
+
+}
diff --git a/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/test/java/org/apache/felix/ipojo/handler/eventadmin/test/TestEventAdminHandlerWithNewAttributes.java b/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/test/java/org/apache/felix/ipojo/handler/eventadmin/test/TestEventAdminHandlerWithNewAttributes.java
new file mode 100644
index 0000000..d7f6b57
--- /dev/null
+++ b/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/test/java/org/apache/felix/ipojo/handler/eventadmin/test/TestEventAdminHandlerWithNewAttributes.java
@@ -0,0 +1,714 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.ipojo.handler.eventadmin.test;
+
+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.handler.eventadmin.test.donut.Donut;
+import org.apache.felix.ipojo.handler.eventadmin.test.donut.DonutConsumer;
+import org.apache.felix.ipojo.handler.eventadmin.test.donut.DonutProvider;
+import org.apache.felix.ipojo.handler.eventadmin.test.donut.EventTracker;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.event.Event;
+
+import java.util.*;
+
+import static junit.framework.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Test the good behaviour of the EventAdminHandler.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class TestEventAdminHandlerWithNewAttributes extends Common {
+
+ /**
+ * 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.
+ * <p/>
+ * Create all the instances
+ *
+ * @throws org.apache.felix.ipojo.UnacceptableConfiguration
+ * something bad happened
+ * @throws org.apache.felix.ipojo.MissingHandlerException
+ * something bad happened
+ * @throws org.apache.felix.ipojo.ConfigurationException
+ * something bad happened
+ */
+ @Before
+ public void setUp()
+ throws UnacceptableConfiguration, MissingHandlerException,
+ ConfigurationException {
+
+ m_utils = new EahTestUtils(bc, ipojoHelper);
+ 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.getSynchronousDonutProvider2Factory()
+ .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] = ipojoHelper.getServiceReferenceByName(
+ DonutProvider.class.getName(),
+ m_providersInstances[i].getInstanceName());
+ m_providers[i] = (DonutProvider) bc
+ .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.getDonutConsumer2Factory()
+ .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.getDonutConsumer2Factory()
+ .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] = ipojoHelper.getServiceReferenceByName(
+ DonutConsumer.class.getName(),
+ m_consumersInstances[i].getInstanceName());
+ m_consumers[i] = (DonutConsumer) bc
+ .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 = ipojoHelper.getServiceReferenceByName(
+ EventTracker.class.getName(), m_eventTrackerInstance
+ .getInstanceName());
+ m_eventTracker = (EventTracker) bc
+ .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] = ipojoHelper
+ .getServiceReferenceByName(DonutConsumer.class
+ .getName(), m_filteredConsumersInstances[i]
+ .getInstanceName());
+ m_filteredConsumers[i] = (DonutConsumer) bc
+ .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] = ipojoHelper
+ .getServiceReferenceByName(DonutProvider.class
+ .getName(), m_topicsProvidersInstances[i]
+ .getInstanceName());
+ m_topicsProviders[i] = (DonutProvider) bc
+ .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.getDonutConsumer2Factory()
+ .createComponentInstance(properties);
+ m_topicsConsumersServices[i] = ipojoHelper
+ .getServiceReferenceByName(DonutConsumer.class
+ .getName(), m_topicsConsumersInstances[i]
+ .getInstanceName());
+ m_topicsConsumers[i] = (DonutConsumer) bc
+ .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 org.apache.felix.ipojo.ConfigurationException
+ * something bad happened.
+ * @throws org.apache.felix.ipojo.MissingHandlerException
+ * something bad happened.
+ * @throws org.apache.felix.ipojo.UnacceptableConfiguration
+ * something bad happened.
+ */
+ @Test
+ 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.getDonutConsumer2Factory()
+ .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.
+ */
+ @Test
+ 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.
+ * <p/>
+ * This test consists to send synchronously a big amount of donuts and to
+ * check immediately if it has been received (by all quick consumers).
+ */
+ @Test
+ 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.
+ */
+ @Test
+ 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.
+ * <p/>
+ * 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.
+ */
+ @Test
+ 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.
+ * <p/>
+ * This test send donuts on several topics. Each consumer (who listens to
+ * one or several topics) must receive donuts sent on his specifics topics.
+ */
+ @Test
+ 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.
+ * <p/>
+ * Release all services references and destroy instances.
+ */
+ @After
+ public void tearDown() {
+ int index;
+ for (index = 0; index < NUMBER_OF_PROVIDERS; index++) {
+ bc.ungetService(m_providersServices[index]);
+ m_providersInstances[index].dispose();
+ }
+ for (index = 0; index < NUMBER_OF_CONSUMERS; index++) {
+ bc.ungetService(m_consumersServices[index]);
+ m_consumersInstances[index].dispose();
+ }
+ bc.ungetService(m_eventTrackerService);
+ m_eventTrackerInstance.dispose();
+ for (int i = 0; i < Donut.FLAVOURS.length; i++) {
+ bc.ungetService(m_filteredConsumersServices[i]);
+ m_filteredConsumersInstances[i].dispose();
+ }
+ for (int i = 0; i < TOPICS_LIST.length; i++) {
+ bc.ungetService(m_topicsProvidersServices[i]);
+ m_topicsProvidersInstances[i].dispose();
+ bc.ungetService(m_topicsConsumersServices[i]);
+ m_topicsConsumersInstances[i].dispose();
+ }
+
+ }
+
+}
diff --git a/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/test/java/org/apache/felix/ipojo/handler/eventadmin/test/TestPublisher.java b/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/test/java/org/apache/felix/ipojo/handler/eventadmin/test/TestPublisher.java
new file mode 100644
index 0000000..950405b
--- /dev/null
+++ b/ipojo/handler/eventadmin/eventadmin-handler-it/src/it/event-admin-it/src/test/java/org/apache/felix/ipojo/handler/eventadmin/test/TestPublisher.java
@@ -0,0 +1,713 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.ipojo.handler.eventadmin.test;
+
+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.handler.eventadmin.test.donut.Donut;
+import org.apache.felix.ipojo.handler.eventadmin.test.donut.DonutConsumer;
+import org.apache.felix.ipojo.handler.eventadmin.test.donut.DonutProvider;
+import org.apache.felix.ipojo.handler.eventadmin.test.donut.EventTracker;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.event.Event;
+
+import java.util.*;
+
+import static junit.framework.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Test the good behaviour of the EventAdminHandler.
+ *
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class TestPublisher extends Common {
+
+ /**
+ * 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.
+ * <p/>
+ * Create all the instances
+ *
+ * @throws org.apache.felix.ipojo.UnacceptableConfiguration
+ * something bad happened
+ * @throws org.apache.felix.ipojo.MissingHandlerException
+ * something bad happened
+ * @throws org.apache.felix.ipojo.ConfigurationException
+ * something bad happened
+ */
+ @Before
+ public void setUp()
+ throws UnacceptableConfiguration, MissingHandlerException,
+ ConfigurationException {
+
+ m_utils = new EahTestUtils(bc, ipojoHelper);
+ 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.getDonutProviderUsingPublishesFactory()
+ .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] = ipojoHelper.getServiceReferenceByName(
+ DonutProvider.class.getName(),
+ m_providersInstances[i].getInstanceName());
+ m_providers[i] = (DonutProvider) bc
+ .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] = ipojoHelper.getServiceReferenceByName(
+ DonutConsumer.class.getName(),
+ m_consumersInstances[i].getInstanceName());
+ m_consumers[i] = (DonutConsumer) bc
+ .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 = ipojoHelper.getServiceReferenceByName(
+ EventTracker.class.getName(), m_eventTrackerInstance
+ .getInstanceName());
+ m_eventTracker = (EventTracker) bc
+ .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] = ipojoHelper
+ .getServiceReferenceByName(DonutConsumer.class
+ .getName(), m_filteredConsumersInstances[i]
+ .getInstanceName());
+ m_filteredConsumers[i] = (DonutConsumer) bc
+ .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] = ipojoHelper
+ .getServiceReferenceByName(DonutProvider.class
+ .getName(), m_topicsProvidersInstances[i]
+ .getInstanceName());
+ m_topicsProviders[i] = (DonutProvider) bc
+ .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] = ipojoHelper
+ .getServiceReferenceByName(DonutConsumer.class
+ .getName(), m_topicsConsumersInstances[i]
+ .getInstanceName());
+ m_topicsConsumers[i] = (DonutConsumer) bc
+ .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 org.apache.felix.ipojo.ConfigurationException
+ * something bad happened.
+ * @throws org.apache.felix.ipojo.MissingHandlerException
+ * something bad happened.
+ * @throws org.apache.felix.ipojo.UnacceptableConfiguration
+ * something bad happened.
+ */
+ @Test
+ 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.
+ */
+ @Test
+ 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.
+ * <p/>
+ * This test consists to send synchronously a big amount of donuts and to
+ * check immediately if it has been received (by all quick consumers).
+ */
+ @Test
+ 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.
+ */
+ @Test
+ 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.
+ * <p/>
+ * 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.
+ */
+ @Test
+ 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.
+ * <p/>
+ * This test send donuts on several topics. Each consumer (who listens to
+ * one or several topics) must receive donuts sent on his specifics topics.
+ */
+ @Test
+ 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.
+ * <p/>
+ * Release all services references and destroy instances.
+ */
+ @After
+ public void tearDown() {
+ int index;
+ for (index = 0; index < NUMBER_OF_PROVIDERS; index++) {
+ bc.ungetService(m_providersServices[index]);
+ m_providersInstances[index].dispose();
+ }
+ for (index = 0; index < NUMBER_OF_CONSUMERS; index++) {
+ bc.ungetService(m_consumersServices[index]);
+ m_consumersInstances[index].dispose();
+ }
+ bc.ungetService(m_eventTrackerService);
+ m_eventTrackerInstance.dispose();
+ for (int i = 0; i < Donut.FLAVOURS.length; i++) {
+ bc.ungetService(m_filteredConsumersServices[i]);
+ m_filteredConsumersInstances[i].dispose();
+ }
+ for (int i = 0; i < TOPICS_LIST.length; i++) {
+ bc.ungetService(m_topicsProvidersServices[i]);
+ m_topicsProvidersInstances[i].dispose();
+ bc.ungetService(m_topicsConsumersServices[i]);
+ m_topicsConsumersInstances[i].dispose();
+ }
+
+ }
+
+}