Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'server-side/bundles/org.eclipse.ecf.remoteservice.eventadmin/src/org/eclipse/ecf/internal/remoteservice/eventadmin/EventHandlerTracker.java')
-rw-r--r--server-side/bundles/org.eclipse.ecf.remoteservice.eventadmin/src/org/eclipse/ecf/internal/remoteservice/eventadmin/EventHandlerTracker.java209
1 files changed, 209 insertions, 0 deletions
diff --git a/server-side/bundles/org.eclipse.ecf.remoteservice.eventadmin/src/org/eclipse/ecf/internal/remoteservice/eventadmin/EventHandlerTracker.java b/server-side/bundles/org.eclipse.ecf.remoteservice.eventadmin/src/org/eclipse/ecf/internal/remoteservice/eventadmin/EventHandlerTracker.java
new file mode 100644
index 000000000..8b99deb7a
--- /dev/null
+++ b/server-side/bundles/org.eclipse.ecf.remoteservice.eventadmin/src/org/eclipse/ecf/internal/remoteservice/eventadmin/EventHandlerTracker.java
@@ -0,0 +1,209 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 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.ecf.internal.remoteservice.eventadmin;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.event.EventHandler;
+import org.osgi.service.log.LogService;
+import org.osgi.util.tracker.ServiceTracker;
+
+public class EventHandlerTracker extends ServiceTracker {
+ private final LogService log;
+ // * List<EventHandlerWrapper> of all handlers with topic of "*"
+ private final List globalWildcard;
+ // Map<String,List<EventHandlerWrapper>> key is topic prefix of partial
+ // wildcard
+ private final Map partialWildcard;
+ // Map<String,List<EventHandlerWrapper>> key is topic name
+ private final Map topicName;
+
+ public EventHandlerTracker(BundleContext context, LogService log) {
+ super(context, EventHandler.class.getName(), null);
+ this.log = log;
+ globalWildcard = new ArrayList();
+ partialWildcard = new HashMap();
+ topicName = new HashMap();
+ }
+
+ public Object addingService(ServiceReference reference) {
+ EventHandlerWrapper wrapper = new EventHandlerWrapper(reference,
+ context, log);
+ synchronized (this) {
+ if (wrapper.init()) {
+ bucket(wrapper);
+ }
+ }
+ return wrapper;
+ }
+
+ public void modifiedService(ServiceReference reference, Object service) {
+ EventHandlerWrapper wrapper = (EventHandlerWrapper) service;
+ synchronized (this) {
+ unbucket(wrapper);
+ if (wrapper.init()) {
+ bucket(wrapper);
+ return;
+ }
+ }
+
+ wrapper.flush(); // needs to be called outside sync region
+ }
+
+ public void removedService(ServiceReference reference, Object service) {
+ EventHandlerWrapper wrapper = (EventHandlerWrapper) service;
+ synchronized (this) {
+ unbucket(wrapper);
+ }
+ wrapper.flush(); // needs to be called outside sync region
+ }
+
+ /**
+ * Place the wrapper into the appropriate buckets. This is a performance
+ * optimization for event delivery.
+ *
+ * @param wrapper
+ * The wrapper to place in buckets.
+ * @GuardedBy this
+ */
+ private void bucket(EventHandlerWrapper wrapper) {
+ final String[] topics = wrapper.getTopics();
+ final int length = (topics == null) ? 0 : topics.length;
+ for (int i = 0; i < length; i++) {
+ String topic = topics[i];
+ // global wildcard
+ if (topic.equals("*")) { //$NON-NLS-1$
+ globalWildcard.add(wrapper);
+ }
+ // partial wildcard
+ else if (topic.endsWith("/*")) { //$NON-NLS-1$
+ String key = topic.substring(0, topic.length() - 2); // Strip
+ // off
+ // "/*"
+ // from
+ // the
+ // end
+ List wrappers = (List) partialWildcard.get(key);
+ if (wrappers == null) {
+ wrappers = new ArrayList();
+ partialWildcard.put(key, wrappers);
+ }
+ wrappers.add(wrapper);
+ }
+ // simple topic name
+ else {
+ List wrappers = (List) topicName.get(topic);
+ if (wrappers == null) {
+ wrappers = new ArrayList();
+ topicName.put(topic, wrappers);
+ }
+ wrappers.add(wrapper);
+ }
+ }
+ }
+
+ /**
+ * Remove the wrapper from the buckets.
+ *
+ * @param wrapper
+ * The wrapper to remove from the buckets.
+ * @GuardedBy this
+ */
+ private void unbucket(EventHandlerWrapper wrapper) {
+ final String[] topics = wrapper.getTopics();
+ final int length = (topics == null) ? 0 : topics.length;
+ for (int i = 0; i < length; i++) {
+ String topic = topics[i];
+ // global wilcard
+ if (topic.equals("*")) { //$NON-NLS-1$
+ globalWildcard.remove(wrapper);
+ }
+ // partial wildcard
+ else if (topic.endsWith("/*")) { //$NON-NLS-1$
+ String key = topic.substring(0, topic.length() - 2); // Strip
+ // off
+ // "/*"
+ // from
+ // the
+ // end
+ List wrappers = (List) partialWildcard.get(key);
+ if (wrappers != null) {
+ wrappers.remove(wrapper);
+ if (wrappers.size() == 0) {
+ partialWildcard.remove(key);
+ }
+ }
+ }
+ // simple topic name
+ else {
+ List wrappers = (List) topicName.get(topic);
+ if (wrappers != null) {
+ wrappers.remove(wrapper);
+ if (wrappers.size() == 0) {
+ topicName.remove(topic);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Return the set of handlers which subscribe to the event topic. A set is
+ * used to ensure a handler is not called for an event more than once.
+ *
+ * @param topic
+ * @return a set of handlers
+ */
+ public synchronized Set getHandlers(final String topic) {
+ // Use a set to remove duplicates
+ Set handlers = new HashSet();
+
+ // Add the "*" handlers
+ handlers.addAll(globalWildcard);
+
+ // Add the handlers with partial matches
+ if (partialWildcard.size() > 0) {
+ int index = topic.length();
+ while (index >= 0) {
+ String subTopic = topic.substring(0, index); // First subtopic
+ // is the
+ // complete
+ // topic.
+ List wrappers = (List) partialWildcard.get(subTopic);
+ if (wrappers != null) {
+ handlers.addAll(wrappers);
+ }
+ // Strip the last level from the topic. For example,
+ // org/osgi/framework becomes org/osgi.
+ // Wildcard topics are inserted into the map with the "/*"
+ // stripped off.
+ index = subTopic.lastIndexOf('/');
+ }
+ }
+
+ // Add the handlers for matching topic names
+ List wrappers = (List) topicName.get(topic);
+ if (wrappers != null) {
+ handlers.addAll(wrappers);
+ }
+
+ return handlers;
+ }
+
+}

Back to the top