diff options
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.java | 209 |
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; + } + +} |