Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorslewis2009-09-15 16:19:32 -0400
committerslewis2009-09-15 16:19:32 -0400
commit235550ed84ca660a7107cdbf27d805f7523fbabd (patch)
tree3bdb984386d09c355e52374a23673f61a397d4f7
parentf0581dd000d94adc99f0ce4bf1db66e4523b0b3f (diff)
downloadorg.eclipse.ecf-235550ed84ca660a7107cdbf27d805f7523fbabd.tar.gz
org.eclipse.ecf-235550ed84ca660a7107cdbf27d805f7523fbabd.tar.xz
org.eclipse.ecf-235550ed84ca660a7107cdbf27d805f7523fbabd.zip
Additions to support full implementation of OSGI EventAdmin specification
-rw-r--r--server-side/bundles/org.eclipse.ecf.remoteservice.eventadmin/META-INF/MANIFEST.MF2
-rw-r--r--server-side/bundles/org.eclipse.ecf.remoteservice.eventadmin/src/org/eclipse/ecf/internal/remoteservice/eventadmin/DistributedEventAdminMessage.java43
-rw-r--r--server-side/bundles/org.eclipse.ecf.remoteservice.eventadmin/src/org/eclipse/ecf/internal/remoteservice/eventadmin/EventHandlerTracker.java209
-rw-r--r--server-side/bundles/org.eclipse.ecf.remoteservice.eventadmin/src/org/eclipse/ecf/internal/remoteservice/eventadmin/EventHandlerWrapper.java200
-rw-r--r--server-side/bundles/org.eclipse.ecf.remoteservice.eventadmin/src/org/eclipse/ecf/internal/remoteservice/eventadmin/LogTracker.java182
-rw-r--r--server-side/bundles/org.eclipse.ecf.remoteservice.eventadmin/src/org/eclipse/ecf/remoteservice/eventadmin/DistributedEventAdmin.java251
6 files changed, 741 insertions, 146 deletions
diff --git a/server-side/bundles/org.eclipse.ecf.remoteservice.eventadmin/META-INF/MANIFEST.MF b/server-side/bundles/org.eclipse.ecf.remoteservice.eventadmin/META-INF/MANIFEST.MF
index 8baf26b99..eb7c2d1de 100644
--- a/server-side/bundles/org.eclipse.ecf.remoteservice.eventadmin/META-INF/MANIFEST.MF
+++ b/server-side/bundles/org.eclipse.ecf.remoteservice.eventadmin/META-INF/MANIFEST.MF
@@ -10,8 +10,10 @@ Bundle-Localization: bundle
Import-Package: org.eclipse.ecf.core.identity;version="3.0.0",
org.eclipse.ecf.core.sharedobject,
org.eclipse.equinox.concurrent.future;version="1.0.0",
+ org.eclipse.osgi.util;version="1.1.0",
org.osgi.framework;version="1.3.0",
org.osgi.service.event;version="1.2.0",
+ org.osgi.service.log;version="1.3.0",
org.osgi.util.tracker;version="1.4.2"
Require-Bundle: org.eclipse.equinox.common;bundle-version="3.5.0"
Export-Package: org.eclipse.ecf.internal.remoteservice.eventadmin;x-internal:=true,
diff --git a/server-side/bundles/org.eclipse.ecf.remoteservice.eventadmin/src/org/eclipse/ecf/internal/remoteservice/eventadmin/DistributedEventAdminMessage.java b/server-side/bundles/org.eclipse.ecf.remoteservice.eventadmin/src/org/eclipse/ecf/internal/remoteservice/eventadmin/DistributedEventAdminMessage.java
index ff13c3b28..5a1f679e3 100644
--- a/server-side/bundles/org.eclipse.ecf.remoteservice.eventadmin/src/org/eclipse/ecf/internal/remoteservice/eventadmin/DistributedEventAdminMessage.java
+++ b/server-side/bundles/org.eclipse.ecf.remoteservice.eventadmin/src/org/eclipse/ecf/internal/remoteservice/eventadmin/DistributedEventAdminMessage.java
@@ -1,12 +1,12 @@
/*******************************************************************************
-* Copyright (c) 2009 EclipseSource 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:
-* EclipseSource - initial API and implementation
-******************************************************************************/
+ * Copyright (c) 2009 EclipseSource 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:
+ * EclipseSource - initial API and implementation
+ ******************************************************************************/
package org.eclipse.ecf.internal.remoteservice.eventadmin;
import java.io.NotSerializableException;
@@ -14,6 +14,7 @@ import java.io.Serializable;
import java.util.Hashtable;
import java.util.Map;
+import org.eclipse.osgi.util.NLS;
import org.osgi.service.event.Event;
public class DistributedEventAdminMessage implements Serializable {
@@ -21,28 +22,36 @@ public class DistributedEventAdminMessage implements Serializable {
private static final long serialVersionUID = 2743430591605178391L;
private String topic;
private Map properties;
-
+
private transient Event localEvent;
-
- public DistributedEventAdminMessage(Event event) throws NotSerializableException {
+
+ public DistributedEventAdminMessage(Event event)
+ throws NotSerializableException {
this.topic = event.getTopic();
this.properties = createPropertiesFromEvent(event);
}
- private Map createPropertiesFromEvent(Event event) throws NotSerializableException {
+ private Map createPropertiesFromEvent(Event event)
+ throws NotSerializableException {
String[] propertyNames = event.getPropertyNames();
- Hashtable ht = (propertyNames == null)?new Hashtable(1):new Hashtable(propertyNames.length);
- for(int i=0; i < propertyNames.length; i++) {
+ Hashtable ht = (propertyNames == null) ? new Hashtable(1)
+ : new Hashtable(propertyNames.length);
+ for (int i = 0; i < propertyNames.length; i++) {
Object val = event.getProperty(propertyNames[i]);
- if (!(val instanceof Serializable)) throw new NotSerializableException("Cannot serialize property value of name="+propertyNames[i]+", value="+val);
+ if (!(val instanceof Serializable))
+ throw new NotSerializableException(
+ NLS
+ .bind(
+ "Cannot serialize property value of name={0} and value={1}",
+ propertyNames[i], val));
ht.put(propertyNames[i], val);
}
return ht;
}
-
+
public synchronized Event getEvent() {
if (localEvent == null) {
- localEvent = new Event(topic,properties);
+ localEvent = new Event(topic, properties);
}
return localEvent;
}
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;
+ }
+
+}
diff --git a/server-side/bundles/org.eclipse.ecf.remoteservice.eventadmin/src/org/eclipse/ecf/internal/remoteservice/eventadmin/EventHandlerWrapper.java b/server-side/bundles/org.eclipse.ecf.remoteservice.eventadmin/src/org/eclipse/ecf/internal/remoteservice/eventadmin/EventHandlerWrapper.java
new file mode 100644
index 000000000..8e973478d
--- /dev/null
+++ b/server-side/bundles/org.eclipse.ecf.remoteservice.eventadmin/src/org/eclipse/ecf/internal/remoteservice/eventadmin/EventHandlerWrapper.java
@@ -0,0 +1,200 @@
+/*******************************************************************************
+ * 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.security.Permission;
+
+import org.eclipse.osgi.util.NLS;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Filter;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.event.Event;
+import org.osgi.service.event.EventConstants;
+import org.osgi.service.event.EventHandler;
+import org.osgi.service.log.LogService;
+
+/**
+ * A wrapper for EventHandlers. This class caches property values and performs
+ * final checks before calling the wrapped handler.
+ *
+ */
+public class EventHandlerWrapper {
+ private final ServiceReference reference;
+ private final LogService log;
+ private final BundleContext context;
+ private EventHandler handler;
+ private String[] topics;
+ private Filter filter;
+
+ /**
+ * Create an EventHandlerWrapper.
+ *
+ * @param reference
+ * Reference to the EventHandler
+ * @param context
+ * Bundle Context of the Event Admin bundle
+ * @param log
+ * LogService object for logging
+ */
+ public EventHandlerWrapper(ServiceReference reference,
+ BundleContext context, LogService log) {
+ this.reference = reference;
+ this.context = context;
+ this.log = log;
+ }
+
+ /**
+ * Cache values from service properties
+ *
+ * @return true if the handler should be called; false if the handler should
+ * not be called
+ */
+ public synchronized boolean init() {
+ topics = null;
+ filter = null;
+
+ // Get topic names
+ Object o = reference.getProperty(EventConstants.EVENT_TOPIC);
+ if (o instanceof String) {
+ topics = new String[] { (String) o };
+ } else if (o instanceof String[]) {
+ topics = (String[]) o;
+ }
+
+ if (topics == null) {
+ return false;
+ }
+
+ // get filter
+ o = reference.getProperty(EventConstants.EVENT_FILTER);
+ if (o instanceof String) {
+ try {
+ filter = context.createFilter((String) o);
+ } catch (InvalidSyntaxException e) {
+ log.log(LogService.LOG_ERROR, NLS.bind(
+ "Invalid handler filter {0}", o), e);
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Flush the handler service if it has been obtained.
+ */
+ public void flush() {
+ synchronized (this) {
+ if (handler == null) {
+ return;
+ }
+ handler = null;
+ }
+ context.ungetService(reference);
+ }
+
+ /**
+ * Get the event topics for the wrapped handler.
+ *
+ * @return The wrapped handler's event topics
+ */
+ public synchronized String[] getTopics() {
+ return topics;
+ }
+
+ /**
+ * Return the wrapped handler.
+ *
+ * @return The wrapped handler.
+ */
+ private EventHandler getHandler() {
+ synchronized (this) {
+ // if we already have a handler, return it
+ if (handler != null) {
+ return handler;
+ }
+ }
+
+ // we don't have the handler, so lets get it outside the sync region
+ EventHandler tempHandler = (EventHandler) context.getService(reference);
+
+ synchronized (this) {
+ // do we still need the handler we just got?
+ if (handler == null) {
+ handler = tempHandler;
+ return handler;
+ }
+ // get the current handler
+ tempHandler = handler;
+ }
+
+ // unget the handler we just got since we don't need it
+ context.ungetService(reference);
+
+ // return the current handler (copied into the local var)
+ return tempHandler;
+ }
+
+ /**
+ * Get the filter object
+ *
+ * @return The handler's filter
+ */
+ private synchronized Filter getFilter() {
+ return filter;
+ }
+
+ /**
+ * Dispatch event to handler. Perform final tests before actually calling
+ * the handler.
+ *
+ * @param event
+ * The event to dispatch
+ * @param perm
+ * The permission to be checked
+ */
+ public void handleEvent(Event event, Permission perm) {
+ Bundle bundle = reference.getBundle();
+ // is service unregistered?
+ if (bundle == null) {
+ return;
+ }
+
+ // filter match
+ Filter eventFilter = getFilter();
+ if ((eventFilter != null) && !event.matches(eventFilter)) {
+ return;
+ }
+
+ // permission check
+ if ((perm != null) && (!bundle.hasPermission(perm))) {
+ return;
+ }
+
+ // get handler service
+ EventHandler handlerService = getHandler();
+ if (handlerService == null) {
+ return;
+ }
+
+ try {
+ handlerService.handleEvent(event);
+ } catch (Throwable t) {
+ // log/handle any Throwable thrown by the listener
+ log.log(LogService.LOG_ERROR, NLS.bind(
+ "Exception while dispatching event {0} to handler {1}",
+ event, handlerService), t);
+ }
+ }
+}
diff --git a/server-side/bundles/org.eclipse.ecf.remoteservice.eventadmin/src/org/eclipse/ecf/internal/remoteservice/eventadmin/LogTracker.java b/server-side/bundles/org.eclipse.ecf.remoteservice.eventadmin/src/org/eclipse/ecf/internal/remoteservice/eventadmin/LogTracker.java
new file mode 100644
index 000000000..ea9cf0b0c
--- /dev/null
+++ b/server-side/bundles/org.eclipse.ecf.remoteservice.eventadmin/src/org/eclipse/ecf/internal/remoteservice/eventadmin/LogTracker.java
@@ -0,0 +1,182 @@
+/*******************************************************************************
+ * Copyright (c) 1998, 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.io.PrintStream;
+import java.util.Calendar;
+import java.util.Date;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.log.LogService;
+import org.osgi.util.tracker.ServiceTracker;
+
+/**
+ * LogTracker class. This class encapsulates the LogService and handles all
+ * issues such as the service coming and going.
+ */
+
+public class LogTracker extends ServiceTracker implements LogService {
+ /** LogService interface class name */
+ protected final static String clazz = "org.osgi.service.log.LogService"; //$NON-NLS-1$
+
+ /** PrintStream to use if LogService is unavailable */
+ private final PrintStream out;
+
+ /**
+ * Create new LogTracker.
+ *
+ * @param context
+ * BundleContext of parent bundle.
+ * @param out
+ * Default PrintStream to use if LogService is unavailable.
+ */
+ public LogTracker(BundleContext context, PrintStream out) {
+ super(context, clazz, null);
+ this.out = out;
+ }
+
+ /*
+ * ----------------------------------------------------------------------
+ * LogService Interface implementation
+ * ----------------------------------------------------------------------
+ */
+
+ public void log(int level, String message) {
+ log(null, level, message, null);
+ }
+
+ public void log(int level, String message, Throwable exception) {
+ log(null, level, message, exception);
+ }
+
+ public void log(ServiceReference reference, int level, String message) {
+ log(reference, level, message, null);
+ }
+
+ public synchronized void log(ServiceReference reference, int level,
+ String message, Throwable exception) {
+ ServiceReference[] references = getServiceReferences();
+
+ if (references != null) {
+ int size = references.length;
+
+ for (int i = 0; i < size; i++) {
+ LogService service = (LogService) getService(references[i]);
+ if (service != null) {
+ try {
+ service.log(reference, level, message, exception);
+ } catch (Exception e) {
+ // TODO: consider printing to System Error
+ }
+ }
+ }
+
+ return;
+ }
+
+ noLogService(level, message, exception, reference);
+ }
+
+ /**
+ * The LogService is not available so we write the message to a PrintStream.
+ *
+ * @param level
+ * Logging level
+ * @param message
+ * Log message.
+ * @param throwable
+ * Log exception or null if none.
+ * @param reference
+ * ServiceReference associated with message or null if none.
+ */
+ protected void noLogService(int level, String message, Throwable throwable,
+ ServiceReference reference) {
+ if (out != null) {
+ synchronized (out) {
+ // Bug #113286. If no log service present and messages are being
+ // printed to stdout, prepend message with a timestamp.
+ String timestamp = getDate(new Date());
+ out.print(timestamp + " "); //$NON-NLS-1$
+
+ switch (level) {
+ case LOG_DEBUG: {
+ out.print("Log Debug");
+
+ break;
+ }
+ case LOG_INFO: {
+ out.print("Log Info");
+
+ break;
+ }
+ case LOG_WARNING: {
+ out.print("Log Warning");
+
+ break;
+ }
+ case LOG_ERROR: {
+ out.print("Log Error");
+
+ break;
+ }
+ default: {
+ out.print("["); //$NON-NLS-1$
+ out.print("Log Unknown Log Level");
+ out.print("]: "); //$NON-NLS-1$
+
+ break;
+ }
+ }
+
+ out.println(message);
+
+ if (reference != null) {
+ out.println(reference);
+ }
+
+ if (throwable != null) {
+ throwable.printStackTrace(out);
+ }
+ }
+ }
+ }
+
+ // from EclipseLog to avoid using DateFormat -- see bug 149892#c10
+ private String getDate(Date date) {
+ Calendar c = Calendar.getInstance();
+ c.setTime(date);
+ StringBuffer sb = new StringBuffer();
+ appendPaddedInt(c.get(Calendar.YEAR), 4, sb).append('-');
+ appendPaddedInt(c.get(Calendar.MONTH) + 1, 2, sb).append('-');
+ appendPaddedInt(c.get(Calendar.DAY_OF_MONTH), 2, sb).append(' ');
+ appendPaddedInt(c.get(Calendar.HOUR_OF_DAY), 2, sb).append(':');
+ appendPaddedInt(c.get(Calendar.MINUTE), 2, sb).append(':');
+ appendPaddedInt(c.get(Calendar.SECOND), 2, sb).append('.');
+ appendPaddedInt(c.get(Calendar.MILLISECOND), 3, sb);
+ return sb.toString();
+ }
+
+ private StringBuffer appendPaddedInt(int value, int pad, StringBuffer buffer) {
+ pad = pad - 1;
+ if (pad == 0)
+ return buffer.append(Integer.toString(value));
+ int padding = (int) Math.pow(10, pad);
+ if (value >= padding)
+ return buffer.append(Integer.toString(value));
+ while (padding > value && padding > 1) {
+ buffer.append('0');
+ padding = padding / 10;
+ }
+ buffer.append(value);
+ return buffer;
+ }
+}
diff --git a/server-side/bundles/org.eclipse.ecf.remoteservice.eventadmin/src/org/eclipse/ecf/remoteservice/eventadmin/DistributedEventAdmin.java b/server-side/bundles/org.eclipse.ecf.remoteservice.eventadmin/src/org/eclipse/ecf/remoteservice/eventadmin/DistributedEventAdmin.java
index 714f7481e..0c27a3ae1 100644
--- a/server-side/bundles/org.eclipse.ecf.remoteservice.eventadmin/src/org/eclipse/ecf/remoteservice/eventadmin/DistributedEventAdmin.java
+++ b/server-side/bundles/org.eclipse.ecf.remoteservice.eventadmin/src/org/eclipse/ecf/remoteservice/eventadmin/DistributedEventAdmin.java
@@ -10,9 +10,10 @@
package org.eclipse.ecf.remoteservice.eventadmin;
import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
+import java.security.Permission;
+import java.util.Iterator;
import java.util.Properties;
+import java.util.Set;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.IProgressMonitor;
@@ -25,133 +26,105 @@ import org.eclipse.ecf.core.sharedobject.ISharedObjectContainer;
import org.eclipse.ecf.core.sharedobject.SharedObjectAddException;
import org.eclipse.ecf.core.sharedobject.SharedObjectMsg;
import org.eclipse.ecf.internal.remoteservice.eventadmin.DistributedEventAdminMessage;
+import org.eclipse.ecf.internal.remoteservice.eventadmin.EventHandlerTracker;
+import org.eclipse.ecf.internal.remoteservice.eventadmin.EventHandlerWrapper;
+import org.eclipse.ecf.internal.remoteservice.eventadmin.LogTracker;
import org.eclipse.equinox.concurrent.future.IExecutor;
import org.eclipse.equinox.concurrent.future.IProgressRunnable;
import org.eclipse.equinox.concurrent.future.ThreadsExecutor;
+import org.eclipse.osgi.util.NLS;
import org.osgi.framework.BundleContext;
-import org.osgi.framework.Filter;
-import org.osgi.framework.InvalidSyntaxException;
-import org.osgi.framework.ServiceReference;
import org.osgi.framework.ServiceRegistration;
import org.osgi.service.event.Event;
import org.osgi.service.event.EventAdmin;
import org.osgi.service.event.EventConstants;
-import org.osgi.service.event.EventHandler;
-import org.osgi.util.tracker.ServiceTracker;
+import org.osgi.service.event.TopicPermission;
+import org.osgi.service.log.LogService;
-public class DistributedEventAdmin extends BaseSharedObject implements EventAdmin {
+public class DistributedEventAdmin extends BaseSharedObject implements
+ EventAdmin {
private BundleContext context;
-
- private ServiceTracker eventHandlerServiceTracker;
- private final Object eventHandlerSTLock = new Object();
+ private String topic;
+ private ID topicID;
+ private LogTracker log;
+ private EventHandlerTracker eventHandlerTracker;
private IExecutor executor;
- private String topic;
- private ID topicID;
-
- public DistributedEventAdmin(BundleContext context, String topic, IExecutor executor) {
+ public DistributedEventAdmin(BundleContext context, String topic,
+ IExecutor executor) {
this.context = context;
Assert.isNotNull(this.context);
this.topic = topic;
Assert.isNotNull(this.topic);
this.topicID = IDFactory.getDefault().createStringID(getTopic());
- this.executor = (executor == null)?new ThreadsExecutor():executor;
+ this.log = new LogTracker(context, System.out);
+ this.executor = (executor == null) ? new ThreadsExecutor() : executor;
+ this.eventHandlerTracker = new EventHandlerTracker(context, log);
+ this.eventHandlerTracker.open();
}
-
+
public DistributedEventAdmin(BundleContext context, String topic) {
- this(context,topic,null);
+ this(context, topic, null);
}
public String getTopic() {
return topic;
}
-
+
public ID getTopicID() {
return topicID;
}
-
- public void addToContainer(ISharedObjectContainer soContainer) throws SharedObjectAddException {
- soContainer.getSharedObjectManager().addSharedObject(topicID, this, null);
+
+ public void addToContainer(ISharedObjectContainer soContainer)
+ throws SharedObjectAddException {
+ soContainer.getSharedObjectManager().addSharedObject(topicID, this,
+ null);
}
public void removeFromContainer(ISharedObjectContainer soContainer) {
soContainer.getSharedObjectManager().removeSharedObject(getTopicID());
}
-
+
public ServiceRegistration register(Properties props) {
- if (props == null) props = new Properties();
+ if (props == null)
+ props = new Properties();
props.put(EventConstants.EVENT_TOPIC, getTopic());
- return this.context.registerService(EventAdmin.class.getName(), this, props);
+ return this.context.registerService(EventAdmin.class.getName(), this,
+ props);
}
-
+
public ServiceRegistration register() {
return register(null);
}
-
+
public void dispose() {
- if (eventHandlerServiceTracker != null) {
- eventHandlerServiceTracker.close();
- eventHandlerServiceTracker = null;
+ if (this.eventHandlerTracker != null) {
+ this.eventHandlerTracker.close();
+ }
+ if (this.log != null) {
+ this.log.close();
}
topic = null;
topicID = null;
executor = null;
}
-
+
public void postEvent(final Event event) {
try {
sendSharedObjectMsgTo(null, SharedObjectMsg.createMsg(
"handlePostEvent", new DistributedEventAdminMessage(event)));
- localPostEvent(event);
} catch (IOException e) {
- logError("postEvent exception event=" + event + " not sent.", e);
+ logError(NLS.bind(
+ "IOException posting distributed event {0} to {1}", event,
+ topic), e);
}
+ localDispatch(event, true);
}
public void sendEvent(Event event) {
- try {
- sendSharedObjectMsgTo(null, SharedObjectMsg.createMsg(
- "handleSendEvent", new DistributedEventAdminMessage(event)));
- localSendEvent(event);
- } catch (IOException e) {
- logError("sendEvent exception event=" + event + " not sent.", e);
- }
- }
-
- private ServiceReference[] getEventHandlerServiceReferences(Event event) {
- synchronized (eventHandlerSTLock) {
- if (eventHandlerServiceTracker == null) {
- eventHandlerServiceTracker = new ServiceTracker(context,
- EventHandler.class.getName(), null);
- eventHandlerServiceTracker.open();
- }
- ServiceReference[] refs = eventHandlerServiceTracker
- .getServiceReferences();
- List results = new ArrayList();
- if (refs == null)
- return null;
- for (int i = 0; i < refs.length; i++) {
- String eventFilter = (String) refs[i]
- .getProperty(EventConstants.EVENT_FILTER);
- Filter filter = null;
- if (eventFilter != null) {
- try {
- filter = context.createFilter(eventFilter);
- if (event.matches(filter))
- results.add(refs[i]);
- } catch (InvalidSyntaxException e) {
- logError("getEventHandlers eventFilter=" + eventFilter,
- e);
- continue;
- }
- } else
- results.add(refs[i]);
- }
- return (ServiceReference[]) results
- .toArray(new ServiceReference[] {});
- }
+ localDispatch(event, false);
}
protected boolean handleSharedObjectMsg(SharedObjectMsg msg) {
@@ -164,75 +137,95 @@ public class DistributedEventAdmin extends BaseSharedObject implements EventAdmi
return false;
}
- private void localSendEvent(Event event) {
- ServiceReference[] eventHandlerRefs = getEventHandlerServiceReferences(event);
- if (eventHandlerRefs == null) {
- logWarning("sendEvent event=" + event
- + ". No service references found to post to.");
+ protected void localDispatch(Event event, boolean isAsync) {
+ IExecutor exec = executor;
+ if (exec == null)
return;
+
+ if (event == null) {
+ log.log(LogService.LOG_ERROR,
+ "Null event passed to EventAdmin was ignored.");
+ // continue from here will result in an NPE below; the spec for
+ // EventAdmin does not allow for null here
}
- // Now synchronously call every eventhandler
- for (int i = 0; i < eventHandlerRefs.length; i++)
- callSync(eventHandlerRefs[i], (EventHandler) context
- .getService(eventHandlerRefs[i]), event);
- }
+ String eventTopic = event.getTopic();
- private void localPostEvent(Event event) {
- ServiceReference[] refs = getEventHandlerServiceReferences(event);
- if (refs == null) {
- logWarning("localPostEvent event=" + event
- + ". No service references found to post to.");
- return;
+ try {
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null)
+ sm.checkPermission(new TopicPermission(topic,
+ TopicPermission.PUBLISH));
+ } catch (SecurityException e) {
+ String msg = NLS
+ .bind(
+ "Caller bundle does not have TopicPermission to publish topic {0}",
+ eventTopic);
+ logError(msg, e);
+ // must throw a security exception here according to the EventAdmin
+ // spec
+ throw e;
}
- for (int i = 0; i < refs.length; i++)
- fireAsync(refs[i], (EventHandler) context.getService(refs[i]),
- event);
- }
- void handlePostEvent(DistributedEventAdminMessage event) {
- localPostEvent(event.getEvent());
- }
+ Set eventHandlerWrappers = eventHandlerTracker.getHandlers(eventTopic);
- void handleSendEvent(DistributedEventAdminMessage event) {
- localSendEvent(event.getEvent());
- }
+ SecurityManager sm = System.getSecurityManager();
+ Permission perm = (sm == null) ? null : new TopicPermission(topic,
+ TopicPermission.SUBSCRIBE);
- protected void logWarning(String string) {
- System.out.println(string);
- }
+ // Now synchronously call every eventhandler
+ if (isAsync)
+ fireAsync(exec, eventHandlerWrappers, event, perm);
+ else
+ callSync(eventHandlerWrappers, event, perm);
- protected void callSync(final ServiceReference serviceReference,
- final EventHandler eventHandler, final Event event) {
- SafeRunner.run(new ISafeRunnable() {
- public void handleException(Throwable exception) {
- logError(
- "Exception in EventHandler.handleEvent. eventHandler="
- + eventHandler + ". serviceReference="
- + serviceReference + ". event=" + event,
- exception);
- }
+ }
- public void run() throws Exception {
- eventHandler.handleEvent(event);
- }
- });
+ void handlePostEvent(DistributedEventAdminMessage event) {
+ localDispatch(event.getEvent(), true);
+ }
+
+ protected void callSync(Set eventHandlerWrappers, final Event event,
+ final Permission perm) {
+ for (Iterator i = eventHandlerWrappers.iterator(); i.hasNext();) {
+ final EventHandlerWrapper wrapper = (EventHandlerWrapper) i.next();
+ SafeRunner.run(new ISafeRunnable() {
+ public void handleException(Throwable exception) {
+ logError(
+ NLS
+ .bind(
+ "Exception while dispatching event {0} to handler {1}",
+ event, wrapper), exception);
+ }
+
+ public void run() throws Exception {
+ wrapper.handleEvent(event, perm);
+ }
+ });
+ }
}
- protected void fireAsync(final ServiceReference serviceReference,
- final EventHandler eventHandler, final Event event) {
- executor.execute(new IProgressRunnable() {
- public Object run(IProgressMonitor arg0) throws Exception {
- eventHandler.handleEvent(event);
- return null;
- }
- }, null);
+ protected void fireAsync(IExecutor exec, Set eventHandlerWrappers,
+ final Event event, final Permission perm) {
+ for (Iterator i = eventHandlerWrappers.iterator(); i.hasNext();) {
+ final EventHandlerWrapper wrapper = (EventHandlerWrapper) i.next();
+ exec.execute(new IProgressRunnable() {
+ public Object run(IProgressMonitor arg0) throws Exception {
+ wrapper.handleEvent(event, perm);
+ return null;
+ }
+ }, null);
+ }
}
- protected void logError(String string, Throwable e) {
- System.err.println(string);
- if (e != null)
- e.printStackTrace(System.err);
+ protected void logError(String message, Throwable exception) {
+ if (log != null) {
+ log.log(LogService.LOG_ERROR, message, exception);
+ } else {
+ System.err.println(message);
+ if (exception != null)
+ exception.printStackTrace(System.err);
+ }
}
}

Back to the top