mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-07-04 07:35:24 +02:00
[170910][api] Add API for Stream-based shells and terminals in RSE
This commit is contained in:
parent
5253094809
commit
5bb00b5009
8 changed files with 730 additions and 0 deletions
|
@ -13,6 +13,7 @@ Export-Package: org.eclipse.rse.internal.services;x-internal:=true,
|
|||
org.eclipse.rse.internal.services.clientserver.archiveutils;x-internal:=true,
|
||||
org.eclipse.rse.internal.services.clientserver.java;x-internal:=true,
|
||||
org.eclipse.rse.internal.services.shells;x-internal:=true,
|
||||
org.eclipse.rse.internal.services.terminals;x-internal:=true,
|
||||
org.eclipse.rse.services,
|
||||
org.eclipse.rse.services.clientserver,
|
||||
org.eclipse.rse.services.clientserver.archiveutils,
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2008 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:
|
||||
* Martin Oberhuber (Wind River) - initial API and implementation
|
||||
*******************************************************************************/
|
||||
|
||||
package org.eclipse.rse.internal.services.terminals;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
import org.eclipse.core.runtime.PlatformObject;
|
||||
|
||||
/**
|
||||
* Abstract base class for clients to create an ITerminalShell instance.
|
||||
*
|
||||
* This abstract base class provides valid default implementations for all
|
||||
* {@link ITerminalShell} methods where possible. Clients should extend this
|
||||
* base class rather than implementing ITerminalShell directly, in order to
|
||||
* remain compatible when the ITerminalShell interface is evolved in the future.
|
||||
*
|
||||
* <p>
|
||||
* <strong>EXPERIMENTAL</strong>. This class or interface has been added as
|
||||
* part of a work in progress. There is no guarantee that this API will work or
|
||||
* that it will remain the same. Please do not use this API without consulting
|
||||
* with the <a href="http://www.eclipse.org/dsdp/tm/">Target Management</a>
|
||||
* team.
|
||||
* </p>
|
||||
*
|
||||
* @since org.eclipse.rse.services 3.0
|
||||
*/
|
||||
public abstract class AbstractTerminalShell extends PlatformObject implements ITerminalShell {
|
||||
|
||||
public String getDefaultEncoding() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getPtyType() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean isLocalEcho() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void setTerminalSize(int newWidth, int newHeight) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
public InputStream getErrorStream() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public int exitValue() {
|
||||
// exit values are not supported by default, but we need to observe the
|
||||
// API by throwing IllegalThreadStateException
|
||||
if (isActive())
|
||||
throw new IllegalThreadStateException();
|
||||
return 0;
|
||||
}
|
||||
|
||||
public boolean waitFor(long timeout) throws InterruptedException {
|
||||
boolean active = isActive();
|
||||
if (active) {
|
||||
synchronized (this) {
|
||||
wait(timeout);
|
||||
}
|
||||
active = isActive();
|
||||
}
|
||||
return active;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2008 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:
|
||||
* Martin Oberhuber (Wind River) - initial API and implementation
|
||||
*******************************************************************************/
|
||||
|
||||
package org.eclipse.rse.internal.services.terminals;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import org.eclipse.core.runtime.PlatformObject;
|
||||
|
||||
/**
|
||||
* Abstract base class for clients to decorate an IBaseShell instance they have
|
||||
* with additional functionality.
|
||||
*
|
||||
* Typically, such additional functionality can be provided either by additional
|
||||
* knowledge about the underlying system or process, or by analyzing the input
|
||||
* and output streams for some well-known data that gives such additional
|
||||
* knowledge.
|
||||
*
|
||||
* <p>
|
||||
* <strong>EXPERIMENTAL</strong>. This class or interface has been added as
|
||||
* part of a work in progress. There is no guarantee that this API will work or
|
||||
* that it will remain the same. Please do not use this API without consulting
|
||||
* with the <a href="http://www.eclipse.org/dsdp/tm/">Target Management</a>
|
||||
* team.
|
||||
* </p>
|
||||
*
|
||||
* @since org.eclipse.rse.services 3.0
|
||||
*/
|
||||
public abstract class BaseShellDecorator extends PlatformObject implements IBaseShell {
|
||||
|
||||
protected final IBaseShell fDelegate;
|
||||
|
||||
public BaseShellDecorator(IBaseShell delegate) {
|
||||
fDelegate = delegate;
|
||||
}
|
||||
|
||||
public void exit() {
|
||||
fDelegate.exit();
|
||||
}
|
||||
|
||||
public int exitValue() {
|
||||
return fDelegate.exitValue();
|
||||
}
|
||||
|
||||
public InputStream getErrorStream() {
|
||||
return fDelegate.getErrorStream();
|
||||
}
|
||||
|
||||
public InputStream getInputStream() {
|
||||
return fDelegate.getInputStream();
|
||||
}
|
||||
|
||||
public OutputStream getOutputStream() {
|
||||
return fDelegate.getOutputStream();
|
||||
}
|
||||
|
||||
public boolean isActive() {
|
||||
return fDelegate.isActive();
|
||||
}
|
||||
|
||||
public boolean waitFor(long timeout) throws InterruptedException {
|
||||
return fDelegate.waitFor(timeout);
|
||||
}
|
||||
|
||||
public Object getAdapter(Class adapterType) {
|
||||
// TODO do we want to delegate here or have our own adapter???
|
||||
// I think we're most flexible first letting adapt to ourselves,
|
||||
// and only if not successful then ask the delegate to adapt.
|
||||
Object adapter = super.getAdapter(adapterType);
|
||||
if (adapter == null) {
|
||||
adapter = fDelegate.getAdapter(adapterType);
|
||||
}
|
||||
return adapter;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,167 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2008 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:
|
||||
* Martin Oberhuber (Wind River) - initial API and implementation
|
||||
*******************************************************************************/
|
||||
|
||||
package org.eclipse.rse.internal.services.terminals;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import org.eclipse.core.runtime.IAdaptable;
|
||||
import org.eclipse.core.runtime.PlatformObject;
|
||||
|
||||
/**
|
||||
* A basic shell, representing the connection to some process that may be
|
||||
* running local or remote. Clients may implement this interface.
|
||||
*
|
||||
* Clients implementing this interface are encouraged to extend
|
||||
* {@link PlatformObject} for providing the {@link #getAdapter(Class)}
|
||||
* functionality.
|
||||
*
|
||||
* A simple implementation of IBaseShell is the {@link ProcessBaseShell}, which
|
||||
* wraps a Java {@link java.lang.Process} object in the IBaseShell interface to
|
||||
* provide more convenient access to it through the {{@link #isActive()} and {{@link #waitFor(long)}
|
||||
* methods, as well as making it adaptable.
|
||||
*
|
||||
* The resulting IBaseShell can be decorated by clients with additional
|
||||
* functionality easily by instantiating their subclassed variant of
|
||||
* {@link BaseShellDecorator}.
|
||||
*
|
||||
* <p>
|
||||
* <strong>EXPERIMENTAL</strong>. This class or interface has been added as
|
||||
* part of a work in progress. There is no guarantee that this API will work or
|
||||
* that it will remain the same. Please do not use this API without consulting
|
||||
* with the <a href="http://www.eclipse.org/dsdp/tm/">Target Management</a>
|
||||
* team.
|
||||
* </p>
|
||||
*
|
||||
* @see java.lang.Process
|
||||
* @see ProcessBaseShell
|
||||
* @see BaseShellDecorator
|
||||
* @since org.eclipse.rse.services 3.0
|
||||
*/
|
||||
public interface IBaseShell extends IAdaptable {
|
||||
|
||||
/**
|
||||
* Get a local-to-remote OutputStream connected to the standard input of the
|
||||
* underlying Process.
|
||||
*
|
||||
* Clients must not close the obtained OutputStream themselves, since the
|
||||
* behavior that this may have on the underlying shell or process is
|
||||
* undefined. Use {#exit()} instead to terminate the shell if that is
|
||||
* desired, it will close all relevant Streams.
|
||||
*
|
||||
* @return an OutputStream for talking to the underlying process.
|
||||
*/
|
||||
public OutputStream getOutputStream();
|
||||
|
||||
/**
|
||||
* Get a remote-to-local InputStream connected to the standard output of the
|
||||
* underlying Process.
|
||||
*
|
||||
* Clients must not close the obtained InputStream themselves, since the
|
||||
* behavior that this may have on the underlying shell or process is
|
||||
* undefined. Use {#exit()} instead to terminate the shell if that is
|
||||
* desired, it will close all relevant Streams.
|
||||
*
|
||||
* @return an InputStream for reading from the underlying process.
|
||||
*/
|
||||
public InputStream getInputStream();
|
||||
|
||||
/**
|
||||
* Get a remote-to-local InputStream connected to the standard error output
|
||||
* of the underlying Process.
|
||||
*
|
||||
* Implementations may return <code>null</code> if they do not support
|
||||
* separate Streams for output and error.
|
||||
*
|
||||
* Clients must not close the obtained InputStream themselves, since the
|
||||
* behavior that this may have on the underlying shell or process is
|
||||
* undefined. Use {#exit()} instead to terminate the shell if that is
|
||||
* desired, it will close all relevant Streams.
|
||||
*
|
||||
* @return an InputStream for reading error output from the underlying
|
||||
* process, or <code>null</code> if separate output and error
|
||||
* streams are not supported. Error output will be merged with the
|
||||
* Stream obtained from {@link #getInputStream()} in that case.
|
||||
*/
|
||||
public InputStream getErrorStream();
|
||||
|
||||
/**
|
||||
* Test whether this connection is active.
|
||||
*
|
||||
* @return <code>true</code> if the connection is active, i.e. the Process
|
||||
* underlying this connection is running, and the Streams connected
|
||||
* to it are not closed.
|
||||
* @see #exitValue()
|
||||
*/
|
||||
public boolean isActive();
|
||||
|
||||
/**
|
||||
* Exit this shell.
|
||||
*
|
||||
* Implementations are encouraged to try terminating the underlying process
|
||||
* in a clean way, if they can. Depending on the implementation, this may be
|
||||
* possible or not. What's guaranteed to happen is that the Streams
|
||||
* connected with the process are closed so the shell will not be active any
|
||||
* more.
|
||||
*
|
||||
* Execution of this method may run asynchronously in the sense that the
|
||||
* method performs everything to initiate terminating the shell but then
|
||||
* returns immediately. Clients may use {@link #waitFor(long)} after calling
|
||||
* this method to know when the shell is really terminated. At any rate, the
|
||||
* exit() method returns quickly and guarantees that the shell will be
|
||||
* terminated as soon as possible, after any required (and possible) cleanup
|
||||
* is finished.
|
||||
*
|
||||
* @see java.lang.Process#destroy()
|
||||
*/
|
||||
public void exit();
|
||||
|
||||
/**
|
||||
* Return the exit value of the Process connected by this shell.
|
||||
*
|
||||
* Depending on the underlying implementation, this call may not be
|
||||
* supported. Implementations which do not support this must throw an
|
||||
* IllegalThreadStateException when the shell is still active, or return 0
|
||||
* the shell has terminated.
|
||||
*
|
||||
* @return the exit value of the Process connected by this shell, provided
|
||||
* that it has already terminated. By convention, the exit value 0
|
||||
* indicates successful completion or the fact that transmission of
|
||||
* exit values is not supported by an implementation.
|
||||
* @exception IllegalThreadStateException when the shell is still active.
|
||||
* @see java.lang.Process#exitValue()
|
||||
*/
|
||||
public int exitValue();
|
||||
|
||||
/**
|
||||
* Block the calling Thread until this shell is no longer active, or the
|
||||
* specified timeout has elapsed. If the underlying shell has already
|
||||
* terminated, this method returns immediately.
|
||||
*
|
||||
* When this method returns <code>false</code>, the shell is no longer
|
||||
* active, so an {@link #exitValue()} may be obtained.
|
||||
*
|
||||
* @param timeout the maximum time (in milliseconds) to wait.
|
||||
* Implementations may return sooner even if the underlying
|
||||
* Process has not yet terminated, so clients always need to keep
|
||||
* track of time themselves and need to check the return value. A
|
||||
* timeout value of zero causes this method to not limit the wait
|
||||
* time. Negative wait time has undefined behavior.
|
||||
* @return <code>true</code> if the Shell is still active after waiting
|
||||
* (e.g. because the timeout has elapsed); <code>false</code> if
|
||||
* the shell is no longer active.
|
||||
* @throws InterruptedException if the waiting Thread has been interrupted,
|
||||
* e.g. because the main application is shutting down.
|
||||
* @see #isActive()
|
||||
*/
|
||||
public boolean waitFor(long timeout) throws InterruptedException;
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2008 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:
|
||||
* Martin Oberhuber (Wind River) - initial API and implementation
|
||||
*******************************************************************************/
|
||||
|
||||
package org.eclipse.rse.internal.services.terminals;
|
||||
|
||||
import org.eclipse.core.runtime.IProgressMonitor;
|
||||
|
||||
import org.eclipse.rse.services.AbstractService;
|
||||
import org.eclipse.rse.services.IService;
|
||||
import org.eclipse.rse.services.clientserver.messages.SystemMessageException;
|
||||
|
||||
/**
|
||||
* Interface for getting Terminal Connections from a remote side, also known as
|
||||
* terminal session with Streams.
|
||||
*
|
||||
* One ITerminalService instance is typically associated with one particular
|
||||
* connection to a (potentially remote) system, such that the ITerminalService
|
||||
* instance can also hold state data about that session, such as connected
|
||||
* state, login and authentication information, configuration data or
|
||||
* environment variables.
|
||||
*
|
||||
* Each
|
||||
* {@link #launchTerminal(String, String, String[], String, String, IProgressMonitor)}
|
||||
* invocation, however, acts as a factory method such that it creates a new
|
||||
* (remote) process and associated {@link ITerminalShell} connection.
|
||||
*
|
||||
* @noimplement This interface is not intended to be implemented by clients.
|
||||
* Clients must subclass the {@link AbstractService} class rather
|
||||
* than implementing this interface directly.
|
||||
*
|
||||
* <p>
|
||||
* <strong>EXPERIMENTAL</strong>. This class or interface has been added as
|
||||
* part of a work in progress. There is no guarantee that this API will work or
|
||||
* that it will remain the same. Please do not use this API without consulting
|
||||
* with the <a href="http://www.eclipse.org/dsdp/tm/">Target Management</a>
|
||||
* team.
|
||||
* </p>
|
||||
*
|
||||
* @since org.eclipse.rse.services 3.0
|
||||
*
|
||||
*/
|
||||
public interface ITerminalService extends IService {
|
||||
|
||||
/**
|
||||
* Launch a new terminal connection, also known as shell session with
|
||||
* Streams.
|
||||
*
|
||||
* @param ptyType requested terminal type for the new Terminal. Since not
|
||||
* all Terminal implementations support specifying the Terminal
|
||||
* Type, there is no guarantee that a particular setting has any
|
||||
* effect. Use <code>null</code> to fall back to a default
|
||||
* terminal type.
|
||||
* @param encoding Stream encoding to use for sending initial working
|
||||
* directory and initial commandToRun, and to return on
|
||||
* {@link ITerminalShell#getDefaultEncoding()} request. Use
|
||||
* <code>null</code> to fall back to a default encoding. The
|
||||
* Terminal Service will make efforts to determine a proper
|
||||
* default encoding on the remote side but this is not guaranteed
|
||||
* to be correct.
|
||||
* @param environment Array of environment variable Strings of the form
|
||||
* "var=text". Since not all terminal implementations support the
|
||||
* passing of environment variables, there is no guarantee that
|
||||
* the created shell will actually have the specified environment
|
||||
* set. Passing <code>null</code> is allowed in order to
|
||||
* specify that no specific environment needs to be passed.
|
||||
* @param initialWorkingDirectory initial working directory or empty String
|
||||
* ("") if not relevant. The remote shell will launch in a
|
||||
* directory of its own choice in that case (typically a user's
|
||||
* home directory).
|
||||
* @param commandToRun initial command to send to the remote side.
|
||||
* @param monitor Progress Monitor for monitoring and cancellation during
|
||||
* connection creation.
|
||||
* @return the terminal connection object. Note that the connection may not
|
||||
* actually be usable in case the remote side allows opening a
|
||||
* channel but immediately closes it again. In this case,
|
||||
* {@link ITerminalShell#getInputStream()} will throw an
|
||||
* exception or be closed from the very beginning.
|
||||
* @throws SystemMessageException in case an error occurred or the user
|
||||
* chose to cancel the operation via the progress monitor.
|
||||
*/
|
||||
public ITerminalShell launchTerminal(String ptyType, String encoding, String[] environment, String initialWorkingDirectory, String commandToRun,
|
||||
IProgressMonitor monitor) throws SystemMessageException;
|
||||
|
||||
}
|
|
@ -0,0 +1,101 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2008 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:
|
||||
* Martin Oberhuber (Wind River) - initial API and implementation
|
||||
*******************************************************************************/
|
||||
|
||||
package org.eclipse.rse.internal.services.terminals;
|
||||
|
||||
import org.eclipse.rse.services.shells.IHostShell;
|
||||
|
||||
/**
|
||||
* Interface representing a terminal connection through Streams.
|
||||
*
|
||||
* Rather than the underlying {@link IBaseShell}, an ITerminalShell connection
|
||||
* adds methods that describe the presentation of the data transmitted over its
|
||||
* Streams, as well as methods like {@link #setTerminalSize(int, int)} to change
|
||||
* the behavior of the presentation of this data. An instance of ITerminalShell
|
||||
* is typically obtained from an {@link ITerminalService}.
|
||||
*
|
||||
* In RSE, a single remote shell instance can only either support the streamed
|
||||
* ITerminalShell interface or the listener-based {@link IHostShell} interface,
|
||||
* but not both. Note, though, that with the capabilities that an ITerminalShell
|
||||
* has, it is always possible to adapt it to an IHostShell; this is typically
|
||||
* not possible the other way round. We therefore recommend extenders of RSE
|
||||
* that used to subclass IHostShell to move to the new IBaseShell /
|
||||
* ITerminalShell APIs eventually, if they can.
|
||||
*
|
||||
* @noimplement This interface is not intended to be implemented by clients.
|
||||
* Clients must subclass the provided {@link AbstractTerminalShell}
|
||||
* or {@link TerminalShellDecorator} classes rather than
|
||||
* implementing this interface directly.
|
||||
*
|
||||
* <p>
|
||||
* <strong>EXPERIMENTAL</strong>. This class or interface has been added as
|
||||
* part of a work in progress. There is no guarantee that this API will work or
|
||||
* that it will remain the same. Please do not use this API without consulting
|
||||
* with the <a href="http://www.eclipse.org/dsdp/tm/">Target Management</a>
|
||||
* team.
|
||||
* </p>
|
||||
*
|
||||
* @see IBaseShell
|
||||
* @see ITerminalService
|
||||
* @see AbstractTerminalShell
|
||||
* @see TerminalShellDecorator
|
||||
* @since org.eclipse.rse.services 3.0
|
||||
*/
|
||||
public interface ITerminalShell extends IBaseShell {
|
||||
|
||||
/**
|
||||
* Get the Terminal Type that's expected on this connection.
|
||||
*
|
||||
* The terminal type may be specified by the client when constructing a
|
||||
* concrete instance of an ITerminalShell, or a remote side may actually
|
||||
* expect a particular terminal type to be present.
|
||||
*
|
||||
* @return the terminal type expected by the remote side to properly render
|
||||
* the Streams associated with this Terminal, or <code>null</code>
|
||||
* if the ITerminalShell does not know what kind of Terminal Type is
|
||||
* expected.
|
||||
*/
|
||||
public String getPtyType();
|
||||
|
||||
/**
|
||||
* Return the default encoding that the terminal service had specified when
|
||||
* creating this terminal connection, or that's known from the remote side
|
||||
* to be expected. This is not necessarily known or accurate, and may be
|
||||
* <code>null</code>.
|
||||
*
|
||||
* TODO I'm not actually sure if this method is a good idea. Perhaps we
|
||||
* should use the IAdaptable mechanism for dealing with encodings, since our
|
||||
* shells basically deal with binary data only.
|
||||
*
|
||||
* @return the specified default encoding, or <code>null</code> if
|
||||
* unknown.
|
||||
*/
|
||||
public String getDefaultEncoding();
|
||||
|
||||
/**
|
||||
* Notify the remote site that the size of the terminal has changed. There
|
||||
* is no guarantee that the remote side is actually capable of changing the
|
||||
* Terminal size.
|
||||
*
|
||||
* @param newWidth
|
||||
* @param newHeight
|
||||
*/
|
||||
void setTerminalSize(int newWidth, int newHeight);
|
||||
|
||||
/**
|
||||
* Test if local echo is needed on this terminal connection. Clients are
|
||||
* expected to return <code>false</code> if in doubt.
|
||||
*
|
||||
* @return <code>true</code> if a local echo is needed.
|
||||
*/
|
||||
boolean isLocalEcho();
|
||||
|
||||
}
|
|
@ -0,0 +1,148 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2008 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:
|
||||
* Martin Oberhuber (Wind River) - initial API and implementation
|
||||
*******************************************************************************/
|
||||
|
||||
package org.eclipse.rse.internal.services.terminals;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import org.eclipse.core.runtime.PlatformObject;
|
||||
|
||||
/**
|
||||
* A wrapper for Java {@link Process} objects to give more convenient access to
|
||||
* them through the {@link IBaseShell} interface.
|
||||
*
|
||||
* <p>
|
||||
* <strong>EXPERIMENTAL</strong>. This class or interface has been added as
|
||||
* part of a work in progress. There is no guarantee that this API will work or
|
||||
* that it will remain the same. Please do not use this API without consulting
|
||||
* with the <a href="http://www.eclipse.org/dsdp/tm/">Target Management</a>
|
||||
* team.
|
||||
* </p>
|
||||
*
|
||||
* @since org.eclipse.rse.services 3.0
|
||||
*/
|
||||
public class ProcessBaseShell extends PlatformObject implements IBaseShell {
|
||||
|
||||
/**
|
||||
* The underlying Process instance.
|
||||
*/
|
||||
protected final Process fProcess;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param p the Process to wrap with this IBaseShell interface.
|
||||
*/
|
||||
public ProcessBaseShell(Process p) {
|
||||
fProcess = p;
|
||||
}
|
||||
|
||||
/**
|
||||
* Forcefully terminate the underlying Process through
|
||||
* {@link Process#destroy()}. Subclasses may want to override this behavior
|
||||
* by trying to terminate the underlying Process in a cleaner way.
|
||||
*
|
||||
* @see IBaseShell#exit()
|
||||
*/
|
||||
public void exit() {
|
||||
fProcess.destroy();
|
||||
}
|
||||
|
||||
public int exitValue() {
|
||||
return fProcess.exitValue();
|
||||
}
|
||||
|
||||
public InputStream getErrorStream() {
|
||||
return fProcess.getErrorStream();
|
||||
}
|
||||
|
||||
public InputStream getInputStream() {
|
||||
return fProcess.getInputStream();
|
||||
}
|
||||
|
||||
public OutputStream getOutputStream() {
|
||||
return fProcess.getOutputStream();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the underlying Process is still active. Does not check whether
|
||||
* the Streams for the Process have been closed by the client, since this
|
||||
* does not influence the process active state anyways.
|
||||
*
|
||||
* @see IBaseShell#isActive()
|
||||
*/
|
||||
public boolean isActive() {
|
||||
try {
|
||||
fProcess.exitValue();
|
||||
} catch (IllegalThreadStateException e) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* A Watchdog Thread, to interrupt other Threads after a given time unless a
|
||||
* specified condition is met.
|
||||
*
|
||||
* Sleeps for a given time, and upon wakeup checks if a condition is met. If
|
||||
* not, the specified Thread is interrupted.
|
||||
*/
|
||||
private abstract static class Watchdog extends Thread {
|
||||
private final Thread fThreadToWatch;
|
||||
private long fTimeout;
|
||||
|
||||
public Watchdog(Thread threadToWatch, long timeout) {
|
||||
fThreadToWatch = threadToWatch;
|
||||
fTimeout = timeout;
|
||||
}
|
||||
|
||||
protected abstract boolean conditionDone();
|
||||
|
||||
public void run() {
|
||||
try {
|
||||
sleep(fTimeout);
|
||||
} catch (InterruptedException e) {
|
||||
/* ignore */
|
||||
} finally {
|
||||
if (!conditionDone()) {
|
||||
fThreadToWatch.interrupt();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean waitFor(long timeout) throws InterruptedException {
|
||||
boolean active = isActive();
|
||||
if (active) {
|
||||
Thread watchdog = null;
|
||||
if (timeout > 0) {
|
||||
watchdog = new Watchdog(Thread.currentThread(), timeout) {
|
||||
protected boolean conditionDone() {
|
||||
return !isActive();
|
||||
}
|
||||
};
|
||||
watchdog.start();
|
||||
}
|
||||
try {
|
||||
fProcess.waitFor();
|
||||
} catch (InterruptedException e) {
|
||||
/* ignore */
|
||||
}
|
||||
if (watchdog != null) {
|
||||
watchdog.interrupt();
|
||||
}
|
||||
active = isActive();
|
||||
}
|
||||
return active;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2008 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:
|
||||
* Martin Oberhuber (Wind River) - initial API and implementation
|
||||
*******************************************************************************/
|
||||
|
||||
package org.eclipse.rse.internal.services.terminals;
|
||||
|
||||
/**
|
||||
* Abstract base class for clients to decorate an ITerminalShell instance they
|
||||
* have with additional functionality.
|
||||
*
|
||||
* Typically, such additional functionality can be provided either by additional
|
||||
* knowledge about the underlying system or process, or by analyzing the input
|
||||
* and output streams for some well-known data that gives such additional
|
||||
* knowledge.
|
||||
*
|
||||
* <p>
|
||||
* <strong>EXPERIMENTAL</strong>. This class or interface has been added as
|
||||
* part of a work in progress. There is no guarantee that this API will work or
|
||||
* that it will remain the same. Please do not use this API without consulting
|
||||
* with the <a href="http://www.eclipse.org/dsdp/tm/">Target Management</a>
|
||||
* team.
|
||||
* </p>
|
||||
*
|
||||
* @since org.eclipse.rse.services 3.0
|
||||
*/
|
||||
public abstract class TerminalShellDecorator extends BaseShellDecorator implements ITerminalShell {
|
||||
|
||||
public TerminalShellDecorator(ITerminalShell delegate) {
|
||||
super(delegate);
|
||||
}
|
||||
|
||||
protected ITerminalShell getDelegate() {
|
||||
return (ITerminalShell) fDelegate;
|
||||
}
|
||||
|
||||
public String getPtyType() {
|
||||
return getDelegate().getPtyType();
|
||||
}
|
||||
|
||||
public String getDefaultEncoding() {
|
||||
return getDelegate().getDefaultEncoding();
|
||||
}
|
||||
|
||||
public boolean isLocalEcho() {
|
||||
return getDelegate().isLocalEcho();
|
||||
}
|
||||
|
||||
public void setTerminalSize(int newWidth, int newHeight) {
|
||||
getDelegate().setTerminalSize(newWidth, newHeight);
|
||||
}
|
||||
|
||||
}
|
Loading…
Add table
Reference in a new issue