Bug 325064 - Handlers registered w/ topic a/b/c/* should not receive events on topic a/b/c
diff --git a/bundles/org.eclipse.equinox.compendium.tests/src/org/eclipse/equinox/compendium/tests/AllTests.java b/bundles/org.eclipse.equinox.compendium.tests/src/org/eclipse/equinox/compendium/tests/AllTests.java
index c7962a5..b2aeee9 100644
--- a/bundles/org.eclipse.equinox.compendium.tests/src/org/eclipse/equinox/compendium/tests/AllTests.java
+++ b/bundles/org.eclipse.equinox.compendium.tests/src/org/eclipse/equinox/compendium/tests/AllTests.java
@@ -19,6 +19,7 @@
 		TestSuite suite = new TestSuite("Tests for Equinox Compendium"); //$NON-NLS-1$
 		suite.addTest(org.eclipse.equinox.metatype.tests.AllTests.suite());
 		suite.addTest(org.eclipse.equinox.useradmin.tests.AllTests.suite());
+		suite.addTest(org.eclipse.equinox.event.tests.AllTests.suite());
 		return suite;
 	}
 
diff --git a/bundles/org.eclipse.equinox.compendium.tests/src/org/eclipse/equinox/event/tests/AllTests.java b/bundles/org.eclipse.equinox.compendium.tests/src/org/eclipse/equinox/event/tests/AllTests.java
new file mode 100644
index 0000000..274e981
--- /dev/null
+++ b/bundles/org.eclipse.equinox.compendium.tests/src/org/eclipse/equinox/event/tests/AllTests.java
@@ -0,0 +1,22 @@
+/*******************************************************************************
+ * Copyright (c) 2010 IBM Corporation and others
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.event.tests;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+public class AllTests {
+	public static Test suite() {
+		TestSuite suite = new TestSuite("Tests for Equinox EventAdmin"); //$NON-NLS-1$
+		suite.addTestSuite(EventAdminTest.class);
+		return suite;
+	}
+}
diff --git a/bundles/org.eclipse.equinox.compendium.tests/src/org/eclipse/equinox/event/tests/EventAdminTest.java b/bundles/org.eclipse.equinox.compendium.tests/src/org/eclipse/equinox/event/tests/EventAdminTest.java
new file mode 100644
index 0000000..2da46fb
--- /dev/null
+++ b/bundles/org.eclipse.equinox.compendium.tests/src/org/eclipse/equinox/event/tests/EventAdminTest.java
@@ -0,0 +1,153 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2010 IBM Corporation and others
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.event.tests;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+import junit.framework.TestCase;
+import org.eclipse.equinox.compendium.tests.Activator;
+import org.osgi.framework.*;
+import org.osgi.service.event.*;
+
+public class EventAdminTest extends TestCase {
+	private EventAdmin eventAdmin;
+	private ServiceReference eventAdminReference;
+
+	protected void setUp() throws Exception {
+		Activator.getBundle(Activator.BUNDLE_EVENT).start();
+		eventAdminReference = Activator.getBundleContext().getServiceReference(EventAdmin.class.getName());
+		eventAdmin = (EventAdmin) Activator.getBundleContext().getService(eventAdminReference);
+	}
+
+	protected void tearDown() throws Exception {
+		Activator.getBundleContext().ungetService(eventAdminReference);
+		Activator.getBundle(Activator.BUNDLE_EVENT).stop();
+	}
+
+	/*
+	 * Ensures EventAdmin does not deliver an event published on topic "a/b/c" 
+	 * to an EventHandler listening to topic a/b/c/*.
+	 * 
+	 * See https://bugs.eclipse.org/bugs/show_bug.cgi?id=325064.
+	 */
+	public void testEventDeliveryForWildcardTopic1() {
+		Dictionary properties = new Hashtable();
+		properties.put(EventConstants.EVENT_TOPIC, "a/b/c/*"); //$NON-NLS-1$
+		BundleContext bundleContext = Activator.getBundleContext();
+		EventHandlerHelper handler = new EventHandlerHelper();
+		ServiceRegistration handlerRegistration = bundleContext.registerService(EventHandler.class, handler, properties);
+		Event event = new Event("a/b/c", (Dictionary) null); //$NON-NLS-1$
+		eventAdmin.sendEvent(event);
+		assertNull("Received event published to topic 'a/b/c' while listening to 'a/b/c/*'", handler.lastEvent()); //$NON-NLS-1$
+		handlerRegistration.unregister();
+	}
+
+	/*
+	 * Ensures EventAdmin does not deliver an event published on topic "a/b" to 
+	 * an EventHandler listening to topic a/b/c/*.
+	 */
+	public void testEventDeliveryForWildcardTopic2() {
+		Dictionary properties = new Hashtable();
+		properties.put(EventConstants.EVENT_TOPIC, "a/b/c/*"); //$NON-NLS-1$
+		BundleContext bundleContext = Activator.getBundleContext();
+		EventHandlerHelper handler = new EventHandlerHelper();
+		ServiceRegistration handlerRegistration = bundleContext.registerService(EventHandler.class, handler, properties);
+		Event event = new Event("a/b", (Dictionary) null); //$NON-NLS-1$
+		eventAdmin.sendEvent(event);
+		assertNull("Received event published to topic 'a/b' while listening to 'a/b/c/*'", handler.lastEvent()); //$NON-NLS-1$
+		handlerRegistration.unregister();
+	}
+
+	/*
+	 * Ensures EventAdmin does not deliver an event published on topic "a" to 
+	 * an EventHandler listening to topic a/b/c/*.
+	 */
+	public void testEventDeliveryForWildcardTopic3() {
+		Dictionary properties = new Hashtable();
+		properties.put(EventConstants.EVENT_TOPIC, "a/b/c/*"); //$NON-NLS-1$
+		BundleContext bundleContext = Activator.getBundleContext();
+		EventHandlerHelper handler = new EventHandlerHelper();
+		ServiceRegistration handlerRegistration = bundleContext.registerService(EventHandler.class, handler, properties);
+		Event event = new Event("a", (Dictionary) null); //$NON-NLS-1$
+		eventAdmin.sendEvent(event);
+		assertNull("Received event published to topic 'a' while listening to 'a/b/c/*'", handler.lastEvent()); //$NON-NLS-1$
+		handlerRegistration.unregister();
+	}
+
+	/*
+	 * Ensures EventAdmin delivers an event published on topic "a/b/c/d" to an 
+	 * EventHandler listening to topic "a/b/c/*".
+	 */
+	public void testEventDeliveryForWildcardTopic4() {
+		Dictionary properties = new Hashtable();
+		properties.put(EventConstants.EVENT_TOPIC, "a/b/c/*"); //$NON-NLS-1$
+		BundleContext bundleContext = Activator.getBundleContext();
+		EventHandlerHelper handler = new EventHandlerHelper();
+		ServiceRegistration handlerRegistration = bundleContext.registerService(EventHandler.class, handler, properties);
+		Event event = new Event("a/b/c/d", (Dictionary) null); //$NON-NLS-1$
+		eventAdmin.sendEvent(event);
+		assertNotNull("Did not receive event published to topic 'a/b/c/d' while listening to 'a/b/c/*'", handler.lastEvent()); //$NON-NLS-1$
+		handlerRegistration.unregister();
+	}
+
+	/*
+	 * Ensures EventAdmin delivers an event published on topic "a/b/c/d/e" to 
+	 * an EventHandler listening to topic "a/b/c/*".
+	 */
+	public void testEventDeliveryForWildcardTopic5() {
+		Dictionary properties = new Hashtable();
+		properties.put(EventConstants.EVENT_TOPIC, "a/b/c/*"); //$NON-NLS-1$
+		BundleContext bundleContext = Activator.getBundleContext();
+		EventHandlerHelper handler = new EventHandlerHelper();
+		ServiceRegistration handlerRegistration = bundleContext.registerService(EventHandler.class, handler, properties);
+		Event event = new Event("a/b/c/d/e", (Dictionary) null); //$NON-NLS-1$
+		eventAdmin.sendEvent(event);
+		assertNotNull("Did not receive event published to topic 'a/b/c/d/e' while listening to 'a/b/c/*'", handler.lastEvent()); //$NON-NLS-1$
+		handlerRegistration.unregister();
+	}
+
+	/*
+	 * Ensures EventAdmin delivers an event published on topic "a/b/c/d/e/f" to 
+	 * an EventHandler listening to topic "a/b/c/*".
+	 */
+	public void testEventDeliveryForWildcardTopic6() {
+		Dictionary properties = new Hashtable();
+		properties.put(EventConstants.EVENT_TOPIC, "a/b/c/*"); //$NON-NLS-1$
+		BundleContext bundleContext = Activator.getBundleContext();
+		EventHandlerHelper handler = new EventHandlerHelper();
+		ServiceRegistration handlerRegistration = bundleContext.registerService(EventHandler.class, handler, properties);
+		Event event = new Event("a/b/c/d/e/f", (Dictionary) null); //$NON-NLS-1$
+		eventAdmin.sendEvent(event);
+		assertNotNull("Did not receive event published to topic 'a/b/c/d/e/f' while listening to 'a/b/c/*'", handler.lastEvent()); //$NON-NLS-1$
+		handlerRegistration.unregister();
+	}
+
+	/*
+	 * Ensures EventAdmin delivers an event published to topics "a/b/c" and 
+	 * "a/b/c/d" to an EventHandler listening to topics "a/b/c" and "a/b/c/*".
+	 * 
+	 * See https://bugs.eclipse.org/bugs/show_bug.cgi?id=325064.
+	 */
+	public void testEventDeliveryForWildcardTopic7() {
+		Dictionary properties = new Hashtable();
+		properties.put(EventConstants.EVENT_TOPIC, new String[] {"a/b/c", "a/b/c/*"}); //$NON-NLS-1$ //$NON-NLS-2$
+		BundleContext bundleContext = Activator.getBundleContext();
+		EventHandlerHelper handler = new EventHandlerHelper();
+		ServiceRegistration handlerRegistration = bundleContext.registerService(EventHandler.class, handler, properties);
+		Event event = new Event("a/b/c", (Dictionary) null); //$NON-NLS-1$
+		eventAdmin.sendEvent(event);
+		assertNotNull("Did not receive event published to topic 'a/b/c' while listening to 'a/b/c'", handler.clearLastEvent()); //$NON-NLS-1$
+		event = new Event("a/b/c/d", (Dictionary) null); //$NON-NLS-1$
+		eventAdmin.sendEvent(event);
+		assertNotNull("Did not receive event published to topic 'a/b/c/d' while listening to 'a/b/c/*'", handler.lastEvent()); //$NON-NLS-1$
+		handlerRegistration.unregister();
+	}
+}
diff --git a/bundles/org.eclipse.equinox.compendium.tests/src/org/eclipse/equinox/event/tests/EventHandlerHelper.java b/bundles/org.eclipse.equinox.compendium.tests/src/org/eclipse/equinox/event/tests/EventHandlerHelper.java
new file mode 100644
index 0000000..e9b4e08
--- /dev/null
+++ b/bundles/org.eclipse.equinox.compendium.tests/src/org/eclipse/equinox/event/tests/EventHandlerHelper.java
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2010 IBM Corporation and others
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.event.tests;
+
+import org.osgi.service.event.Event;
+import org.osgi.service.event.EventHandler;
+
+public class EventHandlerHelper implements EventHandler {
+	private volatile Event lastEvent;
+
+	public Event clearLastEvent() {
+		Event result = lastEvent;
+		lastEvent = null;
+		return result;
+	}
+
+	public void handleEvent(Event event) {
+		lastEvent = event;
+	}
+
+	public Event lastEvent() {
+		return lastEvent;
+	}
+}
diff --git a/bundles/org.eclipse.equinox.event/.settings/org.eclipse.pde.api.tools.prefs b/bundles/org.eclipse.equinox.event/.settings/org.eclipse.pde.api.tools.prefs
new file mode 100644
index 0000000..ceb4af0
--- /dev/null
+++ b/bundles/org.eclipse.equinox.event/.settings/org.eclipse.pde.api.tools.prefs
@@ -0,0 +1,94 @@
+#Fri Oct 22 19:46:45 EDT 2010
+ENUM_ELEMENT_TYPE_REMOVED_TYPE_MEMBER=Error
+CLASS_ELEMENT_TYPE_CHANGED_NON_ABSTRACT_TO_ABSTRACT=Error
+invalid_since_tag_version=Error
+LEAK_METHOD_RETURN_TYPE=Warning
+INTERFACE_ELEMENT_TYPE_ADDED_METHOD=Error
+CLASS_ELEMENT_TYPE_REMOVED_FIELD=Error
+METHOD_ELEMENT_TYPE_CHANGED_NON_FINAL_TO_FINAL=Error
+TYPE_PARAMETER_ELEMENT_TYPE_CHANGED_CLASS_BOUND=Error
+ILLEGAL_INSTANTIATE=Warning
+FIELD_ELEMENT_TYPE_CHANGED_VALUE=Error
+INTERFACE_ELEMENT_TYPE_ADDED_FIELD=Error
+ANNOTATION_ELEMENT_TYPE_REMOVED_METHOD=Error
+ILLEGAL_IMPLEMENT=Warning
+FIELD_ELEMENT_TYPE_CHANGED_NON_FINAL_TO_FINAL=Error
+INVALID_REFERENCE_IN_SYSTEM_LIBRARIES=Error
+FIELD_ELEMENT_TYPE_CHANGED_STATIC_TO_NON_STATIC=Error
+TYPE_PARAMETER_ELEMENT_TYPE_ADDED_INTERFACE_BOUND=Error
+LEAK_EXTEND=Warning
+INVALID_JAVADOC_TAG=Ignore
+CLASS_ELEMENT_TYPE_REMOVED_CONSTRUCTOR=Error
+METHOD_ELEMENT_TYPE_REMOVED_TYPE_PARAMETER=Error
+INTERFACE_ELEMENT_TYPE_REMOVED_TYPE_PARAMETER=Error
+ENUM_ELEMENT_TYPE_REMOVED_METHOD=Error
+TYPE_PARAMETER_ELEMENT_TYPE_CHANGED_INTERFACE_BOUND=Error
+METHOD_ELEMENT_TYPE_CHANGED_NON_ABSTRACT_TO_ABSTRACT=Error
+CLASS_ELEMENT_TYPE_ADDED_RESTRICTIONS=Error
+ILLEGAL_REFERENCE=Warning
+METHOD_ELEMENT_TYPE_CHANGED_STATIC_TO_NON_STATIC=Error
+CONSTRUCTOR_ELEMENT_TYPE_CHANGED_DECREASE_ACCESS=Error
+INTERFACE_ELEMENT_TYPE_REMOVED_METHOD=Error
+LEAK_METHOD_PARAM=Warning
+API_COMPONENT_ELEMENT_TYPE_REMOVED_API_TYPE=Error
+incompatible_api_component_version=Error
+METHOD_ELEMENT_TYPE_ADDED_RESTRICTIONS=Error
+CLASS_ELEMENT_TYPE_CHANGED_TYPE_CONVERSION=Error
+ILLEGAL_OVERRIDE=Warning
+TYPE_PARAMETER_ELEMENT_TYPE_REMOVED_CLASS_BOUND=Error
+INTERFACE_ELEMENT_TYPE_ADDED_SUPER_INTERFACE_WITH_METHODS=Error
+FIELD_ELEMENT_TYPE_CHANGED_NON_STATIC_TO_STATIC=Error
+CLASS_ELEMENT_TYPE_REMOVED_TYPE_MEMBER=Error
+TYPE_PARAMETER_ELEMENT_TYPE_REMOVED_INTERFACE_BOUND=Error
+CLASS_ELEMENT_TYPE_CHANGED_DECREASE_ACCESS=Error
+FIELD_ELEMENT_TYPE_ADDED_VALUE=Error
+METHOD_ELEMENT_TYPE_ADDED_TYPE_PARAMETER=Error
+INTERFACE_ELEMENT_TYPE_ADDED_RESTRICTIONS=Error
+malformed_since_tag=Error
+INTERFACE_ELEMENT_TYPE_CHANGED_TYPE_CONVERSION=Error
+ANNOTATION_ELEMENT_TYPE_CHANGED_TYPE_CONVERSION=Error
+INTERFACE_ELEMENT_TYPE_ADDED_TYPE_PARAMETER=Error
+automatically_removed_unused_problem_filters=false
+METHOD_ELEMENT_TYPE_CHANGED_NON_STATIC_TO_STATIC=Error
+report_api_breakage_when_major_version_incremented=Disabled
+INTERFACE_ELEMENT_TYPE_REMOVED_FIELD=Error
+CLASS_ELEMENT_TYPE_CHANGED_NON_FINAL_TO_FINAL=Error
+eclipse.preferences.version=1
+CONSTRUCTOR_ELEMENT_TYPE_ADDED_TYPE_PARAMETER=Error
+ANNOTATION_ELEMENT_TYPE_ADDED_METHOD_WITHOUT_DEFAULT_VALUE=Error
+incompatible_api_component_version_include_minor_without_api_change=Disabled
+incompatible_api_component_version_include_major_without_breaking_change=Disabled
+INTERFACE_ELEMENT_TYPE_CHANGED_CONTRACTED_SUPERINTERFACES_SET=Error
+METHOD_ELEMENT_TYPE_CHANGED_VARARGS_TO_ARRAY=Error
+METHOD_ELEMENT_TYPE_CHANGED_DECREASE_ACCESS=Error
+INTERFACE_ELEMENT_TYPE_REMOVED_TYPE_MEMBER=Error
+ANNOTATION_ELEMENT_TYPE_REMOVED_FIELD=Error
+ENUM_ELEMENT_TYPE_CHANGED_CONTRACTED_SUPERINTERFACES_SET=Error
+CLASS_ELEMENT_TYPE_ADDED_TYPE_PARAMETER=Error
+missing_since_tag=Error
+ANNOTATION_ELEMENT_TYPE_REMOVED_TYPE_MEMBER=Error
+FIELD_ELEMENT_TYPE_CHANGED_DECREASE_ACCESS=Error
+UNUSED_PROBLEM_FILTERS=Warning
+ILLEGAL_EXTEND=Warning
+TYPE_PARAMETER_ELEMENT_TYPE_ADDED_CLASS_BOUND=Error
+CLASS_ELEMENT_TYPE_REMOVED_METHOD=Error
+CLASS_ELEMENT_TYPE_CHANGED_CONTRACTED_SUPERINTERFACES_SET=Error
+API_COMPONENT_ELEMENT_TYPE_REMOVED_REEXPORTED_API_TYPE=Error
+ENUM_ELEMENT_TYPE_REMOVED_ENUM_CONSTANT=Error
+CLASS_ELEMENT_TYPE_REMOVED_TYPE_PARAMETER=Error
+API_COMPONENT_ELEMENT_TYPE_REMOVED_TYPE=Error
+CONSTRUCTOR_ELEMENT_TYPE_CHANGED_VARARGS_TO_ARRAY=Error
+METHOD_ELEMENT_TYPE_REMOVED_ANNOTATION_DEFAULT_VALUE=Error
+API_COMPONENT_ELEMENT_TYPE_REMOVED_REEXPORTED_TYPE=Error
+FIELD_ELEMENT_TYPE_REMOVED_TYPE_ARGUMENT=Error
+LEAK_FIELD_DECL=Warning
+FIELD_ELEMENT_TYPE_REMOVED_VALUE=Error
+CLASS_ELEMENT_TYPE_REMOVED_SUPERCLASS=Error
+FIELD_ELEMENT_TYPE_CHANGED_FINAL_TO_NON_FINAL_STATIC_CONSTANT=Error
+CLASS_ELEMENT_TYPE_ADDED_METHOD=Error
+LEAK_IMPLEMENT=Warning
+report_resolution_errors_api_component=Warning
+ENUM_ELEMENT_TYPE_REMOVED_FIELD=Error
+ENUM_ELEMENT_TYPE_CHANGED_TYPE_CONVERSION=Error
+CONSTRUCTOR_ELEMENT_TYPE_REMOVED_TYPE_PARAMETER=Error
+FIELD_ELEMENT_TYPE_CHANGED_TYPE=Error
diff --git a/bundles/org.eclipse.equinox.event/src/org/eclipse/equinox/internal/event/EventHandlerTracker.java b/bundles/org.eclipse.equinox.event/src/org/eclipse/equinox/internal/event/EventHandlerTracker.java
index 91d6bb3..23bb0ba 100644
--- a/bundles/org.eclipse.equinox.event/src/org/eclipse/equinox/internal/event/EventHandlerTracker.java
+++ b/bundles/org.eclipse.equinox.event/src/org/eclipse/equinox/internal/event/EventHandlerTracker.java
@@ -161,9 +161,9 @@
 
 		// Add the handlers with partial matches
 		if (partialWildcard.size() > 0) {
-			int index = topic.length();
+			int index = topic.lastIndexOf('/');
 			while (index >= 0) {
-				String subTopic = topic.substring(0, index); // First subtopic is the complete topic.
+				String subTopic = topic.substring(0, index);
 				List<EventHandlerWrapper> wrappers = partialWildcard.get(subTopic);
 				if (wrappers != null) {
 					handlers.addAll(wrappers);