diff --git a/bundles/org.eclipse.remote.core/plugin.xml b/bundles/org.eclipse.remote.core/plugin.xml
index bedfc2973f3..51b916ebf9e 100644
--- a/bundles/org.eclipse.remote.core/plugin.xml
+++ b/bundles/org.eclipse.remote.core/plugin.xml
@@ -33,6 +33,16 @@
factory="org.eclipse.remote.internal.core.services.local.LocalProcessService$Factory"
service="org.eclipse.remote.core.IRemoteProcessService">
+
+
+
+
diff --git a/bundles/org.eclipse.remote.core/schema/remoteServices.exsd b/bundles/org.eclipse.remote.core/schema/remoteServices.exsd
index ad5a5424dd4..a8e42467cb8 100644
--- a/bundles/org.eclipse.remote.core/schema/remoteServices.exsd
+++ b/bundles/org.eclipse.remote.core/schema/remoteServices.exsd
@@ -21,6 +21,7 @@
+
@@ -173,6 +174,46 @@
+
+
+
+ This is a service that implements the given service interface for processes of a given connection type.
+
+
+
+
+
+
+ The connection type for the connections that this service applies to.
+
+
+
+
+
+
+
+
+
+ The interface class that this service implements. The service is found by calling the getService() method on the IRemoteProcess object with this interface class as the parameter.
+
+
+
+
+
+
+
+
+
+ The factory class used to instantiate the service.
+
+
+
+
+
+
+
+
+
diff --git a/bundles/org.eclipse.remote.core/src/org/eclipse/remote/core/AbstractRemoteProcess.java b/bundles/org.eclipse.remote.core/src/org/eclipse/remote/core/AbstractRemoteProcess.java
deleted file mode 100644
index a3a8972dc2e..00000000000
--- a/bundles/org.eclipse.remote.core/src/org/eclipse/remote/core/AbstractRemoteProcess.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007 IBM Corporation 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:
- * IBM Corporation - Initial API and implementation
- *******************************************************************************/
-package org.eclipse.remote.core;
-
-import java.io.InputStream;
-import java.io.OutputStream;
-
-/**
- * Abstract base class for remote processes. Implementors can use this class to provide a default remote process implementation.
- */
-public abstract class AbstractRemoteProcess extends Process implements IRemoteProcess {
- /*
- * (non-Javadoc)
- *
- * @see java.lang.Process#destroy()
- */
- @Override
- public void destroy() {
- // Nothing
- }
-
- /*
- * (non-Javadoc)
- *
- * @see java.lang.Process#exitValue()
- */
- @Override
- public int exitValue() {
- return 0;
- }
-
- /*
- * (non-Javadoc)
- *
- * @see java.lang.Process#getErrorStream()
- */
- @Override
- public InputStream getErrorStream() {
- return null;
- }
-
- /*
- * (non-Javadoc)
- *
- * @see java.lang.Process#getInputStream()
- */
- @Override
- public InputStream getInputStream() {
- return null;
- }
-
- /*
- * (non-Javadoc)
- *
- * @see java.lang.Process#getOutputStream()
- */
- @Override
- public OutputStream getOutputStream() {
- return null;
- }
-
- /*
- * (non-Javadoc)
- *
- * @see java.lang.Process#waitFor()
- */
- @Override
- public int waitFor() throws InterruptedException {
- return 0;
- }
-
- /*
- * (non-Javadoc)
- *
- * @see org.eclipse.remote.core.IRemoteProcess#isCompleted()
- */
- @Override
- public boolean isCompleted() {
- return true;
- }
-}
diff --git a/bundles/org.eclipse.remote.core/src/org/eclipse/remote/core/AbstractRemoteProcessBuilder.java b/bundles/org.eclipse.remote.core/src/org/eclipse/remote/core/AbstractRemoteProcessBuilder.java
index 839b2a7fa13..1b208f3b218 100644
--- a/bundles/org.eclipse.remote.core/src/org/eclipse/remote/core/AbstractRemoteProcessBuilder.java
+++ b/bundles/org.eclipse.remote.core/src/org/eclipse/remote/core/AbstractRemoteProcessBuilder.java
@@ -25,15 +25,24 @@ import org.eclipse.core.filesystem.IFileStore;
*/
public abstract class AbstractRemoteProcessBuilder implements IRemoteProcessBuilder {
private List fCommandArgs;
- private IFileStore fRemoteDir = null;
- private boolean fRedirectErrorStream = false;
+ private IFileStore fRemoteDir;
+ private boolean fRedirectErrorStream;
- public AbstractRemoteProcessBuilder(List command) {
+ private final IRemoteConnection fConnection;
+
+ /**
+ * @since 2.0
+ */
+ public AbstractRemoteProcessBuilder(IRemoteConnection connection, List command) {
fCommandArgs = command;
+ fConnection = connection;
}
- public AbstractRemoteProcessBuilder(String... command) {
- this(Arrays.asList(command));
+ /**
+ * @since 2.0
+ */
+ public AbstractRemoteProcessBuilder(IRemoteConnection connection, String... command) {
+ this(connection, Arrays.asList(command));
}
/*
@@ -173,4 +182,17 @@ public abstract class AbstractRemoteProcessBuilder implements IRemoteProcessBuil
}
return res.toString();
}
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.remote.core.IRemoteProcessBuilder#getRemoteConnection()
+ */
+ /**
+ * @since 2.0
+ */
+ @Override
+ public IRemoteConnection getRemoteConnection() {
+ return fConnection;
+ }
}
diff --git a/bundles/org.eclipse.remote.core/src/org/eclipse/remote/core/IRemoteConnectionType.java b/bundles/org.eclipse.remote.core/src/org/eclipse/remote/core/IRemoteConnectionType.java
index 94caa2e9f03..19196f0fe0a 100644
--- a/bundles/org.eclipse.remote.core/src/org/eclipse/remote/core/IRemoteConnectionType.java
+++ b/bundles/org.eclipse.remote.core/src/org/eclipse/remote/core/IRemoteConnectionType.java
@@ -110,6 +110,15 @@ public interface IRemoteConnectionType {
*/
boolean hasConnectionService(Class service);
+ /**
+ * Do processes created by this connection type support the given service.
+ *
+ * @param service
+ * the service to be tested
+ * @return true if processes created by this connection type support this service
+ */
+ boolean hasProcessService(Class service);
+
/**
* Gets the remote connection corresponding to the supplied name.
*
diff --git a/bundles/org.eclipse.remote.core/src/org/eclipse/remote/core/IRemoteProcess.java b/bundles/org.eclipse.remote.core/src/org/eclipse/remote/core/IRemoteProcess.java
index c5e86d885fd..ff5fbbb433d 100644
--- a/bundles/org.eclipse.remote.core/src/org/eclipse/remote/core/IRemoteProcess.java
+++ b/bundles/org.eclipse.remote.core/src/org/eclipse/remote/core/IRemoteProcess.java
@@ -14,21 +14,33 @@ import java.io.InputStream;
import java.io.OutputStream;
/**
- * Abstraction of a process running on a remote system. Remote process are created using the {@link IRemoteProcessBuilder}
- * interface.
+ * Represents a process running on a remote system. Remote process are created using the {@link IRemoteProcessBuilder} interface.
*/
public interface IRemoteProcess {
+ /**
+ * The interface that is extend by services provided for this remote connection.
+ *
+ * @since 2.0
+ */
+ interface Service {
+ IRemoteProcess getRemoteProcess();
+
+ interface Factory {
+ T getService(IRemoteProcess remoteProcess, Class service);
+ }
+ }
+
/**
* Terminate the process
*/
- public void destroy();
+ void destroy();
/**
* Returns the exit value for the process
*
* @return the exit value
*/
- public int exitValue();
+ int exitValue();
/**
* Gets the error output stream of the process
@@ -36,7 +48,7 @@ public interface IRemoteProcess {
* @return the output stream connected to the standard
* error of the process
*/
- public InputStream getErrorStream();
+ InputStream getErrorStream();
/**
* Gets an InputStream which can be used to read the standard output stream of the process
@@ -44,7 +56,7 @@ public interface IRemoteProcess {
* @return the input stream connected to the standard
* output of the process
*/
- public InputStream getInputStream();
+ InputStream getInputStream();
/**
* Gets an output stream which can be used to write to the standard input stream of the process
@@ -52,7 +64,27 @@ public interface IRemoteProcess {
* @return the output stream connected to the standard
* input of the process
*/
- public OutputStream getOutputStream();
+ OutputStream getOutputStream();
+
+ /**
+ * Get the service for this remote process that implements the given interface.
+ *
+ * @param service
+ * the interface the required service must implements
+ * @return the desired service or null if there is no such service available
+ * @since 2.0
+ */
+ T getService(Class service);
+
+ /**
+ * Does this remote process support the given service.
+ *
+ * @param service
+ * The service to be tested
+ * @return true if this connection supports the service
+ * @since 2.0
+ */
+ boolean hasService(Class service);
/**
* Wait until the process has terminated
@@ -62,12 +94,28 @@ public interface IRemoteProcess {
* if the current thread is
* interrupted by another thread while it is waiting
*/
- public int waitFor() throws InterruptedException;
+ int waitFor() throws InterruptedException;
/**
* Check if the remote process has completed
*
* @return true if remote process has completed
*/
- public boolean isCompleted();
+ boolean isCompleted();
+
+ /**
+ * Get the connection that is used by this process
+ *
+ * @return connection used by this process
+ * @since 2.0
+ */
+ IRemoteConnection getRemoteConnection();
+
+ /**
+ * Get the process builder used to create this process
+ *
+ * @return process builder used to create this process
+ * @since 2.0
+ */
+ IRemoteProcessBuilder getProcessBuilder();
}
diff --git a/bundles/org.eclipse.remote.core/src/org/eclipse/remote/core/IRemoteProcessBuilder.java b/bundles/org.eclipse.remote.core/src/org/eclipse/remote/core/IRemoteProcessBuilder.java
index 9a8f966e4a5..d46bdd365f5 100644
--- a/bundles/org.eclipse.remote.core/src/org/eclipse/remote/core/IRemoteProcessBuilder.java
+++ b/bundles/org.eclipse.remote.core/src/org/eclipse/remote/core/IRemoteProcessBuilder.java
@@ -46,7 +46,7 @@ public interface IRemoteProcessBuilder {
*
* @return a list containing the program and arguments
*/
- public List command();
+ List command();
/**
* Sets this process builder's operating system program and arguments.
@@ -54,7 +54,7 @@ public interface IRemoteProcessBuilder {
* @param command
* @return This process builder
*/
- public IRemoteProcessBuilder command(List command);
+ IRemoteProcessBuilder command(List command);
/**
* Sets this process builder's operating system program and arguments.
@@ -62,14 +62,14 @@ public interface IRemoteProcessBuilder {
* @param command
* @return this process builder
*/
- public IRemoteProcessBuilder command(String... command);
+ IRemoteProcessBuilder command(String... command);
/**
* Returns this process builder's working directory.
*
* @return an IFileStore reference to the working directory
*/
- public IFileStore directory();
+ IFileStore directory();
/**
* Sets this process builder's working directory.
@@ -77,7 +77,7 @@ public interface IRemoteProcessBuilder {
* @param directory
* @return This process builder
*/
- public IRemoteProcessBuilder directory(IFileStore directory);
+ IRemoteProcessBuilder directory(IFileStore directory);
/**
* Returns a string map view of this process builder's environment. The
@@ -85,7 +85,7 @@ public interface IRemoteProcessBuilder {
*
* @return the process builder's environment
*/
- public Map environment();
+ Map environment();
/**
* Get the flags that are supported by this process builder.
@@ -93,7 +93,7 @@ public interface IRemoteProcessBuilder {
* @return bitwise-or of the supported flags
* @since 5.0
*/
- public int getSupportedFlags();
+ int getSupportedFlags();
/**
* Tells whether this process builder merges standard error and standard
@@ -101,7 +101,7 @@ public interface IRemoteProcessBuilder {
*
* @return true if standard error and standard output will be merged
*/
- public boolean redirectErrorStream();
+ boolean redirectErrorStream();
/**
* Sets this process builder's redirectErrorStream property.
@@ -109,7 +109,7 @@ public interface IRemoteProcessBuilder {
* @param redirectErrorStream
* @return This process builder
*/
- public IRemoteProcessBuilder redirectErrorStream(boolean redirectErrorStream);
+ IRemoteProcessBuilder redirectErrorStream(boolean redirectErrorStream);
/**
* Starts a new process using the attributes of this process builder.
@@ -117,7 +117,7 @@ public interface IRemoteProcessBuilder {
* @return remote process object
* @throws IOException
*/
- public IRemoteProcess start() throws IOException;
+ IRemoteProcess start() throws IOException;
/**
* Starts a new process using the attributes of this process builder. The
@@ -139,5 +139,13 @@ public interface IRemoteProcessBuilder {
* @throws IOException
* @since 5.0
*/
- public IRemoteProcess start(int flags) throws IOException;
+ IRemoteProcess start(int flags) throws IOException;
+
+ /**
+ * Get the connection that will be used by this process builder to create remote processes.
+ *
+ * @return connection used to create remote processes
+ * @since 2.0
+ */
+ IRemoteConnection getRemoteConnection();
}
\ No newline at end of file
diff --git a/bundles/org.eclipse.remote.core/src/org/eclipse/remote/core/IRemoteProcessControlService.java b/bundles/org.eclipse.remote.core/src/org/eclipse/remote/core/IRemoteProcessControlService.java
new file mode 100644
index 00000000000..65b2d4beed7
--- /dev/null
+++ b/bundles/org.eclipse.remote.core/src/org/eclipse/remote/core/IRemoteProcessControlService.java
@@ -0,0 +1,74 @@
+/*******************************************************************************
+ * Copyright (c) 2015 QNX Software Systems and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * QNX - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.remote.core;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * A service to control and report on the state of a process.
+ *
+ * @since 2.0
+ */
+public interface IRemoteProcessControlService extends IRemoteProcess.Service {
+ /**
+ * Terminate the process
+ */
+ public void destroy();
+
+ /**
+ * Returns the exit value for the process
+ *
+ * @return the exit value
+ */
+ public int exitValue();
+
+ /**
+ * Gets the error output stream of the process
+ *
+ * @return the output stream connected to the standard
+ * error of the process
+ */
+ public InputStream getErrorStream();
+
+ /**
+ * Gets an InputStream which can be used to read the standard output stream of the process
+ *
+ * @return the input stream connected to the standard
+ * output of the process
+ */
+ public InputStream getInputStream();
+
+ /**
+ * Gets an output stream which can be used to write to the standard input stream of the process
+ *
+ * @return the output stream connected to the standard
+ * input of the process
+ */
+ public OutputStream getOutputStream();
+
+ /**
+ * Wait until the process has terminated
+ *
+ * @return the exit value of the process
+ * @throws InterruptedException
+ * if the current thread is
+ * interrupted by another thread while it is waiting
+ */
+ public int waitFor() throws InterruptedException;
+
+ /**
+ * Check if the remote process has completed
+ *
+ * @return true if remote process has completed
+ */
+ public boolean isCompleted();
+}
diff --git a/bundles/org.eclipse.remote.core/src/org/eclipse/remote/core/IRemoteProcessSignalService.java b/bundles/org.eclipse.remote.core/src/org/eclipse/remote/core/IRemoteProcessSignalService.java
new file mode 100644
index 00000000000..af09b3a3599
--- /dev/null
+++ b/bundles/org.eclipse.remote.core/src/org/eclipse/remote/core/IRemoteProcessSignalService.java
@@ -0,0 +1,48 @@
+/*******************************************************************************
+ * Copyright (c) 2015 IBM Corporation 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:
+ * IBM Corporation - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.remote.core;
+
+import org.eclipse.remote.core.exception.RemoteConnectionException;
+
+/**
+ * A service abstraction for signals.
+ *
+ * @since 2.0
+ */
+public interface IRemoteProcessSignalService extends IRemoteProcess.Service {
+ public static final int HUP = 1;
+ public static final int INT = 2;
+ public static final int QUIT = 3;
+ public static final int ILL = 4;
+ public static final int ABRT = 6;
+ public static final int FPE = 8;
+ public static final int KILL = 9;
+ public static final int SEGV = 11;
+ public static final int PIPE = 13;
+ public static final int ALRM = 14;
+ public static final int TERM = 15;
+ public static final int STOP = 17;
+ public static final int TSTP = 18;
+ public static final int CONT = 19;
+ public static final int USR1 = 30;
+ public static final int USR2 = 31;
+
+ /**
+ * Send a signal to the remote process.
+ *
+ * @param signal
+ * signal to send.
+ * @throws RemoteConnectionException
+ * if the underlying connection fails
+ * @since 2.0
+ */
+ void sendSignal(int signal) throws RemoteConnectionException;
+}
diff --git a/bundles/org.eclipse.remote.core/src/org/eclipse/remote/core/IRemoteProcessTerminalService.java b/bundles/org.eclipse.remote.core/src/org/eclipse/remote/core/IRemoteProcessTerminalService.java
new file mode 100644
index 00000000000..6c34a207ecd
--- /dev/null
+++ b/bundles/org.eclipse.remote.core/src/org/eclipse/remote/core/IRemoteProcessTerminalService.java
@@ -0,0 +1,33 @@
+/*******************************************************************************
+ * Copyright (c) 2015 IBM Corporation 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:
+ * IBM Corporation - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.remote.core;
+
+/**
+ * A service abstraction for remote terminals.
+ *
+ * @since 2.0
+ */
+public interface IRemoteProcessTerminalService extends IRemoteProcess.Service {
+ /**
+ * Change the terminal window dimension interactively. Refer to RFC 4254 6.7. Window Dimension Change Message. The character/row
+ * dimensions override the pixel dimensions (when nonzero). Pixel dimensions refer to the drawable area of the window.
+ *
+ * @param cols
+ * terminal width in characters
+ * @param rows
+ * terminal height in characters
+ * @param width
+ * terminal width in pixels
+ * @param height
+ * terminal height in pixels
+ */
+ void setTerminalSize(int cols, int rows, int width, int height);
+}
diff --git a/bundles/org.eclipse.remote.core/src/org/eclipse/remote/internal/core/RemoteConnectionType.java b/bundles/org.eclipse.remote.core/src/org/eclipse/remote/internal/core/RemoteConnectionType.java
index a07dacaa239..d62cc98cd86 100644
--- a/bundles/org.eclipse.remote.core/src/org/eclipse/remote/internal/core/RemoteConnectionType.java
+++ b/bundles/org.eclipse.remote.core/src/org/eclipse/remote/internal/core/RemoteConnectionType.java
@@ -22,6 +22,7 @@ import org.eclipse.equinox.security.storage.ISecurePreferences;
import org.eclipse.remote.core.IRemoteConnection;
import org.eclipse.remote.core.IRemoteConnectionType;
import org.eclipse.remote.core.IRemoteConnectionWorkingCopy;
+import org.eclipse.remote.core.IRemoteProcess;
import org.eclipse.remote.core.IRemoteServicesManager;
import org.eclipse.remote.core.RemoteConnectionChangeEvent;
import org.eclipse.remote.core.exception.ConnectionExistsException;
@@ -204,6 +205,44 @@ public class RemoteConnectionType implements IRemoteConnectionType {
return serviceDefinitionMap.get(service.getName()) != null;
}
+ /**
+ * Called from the remote process to get a service object for that process.
+ *
+ * @param process
+ * the process to which the service applies
+ * @param service
+ * the interface the service must implement
+ * @return the service object
+ * @throws CoreException
+ */
+ public T getProcessService(IRemoteProcess process, Class service) {
+ // Both top level and connection services are stored in the serviceDefinitionMap.
+ // In theory the two sets of interfaces can't collide.
+ IConfigurationElement ce = serviceDefinitionMap.get(service.getName());
+ if (ce != null) {
+ try {
+ IRemoteProcess.Service.Factory factory = (IRemoteProcess.Service.Factory) ce.createExecutableExtension("factory"); //$NON-NLS-1$
+ if (factory != null) {
+ return factory.getService(process, service);
+ }
+ } catch (CoreException e) {
+ RemoteCorePlugin.log(e.getStatus());
+ }
+ }
+
+ return null;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.remote.core.IRemoteConnectionType#hasProcessService(java.lang.Class)
+ */
+ @Override
+ public boolean hasProcessService(Class service) {
+ return serviceDefinitionMap.get(service.getName()) != null;
+ }
+
/**
* Called from the remote service manager to register a service extension for
* this remote services implementation
diff --git a/bundles/org.eclipse.remote.core/src/org/eclipse/remote/internal/core/RemoteProcess.java b/bundles/org.eclipse.remote.core/src/org/eclipse/remote/internal/core/RemoteProcess.java
new file mode 100644
index 00000000000..d5ecde6c746
--- /dev/null
+++ b/bundles/org.eclipse.remote.core/src/org/eclipse/remote/internal/core/RemoteProcess.java
@@ -0,0 +1,188 @@
+/*******************************************************************************
+ * Copyright (c) 2007 IBM Corporation 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:
+ * IBM Corporation - Initial API and implementation
+ *******************************************************************************/
+package org.eclipse.remote.internal.core;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.remote.core.IRemoteConnection;
+import org.eclipse.remote.core.IRemoteProcess;
+import org.eclipse.remote.core.IRemoteProcessBuilder;
+import org.eclipse.remote.core.IRemoteProcessControlService;
+
+/**
+ * Standard root class for remote processes.
+ */
+public class RemoteProcess extends Process implements IRemoteProcess {
+ private final Map servicesMap = new HashMap<>();
+ private final IRemoteConnection connection;
+ private final IRemoteProcessBuilder builder;
+
+ /**
+ * @since 2.0
+ */
+ public RemoteProcess(IRemoteConnection connection, IRemoteProcessBuilder builder) {
+ this.connection = connection;
+ this.builder = builder;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Process#destroy()
+ */
+ @Override
+ public void destroy() {
+ IRemoteProcessControlService controlService = getService(IRemoteProcessControlService.class);
+ if (controlService != null) {
+ controlService.destroy();
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Process#exitValue()
+ */
+ @Override
+ public int exitValue() {
+ IRemoteProcessControlService controlService = getService(IRemoteProcessControlService.class);
+ if (controlService != null) {
+ return controlService.exitValue();
+ }
+ return 0;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Process#getErrorStream()
+ */
+ @Override
+ public InputStream getErrorStream() {
+ IRemoteProcessControlService controlService = getService(IRemoteProcessControlService.class);
+ if (controlService != null) {
+ return controlService.getErrorStream();
+ }
+ return null;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Process#getInputStream()
+ */
+ @Override
+ public InputStream getInputStream() {
+ IRemoteProcessControlService controlService = getService(IRemoteProcessControlService.class);
+ if (controlService != null) {
+ return controlService.getInputStream();
+ }
+ return null;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Process#getOutputStream()
+ */
+ @Override
+ public OutputStream getOutputStream() {
+ IRemoteProcessControlService controlService = getService(IRemoteProcessControlService.class);
+ if (controlService != null) {
+ return controlService.getOutputStream();
+ }
+ return null;
+ }
+
+ /**
+ * @since 2.0
+ */
+ @SuppressWarnings("unchecked")
+ @Override
+ public T getService(Class service) {
+ String serviceName = service.getName();
+ Object obj = servicesMap.get(serviceName);
+ if (obj == null) {
+ obj = getConnectionType().getProcessService(this, service);
+ if (obj != null) {
+ servicesMap.put(serviceName, obj);
+ }
+ }
+
+ return (T) obj;
+ }
+
+ /**
+ * @since 2.0
+ */
+ @Override
+ public boolean hasService(Class service) {
+ return servicesMap.get(service.getName()) != null || getConnectionType().hasProcessService(service);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Process#waitFor()
+ */
+ @Override
+ public int waitFor() throws InterruptedException {
+ IRemoteProcessControlService controlService = getService(IRemoteProcessControlService.class);
+ if (controlService != null) {
+ return controlService.waitFor();
+ }
+ return 0;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.remote.core.IRemoteProcess#isCompleted()
+ */
+ @Override
+ public boolean isCompleted() {
+ IRemoteProcessControlService controlService = getService(IRemoteProcessControlService.class);
+ if (controlService != null) {
+ return controlService.isCompleted();
+ }
+ return true;
+ }
+
+ /**
+ * @since 2.0
+ */
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.remote.core.IRemoteProcess#getRemoteConnection()
+ */
+ @Override
+ public IRemoteConnection getRemoteConnection() {
+ return connection;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.remote.core.IRemoteProcess#getProcessBuilder()
+ */
+ @Override
+ public IRemoteProcessBuilder getProcessBuilder() {
+ return builder;
+ }
+
+ private RemoteConnectionType getConnectionType() {
+ return (RemoteConnectionType) getRemoteConnection().getConnectionType();
+ }
+}
diff --git a/bundles/org.eclipse.remote.core/src/org/eclipse/remote/internal/core/RemoteServicesManager.java b/bundles/org.eclipse.remote.core/src/org/eclipse/remote/internal/core/RemoteServicesManager.java
index f7de07d4b6a..5b1008593c2 100644
--- a/bundles/org.eclipse.remote.core/src/org/eclipse/remote/internal/core/RemoteServicesManager.java
+++ b/bundles/org.eclipse.remote.core/src/org/eclipse/remote/internal/core/RemoteServicesManager.java
@@ -83,7 +83,7 @@ public class RemoteServicesManager implements IRemoteServicesManager {
for (IExtension ext : point.getExtensions()) {
for (IConfigurationElement ce : ext.getConfigurationElements()) {
String name = ce.getName();
- if (name.equals("connectionTypeService") || name.equals("connectionService")) { //$NON-NLS-1$ //$NON-NLS-2$
+ if (name.equals("connectionTypeService") || name.equals("connectionService") || name.equals("processService")) { //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
String id = ce.getAttribute("connectionTypeId"); //$NON-NLS-1$
RemoteConnectionType services = connectionTypeMap.get(id);
if (services != null) {
diff --git a/bundles/org.eclipse.remote.core/src/org/eclipse/remote/internal/core/services/local/LocalProcess.java b/bundles/org.eclipse.remote.core/src/org/eclipse/remote/internal/core/services/local/LocalProcess.java
index 4440420d3cc..806cdee790d 100644
--- a/bundles/org.eclipse.remote.core/src/org/eclipse/remote/internal/core/services/local/LocalProcess.java
+++ b/bundles/org.eclipse.remote.core/src/org/eclipse/remote/internal/core/services/local/LocalProcess.java
@@ -16,11 +16,13 @@ import java.io.OutputStream;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
-import org.eclipse.remote.core.AbstractRemoteProcess;
+import org.eclipse.remote.core.IRemoteProcess;
+import org.eclipse.remote.core.IRemoteProcessControlService;
-public class LocalProcess extends AbstractRemoteProcess {
+public class LocalProcess implements IRemoteProcessControlService {
private static int refCount = 0;
+ private final IRemoteProcess remoteProcess;
private final Process localProcess;
private InputStream procStdout;
private InputStream procStderr;
@@ -29,12 +31,35 @@ public class LocalProcess extends AbstractRemoteProcess {
private final Thread completedChecker;
private volatile boolean isCompleted;
+ public static class Factory implements IRemoteProcess.Service.Factory {
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.remote.core.IRemoteProcess.Service.Factory#getService(org.eclipse.remote.core.IRemoteProcess,
+ * java.lang.Class)
+ */
+ @SuppressWarnings("unchecked")
+ @Override
+ public T getService(IRemoteProcess remoteProcess, Class service) {
+ // This little trick creates an instance of this class
+ // then for each interface it implements, it returns the same object.
+ // This works because the connection caches the service so only one gets created.
+ // As a side effect, it makes this class a service too which can be used
+ // by the this plug-in
+ if (LocalProcess.class.equals(service)) {
+ return (T) new LocalProcess(remoteProcess);
+ }
+ if (IRemoteProcessControlService.class.equals(service)) {
+ return (T) remoteProcess.getService(LocalProcess.class);
+ }
+ return null;
+ }
+ }
+
/**
* Thread to merge stdout and stderr. Keeps refcount so that output stream
* is not closed too early.
*
- * @author greg
- *
*/
private class ProcOutputMerger implements Runnable {
private final static int BUF_SIZE = 8192;
@@ -86,23 +111,28 @@ public class LocalProcess extends AbstractRemoteProcess {
}
}
- public LocalProcess(Process proc, boolean merge) throws IOException {
- localProcess = proc;
+ public LocalProcess(IRemoteProcess process) {
+ remoteProcess = process;
+ localProcess = ((LocalProcessBuilder) process.getProcessBuilder()).getProcess();
- if (merge) {
- PipedOutputStream pipedOutput = new PipedOutputStream();
+ try {
+ if (process.getProcessBuilder().redirectErrorStream()) {
+ PipedOutputStream pipedOutput = new PipedOutputStream();
- procStderr = new NullInputStream();
- procStdout = new PipedInputStream(pipedOutput);
+ procStderr = new NullInputStream();
+ procStdout = new PipedInputStream(pipedOutput);
- stderrReader = new Thread(new ProcOutputMerger(proc.getErrorStream(), pipedOutput));
- stdoutReader = new Thread(new ProcOutputMerger(proc.getInputStream(), pipedOutput));
+ stderrReader = new Thread(new ProcOutputMerger(localProcess.getErrorStream(), pipedOutput));
+ stdoutReader = new Thread(new ProcOutputMerger(localProcess.getInputStream(), pipedOutput));
- stderrReader.start();
- stdoutReader.start();
- } else {
- procStderr = localProcess.getErrorStream();
- procStdout = localProcess.getInputStream();
+ stderrReader.start();
+ stdoutReader.start();
+ } else {
+ procStderr = localProcess.getErrorStream();
+ procStdout = localProcess.getInputStream();
+ }
+ } catch (IOException e) {
+ localProcess.destroy();
}
completedChecker = new Thread(new Runnable() {
@@ -185,10 +215,15 @@ public class LocalProcess extends AbstractRemoteProcess {
/*
* (non-Javadoc)
*
- * @see org.eclipse.remote.core.AbstractRemoteProcess#isCompleted()
+ * @see org.eclipse.remote.core.RemoteProcess#isCompleted()
*/
@Override
public boolean isCompleted() {
return isCompleted;
}
+
+ @Override
+ public IRemoteProcess getRemoteProcess() {
+ return remoteProcess;
+ }
}
diff --git a/bundles/org.eclipse.remote.core/src/org/eclipse/remote/internal/core/services/local/LocalProcessBuilder.java b/bundles/org.eclipse.remote.core/src/org/eclipse/remote/internal/core/services/local/LocalProcessBuilder.java
index f26b3a57beb..022f453f94e 100644
--- a/bundles/org.eclipse.remote.core/src/org/eclipse/remote/internal/core/services/local/LocalProcessBuilder.java
+++ b/bundles/org.eclipse.remote.core/src/org/eclipse/remote/internal/core/services/local/LocalProcessBuilder.java
@@ -30,8 +30,10 @@ import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Platform;
import org.eclipse.remote.core.AbstractRemoteProcessBuilder;
import org.eclipse.remote.core.IProcessFactory;
+import org.eclipse.remote.core.IRemoteConnection;
import org.eclipse.remote.core.IRemoteProcess;
import org.eclipse.remote.internal.core.RemoteCorePlugin;
+import org.eclipse.remote.internal.core.RemoteProcess;
public class LocalProcessBuilder extends AbstractRemoteProcessBuilder {
private static final String EXTENSION_POINT_ID = "processFactory"; //$NON-NLS-1$
@@ -40,14 +42,16 @@ public class LocalProcessBuilder extends AbstractRemoteProcessBuilder {
private final IProcessFactory fProcessFactory;
private final Map fRemoteEnv = new HashMap();
- public LocalProcessBuilder(List command) {
- super(command);
+ private Process localProcess;
+
+ public LocalProcessBuilder(IRemoteConnection connection, List command) {
+ super(connection, command);
fRemoteEnv.putAll(System.getenv());
fProcessFactory = getProcessFactory();
}
- public LocalProcessBuilder(String... command) {
- this(Arrays.asList(command));
+ public LocalProcessBuilder(IRemoteConnection connection, String... command) {
+ this(connection, Arrays.asList(command));
}
/*
@@ -104,18 +108,21 @@ public class LocalProcessBuilder extends AbstractRemoteProcessBuilder {
for (Entry entry : environment().entrySet()) {
environmentArray[index++] = entry.getKey() + "=" + entry.getValue(); //$NON-NLS-1$
}
- Process localProc;
if (directory() != null) {
try {
- localProc = fProcessFactory.exec(commandArray, environmentArray,
+ localProcess = fProcessFactory.exec(commandArray, environmentArray,
directory().toLocalFile(EFS.NONE, new NullProgressMonitor()));
} catch (CoreException e) {
throw new IOException(e.getMessage());
}
} else {
- localProc = fProcessFactory.exec(commandArray, environmentArray);
+ localProcess = fProcessFactory.exec(commandArray, environmentArray);
}
- return new LocalProcess(localProc, redirectErrorStream());
+ return new RemoteProcess(getRemoteConnection(), this);
+ }
+
+ public Process getProcess() {
+ return localProcess;
}
private IProcessFactory getProcessFactory() {
diff --git a/bundles/org.eclipse.remote.core/src/org/eclipse/remote/internal/core/services/local/LocalProcessService.java b/bundles/org.eclipse.remote.core/src/org/eclipse/remote/internal/core/services/local/LocalProcessService.java
index 6bdb204c1ee..7dac4f81b5b 100644
--- a/bundles/org.eclipse.remote.core/src/org/eclipse/remote/internal/core/services/local/LocalProcessService.java
+++ b/bundles/org.eclipse.remote.core/src/org/eclipse/remote/internal/core/services/local/LocalProcessService.java
@@ -46,12 +46,12 @@ public class LocalProcessService implements IRemoteProcessService {
@Override
public IRemoteProcessBuilder getProcessBuilder(List command) {
- return new LocalProcessBuilder(command);
+ return new LocalProcessBuilder(remoteConnection, command);
}
@Override
public IRemoteProcessBuilder getProcessBuilder(String... command) {
- return new LocalProcessBuilder(command);
+ return new LocalProcessBuilder(remoteConnection, command);
}
@Override
diff --git a/bundles/org.eclipse.remote.jsch.core/plugin.xml b/bundles/org.eclipse.remote.jsch.core/plugin.xml
index 1c585d04b9d..70b0eb06389 100644
--- a/bundles/org.eclipse.remote.jsch.core/plugin.xml
+++ b/bundles/org.eclipse.remote.jsch.core/plugin.xml
@@ -44,6 +44,26 @@
factory="org.eclipse.remote.internal.jsch.core.JSchConnection$Factory"
service="org.eclipse.remote.internal.jsch.core.JSchConnection">
+
+
+
+
+
+
+
+
command) {
- return new JSchProcessBuilder(this, command);
+ return new JSchProcessBuilder(getRemoteConnection(), command);
}
/*
@@ -576,7 +576,7 @@ public class JSchConnection implements IRemoteConnectionControlService, IRemoteC
*/
@Override
public IRemoteProcessBuilder getProcessBuilder(String... command) {
- return new JSchProcessBuilder(this, command);
+ return new JSchProcessBuilder(getRemoteConnection(), command);
}
/*
diff --git a/bundles/org.eclipse.remote.jsch.core/src/org/eclipse/remote/internal/jsch/core/JSchConnectionProxyFactory.java b/bundles/org.eclipse.remote.jsch.core/src/org/eclipse/remote/internal/jsch/core/JSchConnectionProxyFactory.java
index 0446d5a0d74..4ed92b9d25b 100644
--- a/bundles/org.eclipse.remote.jsch.core/src/org/eclipse/remote/internal/jsch/core/JSchConnectionProxyFactory.java
+++ b/bundles/org.eclipse.remote.jsch.core/src/org/eclipse/remote/internal/jsch/core/JSchConnectionProxyFactory.java
@@ -24,16 +24,13 @@ import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.SubMonitor;
-import org.eclipse.remote.core.IRemoteConnection;
-import org.eclipse.remote.core.IRemoteProcess;
import org.eclipse.remote.core.IRemoteProcessService;
+import org.eclipse.remote.core.IRemoteProcess;
import org.eclipse.remote.core.IRemoteServicesManager;
import org.eclipse.remote.core.exception.RemoteConnectionException;
import org.eclipse.remote.internal.jsch.core.messages.Messages;
import com.jcraft.jsch.Channel;
-import com.jcraft.jsch.ChannelExec;
-import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Proxy;
import com.jcraft.jsch.SocketFactory;
@@ -49,12 +46,13 @@ public class JSchConnectionProxyFactory {
private String command;
private IRemoteProcess process;
private JSchConnection connection;
- private IProgressMonitor monitor;
+ private final IProgressMonitor monitor;
private boolean connectCalled = false;
private CommandProxy(JSchConnection connection, String command, IProgressMonitor monitor) {
- if (command == null || monitor == null)
+ if (command == null || monitor == null) {
throw new IllegalArgumentException();
+ }
this.command = command;
this.connection = connection;
this.monitor = monitor;
@@ -62,7 +60,7 @@ public class JSchConnectionProxyFactory {
/*
* (non-Javadoc)
- *
+ *
* @see com.jcraft.jsch.Proxy#close()
*/
@Override
@@ -72,12 +70,11 @@ public class JSchConnectionProxyFactory {
/*
* (non-Javadoc)
- *
+ *
* @see com.jcraft.jsch.Proxy#connect(com.jcraft.jsch.SocketFactory, java.lang.String, int, int)
*/
@Override
- public void connect(SocketFactory socket_factory, String host,
- int port, int timeout) throws IOException {
+ public void connect(SocketFactory socket_factory, String host, int port, int timeout) throws IOException {
assert !connectCalled : "connect should only be called once"; //$NON-NLS-1$
try {
if (timeout == 0) {
@@ -88,11 +85,14 @@ public class JSchConnectionProxyFactory {
SubMonitor subMon = SubMonitor.convert(monitor, waitSteps * 2);
final SubMonitor childMon = subMon.newChild(waitSteps);
+ if (connection == null) {
+ IRemoteServicesManager manager = Activator.getService(IRemoteServicesManager.class);
+ connection = (JSchConnection) manager.getLocalConnectionType().getConnections().get(0);
+ }
+
// Open connection if it isn't already opened
try {
- if (connection != null) {
- connection.openMinimal(childMon);
- }
+ connection.openMinimal(childMon);
} catch (RemoteConnectionException e) {
throw new IOException(e);
}
@@ -102,22 +102,11 @@ public class JSchConnectionProxyFactory {
command = command.replace("%h", host); //$NON-NLS-1$
command = command.replace("%p", Integer.toString(port)); //$NON-NLS-1$
- if (connection != null) {
- // The process-builder adds unnecessary extra commands (cd, export, ..) and might not work for restricted shells
- try {
- ChannelExec exec = connection.getExecChannel();
- exec.setCommand(command);
- exec.connect();
- process = new JSchProcess(exec, false);
- } catch (JSchException | RemoteConnectionException e) {
- throw new IOException(e);
- }
- } else {
- List cmd = new ArgumentParser(command).getTokenList();
- IRemoteServicesManager manager = Activator.getService(IRemoteServicesManager.class);
- IRemoteConnection connection = manager.getLocalConnectionType().getConnections().get(0);
- process = connection.getService(IRemoteProcessService.class).getProcessBuilder(cmd).start();
- }
+ List cmd = new ArgumentParser(command).getTokenList();
+ JSchProcessBuilder processBuilder = (JSchProcessBuilder) connection.getRemoteConnection()
+ .getService(IRemoteProcessService.class).getProcessBuilder(cmd);
+ processBuilder.setPreamble(false);
+ process = processBuilder.start();
// Wait on command to produce stdout output
long endTime = System.currentTimeMillis() + timeout;
@@ -154,8 +143,8 @@ public class JSchConnectionProxyFactory {
} else if (bCanceled) {
cause = Messages.JSchConnectionProxyFactory_wasCanceled;
}
- throw new IOException(MessageFormat.format(Messages.JSchConnectionProxyFactory_ProxyCommandFailed,
- command, cause, msg));
+ throw new IOException(MessageFormat.format(Messages.JSchConnectionProxyFactory_ProxyCommandFailed, command,
+ cause, msg));
}
// Dump the stderr to log
@@ -166,8 +155,7 @@ public class JSchConnectionProxyFactory {
String line;
try {
while ((line = bufferedReader.readLine()) != null) {
- log.log(new Status(IStatus.INFO, Activator.getUniqueIdentifier(),
- IStatus.OK, line, null));
+ log.log(new Status(IStatus.INFO, Activator.getUniqueIdentifier(), IStatus.OK, line, null));
}
} catch (IOException e) {
Activator.log(e);
@@ -181,7 +169,7 @@ public class JSchConnectionProxyFactory {
/*
* (non-Javadoc)
- *
+ *
* @see com.jcraft.jsch.Proxy#getInputStream()
*/
@Override
@@ -191,7 +179,7 @@ public class JSchConnectionProxyFactory {
/*
* (non-Javadoc)
- *
+ *
* @see com.jcraft.jsch.Proxy#getOutputStream()
*/
@Override
@@ -201,7 +189,7 @@ public class JSchConnectionProxyFactory {
/*
* (non-Javadoc)
- *
+ *
* @see com.jcraft.jsch.Proxy#getSocket()
*/
@Override
@@ -212,20 +200,21 @@ public class JSchConnectionProxyFactory {
private static class SSHForwardProxy implements Proxy {
private Channel channel;
- private JSchConnection connection;
- private IProgressMonitor monitor;
+ private final JSchConnection connection;
+ private final IProgressMonitor monitor;
private boolean connectCalled = false;
private SSHForwardProxy(JSchConnection proxyConnection, IProgressMonitor monitor) {
- if (proxyConnection == null || monitor == null)
+ if (proxyConnection == null || monitor == null) {
throw new IllegalArgumentException();
+ }
this.connection = proxyConnection;
this.monitor = monitor;
}
/*
* (non-Javadoc)
- *
+ *
* @see com.jcraft.jsch.Proxy#close()
*/
@Override
@@ -235,12 +224,11 @@ public class JSchConnectionProxyFactory {
/*
* (non-Javadoc)
- *
+ *
* @see com.jcraft.jsch.Proxy#connect(com.jcraft.jsch.SocketFactory, java.lang.String, int, int)
*/
@Override
- public void connect(SocketFactory socket_factory, String host, int port,
- int timeout) throws Exception {
+ public void connect(SocketFactory socket_factory, String host, int port, int timeout) throws Exception {
assert !connectCalled : "connect should only be called once"; //$NON-NLS-1$
try {
if (!connection.hasOpenSession()) {
@@ -258,7 +246,7 @@ public class JSchConnectionProxyFactory {
/*
* (non-Javadoc)
- *
+ *
* @see com.jcraft.jsch.Proxy#getInputStream()
*/
@Override
@@ -273,7 +261,7 @@ public class JSchConnectionProxyFactory {
/*
* (non-Javadoc)
- *
+ *
* @see com.jcraft.jsch.Proxy#getOutputStream()
*/
@Override
@@ -288,7 +276,7 @@ public class JSchConnectionProxyFactory {
/*
* (non-Javadoc)
- *
+ *
* @see com.jcraft.jsch.Proxy#getSocket()
*/
@Override
diff --git a/bundles/org.eclipse.remote.jsch.core/src/org/eclipse/remote/internal/jsch/core/JSchProcess.java b/bundles/org.eclipse.remote.jsch.core/src/org/eclipse/remote/internal/jsch/core/JSchProcess.java
index 5c99c8c9132..7db09870f68 100644
--- a/bundles/org.eclipse.remote.jsch.core/src/org/eclipse/remote/internal/jsch/core/JSchProcess.java
+++ b/bundles/org.eclipse.remote.jsch.core/src/org/eclipse/remote/internal/jsch/core/JSchProcess.java
@@ -16,20 +16,56 @@ import java.io.OutputStream;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
-import org.eclipse.remote.core.AbstractRemoteProcess;
+import org.eclipse.remote.core.IRemoteProcess;
+import org.eclipse.remote.core.IRemoteProcessControlService;
+import org.eclipse.remote.core.IRemoteProcessSignalService;
+import org.eclipse.remote.core.IRemoteProcessTerminalService;
+import org.eclipse.remote.core.exception.RemoteConnectionException;
import com.jcraft.jsch.ChannelExec;
-public class JSchProcess extends AbstractRemoteProcess {
+public class JSchProcess implements IRemoteProcessControlService, IRemoteProcessSignalService, IRemoteProcessTerminalService {
+ @SuppressWarnings("nls")
+ private final String signals[] = new String[] { "", "HUP", "INT", "QUIT", "ILL", "", "ABRT", "", "FPE", "KILL", "", "SEGV", "",
+ "PIPE", "ALRM", "TERM", "", "STOP", "TSTP", "CONT", "", "", "", "", "", "", "", "", "", "", "USR1", "USR2" };
+
private static int WAIT_TIMEOUT = 1000;
private static int refCount = 0;
private final ChannelExec fChannel;
+ private final IRemoteProcess fProcess;
+
private InputStream fProcStdout;
private InputStream fProcStderr;
private Thread fStdoutReader;
private Thread fStderrReader;
+ public static class Factory implements IRemoteProcess.Service.Factory {
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.remote.core.IRemoteProcess.Service.Factory#getService(org.eclipse.remote.core.IRemoteProcess,
+ * java.lang.Class)
+ */
+ @SuppressWarnings("unchecked")
+ @Override
+ public T getService(IRemoteProcess remoteProcess, Class service) {
+ // This little trick creates an instance of this class
+ // then for each interface it implements, it returns the same object.
+ // This works because the connection caches the service so only one gets created.
+ // As a side effect, it makes this class a service too which can be used
+ // by the this plug-in
+ if (JSchProcess.class.equals(service)) {
+ return (T) new JSchProcess(remoteProcess);
+ }
+ if (IRemoteProcessControlService.class.equals(service) || IRemoteProcessSignalService.class.equals(service)
+ || IRemoteProcessTerminalService.class.equals(service)) {
+ return (T) remoteProcess.getService(JSchProcess.class);
+ }
+ return null;
+ }
+ }
+
private class ProcReader implements Runnable {
private final static int BUF_SIZE = 8192;
@@ -44,6 +80,7 @@ public class JSchProcess extends AbstractRemoteProcess {
}
}
+ @Override
public void run() {
int len;
byte b[] = new byte[BUF_SIZE];
@@ -79,23 +116,29 @@ public class JSchProcess extends AbstractRemoteProcess {
}
}
- public JSchProcess(ChannelExec channel, boolean merge) throws IOException {
- fChannel = channel;
+ public JSchProcess(IRemoteProcess process) {
+ fProcess = process;
+ fChannel = ((JSchProcessBuilder) process.getProcessBuilder()).getChannel();
- if (merge) {
- PipedOutputStream pipedOutput = new PipedOutputStream();
+ try {
+ if (process.getProcessBuilder().redirectErrorStream()) {
+ PipedOutputStream pipedOutput = new PipedOutputStream();
- fProcStdout = new PipedInputStream(pipedOutput);
- fProcStderr = new NullInputStream();
+ fProcStdout = new PipedInputStream(pipedOutput);
+ fProcStderr = new NullInputStream();
- fStderrReader = new Thread(new ProcReader(channel.getErrStream(), pipedOutput));
- fStdoutReader = new Thread(new ProcReader(channel.getInputStream(), pipedOutput));
+ fStderrReader = new Thread(new ProcReader(fChannel.getErrStream(), pipedOutput));
+ fStdoutReader = new Thread(new ProcReader(fChannel.getInputStream(), pipedOutput));
- fStderrReader.start();
- fStdoutReader.start();
- } else {
- fProcStdout = channel.getInputStream();
- fProcStderr = channel.getErrStream();
+ fStderrReader.start();
+ fStdoutReader.start();
+ } else {
+ fProcStdout = fChannel.getInputStream();
+ fProcStderr = fChannel.getErrStream();
+ }
+ } catch (IOException e) {
+ Activator.log(e);
+ destroy();
}
}
@@ -170,10 +213,46 @@ public class JSchProcess extends AbstractRemoteProcess {
/*
* (non-Javadoc)
*
- * @see org.eclipse.remote.core.AbstractRemoteProcess#isCompleted()
+ * @see org.eclipse.remote.core.RemoteProcess#isCompleted()
*/
@Override
public boolean isCompleted() {
return fChannel.isClosed();
}
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.remote.core.IRemoteProcess.Service#getRemoteProcess()
+ */
+ @Override
+ public IRemoteProcess getRemoteProcess() {
+ return fProcess;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.remote.core.IRemoteProcessTerminalService#setTerminalSize(int, int, int, int)
+ */
+ @Override
+ public void setTerminalSize(int cols, int rows, int width, int height) {
+ fChannel.setPtySize(cols, rows, width, height);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.remote.core.IRemoteProcessSignalService#sendSignal(int)
+ */
+ @Override
+ public void sendSignal(int signal) throws RemoteConnectionException {
+ if (signal >= 0 && signal <= USR2) {
+ try {
+ fChannel.sendSignal(signals[signal]);
+ } catch (Exception e) {
+ throw new RemoteConnectionException(e.getMessage());
+ }
+ }
+ }
}
diff --git a/bundles/org.eclipse.remote.jsch.core/src/org/eclipse/remote/internal/jsch/core/JSchProcessBuilder.java b/bundles/org.eclipse.remote.jsch.core/src/org/eclipse/remote/internal/jsch/core/JSchProcessBuilder.java
index 5793bd8c301..820400e5a18 100644
--- a/bundles/org.eclipse.remote.jsch.core/src/org/eclipse/remote/internal/jsch/core/JSchProcessBuilder.java
+++ b/bundles/org.eclipse.remote.jsch.core/src/org/eclipse/remote/internal/jsch/core/JSchProcessBuilder.java
@@ -24,10 +24,12 @@ import java.util.Set;
import org.eclipse.core.filesystem.IFileStore;
import org.eclipse.remote.core.AbstractRemoteProcessBuilder;
+import org.eclipse.remote.core.IRemoteConnection;
import org.eclipse.remote.core.IRemoteFileService;
import org.eclipse.remote.core.IRemoteProcess;
import org.eclipse.remote.core.exception.RemoteConnectionException;
import org.eclipse.remote.internal.core.RemoteDebugOptions;
+import org.eclipse.remote.internal.core.RemoteProcess;
import org.eclipse.remote.internal.jsch.core.messages.Messages;
import com.jcraft.jsch.ChannelExec;
@@ -39,11 +41,13 @@ public class JSchProcessBuilder extends AbstractRemoteProcessBuilder {
private final Map fRemoteEnv = new HashMap();
private final Set charSet = new HashSet();
- private Map fNewRemoteEnv = null;
+ private ChannelExec fChannel;
+ private Map fNewRemoteEnv;
+ private boolean fPreamble = true;
- public JSchProcessBuilder(JSchConnection connection, List command) {
- super(command);
- fConnection = connection;
+ public JSchProcessBuilder(IRemoteConnection connection, List command) {
+ super(connection, command);
+ fConnection = connection.getService(JSchConnection.class);
fRemoteEnv.putAll(fConnection.getEnv());
// Create set of characters not to escape
@@ -56,7 +60,7 @@ public class JSchProcessBuilder extends AbstractRemoteProcessBuilder {
}
}
- public JSchProcessBuilder(JSchConnection connection, String... command) {
+ public JSchProcessBuilder(IRemoteConnection connection, String... command) {
this(connection, Arrays.asList(command));
}
@@ -151,14 +155,14 @@ public class JSchProcessBuilder extends AbstractRemoteProcessBuilder {
}
try {
- ChannelExec exec = fConnection.getExecChannel();
+ fChannel = fConnection.getExecChannel();
String command = buildCommand(remoteCmd, env, clearEnv);
- exec.setCommand(command);
- exec.setPty((flags & ALLOCATE_PTY) == ALLOCATE_PTY);
- exec.setXForwarding((flags & FORWARD_X11) == FORWARD_X11);
- exec.connect();
+ fChannel.setCommand(command);
+ fChannel.setPty((flags & ALLOCATE_PTY) == ALLOCATE_PTY);
+ fChannel.setXForwarding((flags & FORWARD_X11) == FORWARD_X11);
+ fChannel.connect();
RemoteDebugOptions.trace(RemoteDebugOptions.DEBUG_REMOTE_COMMANDS, "executing command: " + command); //$NON-NLS-1$
- return new JSchProcess(exec, redirectErrorStream());
+ return new RemoteProcess(getRemoteConnection(), this);
} catch (RemoteConnectionException e) {
throw new IOException(e.getMessage());
} catch (JSchException e) {
@@ -166,24 +170,34 @@ public class JSchProcessBuilder extends AbstractRemoteProcessBuilder {
}
}
+ public ChannelExec getChannel() {
+ return fChannel;
+ }
+
+ public void setPreamble(boolean enable) {
+ fPreamble = enable;
+ }
+
private String buildCommand(String cmd, List environment, boolean clearEnv) {
StringBuffer sb = new StringBuffer();
- if (directory() != null) {
- sb.append("cd " + charEscapify(directory().toURI().getPath(), charSet) + " && "); //$NON-NLS-1$ //$NON-NLS-2$
- }
- if (clearEnv) {
- sb.append("env -i"); //$NON-NLS-1$
- for (String env : environment) {
- sb.append(" \"" + env + "\""); //$NON-NLS-1$ //$NON-NLS-2$
+ if (fPreamble) {
+ if (directory() != null) {
+ sb.append("cd " + charEscapify(directory().toURI().getPath(), charSet) + " && "); //$NON-NLS-1$ //$NON-NLS-2$
}
- sb.append(" "); //$NON-NLS-1$
- } else {
- for (String env : environment) {
- sb.append("export \"" + env + "\"; "); //$NON-NLS-1$ //$NON-NLS-2$
+ if (clearEnv) {
+ sb.append("env -i"); //$NON-NLS-1$
+ for (String env : environment) {
+ sb.append(" \"" + env + "\""); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ sb.append(" "); //$NON-NLS-1$
+ } else {
+ for (String env : environment) {
+ sb.append("export \"" + env + "\"; "); //$NON-NLS-1$ //$NON-NLS-2$
+ }
}
}
sb.append(cmd);
- if (fConnection.useLoginShell()) {
+ if (fPreamble && fConnection.useLoginShell()) {
sb.insert(0, "/bin/bash -l -c '"); //$NON-NLS-1$
sb.append("'"); //$NON-NLS-1$
}