diff options
Diffstat (limited to 'target_explorer/plugins/org.eclipse.tm.te.tcf.processes.core/src/org/eclipse/tm/te/tcf/processes')
12 files changed, 0 insertions, 2522 deletions
diff --git a/target_explorer/plugins/org.eclipse.tm.te.tcf.processes.core/src/org/eclipse/tm/te/tcf/processes/core/activator/CoreBundleActivator.java b/target_explorer/plugins/org.eclipse.tm.te.tcf.processes.core/src/org/eclipse/tm/te/tcf/processes/core/activator/CoreBundleActivator.java deleted file mode 100644 index 4dff9a5cd..000000000 --- a/target_explorer/plugins/org.eclipse.tm.te.tcf.processes.core/src/org/eclipse/tm/te/tcf/processes/core/activator/CoreBundleActivator.java +++ /dev/null @@ -1,72 +0,0 @@ -/*******************************************************************************
- * 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.tcf.processes.core.activator;
-
-import org.eclipse.tm.te.runtime.tracing.TraceHandler;
-import org.osgi.framework.BundleActivator;
-import org.osgi.framework.BundleContext;
-
-/**
- * The activator class controls the plug-in life cycle
- */
-public class CoreBundleActivator implements BundleActivator {
- // The bundle context
- private static BundleContext context;
- // The trace handler instance
- private static TraceHandler traceHandler;
-
- /**
- * Returns the bundle context
- *
- * @return the bundle context
- */
- public static BundleContext getContext() {
- return context;
- }
-
- /**
- * Convenience method which returns the unique identifier of this plugin.
- */
- public static String getUniqueIdentifier() {
- if (getContext() != null && getContext().getBundle() != null) {
- return getContext().getBundle().getSymbolicName();
- }
- return null;
- }
-
- /**
- * Returns the bundles trace handler.
- *
- * @return The bundles trace handler.
- */
- public static TraceHandler getTraceHandler() {
- if (traceHandler == null) {
- traceHandler = new TraceHandler(getUniqueIdentifier());
- }
- return traceHandler;
- }
-
- /* (non-Javadoc)
- * @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext)
- */
- @Override
- public void start(BundleContext bundleContext) throws Exception {
- CoreBundleActivator.context = bundleContext;
- }
-
- /* (non-Javadoc)
- * @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)
- */
- @Override
- public void stop(BundleContext bundleContext) throws Exception {
- CoreBundleActivator.context = null;
- }
-
-}
diff --git a/target_explorer/plugins/org.eclipse.tm.te.tcf.processes.core/src/org/eclipse/tm/te/tcf/processes/core/interfaces/launcher/IProcessContextAwareListener.java b/target_explorer/plugins/org.eclipse.tm.te.tcf.processes.core/src/org/eclipse/tm/te/tcf/processes/core/interfaces/launcher/IProcessContextAwareListener.java deleted file mode 100644 index 38c8048a1..000000000 --- a/target_explorer/plugins/org.eclipse.tm.te.tcf.processes.core/src/org/eclipse/tm/te/tcf/processes/core/interfaces/launcher/IProcessContextAwareListener.java +++ /dev/null @@ -1,32 +0,0 @@ -/******************************************************************************* - * 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.tcf.processes.core.interfaces.launcher; - -import org.eclipse.tcf.services.IProcesses; - -/** - * Remote process context aware listener. - */ -public interface IProcessContextAwareListener { - - /** - * Sets the process context. - * - * @param context The process context. Must not be <code>null</code>. - */ - public void setProcessContext(IProcesses.ProcessContext context); - - /** - * Returns the process context. - * - * @return The process context. - */ - public IProcesses.ProcessContext getProcessContext(); -} diff --git a/target_explorer/plugins/org.eclipse.tm.te.tcf.processes.core/src/org/eclipse/tm/te/tcf/processes/core/interfaces/launcher/IProcessLauncher.java b/target_explorer/plugins/org.eclipse.tm.te.tcf.processes.core/src/org/eclipse/tm/te/tcf/processes/core/interfaces/launcher/IProcessLauncher.java deleted file mode 100644 index 2d202c516..000000000 --- a/target_explorer/plugins/org.eclipse.tm.te.tcf.processes.core/src/org/eclipse/tm/te/tcf/processes/core/interfaces/launcher/IProcessLauncher.java +++ /dev/null @@ -1,114 +0,0 @@ -/******************************************************************************* - * 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.tcf.processes.core.interfaces.launcher; - -import java.util.Map; - -import org.eclipse.core.runtime.IAdaptable; -import org.eclipse.tcf.protocol.IPeer; -import org.eclipse.tm.te.runtime.interfaces.callback.ICallback; -import org.eclipse.tm.te.runtime.interfaces.properties.IPropertiesContainer; - -/** - * Interface to be implemented by classes providing a remote process launcher. - */ -public interface IProcessLauncher extends IAdaptable { - /** - * Property denoting the process image path. The process image path is the absolute remote path. - * <p> - * The property type is {@link String}. - */ - public static String PROP_PROCESS_PATH = "process.path"; //$NON-NLS-1$ - - /** - * Property denoting the process image path of a monitored application. The process image path - * is the absolute remote path. - * <p> - * <b>Note:</b> Optional: The monitored process path property might be set if the process path - * contains the image path of a monitoring application, like mpatrol. This property influence - * the terminal title construction only. - * <p> - * The property type is {@link String}. - */ - public static String PROP_PROCESS_MONITORED_PATH = "process.monitored.path"; //$NON-NLS-1$ - - /** - * Property denoting the process arguments. - * <p> - * <b>Note:</b> The arguments are passed as is to the launched remote process. In case of shell - * scripts, the client must assure that the first argument ($0) is the absolute process image - * path. - * <p> - * The property type is {@link String}[]. - */ - public static String PROP_PROCESS_ARGS = "process.args"; //$NON-NLS-1$ - - /** - * Property denoting the process working directory. - * <p> - * The property type is {@link String}. - */ - public static String PROP_PROCESS_CWD = "process.cwd"; //$NON-NLS-1$ - - /** - * Property denoting the process environment. - * <p> - * The property type is {@link Map}< {@link String}, {@link String} >. - */ - public static String PROP_PROCESS_ENV = "process.env"; //$NON-NLS-1$ - - /** - * Property denoting if the process is launched attached or not. - * <p> - * The property type is {@link Boolean}. - */ - public static String PROP_PROCESS_ATTACH = "process.attach"; //$NON-NLS-1$ - - /** - * Property denoting if the process is associated with an input/output console. - * <p> - * The property type is {@link Boolean}. - */ - public static String PROP_PROCESS_ASSOCIATE_CONSOLE = "process.associateConsole"; //$NON-NLS-1$ - - /** - * Property denoting if the process is redirecting it's output to an file. - * <p> - * The property type is {@link String}. - */ - public static String PROP_PROCESS_OUTPUT_REDIRECT_TO_FILE = "process.redirectToFile"; //$NON-NLS-1$ - - /** - * Property denoting the full name of the target connection the launcher got invoked for. - * <p> - * The property type is {@link String}. - */ - public static String PROP_CONNECTION_NAME = "connection.name"; //$NON-NLS-1$ - - /** - * Launch a remote process defined by the given launch properties at the target specified by the - * given peer. - * - * @param peer The peer. Must not be <code>null</code>. - * @param params The remote process properties. Must not be <code>null</code>. - * @param callback The callback or <code>null</code>. - */ - public void launch(IPeer peer, IPropertiesContainer properties, ICallback callback); - - /** - * Disposes the remote process launcher instance. - */ - public void dispose(); - - /** - * Terminates the launched remote process (if still running). - */ - public void terminate(); -} diff --git a/target_explorer/plugins/org.eclipse.tm.te.tcf.processes.core/src/org/eclipse/tm/te/tcf/processes/core/interfaces/launcher/IProcessStreamsProxy.java b/target_explorer/plugins/org.eclipse.tm.te.tcf.processes.core/src/org/eclipse/tm/te/tcf/processes/core/interfaces/launcher/IProcessStreamsProxy.java deleted file mode 100644 index ec23157d8..000000000 --- a/target_explorer/plugins/org.eclipse.tm.te.tcf.processes.core/src/org/eclipse/tm/te/tcf/processes/core/interfaces/launcher/IProcessStreamsProxy.java +++ /dev/null @@ -1,50 +0,0 @@ -/******************************************************************************* - * 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.tcf.processes.core.interfaces.launcher; - -import java.io.InputStream; -import java.io.OutputStream; - -import org.eclipse.tm.te.runtime.interfaces.callback.ICallback; - -/** - * An interface to be implemented by clients to receive the remote process I/O instead of the - * standard terminal console. - */ -public interface IProcessStreamsProxy { - - /** - * Connects the stream proxy with the output stream of the remote process. - * - * @param stream The stream connected to the remote process output stream, or <code>null</code>. - */ - public void connectOutputStreamMonitor(InputStream stream); - - /** - * Connects the stream proxy with the input stream of the remote process. - * - * @param stream The stream connected to the remote process input stream, or <code>null</code>. - */ - public void connectInputStreamMonitor(OutputStream stream); - - /** - * Connects the stream proxy with the error stream of the remote process. - * - * @param stream The stream connected to the remote process error stream, or <code>null</code>. - */ - public void connectErrorStreamMonitor(InputStream stream); - - /** - * Dispose the streams proxy instance. - * - * @param callback The callback to invoke or <code>null</code>. - */ - public void dispose(ICallback callback); -} diff --git a/target_explorer/plugins/org.eclipse.tm.te.tcf.processes.core/src/org/eclipse/tm/te/tcf/processes/core/internal/tracing/ITraceIds.java b/target_explorer/plugins/org.eclipse.tm.te.tcf.processes.core/src/org/eclipse/tm/te/tcf/processes/core/internal/tracing/ITraceIds.java deleted file mode 100644 index 74dc4a1c4..000000000 --- a/target_explorer/plugins/org.eclipse.tm.te.tcf.processes.core/src/org/eclipse/tm/te/tcf/processes/core/internal/tracing/ITraceIds.java +++ /dev/null @@ -1,31 +0,0 @@ -/******************************************************************************* - * 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.tcf.processes.core.internal.tracing; - -/** - * Core plug-in trace slot identifiers. - */ -public interface ITraceIds { - - /** - * If activated, tracing information about the remote process launcher is printed out. - */ - public static final String TRACE_PROCESS_LAUNCHER = "trace/processLauncher"; //$NON-NLS-1$ - - /** - * If activated, tracing information about the remote processes listener is printed out. - */ - public static final String TRACE_PROCESSES_LISTENER = "trace/processesListener"; //$NON-NLS-1$ - - /** - * If activated, tracing information about the remote processes streams listener is printed out. - */ - public static final String TRACE_STREAMS_LISTENER = "trace/streamsListener"; //$NON-NLS-1$ -} diff --git a/target_explorer/plugins/org.eclipse.tm.te.tcf.processes.core/src/org/eclipse/tm/te/tcf/processes/core/launcher/ProcessLauncher.java b/target_explorer/plugins/org.eclipse.tm.te.tcf.processes.core/src/org/eclipse/tm/te/tcf/processes/core/launcher/ProcessLauncher.java deleted file mode 100644 index 05097371e..000000000 --- a/target_explorer/plugins/org.eclipse.tm.te.tcf.processes.core/src/org/eclipse/tm/te/tcf/processes/core/launcher/ProcessLauncher.java +++ /dev/null @@ -1,1000 +0,0 @@ -/******************************************************************************* - * 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.tcf.processes.core.launcher; - -import java.io.BufferedWriter; -import java.io.FileWriter; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.OutputStream; -import java.io.OutputStreamWriter; -import java.io.PipedInputStream; -import java.io.PipedOutputStream; -import java.text.DateFormat; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.atomic.AtomicReference; - -import org.eclipse.core.runtime.Assert; -import org.eclipse.core.runtime.IPath; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.Path; -import org.eclipse.core.runtime.Platform; -import org.eclipse.core.runtime.PlatformObject; -import org.eclipse.core.runtime.Status; -import org.eclipse.osgi.util.NLS; -import org.eclipse.tcf.protocol.IChannel; -import org.eclipse.tcf.protocol.IChannel.IChannelListener; -import org.eclipse.tcf.protocol.IPeer; -import org.eclipse.tcf.protocol.IToken; -import org.eclipse.tcf.protocol.Protocol; -import org.eclipse.tcf.services.IProcesses; -import org.eclipse.tcf.services.IProcesses.ProcessContext; -import org.eclipse.tcf.services.IStreams; -import org.eclipse.tm.te.core.async.AsyncCallbackCollector; -import org.eclipse.tm.te.runtime.callback.Callback; -import org.eclipse.tm.te.runtime.events.DisposedEvent; -import org.eclipse.tm.te.runtime.events.EventManager; -import org.eclipse.tm.te.runtime.interfaces.callback.ICallback; -import org.eclipse.tm.te.runtime.interfaces.events.IEventListener; -import org.eclipse.tm.te.runtime.interfaces.properties.IPropertiesContainer; -import org.eclipse.tm.te.runtime.properties.PropertiesContainer; -import org.eclipse.tm.te.runtime.services.ServiceManager; -import org.eclipse.tm.te.runtime.services.interfaces.ITerminalService; -import org.eclipse.tm.te.runtime.services.interfaces.constants.ITerminalsConnectorConstants; -import org.eclipse.tm.te.tcf.core.Tcf; -import org.eclipse.tm.te.tcf.core.interfaces.IChannelManager; -import org.eclipse.tm.te.tcf.core.streams.StreamsDataProvider; -import org.eclipse.tm.te.tcf.core.streams.StreamsDataReceiver; -import org.eclipse.tm.te.tcf.processes.core.activator.CoreBundleActivator; -import org.eclipse.tm.te.tcf.processes.core.interfaces.launcher.IProcessContextAwareListener; -import org.eclipse.tm.te.tcf.processes.core.interfaces.launcher.IProcessLauncher; -import org.eclipse.tm.te.tcf.processes.core.interfaces.launcher.IProcessStreamsProxy; -import org.eclipse.tm.te.tcf.processes.core.internal.tracing.ITraceIds; -import org.eclipse.tm.te.tcf.processes.core.nls.Messages; - -/** - * Remote process launcher. - * <p> - * The process launcher is implemented fully asynchronous. - */ -public class ProcessLauncher extends PlatformObject implements IProcessLauncher { - // The backend channel instance - /* default */ IChannel channel; - // The process properties instance - private IPropertiesContainer properties; - - // The processes service instance - /* default */ IProcesses svcProcesses; - // The streams service instance - /* default */ IStreams svcStreams; - // The remote process context - /* default */ IProcesses.ProcessContext processContext; - - // The callback instance - private ICallback callback; - - // The streams listener instance - private IStreams.StreamsListener streamsListener = null; - // The process listener instance - private IProcesses.ProcessesListener processesListener = null; - // The event listener instance - private IEventListener eventListener = null; - - // The streams proxy instance - private IProcessStreamsProxy streamsProxy = null; - - /** - * Constructor. - */ - public ProcessLauncher() { - this(null); - } - - /** - * Constructor. - */ - public ProcessLauncher(IProcessStreamsProxy streamsProxy) { - super(); - this.streamsProxy = streamsProxy; - } - - /* (non-Javadoc) - * @see org.eclipse.tm.te.tcf.processes.core.interfaces.launcher.IProcessLauncher#dispose() - */ - @Override - public void dispose() { - // Unlink the process context - processContext = null; - - // Store a final reference to the channel instance - final IChannel finChannel = channel; - - // Remove the notification listener - if (eventListener != null) { - EventManager.getInstance().removeEventListener(eventListener); - eventListener = null; - } - - // Create the callback invocation delegate - AsyncCallbackCollector.ICallbackInvocationDelegate delegate = new AsyncCallbackCollector.ICallbackInvocationDelegate() { - @Override - public void invoke(Runnable runnable) { - Assert.isNotNull(runnable); - if (Protocol.isDispatchThread()) runnable.run(); - else Protocol.invokeLater(runnable); - } - }; - - // Create the callback collector - final AsyncCallbackCollector collector = new AsyncCallbackCollector(new Callback() { - @Override - protected void internalDone(Object caller, IStatus status) { - Assert.isTrue(Protocol.isDispatchThread(), "Illegal Thread Access"); //$NON-NLS-1$ - // Close the channel as all disposal is done - if (finChannel != null) finChannel.close(); - } - }, delegate); - - if (streamsListener != null) { - // Dispose the streams listener - if (streamsListener instanceof ProcessStreamsListener) { - ((ProcessStreamsListener)streamsListener).dispose(new AsyncCallbackCollector.SimpleCollectorCallback(collector)); - } - streamsListener = null; - } - - // Dispose the processes listener if created - if (processesListener != null) { - // Dispose the processes listener - if (processesListener instanceof ProcessProcessesListener) { - ((ProcessProcessesListener)processesListener).dispose(new AsyncCallbackCollector.SimpleCollectorCallback(collector)); - } - processesListener = null; - // Remove the processes listener from the processes service - getSvcProcesses().removeListener(processesListener); - } - - // Dispose the streams proxy if created - if (streamsProxy != null) { - streamsProxy.dispose(new AsyncCallbackCollector.SimpleCollectorCallback(collector)); - streamsProxy = null; - } - // Mark the collector initialization as done - collector.initDone(); - - // Dissociate the channel - channel = null; - } - - /* (non-Javadoc) - * @see org.eclipse.tm.te.tcf.processes.core.interfaces.launcher.IProcessLauncher#terminate() - */ - @Override - public void terminate() { - Runnable runnable = new Runnable() { - @Override - public void run() { - if (processContext != null && processContext.canTerminate()) { - // Try to terminate the process the usual way first (sending SIGTERM) - processContext.terminate(new IProcesses.DoneCommand() { - @Override - public void doneCommand(IToken token, Exception error) { - onTerminateDone(processContext, error); - } - }); - } - - } - }; - - if (Protocol.isDispatchThread()) runnable.run(); - else Protocol.invokeAndWait(runnable); - } - - /** - * Check if the process context really died after sending SIGTERM. - * <p> - * Called from {@link #terminate()}. - * - * @param context The process context. Must not be <code>null</code>. - * @param error The exception in case {@link #terminate()} returned with an error or <code>null</code>. - */ - protected void onTerminateDone(IProcesses.ProcessContext context, Exception error) { - Assert.isNotNull(context); - - // If the terminate of the remote process context failed, give a warning to the user - if (error != null) { - String message = NLS.bind(Messages.ProcessLauncher_error_processTerminateFailed, context.getName()); - message += NLS.bind(Messages.ProcessLauncher_error_possibleCause, error.getLocalizedMessage()); - - IStatus status = new Status(IStatus.WARNING, CoreBundleActivator.getUniqueIdentifier(), message, error); - Platform.getLog(CoreBundleActivator.getContext().getBundle()).log(status); - - // Dispose the launcher directly - dispose(); - } - // No error from terminate, this does not mean that the process went down - // really -> SIGTERM might have been ignored from the process! - else { - final IProcesses.ProcessContext finContext = context; - // Let's see if we can still get information about the context - getSvcProcesses().getContext(context.getID(), new IProcesses.DoneGetContext() { - @Override - public void doneGetContext(IToken token, Exception error, ProcessContext context) { - // In case there is no error and we do get back an process context, - // the process must be still running, having ignored the SIGTERM. - if (error == null && context != null && context.getID().equals(finContext.getID())) { - // Let's send a SIGHUP next. - getSvcProcesses().signal(context.getID(), 15, new IProcesses.DoneCommand() { - @Override - public void doneCommand(IToken token, Exception error) { - onSignalSIGHUPDone(finContext, error); - } - }); - } - } - }); - } - } - - /** - * Check if the process context died after sending SIGHUP. - * <p> - * Called from {@link #onTerminateDone(IProcesses.ProcessContext, Exception)}. - * - * @param context The process context. Must not be <code>null</code>. - * @param error The exception in case sending the signal returned with an error or <code>null</code>. - */ - protected void onSignalSIGHUPDone(IProcesses.ProcessContext context, Exception error) { - Assert.isNotNull(context); - - // If the terminate of the remote process context failed, give a warning to the user - if (error != null) { - String message = NLS.bind(Messages.ProcessLauncher_error_processSendSignalFailed, "SIGHUP(15)", context.getName()); //$NON-NLS-1$ - message += NLS.bind(Messages.ProcessLauncher_error_possibleCause, error.getLocalizedMessage()); - - IStatus status = new Status(IStatus.WARNING, CoreBundleActivator.getUniqueIdentifier(), message, error); - Platform.getLog(CoreBundleActivator.getContext().getBundle()).log(status); - - // Dispose the launcher directly - dispose(); - } - // No error from terminate, this does not mean that the process went down - // really -> SIGTERM might have been ignored from the process! - else { - final IProcesses.ProcessContext finContext = context; - // Let's see if we can still get information about the context - getSvcProcesses().getContext(context.getID(), new IProcesses.DoneGetContext() { - @Override - public void doneGetContext(IToken token, Exception error, ProcessContext context) { - // In case there is no error and we do get back an process context, - // the process must be still running, having ignored the SIGHUP. - if (error == null && context != null && context.getID().equals(finContext.getID())) { - // Finally send a SIGKILL. - getSvcProcesses().signal(context.getID(), 9, new IProcesses.DoneCommand() { - @Override - public void doneCommand(IToken token, Exception error) { - if (error != null) { - String message = NLS.bind(Messages.ProcessLauncher_error_processSendSignalFailed, "SIGKILL(15)", finContext.getName()); //$NON-NLS-1$ - message += NLS.bind(Messages.ProcessLauncher_error_possibleCause, error.getLocalizedMessage()); - - IStatus status = new Status(IStatus.WARNING, CoreBundleActivator.getUniqueIdentifier(), message, error); - Platform.getLog(CoreBundleActivator.getContext().getBundle()).log(status); - - // Dispose the launcher directly - dispose(); - } - } - }); - } - } - }); - } - } - - /* (non-Javadoc) - * @see org.eclipse.tm.te.tcf.processes.core.interfaces.launcher.IProcessLauncher#launch(org.eclipse.tcf.protocol.IPeer, org.eclipse.tm.te.runtime.interfaces.properties.IPropertiesContainer, org.eclipse.tm.te.runtime.interfaces.callback.ICallback) - */ - @Override - public void launch(final IPeer peer, final IPropertiesContainer properties, final ICallback callback) { - Assert.isNotNull(peer); - Assert.isNotNull(properties); - - // Normalize the callback - if (callback == null) { - this.callback = new Callback() { - /* (non-Javadoc) - * @see org.eclipse.tm.te.runtime.callback.Callback#internalDone(java.lang.Object, org.eclipse.core.runtime.IStatus) - */ - @Override - public void internalDone(Object caller, IStatus status) { - } - }; - } - else { - this.callback = callback; - } - - // Remember the process properties - this.properties = properties; - - // Open a channel to the given peer - Tcf.getChannelManager().openChannel(peer, new IChannelManager.DoneOpenChannel() { - /* (non-Javadoc) - * @see org.eclipse.tm.te.tcf.core.interfaces.IChannelManager.DoneOpenChannel#doneOpenChannel(java.lang.Throwable, org.eclipse.tcf.protocol.IChannel) - */ - @Override - public void doneOpenChannel(Throwable error, IChannel channel) { - if (error == null) { - ProcessLauncher.this.channel = channel; - - // Attach a channel listener so we can dispose ourself if the channel - // is closed from the remote side. - channel.addChannelListener(new IChannelListener() { - /* (non-Javadoc) - * @see org.eclipse.tcf.protocol.IChannel.IChannelListener#onChannelOpened() - */ - @Override - public void onChannelOpened() { - } - /* (non-Javadoc) - * @see org.eclipse.tcf.protocol.IChannel.IChannelListener#onChannelClosed(java.lang.Throwable) - */ - @Override - public void onChannelClosed(Throwable error) { - if (error != null) { - IStatus status = new Status(IStatus.ERROR, CoreBundleActivator.getUniqueIdentifier(), - NLS.bind(Messages.ProcessLauncher_error_channelConnectFailed, peer.getID(), error.getLocalizedMessage()), - error); - invokeCallback(status, null); - } - } - /* (non-Javadoc) - * @see org.eclipse.tcf.protocol.IChannel.IChannelListener#congestionLevel(int) - */ - @Override - public void congestionLevel(int level) { - } - }); - - - // Check if the channel is in connected state - if (channel.getState() != IChannel.STATE_OPEN) { - IStatus status = new Status(IStatus.ERROR, CoreBundleActivator.getUniqueIdentifier(), - Messages.ProcessLauncher_error_channelNotConnected, - new IllegalStateException()); - invokeCallback(status, null); - return; - } - - // Do some very basic sanity checking on the process properties - if (properties.getStringProperty(PROP_PROCESS_PATH) == null) { - IStatus status = new Status(IStatus.ERROR, CoreBundleActivator.getUniqueIdentifier(), - Messages.ProcessLauncher_error_missingProcessPath, - new IllegalArgumentException(PROP_PROCESS_PATH)); - invokeCallback(status, null); - return; - } - - // Get the process and streams services - svcProcesses = channel.getRemoteService(IProcesses.class); - if (svcProcesses == null) { - IStatus status = new Status(IStatus.ERROR, CoreBundleActivator.getUniqueIdentifier(), - NLS.bind(Messages.ProcessLauncher_error_missingRequiredService, IProcesses.class.getName()), - null); - - invokeCallback(status, null); - return; - } - - svcStreams = channel.getRemoteService(IStreams.class); - if (svcStreams == null) { - IStatus status = new Status(IStatus.ERROR, CoreBundleActivator.getUniqueIdentifier(), - NLS.bind(Messages.ProcessLauncher_error_missingRequiredService, IStreams.class.getName()), - null); - invokeCallback(status, null); - return; - } - - // Execute the launch now - executeLaunch(); - } else { - IStatus status = new Status(IStatus.ERROR, CoreBundleActivator.getUniqueIdentifier(), - NLS.bind(Messages.ProcessLauncher_error_channelConnectFailed, peer.getID(), error.getLocalizedMessage()), - error); - invokeCallback(status, null); - } - } - }); - } - - /** - * Executes the launch of the remote process. - */ - protected void executeLaunch() { - // Get the process properties container - final IPropertiesContainer properties = getProperties(); - if (properties == null) { - // This is an illegal argument. Properties must be set - IStatus status = new Status(IStatus.ERROR, CoreBundleActivator.getUniqueIdentifier(), - NLS.bind(Messages.ProcessLauncher_error_illegalNullArgument, "properties"), //$NON-NLS-1$ - new IllegalArgumentException()); - invokeCallback(status, null); - return; - } - - // If a console should be associated, a streams listener needs to be created - if (properties.getBooleanProperty(IProcessLauncher.PROP_PROCESS_ASSOCIATE_CONSOLE) - || properties.getStringProperty(IProcessLauncher.PROP_PROCESS_OUTPUT_REDIRECT_TO_FILE) != null) { - // Create the streams listener - streamsListener = createStreamsListener(); - // If available, we need to subscribe to the streams. - if (streamsListener != null) { - getSvcStreams().subscribe(IProcesses.NAME, streamsListener, new IStreams.DoneSubscribe() { - @Override - public void doneSubscribe(IToken token, Exception error) { - // In case the subscribe to the stream fails, we pass on - // the error to the user and stop the launch - if (error != null) { - // Construct the error message to show to the user - String message = NLS.bind(Messages.ProcessLauncher_error_processLaunchFailed, - properties.getStringProperty(IProcessLauncher.PROP_PROCESS_PATH), - makeString((String[])properties.getProperty(IProcessLauncher.PROP_PROCESS_ARGS))); - message += NLS.bind(Messages.ProcessLauncher_error_possibleCause, Messages.ProcessLauncher_cause_subscribeFailed); - - // Construct the status object - IStatus status = new Status(IStatus.ERROR, CoreBundleActivator.getUniqueIdentifier(), message, error); - invokeCallback(status, null); - } else { - // Initialize the console or output file - onSubscribeStreamsDone(); - } - } - }); - } else { - // No streams to attach to -> go directly to the process launch - onAttachStreamsDone(); - } - } else { - // No streams to attach to -> go directly to the process launch - onAttachStreamsDone(); - } - } - - /** - * Initialize and attach the output console and/or the output file. - * <p> - * Called from {@link IStreams#subscribe(String, org.eclipse.tcf.services.IStreams.StreamsListener, org.eclipse.tcf.services.IStreams.DoneSubscribe)}. - */ - protected void onSubscribeStreamsDone() { - // Get the process properties container - IPropertiesContainer properties = getProperties(); - if (properties == null) { - // This is an illegal argument. Properties must be set - IStatus status = new Status(IStatus.ERROR, CoreBundleActivator.getUniqueIdentifier(), - NLS.bind(Messages.ProcessLauncher_error_illegalNullArgument, "properties"), //$NON-NLS-1$ - new IllegalArgumentException()); - invokeCallback(status, null); - return; - } - - // The streams got subscribed, check if we shall attach the console - if (properties.getBooleanProperty(IProcessLauncher.PROP_PROCESS_ASSOCIATE_CONSOLE)) { - // If no specific streams proxy is set, the output redirection will default - // to the standard terminals console view - if (streamsProxy == null) { - // Register the notification listener to listen to the console disposal - eventListener = new ProcessLauncherEventListener(this); - EventManager.getInstance().addEventListener(eventListener, DisposedEvent.class); - - // Get the terminal service - ITerminalService terminal = ServiceManager.getInstance().getService(ITerminalService.class); - // If not available, we cannot fulfill this request - if (terminal != null) { - // Create the terminal streams settings - PropertiesContainer props = new PropertiesContainer(); - props.setProperty(ITerminalsConnectorConstants.PROP_CONNECTOR_TYPE_ID, "org.eclipse.tm.te.ui.terminals.type.streams"); //$NON-NLS-1$ - props.setProperty(ITerminalsConnectorConstants.PROP_ID, "org.eclipse.tm.te.ui.terminals.TerminalsView"); //$NON-NLS-1$ - // Set the terminal tab title - String terminalTitle = getTerminalTitle(); - if (terminalTitle != null) { - props.setProperty(ITerminalsConnectorConstants.PROP_TITLE, terminalTitle); - } - - // Create and store the streams which will be connected to the terminals stdin - props.setProperty(ITerminalsConnectorConstants.PROP_STREAMS_STDIN, connectRemoteOutputStream(getStreamsListener(), new String[] { IProcesses.PROP_STDIN_ID })); - // Create and store the streams the terminal will see as stdout - props.setProperty(ITerminalsConnectorConstants.PROP_STREAMS_STDOUT, connectRemoteInputStream(getStreamsListener(), new String[] { IProcesses.PROP_STDOUT_ID })); - // Create and store the streams the terminal will see as stderr - props.setProperty(ITerminalsConnectorConstants.PROP_STREAMS_STDERR, connectRemoteInputStream(getStreamsListener(), new String[] { IProcesses.PROP_STDERR_ID })); - - // Copy the terminal properties - props.setProperty(ITerminalsConnectorConstants.PROP_LOCAL_ECHO, properties.getBooleanProperty(ITerminalsConnectorConstants.PROP_LOCAL_ECHO)); - props.setProperty(ITerminalsConnectorConstants.PROP_LINE_SEPARATOR, properties.getStringProperty(ITerminalsConnectorConstants.PROP_LINE_SEPARATOR)); - - // The custom data object is the process launcher itself - props.setProperty(ITerminalsConnectorConstants.PROP_DATA, this); - - // Open the console - terminal.openConsole(props, null); - } - } else { - // Create and connect the streams which will be connected to the terminals stdin - streamsProxy.connectInputStreamMonitor(connectRemoteOutputStream(getStreamsListener(), new String[] { IProcesses.PROP_STDIN_ID })); - // Create and store the streams the terminal will see as stdout - streamsProxy.connectOutputStreamMonitor(connectRemoteInputStream(getStreamsListener(), new String[] { IProcesses.PROP_STDOUT_ID })); - // Create and store the streams the terminal will see as stderr - streamsProxy.connectErrorStreamMonitor(connectRemoteInputStream(getStreamsListener(), new String[] { IProcesses.PROP_STDERR_ID })); - } - } - - // The streams got subscribed, check if we shall configure the output redirection to a file - if (properties.getStringProperty(IProcessLauncher.PROP_PROCESS_OUTPUT_REDIRECT_TO_FILE) != null) { - // Get the file name where to redirect the process output to - String filename = properties.getStringProperty(IProcessLauncher.PROP_PROCESS_OUTPUT_REDIRECT_TO_FILE); - try { - // Create the receiver instance. If the file already exist, we - // overwrite the file content. - StreamsDataReceiver receiver = new StreamsDataReceiver(new BufferedWriter(new FileWriter(filename)), - new String[] { IProcesses.PROP_STDOUT_ID, IProcesses.PROP_STDERR_ID }); - // Register the receiver to the streams listener - if (getStreamsListener() instanceof ProcessStreamsListener) { - ((ProcessStreamsListener)getStreamsListener()).registerDataReceiver(receiver); - } - } catch (IOException e) { - // Construct the error message to show to the user - String message = NLS.bind(Messages.ProcessLauncher_error_processLaunchFailed, - properties.getStringProperty(IProcessLauncher.PROP_PROCESS_PATH), - makeString((String[])properties.getProperty(IProcessLauncher.PROP_PROCESS_ARGS))); - message += NLS.bind(Messages.ProcessLauncher_error_possibleCause, - e.getLocalizedMessage() != null ? e.getLocalizedMessage() : Messages.ProcessLauncher_cause_ioexception); - - // Construct the status object - IStatus status = new Status(IStatus.ERROR, CoreBundleActivator.getUniqueIdentifier(), message, e); - invokeCallback(status, null); - } - } - - // Launch the process - onAttachStreamsDone(); - } - - /** - * Returns the terminal title string. - * <p> - * The default implementation constructs a title like "<process> (Start time) [channel name]". - * - * @return The terminal title string or <code>null</code>. - */ - protected String getTerminalTitle() { - if (properties == null) { - return null; - } - - StringBuilder title = new StringBuilder(); - - IPath processPath = new Path(properties.getStringProperty(IProcessLauncher.PROP_PROCESS_PATH)); - IPath monitoredProcessPath = null; - if (properties.getStringProperty(IProcessLauncher.PROP_PROCESS_MONITORED_PATH) != null) { - monitoredProcessPath = new Path(properties.getStringProperty(IProcessLauncher.PROP_PROCESS_MONITORED_PATH)); - } - - // In case, we do have a monitored process path here, we construct the title - // as <monitor_app_basename>: <monitored_app>" - if (monitoredProcessPath != null) { - title.append(processPath.lastSegment()); - title.append(": "); //$NON-NLS-1$ - processPath = monitoredProcessPath; - } - - // Avoid very long terminal title's by shortening the path if it has more than 3 segments - if (processPath.segmentCount() > 3) { - title.append(".../"); //$NON-NLS-1$ - title.append(processPath.lastSegment()); - } else { - title.append(processPath.toString()); - } - - // Get the peer name - final AtomicReference<String> peerName = new AtomicReference<String>(getProperties().getStringProperty(IProcessLauncher.PROP_CONNECTION_NAME)); - if (peerName.get() == null) { - // Query the peer from the open channel - Runnable runnable = new Runnable() { - @Override - public void run() { - if (channel != null) { - peerName.set(channel.getRemotePeer().getName()); - } - } - }; - - if (Protocol.isDispatchThread()) runnable.run(); - else Protocol.invokeAndWait(runnable); - } - - if (peerName.get() != null) { - title.append(" [").append(peerName.get()).append("]"); //$NON-NLS-1$ //$NON-NLS-2$ - } - - DateFormat format = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG); - String date = format.format(new Date(System.currentTimeMillis())); - title.append(" (").append(date).append(")"); //$NON-NLS-1$ //$NON-NLS-2$ - - return title.toString(); - } - - /** - * Connects the given stream id's to a local {@link InputStream} instance. - * - * @param streamsListener The streams listener. Must not be <code>null</code>. - * @param streamIds The stream id's. Must not be <code>null</code>. - * - * @return The local input stream instance or <code>null</code>. - */ - protected InputStream connectRemoteInputStream(IStreams.StreamsListener streamsListener, String[] streamIds) { - Assert.isNotNull(streamsListener); - Assert.isNotNull(streamIds); - - InputStream stream = null; - - // Create the output stream receiving the data from remote - PipedOutputStream remoteStreamDataReceiverStream = new PipedOutputStream(); - // Create the piped input stream instance - try { stream = new PipedInputStream(remoteStreamDataReceiverStream); } catch (IOException e) { /* ignored on purpose */ } - - // If the input stream creation succeeded, connect the data receiver - if (stream != null) { - StreamsDataReceiver receiver = new StreamsDataReceiver(new OutputStreamWriter(remoteStreamDataReceiverStream), streamIds); - // Register the data receiver to the streams listener - if (getStreamsListener() instanceof ProcessStreamsListener) { - ((ProcessStreamsListener)getStreamsListener()).registerDataReceiver(receiver); - } - } - - return stream; - } - - /** - * Connects the given stream id's to a local {@link OutputStream} instance. - * - * @param streamsListener The streams listener. Must not be <code>null</code>. - * @param streamIds The stream id's. Must not be <code>null</code>. - * - * @return The local output stream instance or <code>null</code>. - */ - protected OutputStream connectRemoteOutputStream(IStreams.StreamsListener streamsListener, String[] streamIds) { - Assert.isNotNull(streamsListener); - Assert.isNotNull(streamIds); - - PipedInputStream inStream = null; - - // Create the output stream receiving the data from local - PipedOutputStream stream = new PipedOutputStream(); - // Create the piped input stream instance - try { inStream = new PipedInputStream(stream); } catch (IOException e) { stream = null; } - - // If the stream creation succeeded, connect the data provider - if (stream != null && inStream != null) { - StreamsDataProvider provider = new StreamsDataProvider(new InputStreamReader(inStream), streamIds); - // Register the data provider to the streams listener - if (getStreamsListener() instanceof ProcessStreamsListener) { - ((ProcessStreamsListener)getStreamsListener()).setDataProvider(provider); - } - } - - return stream; - } - - /** - * Queries the initial new process environment from remote. - */ - protected void onAttachStreamsDone() { - // Query the default environment for a new process - getSvcProcesses().getEnvironment(new IProcesses.DoneGetEnvironment() { - @Override - public void doneGetEnvironment(IToken token, Exception error, Map<String, String> environment) { - if (error != null) { - // Construct the error message to show to the user - String message = Messages.ProcessLauncher_error_getEnvironmentFailed; - message += NLS.bind(Messages.ProcessLauncher_error_possibleCause, - error.getLocalizedMessage() != null ? error.getLocalizedMessage() : Messages.ProcessLauncher_cause_startFailed); - - // Construct the status object - IStatus status = new Status(IStatus.ERROR, CoreBundleActivator.getUniqueIdentifier(), message, error); - invokeCallback(status, null); - } else { - // Initiate the process launch - onGetEnvironmentDone(environment); - } - } - }); - } - - /** - * Initiate the process launch. - * <p> - * Called from {@link #executeLaunch()} or {@link #onAttachStreamsDone()}. - */ - protected void onGetEnvironmentDone(final Map<String, String> environment) { - // Get the process properties container - final IPropertiesContainer properties = getProperties(); - if (properties == null) { - // This is an illegal argument. Properties must be set - IStatus status = new Status(IStatus.ERROR, CoreBundleActivator.getUniqueIdentifier(), - NLS.bind(Messages.ProcessLauncher_error_illegalNullArgument, "properties"), //$NON-NLS-1$ - new IllegalArgumentException()); - invokeCallback(status, null); - return; - } - - // Create the process listener - processesListener = createProcessesListener(); - if (processesListener != null) { - getSvcProcesses().addListener(processesListener); - } - - // Get the process attributes - String processPath = properties.getStringProperty(IProcessLauncher.PROP_PROCESS_PATH); - - String[] processArgs = (String[])properties.getProperty(IProcessLauncher.PROP_PROCESS_ARGS); - // Assure that the first argument is the process path itself - if (!(processArgs != null && processArgs.length > 0 && processPath.equals(processArgs[0]))) { - // Prepend the process path to the list of arguments - List<String> args = processArgs != null ? new ArrayList<String>(Arrays.asList(processArgs)) : new ArrayList<String>(); - args.add(0, processPath); - processArgs = args.toArray(new String[args.size()]); - } - - String processCWD = properties.getStringProperty(IProcessLauncher.PROP_PROCESS_CWD); - // If the process working directory is not explicitly set, default to the process path directory - if (processCWD == null || "".equals(processCWD.trim())) { //$NON-NLS-1$ - processCWD = new Path(processPath).removeLastSegments(1).toString(); - } - - // Merge the initial process environment and the desired process environment - Map<String, String> processEnv = new HashMap<String, String>(environment); - Map<String, String> processEnvDiff = (Map<String, String>)properties.getProperty(IProcessLauncher.PROP_PROCESS_ENV); - if (processEnvDiff != null && !processEnvDiff.isEmpty()) { - processEnv.putAll(processEnvDiff); - } - // Assure that the TERM variable is set to "ansi" - processEnv.put("TERM", "ansi"); //$NON-NLS-1$ //$NON-NLS-2$ - - boolean attach = properties.getBooleanProperty(IProcessLauncher.PROP_PROCESS_ATTACH); - - // Launch the remote process - getSvcProcesses().start(processCWD, processPath, processArgs, processEnv, attach, new IProcesses.DoneStart() { - @Override - public void doneStart(IToken token, Exception error, ProcessContext process) { - if (error != null) { - // Construct the error message to show to the user - String message = NLS.bind(Messages.ProcessLauncher_error_processLaunchFailed, - properties.getStringProperty(IProcessLauncher.PROP_PROCESS_PATH), - makeString((String[])properties.getProperty(IProcessLauncher.PROP_PROCESS_ARGS))); - message += NLS.bind(Messages.ProcessLauncher_error_possibleCause, - error.getLocalizedMessage() != null ? error.getLocalizedMessage() : Messages.ProcessLauncher_cause_startFailed); - - // Construct the status object - IStatus status = new Status(IStatus.ERROR, CoreBundleActivator.getUniqueIdentifier(), message, error); - invokeCallback(status, null); - } else { - // Register the process context to the listener - onProcessLaunchDone(process); - } - } - }); - } - - /** - * Register the process context to the listeners. - * - * @param process The process context or <code>null</code>. - */ - protected void onProcessLaunchDone(ProcessContext process) { - // Register the process context with the listeners - if (process != null) { - if (CoreBundleActivator.getTraceHandler().isSlotEnabled(0, ITraceIds.TRACE_PROCESS_LAUNCHER)) { - CoreBundleActivator.getTraceHandler().trace("Process context created: id='" + process.getID() + "', name='" + process.getName() + "'", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ - 0, ITraceIds.TRACE_PROCESS_LAUNCHER, IStatus.INFO, getClass()); - } - - // Remember the process context - processContext = process; - - // Push the process context to the listeners - if (getStreamsListener() instanceof IProcessContextAwareListener) { - ((IProcessContextAwareListener)getStreamsListener()).setProcessContext(process); - } - if (getProcessesListener() instanceof IProcessContextAwareListener) { - ((IProcessContextAwareListener)getProcessesListener()).setProcessContext(process); - } - - // Send a notification - ProcessStateChangeEvent event = createRemoteProcessStateChangeEvent(process); - if (event != null) EventManager.getInstance().fireEvent(event); - } - - // Invoke the callback to signal that we are done - invokeCallback(Status.OK_STATUS, process); - } - - /** - * Creates a new remote process state change event instance. - * - * @param context The process context. Must not be <code>null</code>. - * @return The event instance or <code>null</code>. - */ - protected ProcessStateChangeEvent createRemoteProcessStateChangeEvent(IProcesses.ProcessContext context) { - Assert.isNotNull(context); - return new ProcessStateChangeEvent(context, ProcessStateChangeEvent.EVENT_PROCESS_CREATED, Boolean.FALSE, Boolean.TRUE, -1); - } - - /** - * Invoke the callback with the given parameters. If the given status severity - * is {@link IStatus#ERROR}, the process launcher object is disposed automatically. - * - * @param status The status. Must not be <code>null</code>. - * @param result The result object or <code>null</code>. - */ - protected void invokeCallback(IStatus status, Object result) { - // Dispose the process launcher if we report an error - if (status.getSeverity() == IStatus.ERROR) { - dispose(); - } - - // Invoke the callback - ICallback callback = getCallback(); - if (callback != null) { - callback.setResult(result); - callback.done(this, status); - } - } - - /** - * Returns the channel instance. - * - * @return The channel instance or <code>null</code> if none. - */ - public final IChannel getChannel() { - return channel; - } - - /** - * Returns the process properties container. - * - * @return The process properties container or <code>null</code> if none. - */ - public final IPropertiesContainer getProperties() { - return properties; - } - - /** - * Returns the processes service instance. - * - * @return The processes service instance or <code>null</code> if none. - */ - public final IProcesses getSvcProcesses() { - return svcProcesses; - } - - /** - * Returns the streams service instance. - * - * @return The streams service instance or <code>null</code> if none. - */ - public final IStreams getSvcStreams() { - return svcStreams; - } - - /** - * Returns the callback instance. - * - * @return The callback instance or <code>null</code> if none. - */ - protected final ICallback getCallback() { - return callback; - } - - /** - * Create the streams listener instance. - * - * @return The streams listener instance or <code>null</code> if none. - */ - protected IStreams.StreamsListener createStreamsListener() { - return new ProcessStreamsListener(this); - } - - /** - * Returns the streams listener instance. - * - * @return The streams listener instance or <code>null</code>. - */ - protected final IStreams.StreamsListener getStreamsListener() { - return streamsListener; - } - - /** - * Create the processes listener instance. - * - * @return The processes listener instance or <code>null</code> if none. - */ - protected IProcesses.ProcessesListener createProcessesListener() { - return new ProcessProcessesListener(this); - } - - /** - * Returns the processes listener instance. - * - * @return The processes listener instance or <code>null</code> if none. - */ - protected final IProcesses.ProcessesListener getProcessesListener() { - return processesListener; - } - - /* (non-Javadoc) - * @see org.eclipse.core.runtime.PlatformObject#getAdapter(java.lang.Class) - */ - @Override - public Object getAdapter(Class adapter) { - if (adapter.isAssignableFrom(IProcesses.ProcessesListener.class)) { - return processesListener; - } - else if (adapter.isAssignableFrom(IStreams.StreamsListener.class)) { - return streamsListener; - } - else if (adapter.isAssignableFrom(IStreams.class)) { - return svcStreams; - } - else if (adapter.isAssignableFrom(IProcesses.class)) { - return svcProcesses; - } - else if (adapter.isAssignableFrom(IChannel.class)) { - return channel; - } - else if (adapter.isAssignableFrom(IPropertiesContainer.class)) { - return properties; - } - else if (adapter.isAssignableFrom(IProcesses.ProcessContext.class)) { - return processContext; - } - else if (adapter.isAssignableFrom(this.getClass())) { - return this; - } - - - return super.getAdapter(adapter); - } - - /** - * Makes a space separated string from the given array. - * - * @param array The string array or <code>null</code>. - * @return The string. - */ - String makeString(String[] array) { - if (array == null) { - return ""; //$NON-NLS-1$ - } - StringBuilder result = new StringBuilder(); - for (String element : array) { - if (result.length() > 0) { - result.append(' '); - } - result.append(element); - } - return result.toString(); - } -} diff --git a/target_explorer/plugins/org.eclipse.tm.te.tcf.processes.core/src/org/eclipse/tm/te/tcf/processes/core/launcher/ProcessLauncherEventListener.java b/target_explorer/plugins/org.eclipse.tm.te.tcf.processes.core/src/org/eclipse/tm/te/tcf/processes/core/launcher/ProcessLauncherEventListener.java deleted file mode 100644 index 504169c51..000000000 --- a/target_explorer/plugins/org.eclipse.tm.te.tcf.processes.core/src/org/eclipse/tm/te/tcf/processes/core/launcher/ProcessLauncherEventListener.java +++ /dev/null @@ -1,55 +0,0 @@ -/******************************************************************************* - * 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.tcf.processes.core.launcher; - -import java.util.EventObject; - -import org.eclipse.core.runtime.Assert; -import org.eclipse.core.runtime.PlatformObject; -import org.eclipse.tm.te.runtime.events.DisposedEvent; -import org.eclipse.tm.te.runtime.interfaces.events.IEventListener; - -/** - * Remote process launcher default notification listener implementation. - * <p> - * <b>Note:</b> The notifications may occur in every thread! - */ -public class ProcessLauncherEventListener extends PlatformObject implements IEventListener { - // Reference to the parent launcher - private final ProcessLauncher parent; - - /** - * Constructor. - * - * @param parent The parent launcher. Must not be <code>null</code>. - */ - public ProcessLauncherEventListener(ProcessLauncher parent) { - super(); - - Assert.isNotNull(parent); - this.parent = parent; - } - - /* (non-Javadoc) - * @see org.eclipse.tm.te.runtime.interfaces.events.IEventListener#eventFired(java.util.EventObject) - */ - @Override - public void eventFired(EventObject event) { - if (event instanceof DisposedEvent) { - // Get the custom data object from the disposed event - Object data = ((DisposedEvent)event).getData(); - // The custom data object must be of type TcfRemoteProcessLauncher and match the parent launcher - if (data instanceof ProcessLauncher && parent.equals(data)) { - // Terminate the remote process (leads to the disposal of the parent) - parent.terminate(); - } - } - } -} diff --git a/target_explorer/plugins/org.eclipse.tm.te.tcf.processes.core/src/org/eclipse/tm/te/tcf/processes/core/launcher/ProcessProcessesListener.java b/target_explorer/plugins/org.eclipse.tm.te.tcf.processes.core/src/org/eclipse/tm/te/tcf/processes/core/launcher/ProcessProcessesListener.java deleted file mode 100644 index cf8818a33..000000000 --- a/target_explorer/plugins/org.eclipse.tm.te.tcf.processes.core/src/org/eclipse/tm/te/tcf/processes/core/launcher/ProcessProcessesListener.java +++ /dev/null @@ -1,130 +0,0 @@ -/******************************************************************************* - * 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.tcf.processes.core.launcher; - -import org.eclipse.core.runtime.Assert; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.Status; -import org.eclipse.tcf.services.IProcesses; -import org.eclipse.tcf.services.IProcesses.ProcessesListener; -import org.eclipse.tm.te.runtime.events.EventManager; -import org.eclipse.tm.te.runtime.interfaces.callback.ICallback; -import org.eclipse.tm.te.tcf.processes.core.activator.CoreBundleActivator; -import org.eclipse.tm.te.tcf.processes.core.interfaces.launcher.IProcessContextAwareListener; -import org.eclipse.tm.te.tcf.processes.core.internal.tracing.ITraceIds; - -/** - * Remote process processes listener implementation. - */ -public class ProcessProcessesListener implements ProcessesListener, IProcessContextAwareListener { - // The parent process launcher instance - private final ProcessLauncher parent; - // The remote process context - private IProcesses.ProcessContext context; - // A flag to remember if exited(...) got called - private boolean exitedCalled = false; - - /** - * Constructor. - * - * @param parent The parent process launcher instance. Must not be <code>null</code> - */ - public ProcessProcessesListener(ProcessLauncher parent) { - Assert.isNotNull(parent); - this.parent = parent; - } - - /** - * Returns the parent process launcher instance. - * - * @return The parent process launcher instance. - */ - protected final ProcessLauncher getParent() { - return parent; - } - - /** - * Dispose the processes listener instance. - * <p> - * <b>Note:</b> The processes listener is removed from the processes service by the parent remote process launcher. - * - * @param callback The callback to invoke if the dispose finished or <code>null</code>. - */ - public void dispose(ICallback callback) { - // If exited(...) hasn't been called yet, but dispose is invoked, - // send a ... event to signal listeners that a terminated event won't come. - if (!exitedCalled && context != null) { - ProcessStateChangeEvent event = new ProcessStateChangeEvent(context, ProcessStateChangeEvent.EVENT_LOST_COMMUNICATION, Boolean.FALSE, Boolean.TRUE, -1); - EventManager.getInstance().fireEvent(event); - } - // Invoke the callback - if (callback != null) callback.done(this, Status.OK_STATUS); - } - - /* (non-Javadoc) - * @see org.eclipse.tm.te.tcf.processes.core.interfaces.launcher.IProcessContextAwareListener#setProcessContext(org.eclipse.tcf.services.IProcesses.ProcessContext) - */ - @Override - public void setProcessContext(IProcesses.ProcessContext context) { - Assert.isNotNull(context); - this.context = context; - - if (CoreBundleActivator.getTraceHandler().isSlotEnabled(0, ITraceIds.TRACE_PROCESSES_LISTENER)) { - CoreBundleActivator.getTraceHandler().trace("Process context set to: id='" + context.getID() + "', name='" + context.getName() + "'", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ - 0, ITraceIds.TRACE_PROCESSES_LISTENER, - IStatus.INFO, getClass()); - } - } - - /* (non-Javadoc) - * @see org.eclipse.tm.te.tcf.processes.core.interfaces.launcher.IProcessContextAwareListener#getProcessContext() - */ - @Override - public IProcesses.ProcessContext getProcessContext() { - return context; - } - - /* (non-Javadoc) - * @see org.eclipse.tcf.services.IProcesses.ProcessesListener#exited(java.lang.String, int) - */ - @Override - public void exited(String processId, int exitCode) { - if (CoreBundleActivator.getTraceHandler().isSlotEnabled(0, ITraceIds.TRACE_PROCESSES_LISTENER)) { - CoreBundleActivator.getTraceHandler().trace("Process context terminated: id='" + processId + "', exitCode='" + exitCode + "'", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ - 0, ITraceIds.TRACE_PROCESSES_LISTENER, - IStatus.INFO, getClass()); - } - - // If the exited process is the one we are monitoring, - // --> initiate the disposal of the parent remote process launcher - IProcesses.ProcessContext context = getProcessContext(); - if (context != null && processId != null && processId.equals(context.getID())) { - // Exited got called for the associated process context - exitedCalled = true; - // Send a notification - ProcessStateChangeEvent event = createRemoteProcessStateChangeEvent(context, exitCode); - EventManager.getInstance().fireEvent(event); - // Dispose the parent remote process launcher - getParent().dispose(); - } - } - - /** - * Creates a new remote process state change event instance. - * - * @param context The process context. Must not be <code>null</code>. - * @return The event instance or <code>null</code>. - */ - protected ProcessStateChangeEvent createRemoteProcessStateChangeEvent(IProcesses.ProcessContext context, int exitCode) { - Assert.isNotNull(context); - return new ProcessStateChangeEvent(context, ProcessStateChangeEvent.EVENT_PROCESS_TERMINATED, Boolean.FALSE, Boolean.TRUE, exitCode); - } - -} diff --git a/target_explorer/plugins/org.eclipse.tm.te.tcf.processes.core/src/org/eclipse/tm/te/tcf/processes/core/launcher/ProcessStateChangeEvent.java b/target_explorer/plugins/org.eclipse.tm.te.tcf.processes.core/src/org/eclipse/tm/te/tcf/processes/core/launcher/ProcessStateChangeEvent.java deleted file mode 100644 index 757afc72e..000000000 --- a/target_explorer/plugins/org.eclipse.tm.te.tcf.processes.core/src/org/eclipse/tm/te/tcf/processes/core/launcher/ProcessStateChangeEvent.java +++ /dev/null @@ -1,75 +0,0 @@ -/******************************************************************************* - * 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.tcf.processes.core.launcher; - -import org.eclipse.tm.te.runtime.events.ChangeEvent; - -/** - * Remote process state change event implementation. - */ -public class ProcessStateChangeEvent extends ChangeEvent { - private static final long serialVersionUID = -8581379873446721643L; - - /** - * Event id signaling if a remote process got created. - */ - public static final String EVENT_PROCESS_CREATED = "created"; //$NON-NLS-1$ - - /** - * Event id signaling if a remote process terminated. - */ - public static final String EVENT_PROCESS_TERMINATED = "terminated"; //$NON-NLS-1$ - - /** - * Event id signaling that the communication with the process got lost, probably because of a - * channel closed event. Any listener waiting for a process termination event should react on - * this event and stop waiting. - */ - public static final String EVENT_LOST_COMMUNICATION = "lostCommunication"; //$NON-NLS-1$ - - // Exit code of the remote process - private final int exitCode; - - /** - * Constructor. - * - * @param source The event source. Must not be <code>null</code>. - * @param eventId The event id. Must not be <code>null</code>. - * @param oldValue The old value or <code>null</code>. - * @param newValue The new value or <code>null</code>. - */ - public ProcessStateChangeEvent(Object source, Object eventId, Object oldValue, Object newValue) { - this(source, eventId, oldValue, newValue, -1); - } - - /** - * Constructor. - * - * @param source The event source. Must not be <code>null</code>. - * @param eventId The event id. Must not be <code>null</code>. - * @param oldValue The old value or <code>null</code>. - * @param newValue The new value or <code>null</code>. - * @param exitCode The process exit code or <code>-1</code> if not applicable. - */ - public ProcessStateChangeEvent(Object source, Object eventId, Object oldValue, Object newValue, int exitCode) { - super(source, eventId, oldValue, newValue); - this.exitCode = exitCode; - } - - /** - * Returns the remote process exit code. The exit code is only applicable if the set event id is - * {@link #EVENT_PROCESS_TERMINATED}. - * - * @return The remote process exit code or <code>-1</code> if not applicable. - */ - public final int getExitCode() { - return exitCode; - } -} diff --git a/target_explorer/plugins/org.eclipse.tm.te.tcf.processes.core/src/org/eclipse/tm/te/tcf/processes/core/launcher/ProcessStreamsListener.java b/target_explorer/plugins/org.eclipse.tm.te.tcf.processes.core/src/org/eclipse/tm/te/tcf/processes/core/launcher/ProcessStreamsListener.java deleted file mode 100644 index c5b47f198..000000000 --- a/target_explorer/plugins/org.eclipse.tm.te.tcf.processes.core/src/org/eclipse/tm/te/tcf/processes/core/launcher/ProcessStreamsListener.java +++ /dev/null @@ -1,892 +0,0 @@ -/******************************************************************************* - * 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.tcf.processes.core.launcher; - -import java.io.IOException; -import java.io.Writer; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.concurrent.CancellationException; - -import org.eclipse.core.runtime.Assert; -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.tcf.protocol.IToken; -import org.eclipse.tcf.protocol.Protocol; -import org.eclipse.tcf.services.IProcesses; -import org.eclipse.tcf.services.IStreams; -import org.eclipse.tcf.util.TCFTask; -import org.eclipse.tm.te.core.async.AsyncCallbackCollector; -import org.eclipse.tm.te.runtime.callback.Callback; -import org.eclipse.tm.te.runtime.interfaces.callback.ICallback; -import org.eclipse.tm.te.tcf.core.streams.StreamsDataProvider; -import org.eclipse.tm.te.tcf.core.streams.StreamsDataReceiver; -import org.eclipse.tm.te.tcf.core.utils.ExceptionUtils; -import org.eclipse.tm.te.tcf.processes.core.activator.CoreBundleActivator; -import org.eclipse.tm.te.tcf.processes.core.interfaces.launcher.IProcessContextAwareListener; -import org.eclipse.tm.te.tcf.processes.core.internal.tracing.ITraceIds; -import org.eclipse.tm.te.tcf.processes.core.nls.Messages; - -/** - * Remote process streams listener implementation. - */ -public class ProcessStreamsListener implements IStreams.StreamsListener, IProcessContextAwareListener { - // The parent process launcher instance - private final ProcessLauncher parent; - // The remote process context - private IProcesses.ProcessContext context; - // The list of registered stream data receivers - private final List<StreamsDataReceiver> dataReceiver = new ArrayList<StreamsDataReceiver>(); - // The stream data provider - private StreamsDataProvider dataProvider; - // The list of delayed stream created events - private final List<StreamCreatedEvent> delayedCreatedEvents = new ArrayList<StreamCreatedEvent>(); - // The list of created runnable's - private final List<Runnable> runnables = new ArrayList<Runnable>(); - - /** - * Immutable stream created event. - */ - private final static class StreamCreatedEvent { - /** - * The stream type. - */ - public final String streamType; - /** - * The stream id. - */ - public final String streamId; - /** - * The context id. - */ - public final String contextId; - - // As the class is immutable, we do not need to build the toString - // value again and again. Build it once in the constructor and reuse it later. - private final String toString; - - /** - * Constructor. - * - * @param streamType The stream type. - * @param streamId The stream id. - * @param contextId The context id. - */ - public StreamCreatedEvent(String streamType, String streamId, String contextId) { - this.streamType = streamType; - this.streamId = streamId; - this.contextId = contextId; - - toString = toString(); - } - - /* (non-Javadoc) - * @see java.lang.Object#equals(java.lang.Object) - */ - @Override - public boolean equals(Object obj) { - return obj instanceof StreamCreatedEvent - && toString().equals(((StreamCreatedEvent)obj).toString()); - } - - /* (non-Javadoc) - * @see java.lang.Object#hashCode() - */ - @Override - public int hashCode() { - return toString().hashCode(); - } - - /* (non-Javadoc) - * @see java.lang.Object#toString() - */ - @Override - public String toString() { - if (toString != null) return toString; - - StringBuilder builder = new StringBuilder(getClass().getSimpleName()); - builder.append(": streamType = "); //$NON-NLS-1$ - builder.append(streamType); - builder.append("; streamId = "); //$NON-NLS-1$ - builder.append(streamId); - builder.append("; contextId = "); //$NON-NLS-1$ - builder.append(contextId); - - return builder.toString(); - } - } - - /** - * Remote process stream reader runnable implementation. The - * runnable will be executed within a thread and is responsible to read the - * incoming data from the associated stream and forward them to the registered receivers. - */ - protected class StreamReaderRunnable implements Runnable { - // The associated stream id - private final String streamId; - // The associated stream type id - private final String streamTypeId; - // The list of receivers applicable for the associated stream type id - private final List<StreamsDataReceiver> receivers = new ArrayList<StreamsDataReceiver>(); - // The currently active read task - private TCFTask<ReadData> activeTask; - // The callback to invoke if the runnable stopped - private ICallback callback; - - // Flag to stop the runnable - private boolean stopped = false; - - /** - * Immutable class describing the result returned by {@link StreamReaderRunnable#read(IStreams, String, int)}. - */ - protected class ReadData { - /** - * The number of lost bytes in case of a buffer overflow. If <code>-1</code>, - * an unknown number of bytes were lost. If non-zero and <code>data.length</code> is - * non-zero, the lost bytes are considered located right before the read bytes. - */ - public final int lostBytes; - /** - * The read data as byte array. - */ - public final byte[] data; - /** - * Flag to signal if the end of the stream has been reached. - */ - public final boolean eos; - - /** - * Constructor. - */ - public ReadData(int lostBytes, byte[] data, boolean eos) { - this.lostBytes = lostBytes; - this.data = data; - this.eos = eos; - } - } - - /** - * Constructor. - * - * @param streamId The associated stream id. Must not be <code>null</code>. - * @param streamTypeId The associated stream type id. Must not be <code>null</code>. - * @param receivers The list of registered data receivers. Must not be <code>null</code>. - */ - public StreamReaderRunnable(String streamId, String streamTypeId, StreamsDataReceiver[] receivers) { - Assert.isNotNull(streamId); - Assert.isNotNull(streamTypeId); - Assert.isNotNull(receivers); - - this.streamId = streamId; - this.streamTypeId = streamTypeId; - - // Loop the list of receivers and filter out the applicable ones - for (StreamsDataReceiver receiver : receivers) { - if (receiver.isApplicable(this.streamTypeId)) - this.receivers.add(receiver); - } - } - - /** - * Returns the associated stream id. - * - * @return The associated stream id. - */ - public final String getStreamId() { - return streamId; - } - - /** - * Returns if or if not the list of applicable receivers is empty. - * - * @return <code>True</code> if the list of applicable receivers is empty, <code>false</code> otherwise. - */ - public final boolean isEmpty() { - return receivers.isEmpty(); - } - - /** - * Stop the runnable. - * - * @param callback The callback to invoke if the runnable stopped. - */ - public final synchronized void stop(ICallback callback) { - // If the runnable is stopped already, invoke the callback directly - if (stopped) { - if (callback != null) callback.done(this, Status.OK_STATUS); - return; - } - - // Store the callback instance - this.callback = callback; - // Mark the runnable as stopped - stopped = true; - } - - /** - * Returns if the runnable should stop. - */ - protected final synchronized boolean isStopped() { - return stopped; - } - - /** - * Sets the currently active reader task. - * - * @param task The currently active reader task or <code>null</code>. - */ - protected final synchronized void setActiveTask(TCFTask<ReadData> task) { - activeTask = task; - } - - /** - * Returns the currently active reader task. - * - * @return The currently active reader task or <code>null</code>. - */ - protected final TCFTask<ReadData> getActiveTask() { - return activeTask; - } - - /** - * Returns the callback instance to invoke. - * - * @return The callback instance or <code>null</code>. - */ - protected final ICallback getCallback() { - return callback; - } - - /* (non-Javadoc) - * @see java.lang.Runnable#run() - */ - @Override - public void run() { - // Create a snapshot of the receivers - final StreamsDataReceiver[] receivers = this.receivers.toArray(new StreamsDataReceiver[this.receivers.size()]); - // Get the service instance from the parent - final IStreams svcStreams = getParent().getSvcStreams(); - - // Run until stopped and the streams service is available - while (!isStopped() && svcStreams != null) { - try { - ReadData streamData = read(svcStreams, streamId, 1024); - if (streamData != null) { - // Check if the received data contains some stream data - if (streamData.data != null) { - // Notify the data receivers about the new received data - notifyReceiver(new String(streamData.data), receivers); - } - // If the end of the stream have been reached --> break out - if (streamData.eos) break; - } - } catch (Exception e) { - // An error occurred -> Dump to the error log - e = ExceptionUtils.checkAndUnwrapException(e); - // Check if the blocking read task got canceled - if (!(e instanceof CancellationException)) { - // Log the error to the user, might be something serious - IStatus status = new Status(IStatus.ERROR, CoreBundleActivator.getUniqueIdentifier(), - NLS.bind(Messages.ProcessStreamReaderRunnable_error_readFailed, streamId, e.getLocalizedMessage()), - e); - Platform.getLog(CoreBundleActivator.getContext().getBundle()).log(status); - } - // break out of the loop - break; - } - } - - // Disconnect from the stream - if (svcStreams != null) { - svcStreams.disconnect(streamId, new IStreams.DoneDisconnect() { - @Override - @SuppressWarnings("synthetic-access") - public void doneDisconnect(IToken token, Exception error) { - // Disconnect is done, ignore any error, invoke the callback - synchronized (this) { - if (getCallback() != null) getCallback().done(this, Status.OK_STATUS); - } - // Mark the runnable definitely stopped - stopped = true; - } - }); - } else { - // Invoke the callback directly, if any - synchronized (this) { - if (callback != null) callback.done(this, Status.OK_STATUS); - } - // Mark the runnable definitely stopped - stopped = true; - } - } - - /** - * Reads data from the stream and blocks until some data has been received. - * - * @param service The streams service. Must not be <code>null</code>. - * @param streamId The stream id. Must not be <code>null</code>. - * @param size The size of the data to read. - * - * @return The read data. - * - * @throws Exception In case the read fails. - */ - protected final ReadData read(final IStreams service, final String streamId, final int size) throws Exception { - Assert.isNotNull(service); - Assert.isNotNull(streamId); - Assert.isTrue(!Protocol.isDispatchThread()); - - // Create the task object - TCFTask<ReadData> task = new TCFTask<ReadData>(getParent().getChannel()) { - @Override - public void run() { - service.read(streamId, size, new IStreams.DoneRead() { - /* (non-Javadoc) - * @see org.eclipse.tcf.services.IStreams.DoneRead#doneRead(org.eclipse.tcf.protocol.IToken, java.lang.Exception, int, byte[], boolean) - */ - @Override - public void doneRead(IToken token, Exception error, int lostSize, byte[] data, boolean eos) { - if (error == null) done(new ReadData(lostSize, data, eos)); - else error(error); - } - }); - } - }; - - // Push the task object to the runnable instance - setActiveTask(task); - - // Block until some data is received - return task.get(); - } - - /** - * Notify the data receiver that some data has been received. - * - * @param data The data or <code>null</code>. - */ - protected final void notifyReceiver(final String data, final StreamsDataReceiver[] receivers) { - if (data == null) return; - // Notify the data receiver - for (StreamsDataReceiver receiver : receivers) { - try { - // Get the writer - Writer writer = receiver.getWriter(); - // Append the data - writer.append(data); - // And flush it - writer.flush(); - } catch (IOException e) { - if (CoreBundleActivator.getTraceHandler().isSlotEnabled(1, null)) { - IStatus status = new Status(IStatus.WARNING, CoreBundleActivator.getUniqueIdentifier(), - NLS.bind(Messages.ProcessStreamReaderRunnable_error_appendFailed, streamId, data), - e); - Platform.getLog(CoreBundleActivator.getContext().getBundle()).log(status); - } - } - } - } - } - - /** - * Default TCF remote process stream writer runnable implementation. The - * runnable will be executed within a thread and is responsible to read the - * incoming data from the registered providers and forward them to the associated stream. - */ - protected class ProcessStreamWriterRunnable implements Runnable { - // The associated stream id - private final String streamId; - // The associated stream type id - @SuppressWarnings("unused") - private final String streamTypeId; - // The data provider applicable for the associated stream type id - private final StreamsDataProvider provider; - // The currently active write task - private TCFTask<Object> activeTask; - // The callback to invoke if the runnable stopped - private ICallback callback; - - // Flag to stop the runnable - private boolean stopped = false; - - /** - * Constructor. - * - * @param streamId The associated stream id. Must not be <code>null</code>. - * @param streamTypeId The associated stream type id. Must not be <code>null</code>. - * @param provider The data provider. Must not be <code>null</code> and must be applicable for the stream type. - */ - public ProcessStreamWriterRunnable(String streamId, String streamTypeId, StreamsDataProvider provider) { - Assert.isNotNull(streamId); - Assert.isNotNull(streamTypeId); - Assert.isNotNull(provider); - Assert.isTrue(provider.isApplicable(streamTypeId)); - - this.streamId = streamId; - this.streamTypeId = streamTypeId; - this.provider = provider; - } - - /** - * Returns the associated stream id. - * - * @return The associated stream id. - */ - public final String getStreamId() { - return streamId; - } - - /** - * Stop the runnable. - * - * @param callback The callback to invoke if the runnable stopped. - */ - public final synchronized void stop(ICallback callback) { - // If the runnable is stopped already, invoke the callback directly - if (stopped) { - if (callback != null) callback.done(this, Status.OK_STATUS); - return; - } - - // Store the callback instance - this.callback = callback; - // Mark the runnable as stopped - stopped = true; - } - - /** - * Returns if the runnable should stop. - */ - protected final synchronized boolean isStopped() { - return stopped; - } - - /** - * Sets the currently active writer task. - * - * @param task The currently active writer task or <code>null</code>. - */ - protected final synchronized void setActiveTask(TCFTask<Object> task) { - activeTask = task; - } - - /** - * Returns the currently active writer task. - * - * @return The currently active writer task or <code>null</code>. - */ - protected final TCFTask<Object> getActiveTask() { - return activeTask; - } - - /** - * Returns the callback instance to invoke. - * - * @return The callback instance or <code>null</code>. - */ - protected final ICallback getCallback() { - return callback; - } - - /* (non-Javadoc) - * @see java.lang.Runnable#run() - */ - @Override - public void run() { - // If not data provider is set, we are done here immediately - if (provider == null) { - // Invoke the callback directly, if any - synchronized (this) { - if (callback != null) callback.done(this, Status.OK_STATUS); - } - // Mark the runnable definitely stopped - stopped = true; - - return; - } - - // Get the service instance from the parent - final IStreams svcStreams = getParent().getSvcStreams(); - - // Create the data buffer instance - final char[] buffer = new char[1024]; - - // Run until stopped and the streams service is available - while (!isStopped() && svcStreams != null) { - try { - // Read available data from the data provider - int charactersRead = provider.getReader().read(buffer, 0, 1024); - // Have we reached the end of the stream -> break out - if (charactersRead == -1) break; - // If we read some data from the provider, write it to the stream - if (charactersRead > 0) write(svcStreams, streamId, new String(buffer).getBytes(), charactersRead); - } catch (Exception e) { - // An error occurred -> Dump to the error log - e = ExceptionUtils.checkAndUnwrapException(e); - // Check if the blocking read task got canceled - if (!(e instanceof CancellationException)) { - // Log the error to the user, might be something serious - IStatus status = new Status(IStatus.ERROR, CoreBundleActivator.getUniqueIdentifier(), - NLS.bind(Messages.ProcessStreamWriterRunnable_error_writeFailed, streamId, e.getLocalizedMessage()), - e); - Platform.getLog(CoreBundleActivator.getContext().getBundle()).log(status); - } - // break out of the loop - break; - } - } - - // Disconnect from the stream - if (svcStreams != null) { - svcStreams.disconnect(streamId, new IStreams.DoneDisconnect() { - @Override - @SuppressWarnings("synthetic-access") - public void doneDisconnect(IToken token, Exception error) { - // Disconnect is done, ignore any error, invoke the callback - synchronized (this) { - if (getCallback() != null) getCallback().done(this, Status.OK_STATUS); - } - // Mark the runnable definitely stopped - stopped = true; - } - }); - } else { - // Invoke the callback directly, if any - synchronized (this) { - if (callback != null) callback.done(this, Status.OK_STATUS); - } - // Mark the runnable definitely stopped - stopped = true; - } - } - - /** - * Writes data to the stream. - * - * @param service The streams service. Must not be <code>null</code>. - * @param streamId The stream id. Must not be <code>null</code>. - * @param data The data buffer. Must not be <code>null</code>. - * @param size The size of the data to write. - * - * @throws Exception In case the write fails. - */ - protected final void write(final IStreams service, final String streamId, final byte[] data, final int size) throws Exception { - Assert.isNotNull(service); - Assert.isNotNull(streamId); - Assert.isTrue(!Protocol.isDispatchThread()); - - // Create the task object - TCFTask<Object> task = new TCFTask<Object>() { - @Override - public void run() { - service.write(streamId, data, 0, size, new IStreams.DoneWrite() { - /* (non-Javadoc) - * @see org.eclipse.tcf.services.IStreams.DoneWrite#doneWrite(org.eclipse.tcf.protocol.IToken, java.lang.Exception) - */ - @Override - public void doneWrite(IToken token, Exception error) { - if (error == null) done(null); - else error(error); - } - }); - } - }; - task.get(); - - // Push the task object to the runnable instance - setActiveTask(task); - - // Execute the write - task.get(); - } - } - - /** - * Constructor. - * - * @param parent The parent process launcher instance. Must not be <code>null</code> - */ - public ProcessStreamsListener(ProcessLauncher parent) { - Assert.isNotNull(parent); - this.parent = parent; - } - - /** - * Returns the parent process launcher instance. - * - * @return The parent process launcher instance. - */ - protected final ProcessLauncher getParent() { - return parent; - } - - /** - * Dispose the streams listener instance. - * - * @param callback The callback to invoke if the dispose finished or <code>null</code>. - */ - public void dispose(final ICallback callback) { - // Store a final reference to the streams listener instance - final IStreams.StreamsListener finStreamsListener = this; - - // Store a final reference to the data receivers list - final List<StreamsDataReceiver> finDataReceivers; - synchronized (dataReceiver) { - finDataReceivers = new ArrayList<StreamsDataReceiver>(dataReceiver); - dataReceiver.clear(); - } - - // Create the callback invocation delegate - AsyncCallbackCollector.ICallbackInvocationDelegate delegate = new AsyncCallbackCollector.ICallbackInvocationDelegate() { - @Override - public void invoke(Runnable runnable) { - Assert.isNotNull(runnable); - if (Protocol.isDispatchThread()) runnable.run(); - else Protocol.invokeLater(runnable); - } - }; - - // Create a new collector to catch all runnable stop callback's - AsyncCallbackCollector collector = new AsyncCallbackCollector(new Callback() { - /* (non-Javadoc) - * @see org.eclipse.tm.te.runtime.callback.Callback#internalDone(java.lang.Object, org.eclipse.core.runtime.IStatus) - */ - @Override - protected void internalDone(final Object caller, final IStatus status) { - Assert.isTrue(Protocol.isDispatchThread(), "Illegal Thread Access"); //$NON-NLS-1$ - // Get the service instance from the parent - IStreams svcStreams = getParent().getSvcStreams(); - // Unsubscribe the streams listener from the service - svcStreams.unsubscribe(IProcesses.NAME, finStreamsListener, new IStreams.DoneUnsubscribe() { - @Override - public void doneUnsubscribe(IToken token, Exception error) { - // Loop all registered listeners and close them - for (StreamsDataReceiver receiver : finDataReceivers) receiver.dispose(); - // Call the original outer callback - if (callback != null) callback.done(caller, status); - } - }); - } - }, delegate); - - // Loop all runnable's and force them to stop - synchronized (runnables) { - for (Runnable runnable : runnables) { - if (runnable instanceof StreamReaderRunnable) { - ((StreamReaderRunnable)runnable).stop(new AsyncCallbackCollector.SimpleCollectorCallback(collector)); - } - } - runnables.clear(); - } - - // Mark the collector initialization done - collector.initDone(); - } - - /** - * Adds the given receiver to the stream data receiver list. - * - * @param receiver The data receiver. Must not be <code>null</code>. - */ - public void registerDataReceiver(StreamsDataReceiver receiver) { - Assert.isNotNull(receiver); - synchronized (dataReceiver) { - if (!dataReceiver.contains(receiver)) dataReceiver.add(receiver); - } - } - - /** - * Removes the given receiver from the stream data receiver list. - * - * @param receiver The data receiver. Must not be <code>null</code>. - */ - public void unregisterDataReceiver(StreamsDataReceiver receiver) { - Assert.isNotNull(receiver); - synchronized (dataReceiver) { - dataReceiver.remove(receiver); - } - } - - /** - * Sets the stream data provider instance. - * - * @param provider The stream data provider instance or <code>null</code>. - */ - public void setDataProvider(StreamsDataProvider provider) { - dataProvider = provider; - } - - /** - * Returns the stream data provider instance. - * - * @return The stream data provider instance or <code>null</code>. - */ - public StreamsDataProvider getDataProvider() { - return dataProvider; - } - - /* (non-Javadoc) - * @see org.eclipse.tm.te.tcf.processes.core.interfaces.launcher.IProcessContextAwareListener#setProcessContext(org.eclipse.tcf.services.IProcesses.ProcessContext) - */ - @Override - public void setProcessContext(IProcesses.ProcessContext context) { - Assert.isNotNull(context); - this.context = context; - - if (CoreBundleActivator.getTraceHandler().isSlotEnabled(0, ITraceIds.TRACE_STREAMS_LISTENER)) { - CoreBundleActivator.getTraceHandler().trace("Process context set to: id='" + context.getID() + "', name='" + context.getName() + "'", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ - 0, ITraceIds.TRACE_STREAMS_LISTENER, - IStatus.INFO, getClass()); - } - - // Loop all delayed create events and look for the streams for our context - synchronized (delayedCreatedEvents) { - Iterator<StreamCreatedEvent> iterator = delayedCreatedEvents.iterator(); - while (iterator.hasNext()) { - StreamCreatedEvent event = iterator.next(); - if (context.getID().equals(event.contextId) || event.contextId == null) { - // Re-dispatch the event - created(event.streamType, event.streamId, event.contextId); - } - } - // Clear all events - delayedCreatedEvents.clear(); - } - } - - /* (non-Javadoc) - * @see org.eclipse.tm.te.tcf.processes.core.interfaces.launcher.IProcessContextAwareListener#getProcessContext() - */ - @Override - public IProcesses.ProcessContext getProcessContext() { - return context; - } - - /* (non-Javadoc) - * @see org.eclipse.tcf.services.IStreams.StreamsListener#created(java.lang.String, java.lang.String, java.lang.String) - */ - @Override - public void created(String streamType, String streamId, String contextId) { - // We ignore any other stream type than IProcesses.NAME - if (!IProcesses.NAME.equals(streamType)) return; - - if (CoreBundleActivator.getTraceHandler().isSlotEnabled(0, ITraceIds.TRACE_STREAMS_LISTENER)) { - CoreBundleActivator.getTraceHandler().trace("New remote process stream created: streamId='" + streamId + "', contextId='" + contextId + "'", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ - 0, ITraceIds.TRACE_STREAMS_LISTENER, - IStatus.INFO, getClass()); - } - - // If a process context is set, check if the created event is for the - // monitored process context - final IProcesses.ProcessContext context = getProcessContext(); - // The contextId is null if used with an older TCF agent not sending the third parameter - if (context != null && (context.getID().equals(contextId) || contextId == null)) { - // Create a snapshot of the registered data receivers - StreamsDataReceiver[] receivers; - synchronized (dataReceiver) { - receivers = dataReceiver.toArray(new StreamsDataReceiver[dataReceiver.size()]); - } - // The created event is for the monitored process context - // --> Create the stream reader thread(s) - if (streamId != null && streamId.equals(context.getProperties().get(IProcesses.PROP_STDIN_ID))) { - // Data provider set? - if (dataProvider != null) { - // Create the stdin stream writer runnable - ProcessStreamWriterRunnable runnable = new ProcessStreamWriterRunnable(streamId, IProcesses.PROP_STDIN_ID, dataProvider); - // Add to the list of created runnable's - synchronized (runnables) { runnables.add(runnable); } - // And create and start the thread - Thread thread = new Thread(runnable, "Thread-" + IProcesses.PROP_STDIN_ID + "-" + streamId); //$NON-NLS-1$ //$NON-NLS-2$ - thread.start(); - } - } - if (streamId != null && streamId.equals(context.getProperties().get(IProcesses.PROP_STDOUT_ID))) { - // Create the stdout stream reader runnable - StreamReaderRunnable runnable = new StreamReaderRunnable(streamId, IProcesses.PROP_STDOUT_ID, receivers); - // If not empty, create the thread - if (!runnable.isEmpty()) { - // Add to the list of created runnable's - synchronized (runnables) { runnables.add(runnable); } - // And create and start the thread - Thread thread = new Thread(runnable, "Thread-" + IProcesses.PROP_STDOUT_ID + "-" + streamId); //$NON-NLS-1$ //$NON-NLS-2$ - thread.start(); - } - } - if (streamId != null && streamId.equals(context.getProperties().get(IProcesses.PROP_STDERR_ID))) { - // Create the stdout stream reader runnable - StreamReaderRunnable runnable = new StreamReaderRunnable(streamId, IProcesses.PROP_STDERR_ID, receivers); - // If not empty, create the thread - if (!runnable.isEmpty()) { - // Add to the list of created runnable's - synchronized (runnables) { runnables.add(runnable); } - // And create and start the thread - Thread thread = new Thread(runnable, "Thread-" + IProcesses.PROP_STDERR_ID + "-" + streamId); //$NON-NLS-1$ //$NON-NLS-2$ - thread.start(); - } - } - } else if (context == null) { - // Context not set yet --> add to the delayed list - StreamCreatedEvent event = new StreamCreatedEvent(streamType, streamId, contextId); - synchronized (delayedCreatedEvents) { - if (!delayedCreatedEvents.contains(event)) delayedCreatedEvents.add(event); - } - } - } - - /* (non-Javadoc) - * @see org.eclipse.tcf.services.IStreams.StreamsListener#disposed(java.lang.String, java.lang.String) - */ - @Override - public void disposed(String streamType, String streamId) { - // We ignore any other stream type than IProcesses.NAME - if (!IProcesses.NAME.equals(streamType)) return; - - if (CoreBundleActivator.getTraceHandler().isSlotEnabled(0, ITraceIds.TRACE_STREAMS_LISTENER)) { - CoreBundleActivator.getTraceHandler().trace("Remote process stream disposed: streamId='" + streamId + "'", //$NON-NLS-1$ //$NON-NLS-2$ - 0, ITraceIds.TRACE_STREAMS_LISTENER, - IStatus.INFO, getClass()); - } - - // If the delayed created events list is not empty, we have - // to check if one of the delayed create events got disposed - synchronized (delayedCreatedEvents) { - Iterator<StreamCreatedEvent> iterator = delayedCreatedEvents.iterator(); - while (iterator.hasNext()) { - StreamCreatedEvent event = iterator.next(); - if (event.streamType != null && event.streamType.equals(streamType) - && event.streamId != null && event.streamId.equals(streamId)) { - // Remove the create event from the list - iterator.remove(); - } - } - } - - // Stop the thread(s) if the disposed event is for the active - // monitored stream id(s). - synchronized (runnables) { - Iterator<Runnable> iterator = runnables.iterator(); - while (iterator.hasNext()) { - Runnable runnable = iterator.next(); - if (runnable instanceof StreamReaderRunnable) { - StreamReaderRunnable myRunnable = (StreamReaderRunnable)runnable; - if (myRunnable.getStreamId().equals(streamId)) { - // This method is called within the TCF event dispatch thread, so - // we cannot wait for a callback here - myRunnable.stop(null); - iterator.remove(); - } - } - } - } - } -} diff --git a/target_explorer/plugins/org.eclipse.tm.te.tcf.processes.core/src/org/eclipse/tm/te/tcf/processes/core/nls/Messages.java b/target_explorer/plugins/org.eclipse.tm.te.tcf.processes.core/src/org/eclipse/tm/te/tcf/processes/core/nls/Messages.java deleted file mode 100644 index b1b2ab4ad..000000000 --- a/target_explorer/plugins/org.eclipse.tm.te.tcf.processes.core/src/org/eclipse/tm/te/tcf/processes/core/nls/Messages.java +++ /dev/null @@ -1,49 +0,0 @@ -/******************************************************************************* - * 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.tcf.processes.core.nls; - -import org.eclipse.osgi.util.NLS; - -/** - * Target Explorer TCF processes extensions core plug-in externalized strings management. - */ -public class Messages extends NLS { - - // The plug-in resource bundle name - private static final String BUNDLE_NAME = "org.eclipse.tm.te.tcf.processes.core.nls.Messages"; //$NON-NLS-1$ - - /** - * Static constructor. - */ - static { - // Load message values from bundle file - NLS.initializeMessages(BUNDLE_NAME, Messages.class); - } - - // **** Declare externalized string id's down here ***** - - public static String ProcessLauncher_error_channelConnectFailed; - public static String ProcessLauncher_error_channelNotConnected; - public static String ProcessLauncher_error_missingProcessPath; - public static String ProcessLauncher_error_missingRequiredService; - public static String ProcessLauncher_error_illegalNullArgument; - public static String ProcessLauncher_error_getEnvironmentFailed; - public static String ProcessLauncher_error_processLaunchFailed; - public static String ProcessLauncher_error_processTerminateFailed; - public static String ProcessLauncher_error_processSendSignalFailed; - public static String ProcessLauncher_error_possibleCause; - public static String ProcessLauncher_cause_subscribeFailed; - public static String ProcessLauncher_cause_startFailed; - public static String ProcessLauncher_cause_ioexception; - - public static String ProcessStreamReaderRunnable_error_readFailed; - public static String ProcessStreamWriterRunnable_error_writeFailed; - public static String ProcessStreamReaderRunnable_error_appendFailed; -} diff --git a/target_explorer/plugins/org.eclipse.tm.te.tcf.processes.core/src/org/eclipse/tm/te/tcf/processes/core/nls/Messages.properties b/target_explorer/plugins/org.eclipse.tm.te.tcf.processes.core/src/org/eclipse/tm/te/tcf/processes/core/nls/Messages.properties deleted file mode 100644 index 8153df0ae..000000000 --- a/target_explorer/plugins/org.eclipse.tm.te.tcf.processes.core/src/org/eclipse/tm/te/tcf/processes/core/nls/Messages.properties +++ /dev/null @@ -1,22 +0,0 @@ -# -# org.eclipse.tm.te.tcf.processes.core -# Externalized Strings. -# - -ProcessLauncher_error_channelConnectFailed=Failed to connect channel for peer ''{0}''.\n\nPossible Cause:\n{1} -ProcessLauncher_error_channelNotConnected=Channel is not connected! -ProcessLauncher_error_missingProcessPath=Illegal argument: Process image path must be specified! -ProcessLauncher_error_missingRequiredService=Failed to get required service: {0}! -ProcessLauncher_error_illegalNullArgument=Illegal argument: ''{0}'' has to be not null. -ProcessLauncher_error_getEnvironmentFailed=Failed to get initial process environment from remote peer. -ProcessLauncher_error_processLaunchFailed=Failed to launch remote process.\n\nProcess Path: {0}\nProcess Arguments: {1} -ProcessLauncher_error_processTerminateFailed=Failed to terminate remote process.\n\nProcess Name: {0} -ProcessLauncher_error_processSendSignalFailed=Failed to send signal {0} to process.\n\nProcess Name: {1} -ProcessLauncher_error_possibleCause=\n\nPossible Cause:\n{0} -ProcessLauncher_cause_subscribeFailed=Failed to subscribe to the remote process streams service. -ProcessLauncher_cause_startFailed=Failed to start remote process. -ProcessLauncher_cause_ioexception=An IOException occurred. - -ProcessStreamReaderRunnable_error_readFailed=Failed to read data from stream with id ''{0}''.\n\nPossible Cause:\n{1} -ProcessStreamWriterRunnable_error_writeFailed=Failed to write data to stream with id ''{0}''.\n\nPossible Cause:\n{1} -ProcessStreamReaderRunnable_error_appendFailed=Failed to append data from stream with id ''{0}'' to data receiver.\n\nLost data:\n{1}. |