mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-07-16 21:45:22 +02:00
Initial checkin.
This commit is contained in:
commit
9d95f568db
30 changed files with 2104 additions and 0 deletions
7
plugins/org.eclipse.dd.dsf/.classpath
Normal file
7
plugins/org.eclipse.dd.dsf/.classpath
Normal file
|
@ -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>
|
1
plugins/org.eclipse.dd.dsf/.cvsignore
Normal file
1
plugins/org.eclipse.dd.dsf/.cvsignore
Normal file
|
@ -0,0 +1 @@
|
|||
bin
|
28
plugins/org.eclipse.dd.dsf/.project
Normal file
28
plugins/org.eclipse.dd.dsf/.project
Normal file
|
@ -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>
|
|
@ -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
|
14
plugins/org.eclipse.dd.dsf/META-INF/MANIFEST.MF
Normal file
14
plugins/org.eclipse.dd.dsf/META-INF/MANIFEST.MF
Normal file
|
@ -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
|
5
plugins/org.eclipse.dd.dsf/build.properties
Normal file
5
plugins/org.eclipse.dd.dsf/build.properties
Normal file
|
@ -0,0 +1,5 @@
|
|||
source.. = src/
|
||||
output.. = bin/
|
||||
bin.includes = META-INF/,\
|
||||
.,\
|
||||
plugin.xml
|
5
plugins/org.eclipse.dd.dsf/plugin.xml
Normal file
5
plugins/org.eclipse.dd.dsf/plugin.xml
Normal file
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<?eclipse version="3.2"?>
|
||||
<plugin>
|
||||
|
||||
</plugin>
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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; }
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
@ -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 {
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}});
|
||||
}
|
||||
|
||||
}
|
|
@ -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; }
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -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. 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. 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. 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>
|
|
@ -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; }
|
||||
}
|
|
@ -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 {
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
Loading…
Add table
Reference in a new issue