diff options
17 files changed, 1508 insertions, 1 deletions
diff --git a/target_explorer/plugins/org.eclipse.tm.te.core.concurrent/build.properties b/target_explorer/plugins/org.eclipse.tm.te.core.concurrent/build.properties index f4ae97015..73a5119ed 100644 --- a/target_explorer/plugins/org.eclipse.tm.te.core.concurrent/build.properties +++ b/target_explorer/plugins/org.eclipse.tm.te.core.concurrent/build.properties @@ -2,4 +2,5 @@ source.. = src/ output.. = bin/
bin.includes = META-INF/,\
.,\
- plugin.properties
+ plugin.properties,\
+ plugin.xml
diff --git a/target_explorer/plugins/org.eclipse.tm.te.core.concurrent/plugin.properties b/target_explorer/plugins/org.eclipse.tm.te.core.concurrent/plugin.properties index 708f53360..d3682ad53 100644 --- a/target_explorer/plugins/org.eclipse.tm.te.core.concurrent/plugin.properties +++ b/target_explorer/plugins/org.eclipse.tm.te.core.concurrent/plugin.properties @@ -10,3 +10,6 @@ pluginName = Target Explorer, Concurrent Core plug-in providerName = Eclipse.org + +ExtensionPoint.executorServices.name=Executor Services +ExtensionPoint.executorUtilDelegates.name=Executor Utility Wait and Dispatch Delegates diff --git a/target_explorer/plugins/org.eclipse.tm.te.core.concurrent/plugin.xml b/target_explorer/plugins/org.eclipse.tm.te.core.concurrent/plugin.xml new file mode 100644 index 000000000..eb9707c1b --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tm.te.core.concurrent/plugin.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.4"?>
+<plugin>
+
+<!-- Extension point contributions -->
+ <extension-point id="executorServices" name="%ExtensionPoint.executorServices.name" schema="schema/executorServices.exsd"/>
+ <extension-point id="executorUtilDelegates" name="%ExtensionPoint.executorUtilDelegates.name" schema="schema/executorUtilDelegates.exsd"/>
+
+<!-- Executor service contributions -->
+ <extension point="org.eclipse.tm.te.core.concurrent.executorServices">
+ <executorService
+ id="org.eclipse.tm.te.core.concurrent.executors.singleThreaded"
+ label="Single Threaded Executor">
+ <class
+ class="org.eclipse.tm.te.core.concurrent.executors.SingleThreadedExecutorService">
+ <parameter
+ name="threadPoolNamePrefix"
+ value="Target Explorer Single Thread Executor">
+ </parameter>
+ </class>
+ </executorService>
+ </extension>
+
+</plugin>
diff --git a/target_explorer/plugins/org.eclipse.tm.te.core.concurrent/schema/executorServices.exsd b/target_explorer/plugins/org.eclipse.tm.te.core.concurrent/schema/executorServices.exsd new file mode 100644 index 000000000..2bb2977c4 --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tm.te.core.concurrent/schema/executorServices.exsd @@ -0,0 +1,200 @@ +<?xml version='1.0' encoding='UTF-8'?>
+<!-- Schema file written by PDE -->
+<schema targetNamespace="org.eclipse.tm.te.core.concurrent" xmlns="http://www.w3.org/2001/XMLSchema">
+<annotation>
+ <appinfo>
+ <meta.schema plugin="org.eclipse.tm.te.core.concurrent" id="executorServices" name="Executor Services"/>
+ </appinfo>
+ <documentation>
+ This extension point is used to contribute executor services.
+ </documentation>
+ </annotation>
+
+ <element name="extension">
+ <annotation>
+ <appinfo>
+ <meta.element />
+ </appinfo>
+ </annotation>
+ <complexType>
+ <sequence>
+ <element ref="executorService" minOccurs="1" maxOccurs="unbounded"/>
+ </sequence>
+ <attribute name="point" type="string" use="required">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="id" type="string">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="name" type="string">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ <appinfo>
+ <meta.attribute translatable="true"/>
+ </appinfo>
+ </annotation>
+ </attribute>
+ </complexType>
+ </element>
+
+ <element name="executorService">
+ <annotation>
+ <documentation>
+ Declares a Wind River executor service contribution.
+ </documentation>
+ </annotation>
+ <complexType>
+ <sequence>
+ <element ref="class" minOccurs="0" maxOccurs="1"/>
+ <element ref="description" minOccurs="0" maxOccurs="1"/>
+ </sequence>
+ <attribute name="id" type="string" use="required">
+ <annotation>
+ <documentation>
+ The unique id of the executor service contribution.
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="label" type="string" use="required">
+ <annotation>
+ <documentation>
+ The label representing the executor service within the UI.
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="class" type="string">
+ <annotation>
+ <documentation>
+ The class that implements <code>com.windriver.core.runtime.concurrent.interfaces.IWRExecutor</code> or extends <code>com.windriver.core.runtime.concurrent.executors.AbstractDelegatingExecutorService</code>.
+<p>
+The executor service implementation class must be specified either by the class attribute or the class child element!
+ </documentation>
+ <appinfo>
+ <meta.attribute kind="java" basedOn=":com.windriver.core.runtime.concurrent.interfaces.IWRExecutor"/>
+ </appinfo>
+ </annotation>
+ </attribute>
+ </complexType>
+ </element>
+
+ <element name="description" type="string">
+ <annotation>
+ <documentation>
+ A short description of the executor service to be presented in the UI.
+ </documentation>
+ </annotation>
+ </element>
+
+ <element name="class">
+ <annotation>
+ <documentation>
+ <p>Used when creating an <code>IExecutableExtension</code> with a named parameter, or more than one.</p>
+ </documentation>
+ </annotation>
+ <complexType>
+ <sequence>
+ <element ref="parameter" minOccurs="0" maxOccurs="unbounded"/>
+ </sequence>
+ <attribute name="class" type="string">
+ <annotation>
+ <documentation>
+ The class that implements <code>com.windriver.core.runtime.concurrent.interfaces.IWRExecutor</code> or extends <code>com.windriver.core.runtime.concurrent.executors.AbstractDelegatingExecutorService</code>.
+<p>
+The executor service implementation class must be specified either by the class attribute or the class child element!
+ </documentation>
+ <appinfo>
+ <meta.attribute kind="java" basedOn=":com.windriver.core.runtime.concurrent.interfaces.IWRExecutor"/>
+ </appinfo>
+ </annotation>
+ </attribute>
+ </complexType>
+ </element>
+
+ <element name="parameter">
+ <annotation>
+ <documentation>
+ <p>A parameter for an <code>IExecutableExtension</code>.</p>
+ </documentation>
+ </annotation>
+ <complexType>
+ <attribute name="name" type="string" use="required">
+ <annotation>
+ <documentation>
+ <p>The parameter name.</p>
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="value" type="string" use="required">
+ <annotation>
+ <documentation>
+ <p>The parameter value.</p>
+ </documentation>
+ </annotation>
+ </attribute>
+ </complexType>
+ </element>
+
+ <annotation>
+ <appinfo>
+ <meta.section type="since"/>
+ </appinfo>
+ <documentation>
+ Target Explorer 1.0.0
+ </documentation>
+ </annotation>
+
+ <annotation>
+ <appinfo>
+ <meta.section type="examples"/>
+ </appinfo>
+ <documentation>
+ This is an example of the extension point usage:
+<p>
+<pre><code>
+ <extension point="org.eclipse.tm.te.core.concurrent.executorServices">
+ <executorService
+ id="org.eclipse.tm.te.core.concurrent.executors.singleThreaded"
+ class="org.eclipse.tm.te.core.concurrent.executors.SingleThreadedExecutorService"
+ label="Single Threaded Executor Service">
+ </exectorService>
+ </extension>
+</code></pre>
+ </documentation>
+ </annotation>
+
+ <annotation>
+ <appinfo>
+ <meta.section type="apiinfo"/>
+ </appinfo>
+ <documentation>
+ The provider of a executor service must implement <samp>org.eclipse.tm.te.core.concurrent.interfaces.IExecutor</samp>.
+ </documentation>
+ </annotation>
+
+
+ <annotation>
+ <appinfo>
+ <meta.section type="copyright"/>
+ </appinfo>
+ <documentation>
+ Copyright (c) 2011 Wind River Systems, Inc. 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.
+ </documentation>
+ </annotation>
+
+</schema>
diff --git a/target_explorer/plugins/org.eclipse.tm.te.core.concurrent/schema/executorUtilDelegates.exsd b/target_explorer/plugins/org.eclipse.tm.te.core.concurrent/schema/executorUtilDelegates.exsd new file mode 100644 index 000000000..29cab0c64 --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tm.te.core.concurrent/schema/executorUtilDelegates.exsd @@ -0,0 +1,200 @@ +<?xml version='1.0' encoding='UTF-8'?>
+<!-- Schema file written by PDE -->
+<schema targetNamespace="org.eclipse.tm.te.core.concurrent" xmlns="http://www.w3.org/2001/XMLSchema">
+<annotation>
+ <appinfo>
+ <meta.schema plugin="org.eclipse.tm.te.core.concurrent" id="executorUtilDelegates" name="Executor Utility Delegates"/>
+ </appinfo>
+ <documentation>
+ This extension point is used to contribute executor utility delegates.
+ </documentation>
+ </annotation>
+
+ <element name="extension">
+ <annotation>
+ <appinfo>
+ <meta.element />
+ </appinfo>
+ </annotation>
+ <complexType>
+ <sequence>
+ <element ref="executorUtilDelegate" minOccurs="1" maxOccurs="unbounded"/>
+ </sequence>
+ <attribute name="point" type="string" use="required">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="id" type="string">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="name" type="string">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ <appinfo>
+ <meta.attribute translatable="true"/>
+ </appinfo>
+ </annotation>
+ </attribute>
+ </complexType>
+ </element>
+
+ <element name="executorUtilDelegate">
+ <annotation>
+ <documentation>
+ Declares a Wind River executor utility delegate contribution.
+ </documentation>
+ </annotation>
+ <complexType>
+ <sequence>
+ <element ref="class" minOccurs="0" maxOccurs="1"/>
+ <element ref="description" minOccurs="0" maxOccurs="1"/>
+ </sequence>
+ <attribute name="id" type="string" use="required">
+ <annotation>
+ <documentation>
+ The unique id of the executor utility delegate contribution.
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="label" type="string" use="required">
+ <annotation>
+ <documentation>
+ The label representing the executor utility delegate within the UI.
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="class" type="string">
+ <annotation>
+ <documentation>
+ The class that implements <code>com.windriver.core.runtime.concurrent.interfaces.IWRExecutorUtilDelegate</code>.
+<p>
+The executor utility delegate implementation class must be specified either by the class attribute or the class child element!
+ </documentation>
+ <appinfo>
+ <meta.attribute kind="java" basedOn=":com.windriver.core.runtime.concurrent.interfaces.IWRExecutorUtilDelegate"/>
+ </appinfo>
+ </annotation>
+ </attribute>
+ </complexType>
+ </element>
+
+ <element name="description" type="string">
+ <annotation>
+ <documentation>
+ A short description of the executor utility delegate to be presented in the UI.
+ </documentation>
+ </annotation>
+ </element>
+
+ <element name="class">
+ <annotation>
+ <documentation>
+ <p>Used when creating an <code>IExecutableExtension</code> with a named parameter, or more than one.</p>
+ </documentation>
+ </annotation>
+ <complexType>
+ <sequence>
+ <element ref="parameter" minOccurs="0" maxOccurs="unbounded"/>
+ </sequence>
+ <attribute name="class" type="string">
+ <annotation>
+ <documentation>
+ The class that implements <code>com.windriver.core.runtime.concurrent.interfaces.IWRExecutorUtilDelegate</code>.
+<p>
+The executor utility delegate implementation class must be specified either by the class attribute or the class child element!
+ </documentation>
+ <appinfo>
+ <meta.attribute kind="java" basedOn=":com.windriver.core.runtime.concurrent.interfaces.IWRExecutorUtilDelegate"/>
+ </appinfo>
+ </annotation>
+ </attribute>
+ </complexType>
+ </element>
+
+ <element name="parameter">
+ <annotation>
+ <documentation>
+ <p>A parameter for an <code>IExecutableExtension</code>.</p>
+ </documentation>
+ </annotation>
+ <complexType>
+ <attribute name="name" type="string" use="required">
+ <annotation>
+ <documentation>
+ <p>The parameter name.</p>
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="value" type="string" use="required">
+ <annotation>
+ <documentation>
+ <p>The parameter value.</p>
+ </documentation>
+ </annotation>
+ </attribute>
+ </complexType>
+ </element>
+
+ <annotation>
+ <appinfo>
+ <meta.section type="since"/>
+ </appinfo>
+ <documentation>
+ Target Explorer 1.0.0
+ </documentation>
+ </annotation>
+
+ <annotation>
+ <appinfo>
+ <meta.section type="examples"/>
+ </appinfo>
+ <documentation>
+ This is an example of the extension point usage:
+<p>
+<pre><code>
+ <extension point="org.eclipse.tm.te.core.concurrent.executorUtilDelegates">
+ <executorUtilDelegate
+ id="org.eclipse.tm.te.core.concurrent.executor.delegates.swt"
+ class="org.eclipse.tm.te.ui.swt.executor.delegates.SWTExecutorUtilDelegate"
+ label="SWT Executor Utility Delegate">
+ </exectorUtilDelegate>
+ </extension>
+</code></pre>
+ </documentation>
+ </annotation>
+
+ <annotation>
+ <appinfo>
+ <meta.section type="apiinfo"/>
+ </appinfo>
+ <documentation>
+ The provider of a executor utility delegates must implement <samp>org.eclipse.tm.te.core.concurrent.interfaces.IExecutorUtilDelegate</samp>.
+ </documentation>
+ </annotation>
+
+
+ <annotation>
+ <appinfo>
+ <meta.section type="copyright"/>
+ </appinfo>
+ <documentation>
+ Copyright (c) 2011 Wind River Systems, Inc. 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.
+ </documentation>
+ </annotation>
+
+</schema>
diff --git a/target_explorer/plugins/org.eclipse.tm.te.core.concurrent/src/org/eclipse/tm/te/core/concurrent/Executors.java b/target_explorer/plugins/org.eclipse.tm.te.core.concurrent/src/org/eclipse/tm/te/core/concurrent/Executors.java new file mode 100644 index 000000000..b298a28cd --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tm.te.core.concurrent/src/org/eclipse/tm/te/core/concurrent/Executors.java @@ -0,0 +1,147 @@ +/******************************************************************************* + * Copyright (c) 2011 Wind River Systems, Inc. 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.tm.te.core.concurrent; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.tm.te.core.concurrent.interfaces.IExecutor; +import org.eclipse.tm.te.core.extensions.AbstractExtensionPointManager; +import org.eclipse.tm.te.core.extensions.ExecutableExtensionProxy; + + +/** + * Class is providing the entry points to create or query the executor service + * instances. + */ +public final class Executors { + + /** + * Execution service extension point manager. + */ + protected static class ExecutorServiceExtensionPointManager extends AbstractExtensionPointManager<IExecutor> { + + /* + * (non-Javadoc) + * + * @see org.eclipse.tm.te.core.extensions.AbstractExtensionPointManager# + * getExtensionPointId() + */ + @Override + protected String getExtensionPointId() { + return "org.eclipse.tm.te.core.concurrent.executorServices"; //$NON-NLS-1$ + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.tm.te.core.extensions.AbstractExtensionPointManager# + * getConfigurationElementName() + */ + @Override + protected String getConfigurationElementName() { + return "executorService"; //$NON-NLS-1$ + } + + /** + * Returns the list of all contributed executors. + * + * @return The list of contributed executors, or an empty array. + */ + public IExecutor[] getExecutors() { + List<IExecutor> contributions = new ArrayList<IExecutor>(); + Collection<ExecutableExtensionProxy<IExecutor>> proxies = getExtensions().values(); + for (ExecutableExtensionProxy<IExecutor> proxy : proxies) + if (proxy.getInstance() != null + && !contributions.contains(proxy.getInstance())) + contributions.add(proxy.getInstance()); + + return contributions.toArray(new IExecutor[contributions.size()]); + } + + /** + * Returns the executor identified by its unique id. If no executor with + * the specified id is registered, <code>null</code> is returned. + * + * @param id + * The unique id of the executor. Must not be + * <code>null</code> + * @param newInstance + * Specify <code>true</code> to get a new executor service + * instance, <code>false</code> otherwise. + * + * @return The executor instance or <code>null</code>. + */ + public IExecutor getExecutor(String id, boolean newInstance) { + Assert.isNotNull(id); + + IExecutor executorService = null; + if (getExtensions().containsKey(id)) { + ExecutableExtensionProxy<IExecutor> proxy = getExtensions().get(id); + // Get the extension instance + executorService = newInstance ? proxy.newInstance() : proxy.getInstance(); + } + + return executorService; + } + } + + // Reference to the executor service extension point manager + private final static ExecutorServiceExtensionPointManager EXTENSION_POINT_MANAGER = new ExecutorServiceExtensionPointManager(); + + /** + * Constructor. + * <p> + * <b>Note:</b> The class cannot be instantiated. + */ + private Executors() { + } + + /** + * Creates an instance of the executor registered with the specified id. If + * no executor is registered under the given id, the method will return + * <code>null</code>. + * + * @param id + * The id of the executor. Must not be <code>null</code>. + * @return The new executor instance or <code>null</code>. + */ + public static IExecutor newExecutor(String id) { + Assert.isNotNull(id); + return EXTENSION_POINT_MANAGER.getExecutor(id, true); + } + + /** + * Returns the shared instance of the executor registered with the specified + * id. If the shared instance hasn't been created yet, the instance will be + * created and saved. Subsequent calls to this method with the same id will + * return always the same executor instance. If no executor is registered + * under the given id, the method will return <code>null</code>. + * + * @param id + * The id of the executor. Must not be <code>null</code>. + * @return The new executor instance or <code>null</code>. + */ + public static IExecutor getSharedExecutor(String id) { + Assert.isNotNull(id); + return EXTENSION_POINT_MANAGER.getExecutor(id, false); + } + + /** + * Returns the shared instances of all registered executors. + * + * @return All executor instances or an empty array. + */ + public static IExecutor[] getAllSharedExecutors() { + return EXTENSION_POINT_MANAGER.getExecutors(); + } +} diff --git a/target_explorer/plugins/org.eclipse.tm.te.core.concurrent/src/org/eclipse/tm/te/core/concurrent/event/ExecutorThreadNotificationListener.java b/target_explorer/plugins/org.eclipse.tm.te.core.concurrent/src/org/eclipse/tm/te/core/concurrent/event/ExecutorThreadNotificationListener.java new file mode 100644 index 000000000..18720ee4b --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tm.te.core.concurrent/src/org/eclipse/tm/te/core/concurrent/event/ExecutorThreadNotificationListener.java @@ -0,0 +1,34 @@ +/******************************************************************************* + * Copyright (c) 2011 Wind River Systems, Inc. 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.tm.te.core.concurrent.event; + +import org.eclipse.core.runtime.PlatformObject; +import org.eclipse.tm.te.core.concurrent.util.ExecutorsUtil; +import org.eclipse.tm.te.core.interfaces.events.IEventFireDelegate; +import org.eclipse.tm.te.core.interfaces.events.IEventListener; + +/** + * Abstract notification listener implementation executing the + * notifications within the shared executor thread. + */ +public abstract class ExecutorThreadNotificationListener extends PlatformObject implements IEventListener, IEventFireDelegate { + + /* (non-Javadoc) + * @see org.eclipse.tm.te.core.interfaces.events.IEventFireDelegate#fire(java.lang.Runnable) + */ + public final void fire(Runnable runnable) { + // Force notification into the executor thread. + // + // Note: The executor thread is not identical with the display thread! + // Use ExecutorsUtil.executeInUI(runnable) to execute the runnable + // within the display thread. + ExecutorsUtil.execute(runnable); + } +} diff --git a/target_explorer/plugins/org.eclipse.tm.te.core.concurrent/src/org/eclipse/tm/te/core/concurrent/executors/AbstractDelegatingExecutorService.java b/target_explorer/plugins/org.eclipse.tm.te.core.concurrent/src/org/eclipse/tm/te/core/concurrent/executors/AbstractDelegatingExecutorService.java new file mode 100644 index 000000000..72b3e8c39 --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tm.te.core.concurrent/src/org/eclipse/tm/te/core/concurrent/executors/AbstractDelegatingExecutorService.java @@ -0,0 +1,206 @@ +/******************************************************************************* + * Copyright (c) 2011 Wind River Systems, Inc. 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.tm.te.core.concurrent.executors; + +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IConfigurationElement; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.Status; +import org.eclipse.osgi.util.NLS; +import org.eclipse.tm.te.core.concurrent.activator.CoreBundleActivator; +import org.eclipse.tm.te.core.concurrent.interfaces.IExecutor; +import org.eclipse.tm.te.core.concurrent.nls.Messages; +import org.eclipse.tm.te.core.extensions.ExecutableExtension; + +/** + * Abstract delegating execution service implementation. + */ +public abstract class AbstractDelegatingExecutorService extends + ExecutableExtension implements IExecutor, ExecutorService { + // The executor service to delegate the API calls to + private ExecutorService delegate; + + // The thread pool name prefix + private String threadPoolNamePrefix; + + /** + * Constructor. + */ + public AbstractDelegatingExecutorService() { + } + + /* (non-Javadoc) + * @see org.eclipse.tm.te.core.extensions.ExecutableExtension#setInitializationData(org.eclipse.core.runtime.IConfigurationElement, java.lang.String, java.lang.Object) + */ + @Override + public void setInitializationData(IConfigurationElement config, String propertyName, Object data) throws CoreException { + super.setInitializationData(config, propertyName, data); + + if (config != null && data instanceof Map<?, ?>) { + Map<?, ?> params = (Map<?, ?>) data; + // Initialize the thread pool name prefix field by reading the + // "threadPoolNamePrefix" extension attribute if present. + threadPoolNamePrefix = (String) params.get("threadPoolNamePrefix"); //$NON-NLS-1$ + if (threadPoolNamePrefix == null || threadPoolNamePrefix.trim().length() == 0) { + threadPoolNamePrefix = ""; //$NON-NLS-1$ + } + } + + // Create the executor service delegate + this.delegate = createExecutorServiceDelegate(); + Assert.isNotNull(delegate); + } + + /** + * Returns the thread pool name prefix if specified by the extension. + * + * @return The thread pool name prefix or an empty string. + */ + public String getThreadPoolNamePrefix() { + return threadPoolNamePrefix != null ? threadPoolNamePrefix : ""; //$NON-NLS-1$ + } + + /** + * Invoked by the constructor exactly once to create the executor service + * delegate instance. + * + * @return The executor service instance and never <code>null</code>. + */ + protected abstract ExecutorService createExecutorServiceDelegate(); + + /** + * Returns the executor service delegate instance. + * + * @return The executor service delegate instance. + */ + protected final ExecutorService getExecutorServiceDelegate() { + return delegate; + } + + /** + * Log the given exception as error to the error log. + * + * @param e + * The exception or <code>null</code>. + */ + protected void logException(Throwable e) { + if (e != null) { + IStatus status = new Status( + IStatus.ERROR, + CoreBundleActivator.getUniqueIdentifier(), + NLS.bind(Messages.AbstractDelegatingExecutorService_unhandledException, + e.getLocalizedMessage()), e); + Platform.getLog(CoreBundleActivator.getContext().getBundle()).log(status); + } + } + + /* (non-Javadoc) + * @see java.util.concurrent.Executor#execute(java.lang.Runnable) + */ + public void execute(Runnable command) { + delegate.execute(command); + } + + /* (non-Javadoc) + * @see java.util.concurrent.ExecutorService#shutdown() + */ + public void shutdown() { + delegate.shutdown(); + } + + /* (non-Javadoc) + * @see java.util.concurrent.ExecutorService#shutdownNow() + */ + public List<Runnable> shutdownNow() { + return delegate.shutdownNow(); + } + + /* (non-Javadoc) + * @see java.util.concurrent.ExecutorService#isShutdown() + */ + public boolean isShutdown() { + return delegate.isShutdown(); + } + + /* (non-Javadoc) + * @see java.util.concurrent.ExecutorService#isTerminated() + */ + public boolean isTerminated() { + return delegate.isTerminated(); + } + + /* (non-Javadoc) + * @see java.util.concurrent.ExecutorService#awaitTermination(long, java.util.concurrent.TimeUnit) + */ + public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException { + return delegate.awaitTermination(timeout, unit); + } + + /* (non-Javadoc) + * @see java.util.concurrent.ExecutorService#submit(java.util.concurrent.Callable) + */ + public <T> Future<T> submit(Callable<T> task) { + return delegate.submit(task); + } + + /* (non-Javadoc) + * @see java.util.concurrent.ExecutorService#submit(java.lang.Runnable, java.lang.Object) + */ + public <T> Future<T> submit(Runnable task, T result) { + return delegate.submit(task, result); + } + + /* (non-Javadoc) + * @see java.util.concurrent.ExecutorService#submit(java.lang.Runnable) + */ + public Future<?> submit(Runnable task) { + return delegate.submit(task); + } + + /* (non-Javadoc) + * @see java.util.concurrent.ExecutorService#invokeAll(java.util.Collection) + */ + public <T> List<Future<T>> invokeAll(Collection<Callable<T>> tasks) throws InterruptedException { + return delegate.invokeAll(tasks); + } + + /* (non-Javadoc) + * @see java.util.concurrent.ExecutorService#invokeAll(java.util.Collection, long, java.util.concurrent.TimeUnit) + */ + public <T> List<Future<T>> invokeAll(Collection<Callable<T>> tasks, long timeout, TimeUnit unit) throws InterruptedException { + return delegate.invokeAll(tasks, timeout, unit); + } + + /* (non-Javadoc) + * @see java.util.concurrent.ExecutorService#invokeAny(java.util.Collection) + */ + public <T> T invokeAny(Collection<Callable<T>> tasks) throws InterruptedException, ExecutionException { + return delegate.invokeAny(tasks); + } + + /* (non-Javadoc) + * @see java.util.concurrent.ExecutorService#invokeAny(java.util.Collection, long, java.util.concurrent.TimeUnit) + */ + public <T> T invokeAny(Collection<Callable<T>> tasks, long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { + return delegate.invokeAny(tasks, timeout, unit); + } +} diff --git a/target_explorer/plugins/org.eclipse.tm.te.core.concurrent/src/org/eclipse/tm/te/core/concurrent/executors/SingleThreadedExecutorService.java b/target_explorer/plugins/org.eclipse.tm.te.core.concurrent/src/org/eclipse/tm/te/core/concurrent/executors/SingleThreadedExecutorService.java new file mode 100644 index 000000000..095817642 --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tm.te.core.concurrent/src/org/eclipse/tm/te/core/concurrent/executors/SingleThreadedExecutorService.java @@ -0,0 +1,182 @@ +/******************************************************************************* + * Copyright (c) 2011 Wind River Systems, Inc. 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.tm.te.core.concurrent.executors; + +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + +import org.eclipse.tm.te.core.concurrent.factories.SingleThreadThreadFactory; +import org.eclipse.tm.te.core.concurrent.interfaces.INestableExecutor; +import org.eclipse.tm.te.core.concurrent.interfaces.ISingleThreadedExecutor; + +/** + * A single threaded executor service implementation. + */ +public class SingleThreadedExecutorService extends AbstractDelegatingExecutorService implements ISingleThreadedExecutor, INestableExecutor { + + /** + * A single threaded executor implementation. + */ + protected class SingleThreadedExecutor extends ThreadPoolExecutor implements INestableExecutor { + // The current nesting depth + private final AtomicInteger currentNestingDepth = new AtomicInteger(0); + + /** + * Constructor. + * + * @param threadFactory + * The thread factory instance. Must not be <code>null</code>. + * + * @throws NullPointerException + * if threadFactory is <code>null</code>. + */ + public SingleThreadedExecutor(ThreadFactory threadFactory) { + this(threadFactory, new LinkedBlockingQueue<Runnable>()); + } + + /** + * Constructor. + * <p> + * Private constructor to catch the work queue instance passed into the + * {@link ThreadPoolExecutor} constructor. + * + * @param threadFactory + * The thread factory instance. Must not be <code>null</code>. + * @param workQueue + * The work queue instance. Must not be <code>null</code>. + */ + private SingleThreadedExecutor(ThreadFactory threadFactory, BlockingQueue<Runnable> workQueue) { + super(1, 1, 0L, TimeUnit.NANOSECONDS, workQueue, threadFactory); + } + + /* (non-Javadoc) + * @see org.eclipse.tm.te.core.concurrent.interfaces.INestableExecutor#getMaxDepth() + */ + public int getMaxDepth() { + return 1; + } + + /* (non-Javadoc) + * @see org.eclipse.tm.te.core.concurrent.interfaces.INestableExecutor#readAndExecute() + */ + public boolean readAndExecute() { + // Method is callable from the executor thread only + if (!isExecutorThread()) { + throw new IllegalStateException("Must be called from within the executor thread!"); //$NON-NLS-1$ + } + + BlockingQueue<Runnable> queue = getQueue(); + + // If the work queue is empty, there is nothing to do + if (!queue.isEmpty()) { + // Work queue not empty, check if we reached the maximum nesting + // depth + if (currentNestingDepth.get() >= getMaxDepth()) { + throw new IllegalStateException("Maximum nesting depth exceeded!"); //$NON-NLS-1$ + } + + // Get the next work item to do + Runnable runnable = null; + try { + // Double check that the queue is not empty, we desire to + // avoid + // blocking here! + if (!queue.isEmpty()) { + runnable = queue.take(); + } + } catch (InterruptedException e) { /* ignored on purpose */ } + + if (runnable != null) { + // Increase the nesting depth + currentNestingDepth.incrementAndGet(); + try { + // Execute the runnable + runnable.run(); + } finally { + // Decrease nesting depth + currentNestingDepth.decrementAndGet(); + } + } + } + + return !queue.isEmpty(); + } + + /* (non-Javadoc) + * @see java.util.concurrent.ThreadPoolExecutor#afterExecute(java.lang.Runnable, java.lang.Throwable) + */ + @Override + protected void afterExecute(Runnable r, Throwable t) { + super.afterExecute(r, t); + if (t != null) + logException(t); + } + } + + // Internal reference to the one shot thread factory instance + private SingleThreadThreadFactory threadFactory; + + /** + * Constructor. + */ + public SingleThreadedExecutorService() { + } + + /* (non-Javadoc) + * @see org.eclipse.tm.te.core.concurrent.executors.AbstractDelegatingExecutorService#createExecutorServiceDelegate() + */ + @Override + protected ExecutorService createExecutorServiceDelegate() { + threadFactory = new SingleThreadThreadFactory(getThreadPoolNamePrefix()); + return new SingleThreadedExecutor(threadFactory); + } + + /* (non-Javadoc) + * @see org.eclipse.tm.te.core.concurrent.interfaces.ISingleThreadedExecutor#isExecutorThread() + */ + public final boolean isExecutorThread() { + return isExecutorThread(Thread.currentThread()); + } + + /* (non-Javadoc) + * @see org.eclipse.tm.te.core.concurrent.interfaces.ISingleThreadedExecutor#isExecutorThread(java.lang.Thread) + */ + public final boolean isExecutorThread(Thread thread) { + if (thread != null && threadFactory != null) { + return thread.equals(threadFactory.getThread()); + } + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.tm.te.core.concurrent.interfaces.INestableExecutor#getMaxDepth() + */ + public int getMaxDepth() { + if (!(getExecutorServiceDelegate() instanceof INestableExecutor)) { + throw new UnsupportedOperationException("Executor service delegate must implement INestableExecutor"); //$NON-NLS-1$ + } + return ((INestableExecutor) getExecutorServiceDelegate()).getMaxDepth(); + } + + /* (non-Javadoc) + * @see org.eclipse.tm.te.core.concurrent.interfaces.INestableExecutor#readAndExecute() + */ + public boolean readAndExecute() { + if (!(getExecutorServiceDelegate() instanceof INestableExecutor)) { + throw new UnsupportedOperationException("Executor service delegate must implement INestableExecutor"); //$NON-NLS-1$ + } + return ((INestableExecutor) getExecutorServiceDelegate()).readAndExecute(); + } +} diff --git a/target_explorer/plugins/org.eclipse.tm.te.core.concurrent/src/org/eclipse/tm/te/core/concurrent/factories/SingleThreadThreadFactory.java b/target_explorer/plugins/org.eclipse.tm.te.core.concurrent/src/org/eclipse/tm/te/core/concurrent/factories/SingleThreadThreadFactory.java new file mode 100644 index 000000000..a80ac0a36 --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tm.te.core.concurrent/src/org/eclipse/tm/te/core/concurrent/factories/SingleThreadThreadFactory.java @@ -0,0 +1,71 @@ +/******************************************************************************* + * Copyright (c) 2011 Wind River Systems, Inc. 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.tm.te.core.concurrent.factories; + +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.atomic.AtomicInteger; + +import org.eclipse.core.runtime.Assert; + +/** + * A thread factory implementation creating a single thread only. + */ +public class SingleThreadThreadFactory implements ThreadFactory { + private final ThreadGroup threadGroup; + private final String threadName; + private Thread thread; + + private final AtomicInteger threadNumber = new AtomicInteger(1); + + /** + * Constructor. + * + * @param namePrefix + * The name prefix to name the created threads. Must not be + * <code>null</code>. + */ + public SingleThreadThreadFactory(String namePrefix) { + Assert.isNotNull(namePrefix); + + // Determine the thread group. Use the security manager if available. + this.threadGroup = (System.getSecurityManager() != null) ? System.getSecurityManager().getThreadGroup() : Thread.currentThread().getThreadGroup(); + // Set the thread name prefix + this.threadName = ("".equals(namePrefix.trim()) ? "Executor" : namePrefix) + " - " + threadNumber.getAndIncrement(); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } + + /* + * (non-Javadoc) + * + * @see java.util.concurrent.ThreadFactory#newThread(java.lang.Runnable) + */ + public Thread newThread(Runnable r) { + // The thread can be created on once. If called a second time, + // this factory cannot create any additional threads. + if (thread != null) return null; + + // Create the thread with the desired name and the current thread number + thread = new Thread(threadGroup, r, threadName); + thread.setDaemon(false); + thread.setPriority(Thread.NORM_PRIORITY); + + // Return the thread + return thread; + } + + /** + * Returns the single created thread instance or <code>null</code> if + * {@link #newThread(Runnable)} have not been called yet. + * + * @return The single created thread instance or <code>null</code>. + */ + public Thread getThread() { + return thread; + } +} diff --git a/target_explorer/plugins/org.eclipse.tm.te.core.concurrent/src/org/eclipse/tm/te/core/concurrent/interfaces/IExecutor.java b/target_explorer/plugins/org.eclipse.tm.te.core.concurrent/src/org/eclipse/tm/te/core/concurrent/interfaces/IExecutor.java new file mode 100644 index 000000000..eb48fd30d --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tm.te.core.concurrent/src/org/eclipse/tm/te/core/concurrent/interfaces/IExecutor.java @@ -0,0 +1,21 @@ +/******************************************************************************* + * Copyright (c) 2011 Wind River Systems, Inc. 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.tm.te.core.concurrent.interfaces; + +import java.util.concurrent.Executor; + +import org.eclipse.tm.te.core.interfaces.IExecutableExtension; + +/** + * Execution interface declaration. + */ +public interface IExecutor extends Executor, IExecutableExtension { + +} diff --git a/target_explorer/plugins/org.eclipse.tm.te.core.concurrent/src/org/eclipse/tm/te/core/concurrent/interfaces/IExecutorUtilDelegate.java b/target_explorer/plugins/org.eclipse.tm.te.core.concurrent/src/org/eclipse/tm/te/core/concurrent/interfaces/IExecutorUtilDelegate.java new file mode 100644 index 000000000..2969a382f --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tm.te.core.concurrent/src/org/eclipse/tm/te/core/concurrent/interfaces/IExecutorUtilDelegate.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * Copyright (c) 2011 Wind River Systems, Inc. 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.tm.te.core.concurrent.interfaces; + +import org.eclipse.tm.te.core.interfaces.IExecutableExtension; + +/** + * Executor utility delegate interface declaration. + */ +public interface IExecutorUtilDelegate extends IExecutableExtension { + + /** + * Returns if or if not the current thread is an executor thread handled by + * this executor utility wait and dispatch delegate. + * + * @return <code>True</code> if the current thread is handled, + * <code>false</code> otherwise. + */ + public boolean isHandledExecutorThread(); + + /** + * Reads an event from the handled executors event queue, dispatches it + * appropriately, and returns <code>true</code> if there is potentially more + * work to do, or <code>false</code> if the caller can sleep until another + * event is placed on the event queue. + * + * @return <code>True</code> if there is potentially more work to do, + * <code>false</code> otherwise. + */ + public boolean readAndDispatch(); +} diff --git a/target_explorer/plugins/org.eclipse.tm.te.core.concurrent/src/org/eclipse/tm/te/core/concurrent/interfaces/INestableExecutor.java b/target_explorer/plugins/org.eclipse.tm.te.core.concurrent/src/org/eclipse/tm/te/core/concurrent/interfaces/INestableExecutor.java new file mode 100644 index 000000000..55eb0c1ae --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tm.te.core.concurrent/src/org/eclipse/tm/te/core/concurrent/interfaces/INestableExecutor.java @@ -0,0 +1,37 @@ +/******************************************************************************* + * Copyright (c) 2011 Wind River Systems, Inc. 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.tm.te.core.concurrent.interfaces; + +import java.util.concurrent.Executor; + +/** + * Nestable execution interface declaration. + */ +public interface INestableExecutor extends Executor { + + /** + * Returns the maximum allowed nesting depth. If this methods returns an + * integer value <= 0, nesting is disabled. + * + * @return The maximum allowed nesting depth or 0 to disable nesting. + */ + public int getMaxDepth(); + + /** + * Reads the next command from the task queue and execute it if the maximum + * allowed nesting depth has not been exceeded. If the maximum nesting depth + * has been reached, the method will throw an {@link IllegalStateException}. + * + * @return <code>True</code> if there is potentially more work to do, or + * <code>false</code> if the caller can sleep until another event is + * placed on the task queue. + */ + public boolean readAndExecute(); +} diff --git a/target_explorer/plugins/org.eclipse.tm.te.core.concurrent/src/org/eclipse/tm/te/core/concurrent/interfaces/ISingleThreadedExecutor.java b/target_explorer/plugins/org.eclipse.tm.te.core.concurrent/src/org/eclipse/tm/te/core/concurrent/interfaces/ISingleThreadedExecutor.java new file mode 100644 index 000000000..1d9269c9e --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tm.te.core.concurrent/src/org/eclipse/tm/te/core/concurrent/interfaces/ISingleThreadedExecutor.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * Copyright (c) 2011 Wind River Systems, Inc. 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.tm.te.core.concurrent.interfaces; + +import java.util.concurrent.Executor; + +/** + * Single threaded execution service interface declaration. + */ +public interface ISingleThreadedExecutor extends Executor { + + /** + * Returns if or if not the current thread is identical to the executor + * thread. + * + * @return <code>True</code> if the current thread is the executor thread, + * <code>false</code> otherwise. + */ + public boolean isExecutorThread(); + + /** + * Returns if or if not the given thread is identical to the executor + * thread. + * + * @param thread + * The thread or <code>null</code>. + * @return <code>True</code> if the current thread is the executor thread, + * <code>false</code> otherwise. + */ + public boolean isExecutorThread(Thread thread); +} diff --git a/target_explorer/plugins/org.eclipse.tm.te.core.concurrent/src/org/eclipse/tm/te/core/concurrent/nls/Messages.java b/target_explorer/plugins/org.eclipse.tm.te.core.concurrent/src/org/eclipse/tm/te/core/concurrent/nls/Messages.java index 53ce81a5d..a43ba20e5 100644 --- a/target_explorer/plugins/org.eclipse.tm.te.core.concurrent/src/org/eclipse/tm/te/core/concurrent/nls/Messages.java +++ b/target_explorer/plugins/org.eclipse.tm.te.core.concurrent/src/org/eclipse/tm/te/core/concurrent/nls/Messages.java @@ -29,4 +29,5 @@ public class Messages extends NLS { // **** Declare externalized string id's down here ***** + public static String AbstractDelegatingExecutorService_unhandledException; } diff --git a/target_explorer/plugins/org.eclipse.tm.te.core.concurrent/src/org/eclipse/tm/te/core/concurrent/nls/Messages.properties b/target_explorer/plugins/org.eclipse.tm.te.core.concurrent/src/org/eclipse/tm/te/core/concurrent/nls/Messages.properties index 3017309b8..58d39fc78 100644 --- a/target_explorer/plugins/org.eclipse.tm.te.core.concurrent/src/org/eclipse/tm/te/core/concurrent/nls/Messages.properties +++ b/target_explorer/plugins/org.eclipse.tm.te.core.concurrent/src/org/eclipse/tm/te/core/concurrent/nls/Messages.properties @@ -4,3 +4,5 @@ # PendingOperationModelNode_label=Pending... + +AbstractDelegatingExecutorService_unhandledException=Unhandled exception caught in executor: {0} diff --git a/target_explorer/plugins/org.eclipse.tm.te.core.concurrent/src/org/eclipse/tm/te/core/concurrent/util/ExecutorsUtil.java b/target_explorer/plugins/org.eclipse.tm.te.core.concurrent/src/org/eclipse/tm/te/core/concurrent/util/ExecutorsUtil.java new file mode 100644 index 000000000..fc2011b12 --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tm.te.core.concurrent/src/org/eclipse/tm/te/core/concurrent/util/ExecutorsUtil.java @@ -0,0 +1,302 @@ +/******************************************************************************* + * Copyright (c) 2011 Wind River Systems, Inc. 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.tm.te.core.concurrent.util; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.concurrent.ExecutorService; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.tm.te.core.concurrent.Executors; +import org.eclipse.tm.te.core.concurrent.interfaces.IExecutorUtilDelegate; +import org.eclipse.tm.te.core.concurrent.interfaces.INestableExecutor; +import org.eclipse.tm.te.core.concurrent.interfaces.ISingleThreadedExecutor; +import org.eclipse.tm.te.core.extensions.AbstractExtensionPointManager; +import org.eclipse.tm.te.core.extensions.ExecutableExtensionProxy; +import org.eclipse.tm.te.core.interfaces.IConditionTester; + + +/** + * Utility class to provide helper methods to execute tasks at + * a executor service asynchronous and synchronous. + */ +public final class ExecutorsUtil { + + /** + * Execution utility wait and dispatch utility extension point manager. + */ + protected static class ExecutorUtilDelegateExtensionPointManager extends AbstractExtensionPointManager<IExecutorUtilDelegate> { + + /* (non-Javadoc) + * @see org.eclipse.tm.te.core.extensions.AbstractExtensionPointManager#getExtensionPointId() + */ + @Override + protected String getExtensionPointId() { + return "org.eclipse.tm.te.core.concurrent.executorUtilDelegates"; //$NON-NLS-1$ + } + + /* (non-Javadoc) + * @see org.eclipse.tm.te.core.extensions.AbstractExtensionPointManager#getConfigurationElementName() + */ + @Override + protected String getConfigurationElementName() { + return "executorUtilDelegate"; //$NON-NLS-1$ + } + + /** + * Returns the list of all contributed executor utility delegates. + * + * @return The list of contributed executor utility delegates, or an + * empty array. + */ + public IExecutorUtilDelegate[] getExecutorUtilDelegates() { + List<IExecutorUtilDelegate> contributions = new ArrayList<IExecutorUtilDelegate>(); + Collection<ExecutableExtensionProxy<IExecutorUtilDelegate>> proxies = getExtensions().values(); + for (ExecutableExtensionProxy<IExecutorUtilDelegate> proxy : proxies) { + if (proxy.getInstance() != null&& !contributions.contains(proxy.getInstance())) { + contributions.add(proxy.getInstance()); + } + } + + return contributions.toArray(new IExecutorUtilDelegate[contributions.size()]); + } + + /** + * Returns the executor utility delegate identified by its unique id. If + * no executor utility delegate with the specified id is registered, + * <code>null</code> is returned. + * + * @param id + * The unique id of the executor utility delegate. Must not + * be <code>null</code> + * @param newInstance + * Specify <code>true</code> to get a new executor utility + * delegate instance, <code>false</code> otherwise. + * + * @return The executor instance or <code>null</code>. + */ + public IExecutorUtilDelegate getExecutorUtilDelegate(String id, boolean newInstance) { + Assert.isNotNull(id); + + IExecutorUtilDelegate executorUtilDelegate = null; + if (getExtensions().containsKey(id)) { + ExecutableExtensionProxy<IExecutorUtilDelegate> proxy = getExtensions().get(id); + // Get the extension instance + executorUtilDelegate = newInstance ? proxy.newInstance() : proxy.getInstance(); + } + + return executorUtilDelegate; + } + } + + // Reference to the executor service extension point manager + private final static ExecutorUtilDelegateExtensionPointManager EXTENSION_POINT_MANAGER = new ExecutorUtilDelegateExtensionPointManager(); + + // Reference to the used executor service. + private final static ISingleThreadedExecutor EXECUTOR; + // Reference to the used UI executor service (might be null if not available) + private final static ISingleThreadedExecutor UI_EXECUTOR; + + /** + * Static constructor. + */ + static { + EXECUTOR = (ISingleThreadedExecutor) Executors.getSharedExecutor("org.eclipse.tm.te.core.concurrent.executors.singleThreaded"); //$NON-NLS-1$ + Assert.isNotNull(EXECUTOR); + UI_EXECUTOR = (ISingleThreadedExecutor) Executors.getSharedExecutor("org.eclipse.tm.ui.swt.executors.display"); //$NON-NLS-1$ + } + + /** + * Shutdown the executor service used. + */ + public static void shutdown() { + if (EXECUTOR instanceof ExecutorService) { + ((ExecutorService) EXECUTOR).shutdown(); + } + if (UI_EXECUTOR instanceof ExecutorService) { + ((ExecutorService) UI_EXECUTOR).shutdown(); + } + } + + /** + * Checks if the current thread is identical with the executor thread. + * + * @return <code>True</code> if the current thread is the executor thread, + * <code>false</code> otherwise. + */ + public static boolean isExecutorThread() { + return EXECUTOR != null ? EXECUTOR.isExecutorThread() : false; + } + + /** + * Checks if the current thread is identical with the UI executor thread. + * + * @return <code>True</code> if the current thread is the UI executor + * thread, <code>false</code> otherwise. + */ + public static boolean isUIExecutorThread() { + return UI_EXECUTOR != null ? UI_EXECUTOR.isExecutorThread() : false; + } + + /** + * Schedule the given {@link Runnable} for invocation within the used + * executor thread. + * + * @param runnable + * The <code>java.lang.Runnable</code> to execute within the + * executor thread. + */ + public static void execute(Runnable runnable) { + if (runnable != null) { + if (EXECUTOR instanceof ExecutorService) { + if (!((ExecutorService) EXECUTOR).isShutdown() + && !((ExecutorService) EXECUTOR).isTerminated()) { + EXECUTOR.execute(runnable); + } + } else { + if (EXECUTOR != null) { + EXECUTOR.execute(runnable); + } + } + } + } + + /** + * Schedule the given {@link Runnable} to run the current workbench display + * thread. + * + * @param runnable + * The runnable to execute. + */ + public static void executeInUI(Runnable runnable) { + if (runnable != null) { + if (UI_EXECUTOR instanceof ExecutorService) { + if (!((ExecutorService) UI_EXECUTOR).isShutdown() + && !((ExecutorService) UI_EXECUTOR).isTerminated()) { + UI_EXECUTOR.execute(runnable); + } + } else { + if (UI_EXECUTOR != null) { + UI_EXECUTOR.execute(runnable); + } + } + } + } + + /** + * Waits either for the given condition tester to signal that the condition, + * the caller want's to wait for, has been completely fulfilled or till the + * timeout runs out. If the specified condition tester is <code>null</code>, + * the method will always wait till the timeout occurs. In case + * <code>timeout == 0</code> and <code>conditionTester == null</code>, the + * method returns immediately with the return value <code>true</code>! + * + * @param timeout + * The timeout to wait in milliseconds. <code>0</code> means + * infinite wait time! + * @param conditionTester + * The condition tester to use for checking the interrupt + * condition. + * + * @return <code>false</code> if the exit reason if that the waiting + * condition has been fulfilled, <code>true</code> if the exit + * reason is the timeout! + */ + public static boolean waitAndExecute(final long timeout, + final IConditionTester conditionTester) { + // both parameter are null, return immediately! + if (conditionTester == null && timeout == 0) + return true; + + // we assume that the exit reason will be the timeout + boolean exitReason = true; + + // Remember the executors utility delegate down the road. As long + // we don't leave the waitAndExecute method, the thread cannot change. + IExecutorUtilDelegate lastDelegate = null; + + // Remember the start time to calculate the timeout + final long startTime = System.currentTimeMillis(); + // keep going till either the condition tester or the timeout will + // break the loop! + while (true) { + if (conditionTester != null && conditionTester.isConditionFulfilled()) { + // the exit reason is the condition tester! + exitReason = false; + break; + } + if (timeout != 0 && ((System.currentTimeMillis() - startTime) >= timeout)) { + // timeout occurred, just break the loop + break; + } + // none of the break conditions are fulfilled, so wait a little bit + // before testing again. + if (isExecutorThread()) { + // We are in the executor thread. Keep the command dispatching running. + if (EXECUTOR instanceof INestableExecutor) { + ((INestableExecutor) EXECUTOR).readAndExecute(); + Thread.yield(); + } else { + throw new IllegalStateException("waitAndExecute called from within a non-nestable executor service!"); //$NON-NLS-1$ + } + } + // Check if we are in the UI executor thread + else if (isUIExecutorThread()) { + // We are in the executor thread. Keep the command dispatching + // running. + if (UI_EXECUTOR instanceof INestableExecutor) { + ((INestableExecutor) UI_EXECUTOR).readAndExecute(); + Thread.yield(); + } else { + throw new IllegalStateException("waitAndExecute called from within a non-nestable UI executor service!"); //$NON-NLS-1$ + } + } + // Check if we have a delegate contribution which is handling + // the current thread. + else { + boolean foundHandlingDelegate = false; + + if (lastDelegate == null) { + // Get all registered delegates + IExecutorUtilDelegate[] delegates = EXTENSION_POINT_MANAGER.getExecutorUtilDelegates(); + for (IExecutorUtilDelegate delegate : delegates) { + // Does the delegate handles the current thread? + if (delegate.isHandledExecutorThread()) { + foundHandlingDelegate = true; + lastDelegate = delegate; + // Read and dispatch one event + delegate.readAndDispatch(); + break; + } + } + } else { + foundHandlingDelegate = true; + // Read and dispatch one event + lastDelegate.readAndDispatch(); + } + + if (!foundHandlingDelegate) { + // Not in any executor thread, put the current thread to sleep + try { + Thread.sleep(10); + } catch (InterruptedException e) { /* ignored on purpose */ } + } + } + } + + // give the condition tester the chance to cleanup + if (conditionTester != null) { + conditionTester.cleanup(); + } + + return exitReason; + } +} |