Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPawel Piech2006-07-28 16:01:39 +0000
committerPawel Piech2006-07-28 16:01:39 +0000
commit9d95f568dbd6b45c659909dc849eb0808c1f590b (patch)
tree0c116b49e0f88742e56a6ccfecdc45aa662318f8
downloadorg.eclipse.cdt-9d95f568dbd6b45c659909dc849eb0808c1f590b.tar.gz
org.eclipse.cdt-9d95f568dbd6b45c659909dc849eb0808c1f590b.tar.xz
org.eclipse.cdt-9d95f568dbd6b45c659909dc849eb0808c1f590b.zip
Initial checkin.
-rw-r--r--plugins/org.eclipse.dd.dsf/.classpath7
-rw-r--r--plugins/org.eclipse.dd.dsf/.cvsignore1
-rw-r--r--plugins/org.eclipse.dd.dsf/.project28
-rw-r--r--plugins/org.eclipse.dd.dsf/.settings/org.eclipse.jdt.core.prefs12
-rw-r--r--plugins/org.eclipse.dd.dsf/META-INF/MANIFEST.MF14
-rw-r--r--plugins/org.eclipse.dd.dsf/build.properties5
-rw-r--r--plugins/org.eclipse.dd.dsf/plugin.xml5
-rw-r--r--plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/DsfPlugin.java68
-rw-r--r--plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/concurrent/DefaultDsfExecutor.java60
-rw-r--r--plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/concurrent/Done.java48
-rw-r--r--plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/concurrent/DoneTracker.java104
-rw-r--r--plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/concurrent/DsfExecutor.java31
-rw-r--r--plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/concurrent/DsfQuery.java161
-rw-r--r--plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/concurrent/DsfRunnable.java21
-rw-r--r--plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/concurrent/DsfSequence.java249
-rw-r--r--plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/concurrent/GetDataDone.java33
-rw-r--r--plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/concurrent/GetDataDoneWithClientDone.java53
-rw-r--r--plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/model/AbstractDMC.java119
-rw-r--r--plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/model/DMCs.java44
-rw-r--r--plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/model/DataModelEvent.java29
-rw-r--r--plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/model/IDataModelContext.java75
-rw-r--r--plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/model/IDataModelData.java31
-rw-r--r--plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/model/IDataModelEvent.java21
-rw-r--r--plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/model/IDataModelService.java29
-rw-r--r--plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/model/package.html26
-rw-r--r--plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/service/AbstractDsfService.java139
-rw-r--r--plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/service/DsfServiceEventHandler.java45
-rw-r--r--plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/service/DsfServicesTracker.java163
-rw-r--r--plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/service/DsfSession.java395
-rw-r--r--plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/service/IDsfService.java88
30 files changed, 2104 insertions, 0 deletions
diff --git a/plugins/org.eclipse.dd.dsf/.classpath b/plugins/org.eclipse.dd.dsf/.classpath
new file mode 100644
index 00000000000..751c8f2e504
--- /dev/null
+++ b/plugins/org.eclipse.dd.dsf/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/plugins/org.eclipse.dd.dsf/.cvsignore b/plugins/org.eclipse.dd.dsf/.cvsignore
new file mode 100644
index 00000000000..ba077a4031a
--- /dev/null
+++ b/plugins/org.eclipse.dd.dsf/.cvsignore
@@ -0,0 +1 @@
+bin
diff --git a/plugins/org.eclipse.dd.dsf/.project b/plugins/org.eclipse.dd.dsf/.project
new file mode 100644
index 00000000000..63ae142e1be
--- /dev/null
+++ b/plugins/org.eclipse.dd.dsf/.project
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.eclipse.dd.dsf</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
diff --git a/plugins/org.eclipse.dd.dsf/.settings/org.eclipse.jdt.core.prefs b/plugins/org.eclipse.dd.dsf/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 00000000000..93a2ad59b5e
--- /dev/null
+++ b/plugins/org.eclipse.dd.dsf/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,12 @@
+#Thu Jul 27 15:22:22 PDT 2006
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.5
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.5
diff --git a/plugins/org.eclipse.dd.dsf/META-INF/MANIFEST.MF b/plugins/org.eclipse.dd.dsf/META-INF/MANIFEST.MF
new file mode 100644
index 00000000000..300d22e0fe2
--- /dev/null
+++ b/plugins/org.eclipse.dd.dsf/META-INF/MANIFEST.MF
@@ -0,0 +1,14 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: Riverbed Plug-in
+Bundle-SymbolicName: org.eclipse.dd.dsf
+Bundle-Version: 1.0.0
+Bundle-Activator: org.eclipse.dd.dsf.DsfPlugin
+Bundle-Localization: plugin
+Require-Bundle: org.eclipse.core.runtime,
+ org.eclipse.debug.core
+Eclipse-LazyStart: true
+Export-Package: org.eclipse.dd.dsf.concurrent,
+ org.eclipse.dd.dsf.debug,
+ org.eclipse.dd.dsf.model,
+ org.eclipse.dd.dsf.service
diff --git a/plugins/org.eclipse.dd.dsf/build.properties b/plugins/org.eclipse.dd.dsf/build.properties
new file mode 100644
index 00000000000..e9863e281ea
--- /dev/null
+++ b/plugins/org.eclipse.dd.dsf/build.properties
@@ -0,0 +1,5 @@
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+ .,\
+ plugin.xml
diff --git a/plugins/org.eclipse.dd.dsf/plugin.xml b/plugins/org.eclipse.dd.dsf/plugin.xml
new file mode 100644
index 00000000000..33ca93ceb1b
--- /dev/null
+++ b/plugins/org.eclipse.dd.dsf/plugin.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.2"?>
+<plugin>
+
+</plugin>
diff --git a/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/DsfPlugin.java b/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/DsfPlugin.java
new file mode 100644
index 00000000000..a87ce47e211
--- /dev/null
+++ b/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/DsfPlugin.java
@@ -0,0 +1,68 @@
+/*******************************************************************************
+ * Copyright (c) 2006 Wind River Systems 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:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.dd.dsf;
+
+import org.eclipse.core.runtime.Plugin;
+import org.osgi.framework.BundleContext;
+
+/**
+ * The activator class controls the plug-in life cycle
+ */
+public class DsfPlugin extends Plugin {
+
+ // The plug-in ID
+ public static final String PLUGIN_ID = "org.eclipse.dd.dsf";
+
+ // The shared instance
+ private static DsfPlugin fgPlugin;
+
+ private static BundleContext fgBundleContext;
+
+ /**
+ * The constructor
+ */
+ public DsfPlugin() {
+ fgPlugin = this;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.core.runtime.Plugins#start(org.osgi.framework.BundleContext)
+ */
+ public void start(BundleContext context) throws Exception {
+ fgBundleContext = context;
+ super.start(context);
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.core.runtime.Plugin#stop(org.osgi.framework.BundleContext)
+ */
+ public void stop(BundleContext context) throws Exception {
+ fgPlugin = null;
+ fgBundleContext = null;
+ super.stop(context);
+ }
+
+ /**
+ * Returns the shared instance
+ *
+ * @return the shared instance
+ */
+ public static DsfPlugin getDefault() {
+ return fgPlugin;
+ }
+
+ public static BundleContext getBundleContext() {
+ return fgBundleContext;
+ }
+
+}
diff --git a/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/concurrent/DefaultDsfExecutor.java b/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/concurrent/DefaultDsfExecutor.java
new file mode 100644
index 00000000000..3bd4e996661
--- /dev/null
+++ b/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/concurrent/DefaultDsfExecutor.java
@@ -0,0 +1,60 @@
+/*******************************************************************************
+ * Copyright (c) 2006 Wind River Systems 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:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.dd.dsf.concurrent;
+
+import java.util.concurrent.ScheduledThreadPoolExecutor;
+import java.util.concurrent.ThreadFactory;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.dd.dsf.DsfPlugin;
+
+/**
+ * Default implementation of a Riverbed executor interfaces, based on the
+ * standard java.util.concurrent.ThreadPoolExecutor.
+ */
+
+public class DefaultDsfExecutor extends ScheduledThreadPoolExecutor
+ implements DsfExecutor
+{
+ static class DsfThreadFactory implements ThreadFactory {
+ Thread fThread;
+ public Thread newThread(Runnable r) {
+ assert fThread == null; // Should be called only once.
+ fThread = new Thread(new ThreadGroup("Riverbed Thread Group"), r, "Riverbed Dispatch Thread", 0);
+ return fThread;
+ }
+ }
+
+
+
+ public DefaultDsfExecutor() {
+ super(1, new DsfThreadFactory());
+ }
+
+ public boolean isInExecutorThread() {
+ return Thread.currentThread().equals( ((DsfThreadFactory)getThreadFactory()).fThread );
+ }
+
+ @Override
+ protected void afterExecute(Runnable r, Throwable t) {
+ // FIXME: Unfortunately this is not enough to catch runnable exceptions, because
+ // FutureTask implementation swallows exceptions when they're thrown by runnables.
+ // Need to override the FutureTask class, and the AbstractExecutorService.submit()
+ // methods in order to provide access to these exceptions.
+
+ super.afterExecute(r, t);
+ if (t != null) {
+ DsfPlugin.getDefault().getLog().log(new Status(
+ IStatus.ERROR, DsfPlugin.PLUGIN_ID, -1, "Uncaught exception in dispatch thread.", t));
+ }
+ }
+}
diff --git a/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/concurrent/Done.java b/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/concurrent/Done.java
new file mode 100644
index 00000000000..e36dbb23cee
--- /dev/null
+++ b/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/concurrent/Done.java
@@ -0,0 +1,48 @@
+/*******************************************************************************
+ * Copyright (c) 2006 Wind River Systems 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:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.dd.dsf.concurrent;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.MultiStatus;
+import org.eclipse.core.runtime.Status;
+
+/**
+ * Base class for Riverbed service method-completion callbacks. By default
+ * all callbacks that indicate a complition of a method contain the status
+ * of the result.
+ * <br>NOTE: Access to the status data is not synchronized, so
+ * clients have to make sure that access to this object is thread safe if
+ * it's used outside of the caller's dispatch thread.
+ */
+abstract public class Done extends DsfRunnable {
+ private IStatus fStatus = Status.OK_STATUS;
+
+ /** Sets the status of the called method. */
+ public void setStatus(IStatus status) { fStatus = status; }
+
+ /** Returns the status of the completed method. */
+ public IStatus getStatus() { return fStatus; }
+
+ /**
+ * Convenience method for setting the status using a status object of a
+ * sub-command.
+ * @param pluginId plugin id of the invoked method
+ * @param code status code
+ * @param message message to include
+ * @param subStatus status object to base the Done status on
+ */
+ public void setErrorStatus(String pluginId, int code, String message, final IStatus subStatus) {
+ MultiStatus status = new MultiStatus(pluginId, code, message, null);
+ status.merge(subStatus);
+ fStatus = status;
+ }
+
+}
diff --git a/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/concurrent/DoneTracker.java b/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/concurrent/DoneTracker.java
new file mode 100644
index 00000000000..3805a0e0b89
--- /dev/null
+++ b/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/concurrent/DoneTracker.java
@@ -0,0 +1,104 @@
+/*******************************************************************************
+ * Copyright (c) 2006 Wind River Systems 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:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.dd.dsf.concurrent;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.core.runtime.MultiStatus;
+import org.eclipse.dd.dsf.DsfPlugin;
+
+/**
+ * Utility class to track multiple done (callback) results of commands
+ * that are initiated simultaneously. The usage is as follows:
+ * <pre>
+ * final DoneTracker doneTracker = new DoneTracker() {
+ * public void run() {
+ * System.out.println("All complete, errors=" + !getStatus().isOK());
+ * }
+ * };
+ * for (int i = 0; i < 10; i++) {
+ * service.call(i, doneTracker.addDone(new Done() {
+ * public void run() {
+ * System.out.println(Integer.toString(i) + " complete");
+ * doneTracker.doneDone(this);
+ * }
+ * }));
+ * }
+ * </pre>
+ */
+public abstract class DoneTracker extends Done {
+ private Map<Done,Boolean> fDones = new HashMap<Done,Boolean>();
+ private int fDoneCounter;
+
+ /**
+ * No-arg constructor.
+ * <br>
+ * Note: this runnable will be executed following
+ * execution of the last done, and in the same dispatch loop.
+ *
+ */
+ public DoneTracker() {
+ setStatus(new MultiStatus(DsfPlugin.PLUGIN_ID, 0, "Collective status for set of sub-operations.", null));
+ }
+
+ /**
+ * Adds a new Done callback to this tracker's list.
+ * @param <V> Service-specific class of the Done callback, to avoid an
+ * unnecessary cast.
+ * @param done callback object to add to the tracker
+ * @return the done that was just added, it allows this method to be used
+ * inlined in service method calls
+ */
+ public <V extends Done> V add(V done) {
+ assert !fDones.containsKey(done);
+ fDones.put(done, false);
+ fDoneCounter++;
+ return done;
+ }
+
+ /**
+ * Adds a Done which performs no actions. This is useful if all work
+ * is performed inside DoneTracker.run().
+ * @return Done which is to be passed as an argument to a service method.
+ */
+ public Done addNoActionDone() {
+ return add(new Done() { public void run() {
+ doneDone(this);
+ }});
+ }
+
+ /**
+ * Marks the given Done callback as completed. Client implementations of
+ * the Done callback have to call this method in order for the tracker
+ * to complete.
+ * <br>
+ * Note: funniest method signature ever!
+ * @param done
+ */
+ public void doneDone(Done done) {
+ ((MultiStatus)getStatus()).merge(done.getStatus());
+ fDones.put(done, true);
+ fDoneCounter--;
+ if (fDoneCounter == 0) {
+ assert !fDones.containsValue(false);
+ run();
+ }
+ }
+
+ /**
+ * Returns the map of Done callbacks. Access to this data is provided
+ * in case overriding classes need access to the collected data in the
+ * done callbacks.
+ * @return map of the done callbacks.
+ */
+ public Map<Done,Boolean> getDones() { return fDones; }
+}
diff --git a/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/concurrent/DsfExecutor.java b/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/concurrent/DsfExecutor.java
new file mode 100644
index 00000000000..a3243f4cbb8
--- /dev/null
+++ b/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/concurrent/DsfExecutor.java
@@ -0,0 +1,31 @@
+/*******************************************************************************
+ * Copyright (c) 2006 Wind River Systems 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:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.dd.dsf.concurrent;
+
+import java.util.concurrent.ScheduledExecutorService;
+
+/**
+ * DSF executor service. Implementations of this executor must ensure
+ * that all runnables and callables are executed in the same thread: the
+ * executor's single dispatch thread.
+ * <br>Note: A DSF executor dispatch thread does not necessarily have
+ * to be exclusive to the executor, it could be shared with
+ * another event dispatch service, such as the SWT display dispatch thread.
+ */
+public interface DsfExecutor extends ScheduledExecutorService
+{
+ /**
+ * Checks if the thread that this method is called in is the same as the
+ * executor's dispatch thread.
+ * @return true if in DSF executor's dispatch thread
+ */
+ public boolean isInExecutorThread();
+}
diff --git a/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/concurrent/DsfQuery.java b/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/concurrent/DsfQuery.java
new file mode 100644
index 00000000000..0d58590c65a
--- /dev/null
+++ b/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/concurrent/DsfQuery.java
@@ -0,0 +1,161 @@
+/*******************************************************************************
+ * Copyright (c) 2006 Wind River Systems 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:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.dd.dsf.concurrent;
+
+import java.util.concurrent.Future;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.dd.dsf.DsfPlugin;
+
+/**
+ * A convenience class that allows a client to retrieve data from services
+ * synchronously from a non-dispatch thread. This class is different from
+ * a Callable<V> in that it allows the implementation code to calculate
+ * the result in several dispatches, rather than requiring it to return the
+ * data at end of Callable#call method.
+ *
+ * @see java.util.concurrent.Callable
+ * FIXME: make this class implement the Future<V> interface.
+ */
+abstract public class DsfQuery {
+
+ private Object fResult;
+ private boolean fValid;
+ private DsfExecutor fExecutor;
+ private Future fFuture;
+ private boolean fWaiting;
+ private IStatus fStatus = Status.OK_STATUS;
+
+ public DsfQuery(DsfExecutor executor) {
+ fExecutor = executor;
+ }
+
+ /**
+ * Start data retrieval.
+ * Client must implement this method to do whatever is needed to retrieve data.
+ * Retrieval can be (but does not have to be) asynchronious - it meas this method can return
+ * before data is retrieved. When data is ready Proxy must be notified by calling done() method.
+ */
+ protected abstract void execute();
+
+ /**
+ * Allows deriving classes to implement their own snipped additional
+ * cancellation code.
+ */
+ protected void revokeChildren(Object result) {};
+
+ /**
+ * Get data associated with this proxy. This method is thread safe and
+ * it will block until data is ready. Because it's a blocking call and it waits
+ * for commands to be processed on the dispatch thread, this methods itself
+ * CANNOT be called on the dispatch thread.
+ */
+ public synchronized Object get() {
+ assert !fExecutor.isInExecutorThread();
+ if(!fValid) {
+ if (!fWaiting) {
+ fFuture = fExecutor.submit(new DsfRunnable() {
+ public void run() {
+ // TODO: not sure if this try-catch is desirable. It might encourage
+ // implementors to not catch its own exceptions. If the query code takes
+ // more than one dispatch, then this code will not be helpful anyway.
+ try {
+ DsfQuery.this.execute();
+ } catch (Throwable t) {
+ doneException(t);
+ }
+ }
+ });
+ }
+
+ fWaiting = true;
+ try {
+ while(fWaiting) {
+ wait();
+ }
+ } catch (InterruptedException e) {
+ fStatus = new Status(IStatus.ERROR, DsfPlugin.PLUGIN_ID, -1,
+ "Interrupted exception while waiting for result.", e);
+ fValid = true;
+ }
+ assert fValid;
+ }
+ return fResult;
+ }
+
+ /**
+ * Same as get(), but with code to automatically re-threw the exception if one
+ * was reported by the run() method.
+ */
+ public Object getWithThrows() throws CoreException {
+ Object retVal = get();
+ if (!getStatus().isOK()) {
+ throw new CoreException(getStatus());
+ }
+ return retVal;
+ }
+
+ public IStatus getStatus() { return fStatus; }
+
+ /** Abort current operation and keep old proxy data */
+ public synchronized void cancel() {
+ assert fExecutor.isInExecutorThread();
+ assert !fWaiting || !fValid;
+ if (fWaiting) {
+ fFuture.cancel(false);
+ fWaiting = false;
+ notifyAll();
+ } else if (fValid) {
+ revokeChildren(fResult);
+ }
+ fValid = true;
+ }
+
+ /** Abort current operation and set proxy data to 'result' */
+ public synchronized void cancel(Object newResult) {
+ fResult = newResult;
+ cancel();
+ }
+
+ public Object getCachedResult() {
+ return fResult;
+ }
+
+ public boolean isValid() { return fValid; }
+
+ public synchronized void done(Object result) {
+ // Valid could be true if request was cancelled while data was
+ // being retrieved, and then done() was called.
+ if (fValid) return;
+
+ fResult = result;
+ fValid = true;
+ if (fWaiting) {
+ fWaiting = false;
+ notifyAll();
+ }
+ }
+
+ public synchronized void doneError(IStatus errorStatus) {
+ if (fValid) return;
+ fStatus = errorStatus;
+ done(null);
+ }
+
+ public synchronized void doneException(Throwable t) {
+ if (fValid) return;
+ doneError(new Status(IStatus.ERROR, DsfPlugin.PLUGIN_ID, -1,
+ "Exception while computing result.", t));
+ }
+}
+
diff --git a/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/concurrent/DsfRunnable.java b/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/concurrent/DsfRunnable.java
new file mode 100644
index 00000000000..caf610210ae
--- /dev/null
+++ b/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/concurrent/DsfRunnable.java
@@ -0,0 +1,21 @@
+/*******************************************************************************
+ * Copyright (c) 2006 Wind River Systems 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:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.dd.dsf.concurrent;
+
+/**
+ * A DSF-instrumented alternative to the Runnable interface.
+ * <p>
+ * While it is perfectly fine for clients to call the Riverbed executor with
+ * an object only implementing the Runnable interface, the RbRunnable is a
+ * place holder for future tracing enhancments for Riverbed.
+ */
+abstract public class DsfRunnable implements Runnable {
+}
diff --git a/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/concurrent/DsfSequence.java b/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/concurrent/DsfSequence.java
new file mode 100644
index 00000000000..b8f852585b2
--- /dev/null
+++ b/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/concurrent/DsfSequence.java
@@ -0,0 +1,249 @@
+/*******************************************************************************
+ * Copyright (c) 2006 Wind River Systems 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:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.dd.dsf.concurrent;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.dd.dsf.DsfPlugin;
+
+/**
+ * Convenience class for implementing a series of commands that need to be
+ * executed asynchronously.
+ * <p>
+ * Certain complex tasks require multiple commands to be executed in a chain,
+ * because for example result of one command is used as input into another
+ * command. The typical Riverbed pattern of solving this problem is the following:
+ * <li>
+ * <br> 1. original caller passes a Done callback to a method and invokes it
+ * <br> 2. the method is executed by a subsystem
+ * <br> 3. when the method is finished it calls another method and passes
+ * the original callback to it
+ * <br> 4. steps 2-3 are repeated number of times
+ * <br> 5. when the last method in a chain is executed, it submits the original
+ * Done callback
+ * </li>
+ * <p>
+ * This pattern is very useful in itself, but it proves very difficult to follow
+ * because the methods can be scattered accross many classes and systems. Also
+ * if progress reporting, cancellability, and roll-back ability is required, it
+ * has to be re-implemented every time. The Sequence class tries to address
+ * this problem by containing this pattern in a single class.
+ *
+ * <br>TODO: should a sequence be re-entrant. I.e. should the arguments be
+ * passed in through a map, and the return values returned back in the done?
+ * <br>FIXME: convert to implement Future interface
+ */
+abstract public class DsfSequence {
+
+ /**
+ * The abstract class that each step has to implement
+ * <br>FIXME: convert execute() and rollBacl() to take "done" as an argument.
+ * This way we can make step a static class, and make its paradigm
+ * more consistent with rest of Riverbed.
+ */
+ abstract public class Step {
+ public void execute() { stepFinished(); }
+ public void rollBack() { stepRolledBack(); }
+ public int getTicks() { return 1; }
+ }
+
+ private DsfExecutor fExecutor;
+ private Step[] fSteps;
+ private Done fDoneQC;
+ private String fTaskName;
+ private String fRollbackTaskName;
+ private IProgressMonitor fProgressMonitor = new NullProgressMonitor();
+ private int fCurrentStepIdx = 0;
+ boolean fCancelled = false;
+
+ /**
+ * Default constructor. If this constructor is used, the steps need to be initialized
+ * before the sequence can be invoked.
+ * @param executor the Riverbed executor which will be used to invoke all steps
+ */
+ public DsfSequence(DsfExecutor executor) {
+ this(executor, null);
+ }
+
+ /**
+ * Constructor that initialized the steps.
+ * @param executor the Riverbed executor which will be used to invoke all steps
+ * @param steps sequence steps
+ */
+ public DsfSequence(DsfExecutor executor, Step[] steps) {
+ fExecutor = executor;
+ fSteps = steps;
+ }
+
+ /** Returns the riverbed executor for this sequence */
+ public DsfExecutor getExecutor() { return fExecutor; }
+
+ /**
+ * Sets the done callback to be submitted when the sequence is finished.
+ * If the sequence is submitted by a caller in the dispatch thread, this is
+ * the way that the original caller can be notified of the sequence
+ * completion. If the caller blocks and waits for the sequence
+ * completion, the Done callback is not necessary.
+ * @param doneQC callback to submit when sequence completes, can be null
+ */
+ public void setDone(Done doneQC) {
+ fDoneQC = doneQC;
+ }
+
+ /**
+ * Returns the Done callback that is registered with the Sequence
+ * @param doneQC callback that will be submitted when sequence completes,
+ * null if there is no callback configured
+ */
+ public Done getDone() { return fDoneQC; }
+
+ /** Sets the steps to be executed. */
+ public void setSteps(Step[] steps) {
+ assert fCurrentStepIdx == 0;
+ fSteps = steps;
+ }
+
+ /** Returns the steps to be executed. */
+ public Step[] getSteps() { return fSteps; }
+
+ /**
+ * Returns index of the step that is currently being executed.
+ * <br>NOTE: After sequence is invoked, this method should be called
+ * only in the Riverbed executor thread.
+ * @return
+ */
+ public int getCurrentIdx() { return fCurrentStepIdx; }
+
+ /**
+ * Sets the progress monitor that will be called by the sequence with udpates.
+ * @param pm
+ */
+ public void setProgressMonitor(IProgressMonitor pm) { fProgressMonitor = pm; }
+
+ /**
+ * Sets the task name for this sequence. To be used with progress monitor;
+ * @param taskName
+ */
+ public void setTaskName(String taskName) { fTaskName = taskName; }
+
+ /**
+ * Sets the task name to be used with progress monitor, if this sequence needs
+ * to be rolled back as result of cancellation or error.
+ * @param taskName
+ */
+ public void setRollBackTaskName(String n) { fRollbackTaskName = n; }
+
+
+ /** Submits this sequence to the executor. */
+ public void invokeLater() {
+ getExecutor().submit( new DsfRunnable() { public void run() { doInvoke(); } });
+ }
+
+ /**
+ * Submits this sequence to the Riverbed executor, and blocks waiting for the
+ * sequence to complete.
+ * <br>NOTE: This method is NOT to be called on the Riverbed executor thread.
+ */
+ public synchronized void invoke() {
+ assert !fExecutor.isInExecutorThread() :
+ "Cannot be called on dispatch thread: " + this;
+ setDone(new Done() {
+ public void run() {
+ synchronized(DsfSequence.this) { DsfSequence.this.notifyAll(); }
+ }
+ });
+ invokeLater();
+ try {
+ wait();
+ } catch (InterruptedException e) {
+ // TODO: error handling?
+ }
+ }
+
+ private void doInvoke() {
+ assert fCurrentStepIdx == 0;
+ if (fTaskName != null) {
+ fProgressMonitor.subTask(fTaskName);
+ }
+ fSteps[fCurrentStepIdx].execute();
+ }
+
+ /**
+ * Cancells the execution of this sequence. The roll-back will start when
+ * the current step completes.
+ *
+ */
+ public void cancel() {
+ fCancelled = true;
+ }
+
+ /**
+ * To be called only by the step implementation, Tells the sequence to
+ * submit the next step.
+ */
+ public void stepFinished() {
+ getExecutor().submit(new DsfRunnable() { public void run() {
+ fProgressMonitor.worked(getSteps()[fCurrentStepIdx].getTicks());
+ fCurrentStepIdx++;
+ if (fCurrentStepIdx < fSteps.length) {
+ if (fCancelled) {
+ abort(new Status(
+ IStatus.CANCEL, DsfPlugin.PLUGIN_ID, -1,
+ "Cancelled" + fTaskName != null ? ": " + fTaskName : "",
+ null));
+ }
+ fSteps[fCurrentStepIdx].execute();
+ } else {
+ if (fDoneQC != null) getExecutor().submit(fDoneQC);
+ }
+ }});
+ }
+
+ /**
+ * To be called only by the step implementation. Tells the sequence to
+ * roll back next step.
+ */
+ public void stepRolledBack() {
+ getExecutor().submit(new DsfRunnable() { public void run() {
+ fProgressMonitor.worked(getSteps()[fCurrentStepIdx].getTicks());
+ fCurrentStepIdx--;
+ if (fCurrentStepIdx >= 0) {
+ fSteps[fCurrentStepIdx].rollBack();
+ } else {
+ if (fDoneQC != null) getExecutor().submit(fDoneQC);
+ }
+ }});
+ }
+
+ /**
+ * To be called only by step implementation. Tells the sequence
+ * that its execution is to be aborted and it should start rolling back
+ * the sequence as if it was cancelled by user.
+ * @param error
+ */
+ public void abort(final IStatus error) {
+ getExecutor().submit(new DsfRunnable() { public void run() {
+ if (fRollbackTaskName != null) {
+ fProgressMonitor.subTask(fRollbackTaskName);
+ }
+ fDoneQC.setStatus(error);
+ fCurrentStepIdx--;
+ if (fCurrentStepIdx >= 0) {
+ fSteps[fCurrentStepIdx].rollBack();
+ } else {
+ if (fDoneQC != null) getExecutor().submit(fDoneQC);
+ }
+ }});
+ }
+
+}
diff --git a/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/concurrent/GetDataDone.java b/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/concurrent/GetDataDone.java
new file mode 100644
index 00000000000..3a8784d10ee
--- /dev/null
+++ b/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/concurrent/GetDataDone.java
@@ -0,0 +1,33 @@
+/*******************************************************************************
+ * Copyright (c) 2006 Wind River Systems 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:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.dd.dsf.concurrent;
+
+/**
+ * Asynchronous method callback which returns a data object (in addition to
+ * the base class's getStatus().
+ * @param <V>
+ */
+public abstract class GetDataDone<V> extends Done {
+ /** Data object reference */
+ private V fData;
+
+ /**
+ * Sets the data object to specified value. To be called by the
+ * asynchronous method implementor.
+ * @param data Data value to set.
+ */
+ public void setData(V data) { fData = data; }
+
+ /**
+ * Returns the data value, null if not set.
+ */
+ public V getData() { return fData; }
+}
diff --git a/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/concurrent/GetDataDoneWithClientDone.java b/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/concurrent/GetDataDoneWithClientDone.java
new file mode 100644
index 00000000000..0affa1ff7ae
--- /dev/null
+++ b/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/concurrent/GetDataDoneWithClientDone.java
@@ -0,0 +1,53 @@
+/*******************************************************************************
+ * Copyright (c) 2006 Wind River Systems 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:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.dd.dsf.concurrent;
+
+import org.eclipse.core.runtime.IStatus;
+
+/**
+ * Convenience extension to GetDataDone, which handles posting of the client's
+ * <code>Done</code> upon the completion of this <code>GetDataDone</code>.
+ * @param <V> Class type of data.
+ */
+public abstract class GetDataDoneWithClientDone<V> extends GetDataDone<V> {
+ private DsfExecutor fExecutor;
+ private Done fClientDone;
+
+ /**
+ * Constructor requires the Done to be posted as well as the executor to
+ * post it with.
+ */
+ public GetDataDoneWithClientDone(DsfExecutor executor, Done clientDone) {
+ fExecutor = executor;
+ fClientDone = clientDone;
+ }
+
+ /**
+ * The run method checks the client done for cancellation, and this done
+ * for errors. It calls doRun() for the sub-class execution, and posts
+ * the client done when finished.
+ */
+ public final void run() {
+ if (fClientDone.getStatus().getSeverity() == IStatus.CANCEL) return;
+ if (!getStatus().isOK()) {
+ fClientDone.setStatus(getStatus());
+ } else {
+ doRun();
+ }
+ fExecutor.execute(fClientDone);
+ }
+
+ /**
+ * Method to perform the actual work. It should not post the client done
+ * because it will be posted by this class in run().
+ */
+ protected abstract void doRun();
+} \ No newline at end of file
diff --git a/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/model/AbstractDMC.java b/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/model/AbstractDMC.java
new file mode 100644
index 00000000000..08e03569c18
--- /dev/null
+++ b/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/model/AbstractDMC.java
@@ -0,0 +1,119 @@
+/*******************************************************************************
+ * Copyright (c) 2006 Wind River Systems 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:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.dd.dsf.model;
+
+import org.eclipse.core.runtime.PlatformObject;
+import org.eclipse.dd.dsf.service.AbstractDsfService;
+import org.eclipse.dd.dsf.service.DsfSession;
+
+/**
+ * Base implementation of the DMC object. Most functionality here is centered
+ * around comparing DMCs, as this is a critical to make the views work
+ * correctly.
+ * @param <V> Data model data that this context is for.
+ */
+public class AbstractDMC<V extends IDataModelData> extends PlatformObject
+ implements IDataModelContext
+{
+ private final String fSessionId;
+ private final String fServiceFilter;
+ private final IDataModelContext[] fParents;
+
+ /**
+ * Main constructor provides all data needed to implement the IModelContext
+ * interface.
+ */
+ public AbstractDMC(String sessionId, String filter, IDataModelContext[] parents) {
+ fSessionId = sessionId;
+ fServiceFilter = filter;
+ fParents = parents;
+ }
+
+ /** Convenience constructor */
+ public AbstractDMC(AbstractDsfService service, IDataModelContext parent) {
+ this(service.getSession().getId(),
+ service.getServiceFilter(),
+ parent == null ? new IDataModelContext[] {} : new IDataModelContext[] { parent });
+ }
+
+ /**
+ * Should be used by the deriving class to compare the basic context object
+ * information.
+ * @param other the other service to compare to
+ * @return true if contexts are equal
+ */
+ protected boolean baseEquals(Object other) {
+ if (other == null) return false;
+ if ( !(other.getClass().equals(getClass()))) return false;
+ IDataModelContext otherCtx = (IDataModelContext)other;
+ return getSessionId().equals(otherCtx.getSessionId()) &&
+ getServiceFilter().equals(otherCtx.getServiceFilter()) &&
+ areParentsEqual(otherCtx.getParents());
+ }
+
+ private boolean areParentsEqual(IDataModelContext[] otherParents) {
+ if ( !(fParents.length == otherParents.length) ) return false;
+ for (int i = 0; i < fParents.length; i++) {
+ if (!fParents[i].equals(otherParents[i])) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ protected int baseHashCode() {
+ int parentsHash = 0;
+ for (Object parent : getParents()) {
+ parentsHash += parent.hashCode();
+ }
+ return getSessionId().hashCode() + getServiceFilter().hashCode() + parentsHash;
+ }
+
+ protected String baseToString() {
+ StringBuffer retVal = new StringBuffer();
+ for (IDataModelContext parent : fParents) {
+ retVal.append(parent);
+ }
+ return retVal.toString();
+ }
+
+ public String getSessionId() { return fSessionId; }
+ public String getServiceFilter() { return fServiceFilter; }
+ public IDataModelContext[] getParents() { return fParents; }
+
+ /**
+ * Overrides the standard platform getAdapter to provide session-specific
+ * adapters.
+ * <p>
+ * ModelContext is intended to be used in views, which call the
+ * contexts.getAdapter() method to retrieve model-specific content and
+ * label providers. But since many different sessions could be active
+ * at the same time, each requiring different content providers, the
+ * standard platform <code>IAdapterManager</code> is not sufficient in
+ * handling adapters for the model context object. This is because
+ * <code>IAdapterManager</code> uses only the class of the adaptable to
+ * select the correct adapter factoru, while for model context, the
+ * session is equally important.
+ * @see org.eclipse.runtime.IAdapterManager
+ */
+ public Object getAdapter(Class adapterType) {
+ Object retVal = null;
+ DsfSession session = DsfSession.getSession(fSessionId);
+ if (session != null) {
+ retVal = session.getModelAdapter(adapterType);
+ }
+ if (retVal == null) {
+ retVal = super.getAdapter(adapterType);
+ }
+ return retVal;
+ }
+
+}
diff --git a/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/model/DMCs.java b/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/model/DMCs.java
new file mode 100644
index 00000000000..5aa60ef4d2b
--- /dev/null
+++ b/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/model/DMCs.java
@@ -0,0 +1,44 @@
+/*******************************************************************************
+ * Copyright (c) 2006 Wind River Systems 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:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.dd.dsf.model;
+
+
+/**
+ * Holder for utility static methods for manipulating IDataModelContext
+ * objects.
+ */
+public class DMCs {
+
+ /**
+ * Finds a data model context of given type among ancestors of the
+ * specified context.
+ * @param ctx DMC to search.
+ * @param ancestorType Class type of the desired DMC ancestor.
+ * @return Returns the ancestor if found, null otherwise.
+ */
+ @SuppressWarnings("unchecked")
+ public static <V extends IDataModelContext> V getAncestorOfType(IDataModelContext ctx, Class<V> ancestorType) {
+ for (IDataModelContext parent : ctx.getParents()) {
+ if (parent.getClass().equals(ancestorType)) {
+ return (V)parent;
+ }
+ }
+
+ for (IDataModelContext parent : ctx.getParents()) {
+ if (parent.getClass().equals(ancestorType)) {
+ V ancestor = getAncestorOfType(parent, ancestorType);
+ if (ancestor != null) return ancestor;
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/model/DataModelEvent.java b/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/model/DataModelEvent.java
new file mode 100644
index 00000000000..7a41740ea07
--- /dev/null
+++ b/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/model/DataModelEvent.java
@@ -0,0 +1,29 @@
+/*******************************************************************************
+ * Copyright (c) 2006 Wind River Systems 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:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.dd.dsf.model;
+
+/**
+ * Base implementation of the IDataModelContext interface.
+ * <p>
+ * TODO: consider merging the event interface with this class.
+ */
+public class DataModelEvent<V extends IDataModelContext> implements IDataModelEvent<V> {
+
+ private V fModelContext;
+ public DataModelEvent(V context) {
+ fModelContext = context;
+ }
+
+ public V getDMC() {
+ return fModelContext;
+ }
+
+}
diff --git a/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/model/IDataModelContext.java b/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/model/IDataModelContext.java
new file mode 100644
index 00000000000..362182961ab
--- /dev/null
+++ b/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/model/IDataModelContext.java
@@ -0,0 +1,75 @@
+/*******************************************************************************
+ * Copyright (c) 2006 Wind River Systems 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:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.dd.dsf.model;
+
+import org.eclipse.core.runtime.IAdaptable;
+
+/**
+ * The base class for data model objects.
+ * <p>
+ * DSF services need to return objects to clients which can be used as
+ * handles to track data stored in the service. Clients such as lazy-loading
+ * tree and table views retrieve a list of handles, then as needed, they
+ * retrieve the children and label information for these handles. Because of
+ * this pattern, services need to be able to return a set of handle objects,
+ * then as needed clients can retrieve data corresponding to these handles.
+ * The DMC object is the interface that DSF services should use
+ * to represent the handle objects that are to be referenced by view model.
+ * <p>
+ * <i>Note: DMC objects are meant to be immutable and thus accessible from
+ * any thread instead of just the services dispatch thread. This is because
+ * clients may need to call context objects' methods on non-dispatch thread,
+ * especially equals and hashCode.</i>
+ * <p>
+ * <i>Note #2: DMCs should also avoid holding references to service
+ * instances or other large chunks of data, because some of the clients may
+ * hold onto these objects for longer time than the life of the service.
+ * This may prevent the service from being garbage collected, possibly keeping
+ * a lot of resources tied up.
+ *
+ * @param <V> For each context object there is a corresponding data object
+ * which will contain information about that context. This template argument
+ * allows the clients to avoid casting the data class when retrieving data
+ * for a context object.
+ *
+ * @see IDataModelData
+ */
+public interface IDataModelContext<V extends IDataModelData> extends IAdaptable
+{
+ /**
+ * Each model context object needs to track the session from which it
+ * originated. The session ID allows clients to choose the correct
+ * dispatch thread with which to access the service, and it allows the
+ * service to be uniquely identified among other sessions.
+ * @return Session ID of the service that originated the cotnext.
+ */
+ public String getSessionId();
+
+ /**
+ * Returns the service filter object which can be used to uniquely identify
+ * a service. For most services, it's sufficient to know the service class
+ * and the session-id to find the service, but some services may have
+ * multiple instances running in the same session. For those services, this
+ * filter string can be used to find the correct service instance.
+ * @see org.osgi.framework.BundleContext#getServiceReferences
+ * @return
+ */
+ public String getServiceFilter();
+
+ /**
+ * Returns the parent context of this context. ModelContext objects can be
+ * chained this way to allow methods that require context from multiple
+ * services to retrieve this context from a single handle that comes from
+ * the client.
+ * @return parent context of this context.
+ */
+ public IDataModelContext[] getParents();
+}
diff --git a/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/model/IDataModelData.java b/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/model/IDataModelData.java
new file mode 100644
index 00000000000..5d3df186db0
--- /dev/null
+++ b/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/model/IDataModelData.java
@@ -0,0 +1,31 @@
+/*******************************************************************************
+ * Copyright (c) 2006 Wind River Systems 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:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.dd.dsf.model;
+
+/**
+ * Data object containing information regarding a model context. Unlike the
+ * context object, this object does have to be accessed on the dispatch thread,
+ * unless other-wise noted. And it does not need to be immutable or free of
+ * references to the service.
+ * <p>
+ * This interface is intended primarily to allow for future development of
+ * a generic API to parametrize data model data.
+ *
+ */
+public interface IDataModelData {
+
+ /**
+ * Returns true if the data represented by this object is still valid.
+ * Data may become invalid if, for example the cache object backing this
+ * data was cleared.
+ */
+ public boolean isValid();
+}
diff --git a/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/model/IDataModelEvent.java b/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/model/IDataModelEvent.java
new file mode 100644
index 00000000000..1806112cac9
--- /dev/null
+++ b/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/model/IDataModelEvent.java
@@ -0,0 +1,21 @@
+/*******************************************************************************
+ * Copyright (c) 2006 Wind River Systems 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:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.dd.dsf.model;
+
+/**
+ * Common interface for events that signify changes in the data model.
+ * The sub-classes should contain specific information about the event, while
+ * this base class only identifies the DMC that is affected.
+ * @param <V> DMC that is affected by this event.
+ */
+public interface IDataModelEvent <V extends IDataModelContext> {
+ V getDMC();
+}
diff --git a/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/model/IDataModelService.java b/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/model/IDataModelService.java
new file mode 100644
index 00000000000..da587a61fe2
--- /dev/null
+++ b/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/model/IDataModelService.java
@@ -0,0 +1,29 @@
+/*******************************************************************************
+ * Copyright (c) 2006 Wind River Systems 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:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.dd.dsf.model;
+
+import org.eclipse.dd.dsf.service.IDsfService;
+
+/**
+ * Interface for Riverbed services that provide model data to clients.
+ * <p>
+ * For completeness this service interface derives from <code>IDataModelData</data>
+ * and has a method which allows clients to retrieve the DMC that represents the
+ * service data.
+ */
+public interface IDataModelService extends IDsfService, IDataModelData {
+ /**
+ * Returns the context representing the service in the data model. It is
+ * usually used in events to indicate that lists of contexts in this
+ * service are changed.
+ */
+ IDataModelContext getServiceContext();
+}
diff --git a/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/model/package.html b/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/model/package.html
new file mode 100644
index 00000000000..2ea664a1ee4
--- /dev/null
+++ b/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/model/package.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+ <meta content="text/html; charset=ISO-8859-1"
+ http-equiv="content-type">
+ <title>Eclipse Device Debug - Debugger Services Framework - Data Model</title>
+</head>
+<body>
+Provides a base API and utilities for expoding data model through DSF
+services.<br>
+<br>
+<h2>Package Specification</h2>
+Practically speaking, all state data held by the DSF services makes up
+the "data mode" of the service session.&nbsp; However, to make it easy
+to present this data in standard debug views, as well as customizable
+views, it is useful to present the data using a consisten pattern and
+with a set of published APIs and utilities.&nbsp; This package aims to
+provide these APIs and utilities.<br>
+<h3>Development Plans</h3>
+This package is a work in progress and it is missing a major
+feature.&nbsp; This feature is being able to automatically parametrize
+the contents of the data model in order to generically traverse it, and
+to write data-driven framework for populating views with model data.<br>
+<br>
+</body>
+</html>
diff --git a/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/service/AbstractDsfService.java b/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/service/AbstractDsfService.java
new file mode 100644
index 00000000000..3c4d6b95487
--- /dev/null
+++ b/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/service/AbstractDsfService.java
@@ -0,0 +1,139 @@
+/*******************************************************************************
+ * Copyright (c) 2006 Wind River Systems 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:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.dd.dsf.service;
+
+import java.util.Dictionary;
+import java.util.Enumeration;
+
+import org.eclipse.dd.dsf.concurrent.Done;
+import org.eclipse.dd.dsf.concurrent.DsfExecutor;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceRegistration;
+
+
+/**
+ * Standard base implementation of the Riverbed service. This is a convinience
+ * class that provides the basic functionality that all Riverbed services have
+ * to implement.
+ */
+abstract public class AbstractDsfService
+ implements IDsfService
+{
+ /** Reference to the session that this service belongs to. */
+ private DsfSession fSession;
+
+ /** Startup order number of this service. */
+ private int fStartupNumber;
+
+ /** Registration object for this service. */
+ private ServiceRegistration fRegistration;
+
+ /** Tracker for services that this service depends on. */
+ private DsfServicesTracker fTracker;
+
+ /** Properties that this service was registered with */
+ private Dictionary fProperties;
+
+ /** Properties that this service was registered with */
+ private String fFilter;
+
+
+ /**
+ * Only constructor, requires a reference to the session that this
+ * service belongs to.
+ * @param session
+ */
+ public AbstractDsfService(DsfSession session) {
+ fSession = session;
+ }
+
+ public DsfExecutor getExecutor() { return fSession.getExecutor(); }
+ public Dictionary getProperties() { return fProperties; }
+ public String getServiceFilter() { return fFilter; }
+ public int getStartupNumber() { return fStartupNumber; }
+ public void initialize(Done done) {
+ fTracker = new DsfServicesTracker(getBundleContext(), fSession.getId());
+ fStartupNumber = fSession.getAndIncrementServiceStartupCounter();
+ getExecutor().submit(done);
+ }
+
+ public void shutdown(Done done) {
+ fTracker.dispose();
+ fTracker = null;
+ getExecutor().submit(done);
+ }
+
+ /** Returns the session object for this service */
+ public DsfSession getSession() { return fSession; }
+
+ /**
+ * Sub-classes should return the bundle context of the plugin, which the
+ * service belongs to.
+ */
+ abstract protected BundleContext getBundleContext();
+
+ /** Returns the tracker for the services that this service depends on. */
+ protected DsfServicesTracker getServicesTracker() { return fTracker; }
+
+ /**
+ * Registers this service.
+ * <br> FIXME: Move registering call to default initialize()/shutdown(). Add a new
+ * protected method calcProperties() to get the initial list of properties.
+ */
+ @SuppressWarnings("unchecked")
+ protected void register(String[] classes, Dictionary properties) {
+ String[] newClasses = new String[classes.length + 2];
+ System.arraycopy(classes, 0, newClasses, 2, classes.length);
+ newClasses[0] = IDsfService.class.getName();
+ newClasses[1] = getClass().getName();
+ properties.put(PROP_SESSION_ID, getSession().getId());
+ fProperties = properties;
+ fRegistration = getBundleContext().registerService(newClasses, this, properties);
+ fRegistration.getReference().getProperty(Constants.OBJECTCLASS);
+ fFilter = generateFilter(fProperties);
+ fProperties.put(Constants.OBJECTCLASS, fRegistration.getReference().getProperty(Constants.OBJECTCLASS));
+ }
+
+ private String generateFilter(Dictionary properties) {
+ StringBuffer filter = new StringBuffer();
+ filter.append("(&");
+
+ // Add the service class to the filter.
+ filter.append('(');
+ filter.append(Constants.OBJECTCLASS);
+ filter.append('=');
+ filter.append(this.getClass().getName());
+ filter.append(')');
+
+ for (Enumeration keys = properties.keys(); keys.hasMoreElements();) {
+ Object key = keys.nextElement();
+ filter.append('(');
+ filter.append(key.toString());
+ filter.append('=');
+ filter.append(properties.get(key).toString());
+ filter.append(')');
+ }
+ filter.append(')');
+ return filter.toString();
+ }
+
+ /**
+ * De-registers this service.
+ *
+ */
+ protected void unregister() {
+ fRegistration.unregister();
+ }
+
+ /** Returns the registration object that was obtained when this service was registered */
+ protected ServiceRegistration getServiceRegistration() { return fRegistration; }
+} \ No newline at end of file
diff --git a/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/service/DsfServiceEventHandler.java b/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/service/DsfServiceEventHandler.java
new file mode 100644
index 00000000000..d82886fae2f
--- /dev/null
+++ b/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/service/DsfServiceEventHandler.java
@@ -0,0 +1,45 @@
+/*******************************************************************************
+ * Copyright (c) 2006 Wind River Systems 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:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.dd.dsf.service;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation for service event handler methods. The name of the event
+ * handler method is irrelevant, only the annotation is checked.
+ * <p>
+ * Each service event handler method should have one or two parameters:
+ * <li>
+ * <br> First argument is required and it should be the event object, with
+ * type with the event class desired.
+ * <br> Second argument is optional, and it has to be of type Dictionary<String,String>.
+ * If this parameter is declared, the handler will be passed the properties
+ * dictionary of the service that submitted the event.
+ * </li>
+ * <p>
+ * It is expected that service event classes are hierarchical. So that if a
+ * handler is registered for a super-class of another event, this handler
+ * will be called every time one of the sub-class events is invoked.
+ * If a listener declares a handler for an event AND a superclass of that event,
+ * both handlers will be invoked when the event is dispatched.
+ *
+ * <br>TODO: Handling of second argument is not yet implemented.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.METHOD)
+@Documented
+public @interface DsfServiceEventHandler {
+
+}
diff --git a/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/service/DsfServicesTracker.java b/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/service/DsfServicesTracker.java
new file mode 100644
index 00000000000..5821e8796a6
--- /dev/null
+++ b/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/service/DsfServicesTracker.java
@@ -0,0 +1,163 @@
+/*******************************************************************************
+ * Copyright (c) 2006 Wind River Systems 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:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.dd.dsf.service;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * Convenience class to help track Riverbed services that a given
+ * client needs to use. This class is similar to the standard OSGI
+ * org.osgi.util.tracker.ServiceTracker class, with a few differences:
+ * <br>1. This class is assumed to be accessed by a single thread hence it
+ * has no synchronization built in, while OSGI ServiceTracker synchronized
+ * access to its data.
+ * <br>2. This class is primarily designed to track multiple services of
+ * different type (class), while OSGI ServiceTracker is designed to work with
+ * single class type, with optional filtering options.
+ * <br>3. This class uses knowledge of Riverbed sessions to help narrow down
+ * service references.
+ * <br>4. OSGI Service tracker explicitly listens to OSGI service
+ * startup/shutdown events and it will clear a reference to a service as
+ * soon as it's shut down. This class leaves it up to the client to make
+ * sure that it doesn't access a service once that service has been shut down.
+ * <p>
+ * That said, it might be more convenient for certain types of clients to use
+ * OSGI Service tracker for the additional features it provides.
+ *
+ * @see org.osgi.util.tracker.ServiceTracker
+ */
+public class DsfServicesTracker {
+
+ private static String getServiceFilter(String sessionId) {
+ return ("(" + IDsfService.PROP_SESSION_ID + "=" + sessionId + ")").intern();
+ }
+
+ private static class ServiceKey
+ {
+ String fClassString;
+ String fFilter;
+ public ServiceKey(String classString, String filter) {
+ fClassString = classString;
+ fFilter = filter;
+ }
+
+ public boolean equals(Object other) {
+ // I guess this doesn't have to assume fFilter can be null, but oh well.
+ return other instanceof ServiceKey &&
+ ((ServiceKey)other).fClassString.equals(fClassString) &&
+ ((fFilter == null && ((ServiceKey)other).fFilter == null) ||
+ (fFilter != null && fFilter.equals(((ServiceKey)other).fFilter)));
+ }
+
+ public int hashCode() {
+ return fClassString.hashCode() + (fFilter == null ? 0 : fFilter.hashCode());
+ }
+ }
+
+ private BundleContext fBundleContext;
+ private Map<ServiceKey,ServiceReference> fServiceReferences = new HashMap<ServiceKey,ServiceReference>();
+ private Map<ServiceReference,IDsfService> fServices = new HashMap<ServiceReference,IDsfService>();
+ private String fServiceFilter;
+
+ /**
+ * Only constructor.
+ * @param bundleContext Context of the plugin that the client lives in.
+ * @param sessionId The Riverbed session that this tracker will be used for.
+ */
+ public DsfServicesTracker(BundleContext bundleContext, String sessionId) {
+ fBundleContext = bundleContext;
+ fServiceFilter = getServiceFilter(sessionId);
+ }
+
+ /**
+ * Retrieves a service reference for given service class and optional filter.
+ * Filter should be used if there are multiple instances of the desired service
+ * running within the same session.
+ * @param serviceClass class of the desired service
+ * @param custom filter to use when searching for the service, this filter will
+ * be used instead of the standard filter so it should also specify the desired
+ * session-ID
+ * @return OSGI service reference object to the desired service, null if not found
+ */
+ public ServiceReference getServiceReference(Class serviceClass, String filter) {
+ ServiceKey key = new ServiceKey(serviceClass.getName().intern(), filter != null ? filter : fServiceFilter);
+ if (fServiceReferences.containsKey(key)) {
+ return fServiceReferences.get(key);
+ }
+
+ try {
+ ServiceReference[] references = fBundleContext.getServiceReferences(key.fClassString, key.fFilter);
+ assert references == null || references.length <= 1;
+ if (references == null || references.length == 0) {
+ return null;
+ } else {
+ fServiceReferences.put(key, references[0]);
+ return references[0];
+ }
+ } catch(InvalidSyntaxException e) {
+ assert false : "Invalid session ID syntax";
+ }
+ return null;
+ }
+
+ /**
+ * Convenience class to retrieve a service based on class name only.
+ * @param serviceClass class of the desired service
+ * @return instance of the desired service, null if not found
+ */
+ public <V extends IDsfService> V getService(Class<V> serviceClass) {
+ return getService(serviceClass, null);
+ }
+
+ /**
+ * Retrieves the service given service class and optional filter.
+ * Filter should be used if there are multiple instances of the desired service
+ * running within the same session.
+ * @param serviceClass class of the desired service
+ * @param custom filter to use when searching for the service, this filter will
+ * be used instead of the standard filter so it should also specify the desired
+ * session-ID
+ * @return instance of the desired service, null if not found
+ */
+ @SuppressWarnings("unchecked")
+ public <V extends IDsfService> V getService(Class<V> serviceClass, String filter) {
+ ServiceReference serviceRef = getServiceReference(serviceClass, filter);
+ if (serviceRef == null) {
+ return null;
+ } else {
+ if (fServices.containsKey(serviceRef)) {
+ return (V)fServices.get(serviceRef);
+ } else {
+ V service = (V)fBundleContext.getService(serviceRef);
+ fServices.put(serviceRef, service);
+ return service;
+ }
+ }
+ }
+
+ /**
+ * Un-gets all the serferences held by this tracker. Must be called
+ * to avoid leaking OSGI service references.
+ */
+ public void dispose() {
+ for (Iterator itr = fServices.keySet().iterator(); itr.hasNext();) {
+ fBundleContext.ungetService((ServiceReference)itr.next());
+ itr.remove();
+ }
+ }
+
+}
diff --git a/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/service/DsfSession.java b/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/service/DsfSession.java
new file mode 100644
index 00000000000..aa273865fa9
--- /dev/null
+++ b/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/service/DsfSession.java
@@ -0,0 +1,395 @@
+/*******************************************************************************
+ * Copyright (c) 2006 Wind River Systems 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:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.dd.dsf.service;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Dictionary;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.dd.dsf.DsfPlugin;
+import org.eclipse.dd.dsf.concurrent.DsfExecutor;
+import org.eclipse.dd.dsf.concurrent.DsfRunnable;
+import org.osgi.framework.Filter;
+
+/**
+ * Class to manage Riverbed sessions. A Riverbed session is a way to
+ * associate a set of Riverbed services that are running simultaneously and
+ * are interacting with each other to provide a complete set of functionality.
+ * <p>
+ * Properties of a session are following:
+ * <br>1. Each session is associated with a single Riverbed executor, although there
+ * could be multiple sessions using the same executor.
+ * <br>2. Each session has a unique String identifier, which has to be used by
+ * the services belonging to this session when registering with OSGI services.
+ * <br>3. Each session has its set of service event listeners.
+ * <br>4. Start and end of each session is announced by events, which are always
+ * sent on that session's executor dispatch thread.
+ *
+ * @see org.eclipse.dd.dsf.concurrent.DsfExecutor
+ */
+public class DsfSession
+{
+
+ /**
+ * Listener for session started events. This listener is always going to be
+ * called in the dispatch thread of the session's executor.
+ *
+ */
+ public static interface SessionStartedListener {
+ /**
+ * Called when a new session is started. It is always called in the
+ * dispatch thread of the new session.
+ */
+ public void sessionStarted(DsfSession session);
+ }
+
+ /**
+ * Listener for session ended events. This listener is always going to be
+ * called in the dispatch thread of the session's executor.
+ */
+ public static interface SessionEndedListener {
+ /**
+ * Called when a session is ended. It is always called in the
+ * dispatch thread of the session.
+ */
+ public void sessionEnded(DsfSession session);
+ }
+
+ private static int fgSessionIdCounter = 0;
+ private static Set<DsfSession> fgActiveSessions = Collections.synchronizedSet(new HashSet<DsfSession>());
+ private static List<SessionStartedListener> fSessionStartedListeners = Collections.synchronizedList(new ArrayList<SessionStartedListener>());
+ private static List<SessionEndedListener> fSessionEndedListeners = Collections.synchronizedList(new ArrayList<SessionEndedListener>());
+
+ /** Returns true if given session is currently active */
+ public static boolean isSessionActive(String sessionId) {
+ return getSession(sessionId) != null;
+ }
+
+ /** Returns a session instance for given session identifier */
+ public static DsfSession getSession(String sessionId) {
+ for (DsfSession session : fgActiveSessions) {
+ if (session.getId().equals(sessionId)) {
+ return session;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Registers a listener for session started events.
+ * Can be called on any thread.
+ */
+ public static void addSessionStartedListener(SessionStartedListener listener) {
+ assert !fSessionStartedListeners.contains(listener);
+ fSessionStartedListeners.add(listener);
+ }
+
+ /**
+ * Un-registers a listener for session started events.
+ * Can be called on any thread.
+ */
+ public static void removeSessionStartedListener(SessionStartedListener listener) {
+ assert fSessionStartedListeners.contains(listener);
+ fSessionStartedListeners.remove(listener);
+ }
+
+ /**
+ * Registers a listener for session ended events.
+ * Can be called on any thread.
+ */
+ public static void addSessionEndedListener(SessionEndedListener listener) {
+ assert !fSessionEndedListeners.contains(listener);
+ fSessionEndedListeners.add(listener);
+ }
+
+ /**
+ * Un-registers a listener for session ended events.
+ * Can be called on any thread.
+ */
+ public static void removeSessionEndedListener(SessionEndedListener listener) {
+ assert fSessionEndedListeners.contains(listener);
+ fSessionEndedListeners.remove(listener);
+ }
+
+ /**
+ * Starts and returns a new session instance. This method can be called on any
+ * thread, but the session-started listeners will be called using the session's
+ * executor.
+ * @param executor The Riverbed executor to use for this session.
+ * @return instance object of the new session
+ */
+ public static DsfSession startSession(DsfExecutor executor) {
+ synchronized(fgActiveSessions) {
+ final DsfSession newSession = new DsfSession(executor, Integer.toString(fgSessionIdCounter++));
+ fgActiveSessions.add(newSession);
+ executor.submit( new DsfRunnable() { public void run() {
+ SessionStartedListener[] listeners = fSessionStartedListeners.toArray(
+ new SessionStartedListener[fSessionStartedListeners.size()]);
+ for (int i = 0; i < listeners.length; i++) {
+ listeners[i].sessionStarted(newSession);
+ }
+ }});
+ return newSession;
+ }
+ }
+
+ /**
+ * Terminates the given session. This method can be also called on any
+ * thread, but the session-ended listeners will be called using the session's
+ * executor.
+ * @param session session to terminate
+ */
+ public static void endSession(final DsfSession session) {
+ synchronized(fgActiveSessions) {
+ if (!fgActiveSessions.contains(session)) {
+ throw new IllegalArgumentException();
+ }
+ fgActiveSessions.remove(session);
+ session.getExecutor().submit( new DsfRunnable() { public void run() {
+ SessionEndedListener[] listeners = fSessionEndedListeners.toArray(
+ new SessionEndedListener[fSessionEndedListeners.size()]);
+ for (int i = 0; i < listeners.length; i++) {
+ listeners[i].sessionEnded(session);
+ }
+ }});
+ }
+ }
+
+ private static class ListenerEntry {
+ Object fListener;
+ Filter fFilter;
+
+ ListenerEntry(Object listener, Filter filter) {
+ fListener = listener;
+ fFilter = filter;
+ }
+
+ public boolean equals(Object other) {
+ return other instanceof ListenerEntry && fListener.equals(((ListenerEntry)other).fListener);
+ }
+
+ public int hashCode() { return fListener.hashCode(); }
+ }
+
+ /** Session ID of this session. */
+ private String fId;
+
+ /** Dispatch-thread executor for this session */
+ private DsfExecutor fExecutor;
+
+ /** Service start-up counter for this session */
+ private int fServiceInstanceCounter;
+
+ /** Map of registered event listeners. */
+ private Map<ListenerEntry,Method[]> fListeners = new HashMap<ListenerEntry,Method[]>();
+
+ /**
+ * Map of registered adapters, for implementing the
+ * IModelContext.getAdapter() method.
+ * @see org.eclipse.dd.dsf.model.AbstractDMC#getAdapter
+ */
+ private Map<Class,Object> fAdapters = Collections.synchronizedMap(new HashMap<Class,Object>());
+
+
+ /** Returns the ID of this session */
+ public String getId() { return fId; }
+
+ /** Returns the Riverbed executor of this session */
+ public DsfExecutor getExecutor() { return fExecutor; }
+
+ /**
+ * Adds a new listener for service events in this session.
+ * @param listener the listener that will receive service events
+ * @param filter optional filter to restrict the services that the
+ * listener will receive events from
+ */
+ public void addServiceEventListener(Object listener, Filter filter) {
+ ListenerEntry entry = new ListenerEntry(listener, filter);
+ assert !fListeners.containsKey(entry);
+ fListeners.put(entry, getEventHandlerMethods(listener));
+ }
+
+ /**
+ * Removes the given listener.
+ * @param listener listener to remove
+ */
+ public void removeServiceEventListener(Object listener) {
+ ListenerEntry entry = new ListenerEntry(listener, null);
+ assert fListeners.containsKey(entry);
+ fListeners.remove(entry);
+ }
+
+ /**
+ * Retrieves and increments the startup counter for services in this session.
+ * Riverbed services should retrieve this counter when they are initialized,
+ * and should return it through IService.getStartupNumber(). This number is then
+ * used to prioritize service events.
+ * @return current startup counter value
+ */
+ public int getAndIncrementServiceStartupCounter() { return fServiceInstanceCounter++; }
+
+ /**
+ * Dispatches the given event to service event listeners. The event is submitted to
+ * the executor to be dispatched.
+ * @param event to be sent out
+ * @param serviceProperties properties of the service requesting the event to be dispatched
+ */
+ public void dispatchEvent(final Object event, final Dictionary serviceProperties) {
+ getExecutor().submit(new DsfRunnable() { public void run() {
+ // TED added FIXME otherwise no way to detect!!!
+ try {
+ doDispatchEvent(event, serviceProperties);
+ } catch(Throwable e) { e.printStackTrace(); }
+ }});
+ }
+
+ /**
+ * Registers a IModelContext adapter of given type.
+ * @param adapterType class type to register the adapter for
+ * @param adapter adapter instance to register
+ * @see org.eclipse.dsdp.model.AbstractDMC#getAdapter
+ */
+ public void registerModelAdapter(Class adapterType, Object adapter) {
+ fAdapters.put(adapterType, adapter);
+ }
+
+ /**
+ * Un-registers a IModelContext adapter of given type.
+ * @param adapterType adapter type to unregister
+ * @see org.eclipse.dsdp.model.AbstractDMC#getAdapter
+ */
+ public void unregisterModelAdapter(Class adapterType) {
+ fAdapters.remove(adapterType);
+ }
+
+ /**
+ * Retrieves an adapter for given type for IModelContext.
+ * @param adapterType adapter type to look fors
+ * @return adapter object for given type, null if none is registered with the session
+ * @see org.eclipse.dsdp.model.AbstractDMC#getAdapter
+ */
+ public Object getModelAdapter(Class adapterType) {
+ return fAdapters.get(adapterType);
+ }
+
+ public boolean equals(Object other) {
+ return other instanceof DsfSession && fId.equals(((DsfSession)other).fId);
+ }
+
+ public int hashCode() { return fId.hashCode(); }
+
+ private void doDispatchEvent(Object event, Dictionary serviceProperties) {
+ // Build a list of listeners;
+ SortedMap<ListenerEntry,List<Method>> listeners = new TreeMap<ListenerEntry,List<Method>>(new Comparator<ListenerEntry>() {
+ public int compare(ListenerEntry o1, ListenerEntry o2) {
+ if (o1.fListener == o2.fListener) {
+ return 0;
+ } if (o1.fListener instanceof IDsfService && !(o2.fListener instanceof IDsfService)) {
+ return Integer.MAX_VALUE;
+ } else if (o2.fListener instanceof IDsfService && !(o1.fListener instanceof IDsfService)) {
+ return Integer.MIN_VALUE;
+ } else if ( (o1.fListener instanceof IDsfService) && (o2.fListener instanceof IDsfService) ) {
+ return ((IDsfService)o1.fListener).getStartupNumber() - ((IDsfService)o2.fListener).getStartupNumber();
+ }
+ return 1;
+ };
+
+ public boolean equals(Object obj) {
+ return obj == this;
+ };
+ });
+
+ // Build a list of listeners and methods that are registered for this event class.
+ Class<?> eventClass = event.getClass();
+ for (Map.Entry<ListenerEntry,Method[]> entry : fListeners.entrySet()) {
+ if (entry.getKey().fFilter != null && !entry.getKey().fFilter.match(serviceProperties)) {
+ // Dispatching service doesn't match the listener's filter, skip it.
+ continue;
+ }
+ Method[] allMethods = entry.getValue();
+ List<Method> matchingMethods = new ArrayList<Method>();
+ for (Method method : allMethods) {
+ assert method.getParameterTypes().length > 0 : eventClass.getName() + "." + method.getName()
+ + " signature contains zero parameters";
+ if ( method.getParameterTypes()[0].isAssignableFrom(eventClass) ) {
+ matchingMethods.add(method);
+ }
+ }
+ if (!matchingMethods.isEmpty()) {
+ listeners.put(entry.getKey(), matchingMethods);
+ }
+ }
+
+ // Call the listeners
+ for (Map.Entry<ListenerEntry,List<Method>> entry : listeners.entrySet()) {
+ for (Method method : entry.getValue()) {
+ try {
+ method.invoke(entry.getKey().fListener, new Object[] { event } );
+ }
+ catch (IllegalAccessException e) {
+ DsfPlugin.getDefault().getLog().log(new Status(
+ IStatus.ERROR, DsfPlugin.PLUGIN_ID, -1, "Security exception when calling a service event handler method", e));
+ assert false : "IServiceEventListener.ServiceHandlerMethod method not accessible, is listener declared public?";
+ }
+ catch (InvocationTargetException e) {
+ DsfPlugin.getDefault().getLog().log(new Status(
+ IStatus.ERROR, DsfPlugin.PLUGIN_ID, -1, "Invocation exception when calling a service event handler method", e));
+ assert false : "Exception thrown by a IServiceEventListener.ServiceHandlerMethod method";
+ }
+ }
+ }
+ }
+
+ private Method[] getEventHandlerMethods(Object listener)
+ {
+ List<Method> retVal = new ArrayList<Method>();
+ try {
+ Method[] methods = listener.getClass().getMethods();
+ for (Method method : methods) {
+ if (method.isAnnotationPresent(DsfServiceEventHandler.class)) {
+ Class<?>[] paramTypes = method.getParameterTypes();
+ if (paramTypes.length > 2) {
+ throw new IllegalArgumentException("ServiceEventHandler method has incorrect number of parameters");
+ }
+ retVal.add(method);
+ }
+ }
+ } catch(SecurityException e) {
+ throw new IllegalArgumentException("No permission to access ServiceEventHandler method");
+ }
+
+ if (retVal.isEmpty()) {
+ throw new IllegalArgumentException("No methods marked with @ServiceEventHandler in listener, is listener declared public?");
+ }
+ return retVal.toArray(new Method[retVal.size()]);
+ }
+
+ /**
+ * Class to be instanciated only using startSession()
+ */
+ private DsfSession(DsfExecutor executor, String id) {
+ fId = id;
+ fExecutor = executor;
+ }
+
+} \ No newline at end of file
diff --git a/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/service/IDsfService.java b/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/service/IDsfService.java
new file mode 100644
index 00000000000..82e5c310e32
--- /dev/null
+++ b/plugins/org.eclipse.dd.dsf/src/org/eclipse/dd/dsf/service/IDsfService.java
@@ -0,0 +1,88 @@
+/*******************************************************************************
+ * Copyright (c) 2006 Wind River Systems 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:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.dd.dsf.service;
+
+import java.util.Dictionary;
+
+import org.eclipse.dd.dsf.concurrent.Done;
+import org.eclipse.dd.dsf.concurrent.DsfExecutor;
+
+/**
+ * The inteface that all Riverbed services must implement. It only privides a
+ * few features to help manage and identify the servies using the OSGI services
+ * framework.
+ * <p>
+ * Each service should register itself with OSGI services framework using
+ * the BundleContext.registerService() method. And each service should use the
+ * session ID that it is registering with as one of the service properties. If there
+ * is more than one instance of the service to be instanciated for a given session,
+ * additional properties should be used when registering the service to allow clients
+ * to uniquely identify the services.
+ * <p>
+ * By convention, all methods of Riverbed services can be called only on the dispatch
+ * thread of the Riverbed executor that is associated with the service. If a
+ * service exposes a method that is to be called on non-dispatch thread, it should
+ * be documented so.
+ *
+ * TODO: Add IStatus error code constants for common service related failures.
+ *
+ * @see org.osgi.framework.BundleContext#registerService(String[], Object, Dictionary)
+ */
+public interface IDsfService {
+
+ /**
+ * Property name for the session-id of this service. This property should be set by
+ * all Riverbed services when they are registered with OSGI service framework.
+ */
+ static String PROP_SESSION_ID = "org.eclipse.dd.dsf.service.IService.session_id";
+
+ /**
+ * Returns the executor that should be used to call methods of this service.
+ * @return
+ */
+ DsfExecutor getExecutor();
+
+ /**
+ * Returns a filter string that can be used to uniquely identify this
+ * service. This filter string should be based on the properties and class
+ * name, which were used to register this service.
+ * @see org.osgi.framework.BundleContext#getServiceReferences
+ */
+ String getServiceFilter();
+
+ /**
+ * Performs initialization and registration of the given service. Implementation
+ * should initialize the service, so that all methods and events belonging to this
+ * service can be used following the initialization.
+ * <br>Note: Since service initializaiton should be performed by an external
+ * logic, if this service depends on other services, the implementaion should
+ * assume that these services are already present, and if they are not, the
+ * initializaiton should fail.
+ * @param done callback to be submitted when the initialization is complete
+ */
+ void initialize(Done done);
+
+ /**
+ * Performs shutdown and de-registration of the given service.
+ * @param done callback to be submitted when shutdown is complete
+ */
+ void shutdown(Done done);
+
+ /**
+ * Returns the startup order number of this service among services in the same session.
+ * Implementations should get this number during initialization by calling
+ * Session.getAndIncrementServiceStartupCounter(). This counter is used to Session
+ * objects to prioritize the listeners of service events.
+ * @return startup order number of this service
+ * @see org.eclipse.dd.dsf.service.DsfSession#getAndIncrementServiceStartupCounter()
+ */
+ int getStartupNumber();
+}

Back to the top