diff --git a/bundles/org.eclipse.remote.console/.classpath b/bundles/org.eclipse.remote.console/.classpath index eca7bdba8f0..098194ca4b7 100644 --- a/bundles/org.eclipse.remote.console/.classpath +++ b/bundles/org.eclipse.remote.console/.classpath @@ -1,6 +1,6 @@ - + diff --git a/bundles/org.eclipse.remote.console/.settings/org.eclipse.jdt.core.prefs b/bundles/org.eclipse.remote.console/.settings/org.eclipse.jdt.core.prefs index 0c68a61dca8..f42de363afa 100644 --- a/bundles/org.eclipse.remote.console/.settings/org.eclipse.jdt.core.prefs +++ b/bundles/org.eclipse.remote.console/.settings/org.eclipse.jdt.core.prefs @@ -1,7 +1,7 @@ eclipse.preferences.version=1 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 -org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7 +org.eclipse.jdt.core.compiler.compliance=1.7 org.eclipse.jdt.core.compiler.problem.assertIdentifier=error org.eclipse.jdt.core.compiler.problem.enumIdentifier=error -org.eclipse.jdt.core.compiler.source=1.8 +org.eclipse.jdt.core.compiler.source=1.7 diff --git a/bundles/org.eclipse.remote.console/META-INF/MANIFEST.MF b/bundles/org.eclipse.remote.console/META-INF/MANIFEST.MF index 581674f3964..53980e8d133 100644 --- a/bundles/org.eclipse.remote.console/META-INF/MANIFEST.MF +++ b/bundles/org.eclipse.remote.console/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %pluginName Bundle-SymbolicName: org.eclipse.remote.console;singleton:=true -Bundle-Version: 1.1.0.qualifier +Bundle-Version: 1.2.0.qualifier Bundle-Activator: org.eclipse.remote.internal.console.Activator Bundle-Localization: plugin Bundle-RequiredExecutionEnvironment: JavaSE-1.7 diff --git a/bundles/org.eclipse.remote.console/about.ini b/bundles/org.eclipse.remote.console/about.ini deleted file mode 100644 index 5bd1defab8b..00000000000 --- a/bundles/org.eclipse.remote.console/about.ini +++ /dev/null @@ -1,27 +0,0 @@ -# about.ini -# contains information about a feature -# java.io.Properties file (ISO 8859-1 with "\" escapes) -# "%key" are externalized strings defined in about.properties -# This file does not need to be translated. - -# Property "aboutText" contains blurb for "About" dialog (translated) -aboutText=%blurb - -# Property "windowImage" contains path to window icon (16x16) -# needed for primary features only - -# Property "featureImage" contains path to feature image (32x32) -featureImage=ptp_logo_icon32.png - -# Property "aboutImage" contains path to product image (500x330 or 115x164) -# needed for primary features only - -# Property "appName" contains name of the application (not translated) -# needed for primary features only - -# Property "welcomePage" contains path to welcome page (special XML-based format) -# optional - -# Property "welcomePerspective" contains the id of the perspective in which the -# welcome page is to be opened. -# optional diff --git a/bundles/org.eclipse.remote.console/about.mappings b/bundles/org.eclipse.remote.console/about.mappings deleted file mode 100644 index bddaab43109..00000000000 --- a/bundles/org.eclipse.remote.console/about.mappings +++ /dev/null @@ -1,6 +0,0 @@ -# about.mappings -# contains fill-ins for about.properties -# java.io.Properties file (ISO 8859-1 with "\" escapes) -# This file does not need to be translated. - -0=@build@ \ No newline at end of file diff --git a/bundles/org.eclipse.remote.console/build.properties b/bundles/org.eclipse.remote.console/build.properties index 7cce477fcd5..5c5c659f8fd 100644 --- a/bundles/org.eclipse.remote.console/build.properties +++ b/bundles/org.eclipse.remote.console/build.properties @@ -5,8 +5,4 @@ bin.includes = META-INF/,\ plugin.xml,\ plugin.properties,\ icons/,\ - about.html,\ - about.ini,\ - about.mappings,\ - about.properties,\ - ptp_logo_icon32.png + about.html \ No newline at end of file diff --git a/bundles/org.eclipse.remote.console/pom.xml b/bundles/org.eclipse.remote.console/pom.xml index 1e677e41527..fd240fbc7af 100644 --- a/bundles/org.eclipse.remote.console/pom.xml +++ b/bundles/org.eclipse.remote.console/pom.xml @@ -6,11 +6,11 @@ org.eclipse.remote remote-parent - 2.1.0-SNAPSHOT + 3.0.0-SNAPSHOT ../../releng/org.eclipse.remote.build/pom.xml org.eclipse.remote.console eclipse-plugin -1.1.0-SNAPSHOT +1.2.0-SNAPSHOT diff --git a/bundles/org.eclipse.remote.console/ptp_logo_icon32.png b/bundles/org.eclipse.remote.console/ptp_logo_icon32.png deleted file mode 100644 index e8ec57270f3..00000000000 Binary files a/bundles/org.eclipse.remote.console/ptp_logo_icon32.png and /dev/null differ diff --git a/bundles/org.eclipse.remote.console/src/org/eclipse/remote/console/ITerminalConsole.java b/bundles/org.eclipse.remote.console/src/org/eclipse/remote/console/ITerminalConsole.java new file mode 100644 index 00000000000..9a1a5c89402 --- /dev/null +++ b/bundles/org.eclipse.remote.console/src/org/eclipse/remote/console/ITerminalConsole.java @@ -0,0 +1,14 @@ +package org.eclipse.remote.console; + +import org.eclipse.remote.core.IRemoteConnection; + +/** + * @since 1.2 + */ +public interface ITerminalConsole { + + /** + * @return The {@link IRemoteConnection} associated to this {@link ITerminalConsole} + */ + public IRemoteConnection getConnection(); +} diff --git a/bundles/org.eclipse.remote.console/src/org/eclipse/remote/internal/console/ConsoleMessages.java b/bundles/org.eclipse.remote.console/src/org/eclipse/remote/internal/console/ConsoleMessages.java index 83fe6198c6d..a47d98bd9db 100644 --- a/bundles/org.eclipse.remote.console/src/org/eclipse/remote/internal/console/ConsoleMessages.java +++ b/bundles/org.eclipse.remote.console/src/org/eclipse/remote/internal/console/ConsoleMessages.java @@ -31,4 +31,5 @@ public class ConsoleMessages extends NLS { public static String OPENNING_TERMINAL; public static String MAKING_CONNECTION; public static String DISCONNECTING; + public static String TerminalConsoleConnector_0; } diff --git a/bundles/org.eclipse.remote.console/src/org/eclipse/remote/internal/console/ConsoleMessages.properties b/bundles/org.eclipse.remote.console/src/org/eclipse/remote/internal/console/ConsoleMessages.properties index e07f47400e2..3ea9b5a26a8 100644 --- a/bundles/org.eclipse.remote.console/src/org/eclipse/remote/internal/console/ConsoleMessages.properties +++ b/bundles/org.eclipse.remote.console/src/org/eclipse/remote/internal/console/ConsoleMessages.properties @@ -22,3 +22,4 @@ CONNECTING_TO_TERMINAL = Connecting to Command Shell OPENNING_TERMINAL = Openning Command Shell MAKING_CONNECTION = Making Connection DISCONNECTING = Disconnecting +TerminalConsoleConnector_0=Command shell not supported on this connection diff --git a/bundles/org.eclipse.remote.console/src/org/eclipse/remote/internal/console/TerminalConsole.java b/bundles/org.eclipse.remote.console/src/org/eclipse/remote/internal/console/TerminalConsole.java index 011ad72b278..18eb0d22c71 100644 --- a/bundles/org.eclipse.remote.console/src/org/eclipse/remote/internal/console/TerminalConsole.java +++ b/bundles/org.eclipse.remote.console/src/org/eclipse/remote/internal/console/TerminalConsole.java @@ -13,6 +13,7 @@ package org.eclipse.remote.internal.console; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; +import org.eclipse.remote.console.ITerminalConsole; import org.eclipse.remote.core.IRemoteConnection; import org.eclipse.tm.internal.terminal.provisional.api.TerminalState; import org.eclipse.ui.console.AbstractConsole; @@ -20,7 +21,7 @@ import org.eclipse.ui.console.IConsoleView; import org.eclipse.ui.part.IPageBookViewPage; import org.eclipse.ui.progress.UIJob; -public class TerminalConsole extends AbstractConsole { +public class TerminalConsole extends AbstractConsole implements ITerminalConsole { private final String encoding; private final TerminalConsoleConnector terminalConnector; private final int index; @@ -36,6 +37,7 @@ public class TerminalConsole extends AbstractConsole { return terminalConnector; } + @Override public IRemoteConnection getConnection() { return terminalConnector.getConnection(); } diff --git a/bundles/org.eclipse.remote.console/src/org/eclipse/remote/internal/console/TerminalConsoleConnector.java b/bundles/org.eclipse.remote.console/src/org/eclipse/remote/internal/console/TerminalConsoleConnector.java index e524e4bcb4e..76366a39575 100644 --- a/bundles/org.eclipse.remote.console/src/org/eclipse/remote/internal/console/TerminalConsoleConnector.java +++ b/bundles/org.eclipse.remote.console/src/org/eclipse/remote/internal/console/TerminalConsoleConnector.java @@ -140,6 +140,11 @@ public class TerminalConsoleConnector { return new Status(IStatus.ERROR, Activator.PLUGIN_ID, e.getLocalizedMessage(), e); } } + + if (remoteProcess == null) { + disconnect(); + return new Status(IStatus.ERROR, Activator.PLUGIN_ID, ConsoleMessages.TerminalConsoleConnector_0); + } if (width > 0 || height > 0) { IRemoteProcessTerminalService termService = remoteProcess.getService(IRemoteProcessTerminalService.class); diff --git a/bundles/org.eclipse.remote.core/META-INF/MANIFEST.MF b/bundles/org.eclipse.remote.core/META-INF/MANIFEST.MF index c896fa15561..0af06f041d3 100644 --- a/bundles/org.eclipse.remote.core/META-INF/MANIFEST.MF +++ b/bundles/org.eclipse.remote.core/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %pluginName Bundle-SymbolicName: org.eclipse.remote.core;singleton:=true -Bundle-Version: 3.0.0.qualifier +Bundle-Version: 4.0.0.qualifier Bundle-Activator: org.eclipse.remote.internal.core.RemoteCorePlugin Bundle-Vendor: %pluginProvider Bundle-ActivationPolicy: lazy @@ -19,6 +19,7 @@ Import-Package: org.eclipse.cdt.utils.pty, org.eclipse.core.filesystem, org.eclipse.core.resources, org.eclipse.core.runtime, + org.eclipse.core.runtime.jobs, org.eclipse.core.runtime.preferences, org.eclipse.debug.core, org.eclipse.equinox.security.storage, diff --git a/bundles/org.eclipse.remote.core/pom.xml b/bundles/org.eclipse.remote.core/pom.xml index 37e8ecaff41..b2ce59e61c3 100644 --- a/bundles/org.eclipse.remote.core/pom.xml +++ b/bundles/org.eclipse.remote.core/pom.xml @@ -6,11 +6,11 @@ org.eclipse.remote remote-parent - 2.1.0-SNAPSHOT + 3.0.0-SNAPSHOT ../../releng/org.eclipse.remote.build/pom.xml org.eclipse.remote.core - 3.0.0-SNAPSHOT + 4.0.0-SNAPSHOT eclipse-plugin 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 1b208f3b218..5a0e041d3c5 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 @@ -16,6 +16,7 @@ import java.util.List; import java.util.Map; import org.eclipse.core.filesystem.IFileStore; +import org.eclipse.remote.internal.core.RemoteProcess; /** * Abstract base class for remote process builders. Implementors can use this class to provide a default implementation of a remote @@ -195,4 +196,11 @@ public abstract class AbstractRemoteProcessBuilder implements IRemoteProcessBuil public IRemoteConnection getRemoteConnection() { return fConnection; } + + /** + * @since 4.0 + */ + protected IRemoteProcess newRemoteProcess() { + return new RemoteProcess(getRemoteConnection(), this); + } } 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 d46bdd365f5..a80d4ff6596 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 @@ -41,6 +41,13 @@ public interface IRemoteProcessBuilder { */ public static int FORWARD_X11 = 0x02; + /** + * Flag to request that the supplied environment be apended to the remote environment; otherwise + * it is replaced. + * @since 3.0 + */ + public static int APPEND_ENVIRONMENT = 0x03; + /** * Returns this process builder's operating system program and arguments. * diff --git a/bundles/org.eclipse.remote.core/src/org/eclipse/remote/core/RemoteConnectionChangeEvent.java b/bundles/org.eclipse.remote.core/src/org/eclipse/remote/core/RemoteConnectionChangeEvent.java index f73ca7343d4..d4b8f22739f 100644 --- a/bundles/org.eclipse.remote.core/src/org/eclipse/remote/core/RemoteConnectionChangeEvent.java +++ b/bundles/org.eclipse.remote.core/src/org/eclipse/remote/core/RemoteConnectionChangeEvent.java @@ -51,6 +51,12 @@ public class RemoteConnectionChangeEvent { */ public static final int CONNECTION_REMOVED = 1 << 5; + /** + * Event indicating the connection attributes had changed. + * @since 4.0 + */ + public static final int ATTRIBUTES_CHANGED = 1 << 6; + private final IRemoteConnection connection; private final int type; diff --git a/bundles/org.eclipse.remote.core/src/org/eclipse/remote/internal/core/RemoteConnectionWorkingCopy.java b/bundles/org.eclipse.remote.core/src/org/eclipse/remote/internal/core/RemoteConnectionWorkingCopy.java index 59fb0c46595..33a6f445d70 100644 --- a/bundles/org.eclipse.remote.core/src/org/eclipse/remote/internal/core/RemoteConnectionWorkingCopy.java +++ b/bundles/org.eclipse.remote.core/src/org/eclipse/remote/internal/core/RemoteConnectionWorkingCopy.java @@ -318,6 +318,10 @@ public class RemoteConnectionWorkingCopy implements IRemoteConnectionWorkingCopy throw new RemoteConnectionException(e); } + if (newAttributes.size() > 0 || newSecureAttributes.size() > 0) { + original.fireConnectionChangeEvent(RemoteConnectionChangeEvent.ATTRIBUTES_CHANGED); + } + /* * Reset state for isDirty() */ diff --git a/bundles/org.eclipse.remote.doc.isv/pom.xml b/bundles/org.eclipse.remote.doc.isv/pom.xml index ca7fddc972d..54bba78c942 100644 --- a/bundles/org.eclipse.remote.doc.isv/pom.xml +++ b/bundles/org.eclipse.remote.doc.isv/pom.xml @@ -6,7 +6,7 @@ org.eclipse.remote remote-parent - 2.1.0-SNAPSHOT + 3.0.0-SNAPSHOT ../../releng/org.eclipse.remote.build/pom.xml @@ -20,13 +20,11 @@ ${tycho-extras-version} ${basedir}/html/reference/api - diff --git a/bundles/org.eclipse.remote.jsch.core/pom.xml b/bundles/org.eclipse.remote.jsch.core/pom.xml index ee2758f7a03..0ed3d880e5a 100644 --- a/bundles/org.eclipse.remote.jsch.core/pom.xml +++ b/bundles/org.eclipse.remote.jsch.core/pom.xml @@ -6,7 +6,7 @@ org.eclipse.remote remote-parent - 2.1.0-SNAPSHOT + 3.0.0-SNAPSHOT ../../releng/org.eclipse.remote.build/pom.xml 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 a2926e1e85e..a2b409709f4 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 @@ -29,7 +29,6 @@ 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.Channel; @@ -182,7 +181,7 @@ public class JSchProcessBuilder extends AbstractRemoteProcessBuilder { } fChannel.setXForwarding((flags & FORWARD_X11) == FORWARD_X11); fChannel.connect(); - return new RemoteProcess(getRemoteConnection(), this); + return newRemoteProcess(); } catch (RemoteConnectionException e) { throw new IOException(e.getMessage()); } catch (JSchException e) { diff --git a/bundles/org.eclipse.remote.jsch.ui/pom.xml b/bundles/org.eclipse.remote.jsch.ui/pom.xml index 8b53f595b37..01e932ae361 100644 --- a/bundles/org.eclipse.remote.jsch.ui/pom.xml +++ b/bundles/org.eclipse.remote.jsch.ui/pom.xml @@ -6,7 +6,7 @@ org.eclipse.remote remote-parent - 2.1.0-SNAPSHOT + 3.0.0-SNAPSHOT ../../releng/org.eclipse.remote.build/pom.xml diff --git a/bundles/org.eclipse.remote.proxy.core/.classpath b/bundles/org.eclipse.remote.proxy.core/.classpath new file mode 100644 index 00000000000..eca7bdba8f0 --- /dev/null +++ b/bundles/org.eclipse.remote.proxy.core/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/bundles/org.eclipse.remote.proxy.core/.gitignore b/bundles/org.eclipse.remote.proxy.core/.gitignore new file mode 100644 index 00000000000..5e56e040ec0 --- /dev/null +++ b/bundles/org.eclipse.remote.proxy.core/.gitignore @@ -0,0 +1 @@ +/bin diff --git a/bundles/org.eclipse.remote.proxy.core/.project b/bundles/org.eclipse.remote.proxy.core/.project new file mode 100644 index 00000000000..a6208317c9b --- /dev/null +++ b/bundles/org.eclipse.remote.proxy.core/.project @@ -0,0 +1,34 @@ + + + org.eclipse.remote.proxy.core + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + org.eclipse.pde.api.tools.apiAnalysisBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + org.eclipse.pde.api.tools.apiAnalysisNature + + diff --git a/bundles/org.eclipse.remote.proxy.core/.settings/org.eclipse.jdt.core.prefs b/bundles/org.eclipse.remote.proxy.core/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 00000000000..3a21537071b --- /dev/null +++ b/bundles/org.eclipse.remote.proxy.core/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,11 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/bundles/org.eclipse.remote.proxy.core/META-INF/MANIFEST.MF b/bundles/org.eclipse.remote.proxy.core/META-INF/MANIFEST.MF new file mode 100644 index 00000000000..f379f4dcd9b --- /dev/null +++ b/bundles/org.eclipse.remote.proxy.core/META-INF/MANIFEST.MF @@ -0,0 +1,28 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: %pluginName +Bundle-SymbolicName: org.eclipse.remote.proxy.core;singleton:=true +Bundle-Version: 1.0.0.qualifier +Bundle-Activator: org.eclipse.remote.internal.proxy.core.Activator +Bundle-Vendor: %pluginProvider +Bundle-ActivationPolicy: lazy +Export-Package: org.eclipse.remote.internal.proxy.core;x-friends:="org.eclipse.remote.proxy.ui", + org.eclipse.remote.internal.proxy.core.commands;x-friends:="org.eclipse.remote.proxy.ui", + org.eclipse.remote.internal.proxy.core.messages;x-friends:="org.eclipse.remote.proxy.ui" +Bundle-Localization: plugin +Bundle-RequiredExecutionEnvironment: JavaSE-1.8 +Import-Package: + com.jcraft.jsch, + org.eclipse.core.filesystem, + org.eclipse.core.filesystem.provider, + org.eclipse.core.runtime, + org.eclipse.core.runtime.jobs, + org.eclipse.jsch.core, + org.eclipse.osgi.util, + org.eclipse.remote.core, + org.eclipse.remote.core.exception, + org.eclipse.remote.internal.core, + org.eclipse.remote.internal.jsch.core, + org.eclipse.remote.proxy.protocol.core, + org.eclipse.remote.proxy.protocol.core.exceptions, + org.osgi.framework diff --git a/bundles/org.eclipse.remote.proxy.core/about.html b/bundles/org.eclipse.remote.proxy.core/about.html new file mode 100644 index 00000000000..3f810933b39 --- /dev/null +++ b/bundles/org.eclipse.remote.proxy.core/about.html @@ -0,0 +1,22 @@ + + + +About + + + +

About This Content

+ +

May 2, 2006

+

License

+ +

The Eclipse Foundation makes available all content in this plug-in ("Content"). Unless otherwise indicated below, the Content is provided to you under the terms and conditions of the +Eclipse Public License Version 1.0 ("EPL"). A copy of the EPL is available at http://www.eclipse.org/legal/epl-v10.html. +For purposes of the EPL, "Program" will mean the Content.

+ +

If you did not receive this Content directly from the Eclipse Foundation, the Content is being redistributed by another party ("Redistributor") and different terms and conditions may +apply to your use of any object code in the Content. Check the Redistributor's license that was provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise +indicated below, the terms and conditions of the EPL still apply to any source code in the Content and such source code may be obtained at http://www.eclipse.org.

+ + + \ No newline at end of file diff --git a/bundles/org.eclipse.remote.proxy.core/bootstrap.sh b/bundles/org.eclipse.remote.proxy.core/bootstrap.sh new file mode 100644 index 00000000000..976a6352a98 --- /dev/null +++ b/bundles/org.eclipse.remote.proxy.core/bootstrap.sh @@ -0,0 +1,125 @@ +installdir="$HOME/.eclipsesettings" +if test ! -d $installdir; then + mkdir $installdir + if test ! -d $installdir; then + echo fail:cannot create $installdir + exit 1 + fi +fi +cat > $installdir/bootstrap.sh <<-\EOF +#!/bin/sh +installdir="$HOME/.eclipsesettings" +proxytmp=$installdir/proxy.b64 +success=false + +cleanup() { + rm -f $installdir/bootstrap.sh +} + +trap 'cleanup' EXIT + +parent_is_not_orphan () { + parent=`ps -ef|awk '$2=='$$'{print $3}'` + let parent=$parent+0 + if [[ $parent -eq 1 ]]; then + return 1 + fi + return 0 +} + +do_check() { + java_vers=`java -version 2>&1` + case "$java_vers" in + *"not found") + echo "fail:could not find a valid java installation" + return + ;; + esac + major=`expr "$java_vers" : ".* version \"\([0-9]*\)\.[0-9]*.*\""` + minor=`expr "$java_vers" : ".* version \"[0-9]*\.\([0-9]*\).*\""` + if test "$major" -ge 2 -o "$minor" -ge 8; then + : + else + echo "fail:invalid java version $major.$minor; must be >= 1.8" + return + fi + case "`uname`" in + Linux) + osname="linux"; + osarch=`uname -m`; + proxydir=$installdir/proxy; + plugins=$proxydir/plugins;; + Darwin) + osname="macosx"; + osarch=`uname -m`; + proxydir=$installdir/Proxy.app; + plugins=$proxydir/Contents/Eclipse/plugins;; + *) + echo fail:system not supported; + return;; + esac + proxy=not_found + if test -d $proxydir; then + bundle="org.eclipse.remote.proxy.server.core_$1.jar" + if test -f $plugins/$bundle; then + proxy=found + else + mv $proxydir $proxydir.pre_$1 + fi + fi + echo ok:$proxy/$osname/$osarch +} + +do_download() { + dd of=$proxytmp ibs=680 count=$1 + IFS= read -r last + echo "$last" >> $proxytmp + base64 --decode < $proxytmp | (cd $installdir && tar zxvf -) > /dev/null 2>&1 + if test $? -eq 0; then + echo ok + else + echo fail:download failed + fi +} + +# +# Start java in background so we can clean up after connection is dropped. The only way to tell if this +# has happened is to poll if ppid has changed to 1 (i.e. we no longer have a controlling terminal) +# +start_server() { + # enable debugoptions in order to attach a debugger + #debugoptions="-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=1044,quiet=y" + + # use globbing to find launcher version + java -cp $plugins/org.eclipse.equinox.launcher_1.*.jar \ + $debugoptions \ + org.eclipse.equinox.launcher.Main \ + -application org.eclipse.remote.proxy.server.core.application \ + -noExit 0<&0 & + + pid=$! + + trap 'kill $pid; exit' HUP INT TERM + + while parent_is_not_orphan; do + sleep 10 + done + + kill $pid +} + +echo running + +while read line arg; do + case $line in + check) do_check $arg;; + download) do_download $arg;; + start) start_server;; + exit) break;; + *) echo fail:unrecognized command:$line; exit 1;; + esac +done +exit 0 +EOF +chmod 755 $installdir/bootstrap.sh +exec $installdir/bootstrap.sh diff --git a/bundles/org.eclipse.remote.proxy.core/build.properties b/bundles/org.eclipse.remote.proxy.core/build.properties new file mode 100644 index 00000000000..d86ac1333c4 --- /dev/null +++ b/bundles/org.eclipse.remote.proxy.core/build.properties @@ -0,0 +1,10 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + .,\ + plugin.xml,\ + plugin.properties,\ + about.html,\ + bootstrap.sh + + diff --git a/bundles/org.eclipse.remote.console/about.properties b/bundles/org.eclipse.remote.proxy.core/plugin.properties similarity index 52% rename from bundles/org.eclipse.remote.console/about.properties rename to bundles/org.eclipse.remote.proxy.core/plugin.properties index f68a85a36b4..6497f0460e9 100644 --- a/bundles/org.eclipse.remote.console/about.properties +++ b/bundles/org.eclipse.remote.proxy.core/plugin.properties @@ -1,22 +1,11 @@ ############################################################################### -# Copyright (c) 2005, 2007 IBM Corporation and others. +# Copyright (c) 2016 Oak Ridge National Laboratory 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 ############################################################################### -# NLS_MESSAGEFORMAT_NONE -# NLS_ENCODING=UTF-8 - -blurb=Remote Services\n\ -\n\ -Version: {featureVersion}\n\ -Build id: {0}\n\ -\n\ -Copyright (c) 2008 IBM Corporation, and others. All rights reserved.\n\ -Visit http://www.eclipse.org/ptp\n - +pluginName=Remote Proxy Support +pluginProvider=Eclipse PTP diff --git a/bundles/org.eclipse.remote.proxy.core/plugin.xml b/bundles/org.eclipse.remote.proxy.core/plugin.xml new file mode 100644 index 00000000000..2de33ec7138 --- /dev/null +++ b/bundles/org.eclipse.remote.proxy.core/plugin.xml @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/bundles/org.eclipse.remote.proxy.core/pom.xml b/bundles/org.eclipse.remote.proxy.core/pom.xml new file mode 100644 index 00000000000..04cd0a618b4 --- /dev/null +++ b/bundles/org.eclipse.remote.proxy.core/pom.xml @@ -0,0 +1,16 @@ + + + 4.0.0 + + + org.eclipse.remote + remote-parent + 3.0.0-SNAPSHOT + ../../releng/org.eclipse.remote.build/pom.xml + + + org.eclipse.remote.proxy.core + eclipse-plugin +1.0.0-SNAPSHOT + diff --git a/bundles/org.eclipse.remote.proxy.core/src/org/eclipse/remote/internal/proxy/core/Activator.java b/bundles/org.eclipse.remote.proxy.core/src/org/eclipse/remote/internal/proxy/core/Activator.java new file mode 100644 index 00000000000..38fe3c1a96e --- /dev/null +++ b/bundles/org.eclipse.remote.proxy.core/src/org/eclipse/remote/internal/proxy/core/Activator.java @@ -0,0 +1,116 @@ +package org.eclipse.remote.internal.proxy.core; + +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Plugin; +import org.eclipse.core.runtime.Status; +import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceReference; + +/** + * The activator class controls the plug-in life cycle + */ +public class Activator extends Plugin { + + // The plug-in ID + public static final String PLUGIN_ID = "org.eclipse.remote.proxy.core"; //$NON-NLS-1$ + + // The shared instance + private static Activator plugin; + + /** + * Returns the shared instance + * + * @return the shared instance + */ + public static Activator getDefault() { + return plugin; + } + + /** + * Get unique identifier + * + * @return + * @since 5.0 + */ + public static String getUniqueIdentifier() { + if (getDefault() == null) { + return PLUGIN_ID; + } + return getDefault().getBundle().getSymbolicName(); + } + + /** + * Logs the specified status with this plug-in's log. + * + * @param status + * status to log + */ + public static void log(IStatus status) { + getDefault().getLog().log(status); + } + + /** + * Logs an internal error with the specified message. + * + * @param message + * the error message to log + */ + public static void log(String message) { + log(new Status(IStatus.ERROR, getUniqueIdentifier(), IStatus.ERROR, message, null)); + } + + /** + * Logs an internal error with the specified throwable + * + * @param e + * the exception to be logged + */ + public static void log(Throwable e) { + log(new Status(IStatus.ERROR, getUniqueIdentifier(), IStatus.ERROR, e.getMessage(), e)); + } + + + /** + * The constructor + */ + public Activator() { + } + + /** + * Return the OSGi service with the given service interface. + * + * @param service service interface + * @return the specified service or null if it's not registered + */ + public static T getService(Class service) { + BundleContext context = plugin.getBundle().getBundleContext(); + ServiceReference ref = context.getServiceReference(service); + return ref != null ? context.getService(ref) : null; + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext + * ) + */ + @Override + public void start(BundleContext context) throws Exception { + super.start(context); + plugin = this; + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext + * ) + */ + @Override + public void stop(BundleContext context) throws Exception { + plugin = null; + super.stop(context); + } +} diff --git a/bundles/org.eclipse.remote.proxy.core/src/org/eclipse/remote/internal/proxy/core/ProxyConnection.java b/bundles/org.eclipse.remote.proxy.core/src/org/eclipse/remote/internal/proxy/core/ProxyConnection.java new file mode 100644 index 00000000000..20a0cfcd324 --- /dev/null +++ b/bundles/org.eclipse.remote.proxy.core/src/org/eclipse/remote/internal/proxy/core/ProxyConnection.java @@ -0,0 +1,463 @@ +/******************************************************************************* + * Copyright (c) 2016 Oak Ridge National Laboratory 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 + *******************************************************************************/ +package org.eclipse.remote.internal.proxy.core; + +import java.io.BufferedWriter; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.SubMonitor; +import org.eclipse.remote.core.IRemoteCommandShellService; +import org.eclipse.remote.core.IRemoteConnection; +import org.eclipse.remote.core.IRemoteConnectionChangeListener; +import org.eclipse.remote.core.IRemoteConnectionControlService; +import org.eclipse.remote.core.IRemoteConnectionHostService; +import org.eclipse.remote.core.IRemoteConnectionPropertyService; +import org.eclipse.remote.core.IRemoteConnectionWorkingCopy; +import org.eclipse.remote.core.IRemoteProcess; +import org.eclipse.remote.core.IRemoteProcessBuilder; +import org.eclipse.remote.core.IRemoteProcessService; +import org.eclipse.remote.core.RemoteConnectionChangeEvent; +import org.eclipse.remote.core.RemoteServicesUtils; +import org.eclipse.remote.core.exception.RemoteConnectionException; +import org.eclipse.remote.internal.proxy.core.commands.ExecCommand; +import org.eclipse.remote.internal.proxy.core.commands.GetCwdCommand; +import org.eclipse.remote.internal.proxy.core.commands.GetEnvCommand; +import org.eclipse.remote.internal.proxy.core.commands.GetPropertiesCommand; +import org.eclipse.remote.internal.proxy.core.messages.Messages; +import org.eclipse.remote.proxy.protocol.core.StreamChannel; +import org.eclipse.remote.proxy.protocol.core.StreamChannelManager; +import org.eclipse.remote.proxy.protocol.core.exceptions.ProxyException; + +import com.jcraft.jsch.ChannelShell; + +/** + * @since 5.0 + */ +public class ProxyConnection implements IRemoteConnectionControlService, + IRemoteConnectionChangeListener, IRemoteProcessService, + IRemoteCommandShellService, IRemoteConnectionHostService, + IRemoteConnectionPropertyService { + // Connection Type ID + public static final String JSCH_ID = "org.eclipse.remote.Proxy"; //$NON-NLS-1$ + + public static final int DEFAULT_PORT = 22; + public static final int DEFAULT_TIMEOUT = 0; + public static final boolean DEFAULT_USE_PASSWORD = false; + public static final boolean DEFAULT_USE_DEFAULT_SERVER = true; + public static final String DEFAULT_SERVER_COMMAND = "sh .eclipsesettings/proxy.sh"; //$NON-NLS-1$ + + public static final String HOSTNAME_ATTR = "PROXY_HOSTNAME__ATTR"; //$NON-NLS-1$ + public static final String USERNAME_ATTR = "PROXY_USERNAME_ATTR"; //$NON-NLS-1$ + public static final String PASSWORD_ATTR = "PROXY_PASSWORD_ATTR"; //$NON-NLS-1$ + public static final String PORT_ATTR = "PROXY_PORT_ATTR"; //$NON-NLS-1$ + public static final String USE_PASSWORD_ATTR = "PROXY_USE_PASSWORD_ATTR"; //$NON-NLS-1$ + public static final String PASSPHRASE_ATTR = "PROXY_PASSPHRASE_ATTR"; //$NON-NLS-1$ + public static final String TIMEOUT_ATTR = "PROXY_TIMEOUT_ATTR"; //$NON-NLS-1$ + public static final String SERVER_COMMAND_ATTR = "PROXY_SERVER_COMMAND_ATTR"; //$NON-NLS-1$ + public static final String USE_DEFAULT_SERVER_ATTR = "PROXY_USE_DEFAULT_SERVER_ATTR"; //$NON-NLS-1$ + + private String fWorkingDir; + private StreamChannelManager channelMux; + private StreamChannel commandChannel; + private boolean isOpen; + + private final IRemoteConnection fRemoteConnection; + + private final Map fEnv = new HashMap<>(); + private final Map fProperties = new HashMap<>(); + + private static final Map connectionMap = new HashMap<>(); + + public ProxyConnection(IRemoteConnection connection) { + fRemoteConnection = connection; + connection.addConnectionChangeListener(this); + } + + @Override + public void connectionChanged(RemoteConnectionChangeEvent event) { + if (event.getType() == RemoteConnectionChangeEvent.CONNECTION_REMOVED) { + synchronized (connectionMap) { + connectionMap.remove(event.getConnection()); + } + } + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.remote.core.IRemoteConnection.Service#getRemoteConnection() + */ + @Override + public IRemoteConnection getRemoteConnection() { + return fRemoteConnection; + } + + public static class Factory implements IRemoteConnection.Service.Factory { + /* + * (non-Javadoc) + * + * @see org.eclipse.remote.core.IRemoteConnection.Service.Factory#getService(org.eclipse.remote.core.IRemoteConnection, + * java.lang.Class) + */ + @Override + @SuppressWarnings("unchecked") + public T getService(IRemoteConnection connection, Class service) { + // This little trick creates an instance of this class for a connection + // 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 (ProxyConnection.class.equals(service)) { + synchronized (connectionMap) { + ProxyConnection conn = connectionMap.get(connection); + if (conn == null) { + conn = new ProxyConnection(connection); + connectionMap.put(connection, conn); + } + return (T) conn; + } + } else if (IRemoteConnectionControlService.class.equals(service) + || IRemoteConnectionPropertyService.class.equals(service) + || IRemoteConnectionHostService.class.equals(service) + || IRemoteProcessService.class.equals(service) + || IRemoteCommandShellService.class.equals(service) + || IRemoteConnectionPropertyService.class.equals(service)) { + return (T) connection.getService(ProxyConnection.class); + } else { + return null; + } + } + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.remote.core.IRemoteConnectionControlService#close() + */ + @Override + public synchronized void close() { + if (isOpen) { + channelMux.shutdown(); + isOpen = false; + fRemoteConnection.fireConnectionChangeEvent(RemoteConnectionChangeEvent.CONNECTION_CLOSED); + } + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.remote.core.IRemoteConnectionControlService#isOpen() + */ + @Override + public boolean isOpen() { + return isOpen; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.remote.core.IRemoteConnectionControlService#open(org.eclipse.core.runtime.IProgressMonitor) + */ + @Override + public void open(IProgressMonitor monitor) throws RemoteConnectionException { + SubMonitor subMon = SubMonitor.convert(monitor, Messages.ProxyConnection_0, 20); + if (!isOpen) { + ProxyConnectionBootstrap bootstrap = new ProxyConnectionBootstrap(); + channelMux = bootstrap.run(getRemoteConnection(), subMon.newChild(10)); + new Thread(channelMux, "multiplexer").start(); //$NON-NLS-1$ + try { + commandChannel = channelMux.openChannel(); + initialize(subMon.newChild(10)); + } catch (RemoteConnectionException | IOException e) { + try { + commandChannel.close(); + } catch (IOException e1) { + // Ignore + } + channelMux.shutdown(); + throw new RemoteConnectionException(e.getMessage()); + } + + isOpen = true; + fRemoteConnection.fireConnectionChangeEvent(RemoteConnectionChangeEvent.CONNECTION_OPENED); + } + } + + private void initialize(IProgressMonitor monitor) throws RemoteConnectionException { + SubMonitor subMon = SubMonitor.convert(monitor, 30); + fWorkingDir = getCwd(subMon.newChild(10)); + if (subMon.isCanceled()) { + throw new RemoteConnectionException(Messages.ProxyConnection_2); + } + fEnv.putAll(loadEnv(subMon.newChild(10))); + if (subMon.isCanceled()) { + throw new RemoteConnectionException(Messages.ProxyConnection_2); + } + fProperties.putAll(loadProperties(subMon.newChild(10))); + if (subMon.isCanceled()) { + throw new RemoteConnectionException(Messages.ProxyConnection_2); + } + } + + private String getCwd(IProgressMonitor monitor) throws RemoteConnectionException { + try { + GetCwdCommand cmd = new GetCwdCommand(this); + return cmd.getResult(monitor); + } catch (ProxyException e) { + throw new RemoteConnectionException(e.getMessage()); + } + } + + private Map loadEnv(IProgressMonitor monitor) throws RemoteConnectionException { + try { + GetEnvCommand cmd = new GetEnvCommand(this); + return cmd.getResult(monitor); + } catch (ProxyException e) { + throw new RemoteConnectionException(e.getMessage()); + } + } + + private Map loadProperties(IProgressMonitor monitor) throws RemoteConnectionException { + try { + GetPropertiesCommand cmd = new GetPropertiesCommand(this); + return cmd.getResult(monitor); + } catch (ProxyException e) { + throw new RemoteConnectionException(e.getMessage()); + } + } + + public Map getEnv() { + return Collections.unmodifiableMap(fEnv); + } + + public StreamChannel getCommandChannel() { + return commandChannel; + } + + public StreamChannel openChannel() throws IOException { + return channelMux.openChannel(); + } + + private StringBuffer stdout = new StringBuffer(); + private StringBuffer stderr = new StringBuffer(); + + @SuppressWarnings("unused") + private String executeSshCommand(ChannelShell shell, String command) throws RemoteConnectionException { + try { + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + ByteArrayOutputStream err = new ByteArrayOutputStream(); + shell.setOutputStream(stream); + shell.setExtOutputStream(err); + BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(shell.getOutputStream())); + writer.write(command); + writer.flush(); + if (err.size() > 0) { + throw new RemoteConnectionException(err.toString()); + } + return stream.toString(); + } catch (IOException e) { + throw new RemoteConnectionException(e.getMessage()); + } + } + + @SuppressWarnings("unused") + private String executeCommand(List command, IProgressMonitor monitor) throws ProxyException { + try { + final StreamChannel chanA = channelMux.openChannel(); + final StreamChannel chanB = channelMux.openChannel(); + final StreamChannel chanC = channelMux.openChannel(); + new Thread("cmd stdin reader") { //$NON-NLS-1$ + @Override + public void run() { + byte[] buf = new byte[1024]; + int n; + try { + while ((n = chanA.getInputStream().read(buf)) >= 0) { + stdout.append(new String(buf, 0, n)); + } + } catch (IOException e) { + // Finish + } + } + }.start(); + new Thread("cmd stderr reader") { //$NON-NLS-1$ + @Override + public void run() { + byte[] buf = new byte[1024]; + int n; + try { + while ((n = chanB.getInputStream().read(buf)) >= 0) { + stderr.append(new String(buf, 0, n)); + } + } catch (IOException e) { + // Finish + } + } + }.start(); + ExecCommand cmd = new ExecCommand(this, command, getEnv(), getWorkingDirectory(), false, false, chanA.getId(), chanB.getId(), chanC.getId()); + cmd.getResult(monitor); + DataInputStream status = new DataInputStream(chanC.getInputStream()); + int stat = status.readInt(); + if (stat == 0) { + return stdout.toString(); + } + return stderr.toString(); + } catch (IOException e) { + throw new ProxyException(e.getMessage()); + } + } + + @Override + public String getEnv(String name) { + return getEnv().get(name); + } + + @Override + public IRemoteProcessBuilder getProcessBuilder(List command) { + return new ProxyProcessBuilder(this, command); + } + + @Override + public IRemoteProcessBuilder getProcessBuilder(String... command) { + return new ProxyProcessBuilder(this, command); + } + + @Override + public String getWorkingDirectory() { + return fWorkingDir; + } + + @Override + public void setWorkingDirectory(String path) { + if (RemoteServicesUtils.posixPath(path).isAbsolute()) { + fWorkingDir = path; + } + } + + @Override + public IRemoteProcess getCommandShell(int flags) throws IOException { + return new ProxyProcessBuilder(this).start(flags); + } + + @Override + public String getHostname() { + return fRemoteConnection.getAttribute(HOSTNAME_ATTR); + } + + @Override + public int getPort() { + String portStr = fRemoteConnection.getAttribute(PORT_ATTR); + return !portStr.isEmpty() ? Integer.parseInt(portStr) : DEFAULT_PORT; + } + + @Override + public int getTimeout() { + String portStr = fRemoteConnection.getAttribute(TIMEOUT_ATTR); + return !portStr.isEmpty() ? Integer.parseInt(portStr) : DEFAULT_TIMEOUT; + } + + @Override + public String getPassphrase() { + return fRemoteConnection.getSecureAttribute(PASSPHRASE_ATTR); + } + + @Override + public String getPassword() { + return fRemoteConnection.getSecureAttribute(PASSWORD_ATTR); + } + + @Override + public boolean usePassword() { + String str = fRemoteConnection.getAttribute(USE_PASSWORD_ATTR); + return !str.isEmpty() ? Boolean.parseBoolean(str) : DEFAULT_USE_PASSWORD; + } + + @Override + public String getUsername() { + return fRemoteConnection.getAttribute(USERNAME_ATTR); + } + + @Override + public boolean useLoginShell() { + return false; + } + + @Override + public void setHostname(String hostname) { + if (fRemoteConnection instanceof IRemoteConnectionWorkingCopy) { + IRemoteConnectionWorkingCopy wc = (IRemoteConnectionWorkingCopy) fRemoteConnection; + wc.setAttribute(HOSTNAME_ATTR, hostname); + } + } + + @Override + public void setPassphrase(String passphrase) { + if (fRemoteConnection instanceof IRemoteConnectionWorkingCopy) { + IRemoteConnectionWorkingCopy wc = (IRemoteConnectionWorkingCopy) fRemoteConnection; + wc.setSecureAttribute(PASSPHRASE_ATTR, passphrase); + } + } + + @Override + public void setPassword(String password) { + if (fRemoteConnection instanceof IRemoteConnectionWorkingCopy) { + IRemoteConnectionWorkingCopy wc = (IRemoteConnectionWorkingCopy) fRemoteConnection; + wc.setSecureAttribute(PASSWORD_ATTR, password); + } + } + + @Override + public void setPort(int port) { + if (fRemoteConnection instanceof IRemoteConnectionWorkingCopy) { + IRemoteConnectionWorkingCopy wc = (IRemoteConnectionWorkingCopy) fRemoteConnection; + wc.setAttribute(PORT_ATTR, Integer.toString(port)); + } + } + + @Override + public void setTimeout(int timeout) { + if (fRemoteConnection instanceof IRemoteConnectionWorkingCopy) { + IRemoteConnectionWorkingCopy wc = (IRemoteConnectionWorkingCopy) fRemoteConnection; + wc.setAttribute(TIMEOUT_ATTR, Integer.toString(timeout)); + } + } + + @Override + public void setUseLoginShell(boolean useLogingShell) { + // Not used + } + + @Override + public void setUsePassword(boolean usePassword) { + if (fRemoteConnection instanceof IRemoteConnectionWorkingCopy) { + IRemoteConnectionWorkingCopy wc = (IRemoteConnectionWorkingCopy) fRemoteConnection; + wc.setAttribute(USE_PASSWORD_ATTR, Boolean.toString(usePassword)); + } + } + + @Override + public void setUsername(String username) { + if (fRemoteConnection instanceof IRemoteConnectionWorkingCopy) { + IRemoteConnectionWorkingCopy wc = (IRemoteConnectionWorkingCopy) fRemoteConnection; + wc.setAttribute(USERNAME_ATTR, username); + } + } + + @Override + public String getProperty(String key) { + return fProperties.get(key); + } +} diff --git a/bundles/org.eclipse.remote.proxy.core/src/org/eclipse/remote/internal/proxy/core/ProxyConnectionBootstrap.java b/bundles/org.eclipse.remote.proxy.core/src/org/eclipse/remote/internal/proxy/core/ProxyConnectionBootstrap.java new file mode 100644 index 00000000000..03b2aa2017e --- /dev/null +++ b/bundles/org.eclipse.remote.proxy.core/src/org/eclipse/remote/internal/proxy/core/ProxyConnectionBootstrap.java @@ -0,0 +1,321 @@ +/******************************************************************************* + * Copyright (c) 2016 Oak Ridge National Laboratory 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 + *******************************************************************************/ +package org.eclipse.remote.internal.proxy.core; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.net.URL; +import java.util.Arrays; +import java.util.Base64; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.FileLocator; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.Path; +import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.SubMonitor; +import org.eclipse.jsch.core.IJSchService; +import org.eclipse.osgi.util.NLS; +import org.eclipse.remote.core.IRemoteConnection; +import org.eclipse.remote.core.IRemoteConnectionHostService; +import org.eclipse.remote.core.IRemoteConnectionWorkingCopy; +import org.eclipse.remote.core.IUserAuthenticatorService; +import org.eclipse.remote.core.exception.RemoteConnectionException; +import org.eclipse.remote.internal.jsch.core.JSchUserInfo; +import org.eclipse.remote.internal.proxy.core.messages.Messages; +import org.eclipse.remote.proxy.protocol.core.StreamChannelManager; +import org.osgi.framework.Bundle; + +import com.jcraft.jsch.Channel; +import com.jcraft.jsch.ChannelExec; +import com.jcraft.jsch.JSchException; +import com.jcraft.jsch.Session; + +public class ProxyConnectionBootstrap { + private final IJSchService jSchService; + private Session session; + private ChannelExec exec; + + private class Context { + private State state; + private String osName; + private String osArch; + private String errorMessage; + + private final SubMonitor monitor; + private final BufferedReader reader; + private final BufferedWriter writer; + + public Context(BufferedReader reader, BufferedWriter writer, IProgressMonitor monitor) { + this.reader = reader; + this.writer = writer; + this.monitor = SubMonitor.convert(monitor); + setState(States.INIT); + } + + State getState() { + return state; + } + + SubMonitor getMonitor() { + return monitor; + } + + void setState(State state) { + this.state = state; + } + + String getOSName() { + return osName; + } + + void setOSName(String osName) { + this.osName = osName; + } + + String getOSArch() { + return osArch; + } + + void setOSArch(String osArch) { + this.osArch = osArch; + } + + void setErrorMessage(String message) { + this.errorMessage = message; + } + + String getErrorMessage() { + return errorMessage; + } + } + + private interface State { + /** + * @return true to keep processing, false to read more data. + */ + boolean process(Context context) throws IOException; + } + + private enum States implements State { + INIT { + @Override + public boolean process(Context context) throws IOException { + context.getMonitor().subTask(Messages.ProxyConnectionBootstrap_0); + String line = context.reader.readLine(); + context.getMonitor().worked(1); + if (line.equals("running")) { //$NON-NLS-1$ + context.setState(States.CHECK); + return true; + } + return false; + } + }, + CHECK { + @Override + public boolean process(Context context) throws IOException { + context.getMonitor().subTask(Messages.ProxyConnectionBootstrap_1); + String bundleName = "org.eclipse.remote.proxy.server.core"; //$NON-NLS-1$ + Bundle serverBundle = Platform.getBundle(bundleName); + if (serverBundle == null) { + throw new IOException(NLS.bind(Messages.ProxyConnectionBootstrap_2, bundleName)); + } + context.writer.write("check " + serverBundle.getVersion() + "\n"); //$NON-NLS-1$ //$NON-NLS-2$ + context.writer.flush(); + String line = context.reader.readLine(); + while (line != null) { + context.getMonitor().worked(2); + String[] parts = line.split(":"); //$NON-NLS-1$ + switch (parts[0]) { + case "ok": //$NON-NLS-1$ + String[] status = parts[1].split("/"); //$NON-NLS-1$ + context.setOSName(status[1]); + context.setOSArch(status[2]); + context.setState(status[0].equals("found") ? States.START : States.DOWNLOAD); //$NON-NLS-1$ + return true; + case "fail": //$NON-NLS-1$ + context.setErrorMessage(parts[1]); + System.out.println("fail:"+parts[1]); //$NON-NLS-1$ + return false; + case "debug": //$NON-NLS-1$ + System.err.println(line); + break; + default: + System.err.println("Invalid response from bootstrap script: " + line); //$NON-NLS-1$ + return false; + } + line = context.reader.readLine(); + } + return false; + } + }, + DOWNLOAD { + @Override + public boolean process(Context context) throws IOException { + context.getMonitor().subTask(Messages.ProxyConnectionBootstrap_3); + String bundleName = "org.eclipse.remote.proxy.server." + context.getOSName() + "." + context.getOSArch(); //$NON-NLS-1$ //$NON-NLS-2$ + Bundle serverBundle = Platform.getBundle(bundleName); + if (serverBundle == null) { + throw new IOException(NLS.bind(Messages.ProxyConnectionBootstrap_2, bundleName)); + } + URL fileURL = FileLocator.find(serverBundle, new Path("proxy.server.tar.gz"), null); //$NON-NLS-1$ + if (fileURL == null) { + return false; + } + File file = new File(FileLocator.toFileURL(fileURL).getFile()); + long count = file.length() / 510; + context.writer.write("download " + count + "\n"); //$NON-NLS-1$ //$NON-NLS-2$ + context.writer.flush(); + context.getMonitor().worked(2); + if (downloadFile(file, context.writer, context.getMonitor().newChild(5))) { + String line = context.reader.readLine(); + while (line != null) { + String[] parts = line.split(":"); //$NON-NLS-1$ + switch (parts[0]) { + case "ok": //$NON-NLS-1$ + context.setState(States.START); + return true; + case "fail": //$NON-NLS-1$ + context.setErrorMessage(parts[1]); + System.out.println("fail:"+parts[1]); //$NON-NLS-1$ + return false; + case "debug": //$NON-NLS-1$ + System.err.println(line); + break; + default: + System.err.println("Invalid response from bootstrap script: " + line); //$NON-NLS-1$ + return false; + } + line = context.reader.readLine(); + } + } + return false; + } + + private boolean downloadFile(File file, BufferedWriter writer, IProgressMonitor monitor) { + SubMonitor subMon = SubMonitor.convert(monitor, 10); + try { + Base64.Encoder encoder = Base64.getEncoder(); + FileInputStream in = new FileInputStream(file); + byte[] buf = new byte[510]; // Multiple of 3 + int n; + while ((n = in.read(buf)) >= 0) { + if (n < 510) { + writer.write(encoder.encodeToString(Arrays.copyOf(buf, n)) + "\n"); //$NON-NLS-1$ + } else { + writer.write(encoder.encodeToString(buf)); + } + subMon.setWorkRemaining(8); + } + writer.flush(); + in.close(); + return true; + } catch (IOException e) { + return false; + } + } + }, + START { + @Override + public boolean process(Context context) throws IOException { + context.getMonitor().subTask(Messages.ProxyConnectionBootstrap_4); + context.writer.write("start\n"); //$NON-NLS-1$ + context.writer.flush(); + return false; // Finished + } + } + } + + public ProxyConnectionBootstrap() { + jSchService = Activator.getService(IJSchService.class); + } + + public StreamChannelManager run(IRemoteConnection connection, IProgressMonitor monitor) throws RemoteConnectionException { + SubMonitor subMon = SubMonitor.convert(monitor, 20); + try { + final Channel chan = openChannel(connection, subMon.newChild(10)); + BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(chan.getOutputStream())); + BufferedReader reader = new BufferedReader(new InputStreamReader(chan.getInputStream())); + subMon.beginTask(Messages.ProxyConnectionBootstrap_5, 10); + subMon.subTask(Messages.ProxyConnectionBootstrap_9); + URL fileURL = FileLocator.find(Activator.getDefault().getBundle(), new Path("bootstrap.sh"), null); //$NON-NLS-1$ + if (fileURL == null) { + throw new RemoteConnectionException(Messages.ProxyConnectionBootstrap_6); + } + File file = new File(FileLocator.toFileURL(fileURL).getFile()); + BufferedReader scriptReader = new BufferedReader(new InputStreamReader(new FileInputStream(file))); + String line; + while ((line = scriptReader.readLine()) != null) { + writer.write(line + "\n"); //$NON-NLS-1$ + } + scriptReader.close(); + writer.flush(); + subMon.worked(2); + Context context = new Context(reader, writer, subMon.newChild(8)); + while (context.getState().process(context)) { + // do state machine + } + if (context.getState() != States.START) { + context.writer.write("exit\n"); //$NON-NLS-1$ + context.writer.flush(); + throw new RemoteConnectionException(NLS.bind(Messages.ProxyConnectionBootstrap_7, context.getErrorMessage())); + } + new Thread("server error stream") { //$NON-NLS-1$ + @Override + public void run() { + try { + BufferedReader reader = new BufferedReader(new InputStreamReader(chan.getExtInputStream())); + String line; + while ((line = reader.readLine()) != null) { + System.err.println("server: "+ line); //$NON-NLS-1$ + } + } catch (IOException e) { + // Ignore and terminate thread + } + } + }.start(); + return new StreamChannelManager(chan.getInputStream(), chan.getOutputStream()); + } catch (IOException | CoreException e) { + throw new RemoteConnectionException(e.getMessage()); + } + } + + private Channel openChannel(IRemoteConnection connection, IProgressMonitor monitor) throws RemoteConnectionException { + IRemoteConnectionWorkingCopy wc = connection.getWorkingCopy(); + IRemoteConnectionHostService hostService = wc.getService(IRemoteConnectionHostService.class); + IUserAuthenticatorService authService = wc.getService(IUserAuthenticatorService.class); + try { + session = jSchService.createSession(hostService.getHostname(), hostService.getPort(), hostService.getUsername()); + session.setUserInfo(new JSchUserInfo(hostService, authService)); + if (hostService.usePassword()) { + session.setConfig("PreferredAuthentications", "password,keyboard-interactive,gssapi-with-mic,publickey"); //$NON-NLS-1$ //$NON-NLS-2$ + } else { + session.setConfig("PreferredAuthentications", "publickey,gssapi-with-mic,password,keyboard-interactive"); //$NON-NLS-1$ //$NON-NLS-2$ + } + String password = hostService.getPassword(); + if (!password.isEmpty()) { + session.setPassword(password); + } + jSchService.connect(session, hostService.getTimeout() * 1000, monitor); + if (monitor.isCanceled()) { + throw new RemoteConnectionException(Messages.ProxyConnectionBootstrap_8); + } + exec = (ChannelExec) session.openChannel("exec"); //$NON-NLS-1$ + exec.setCommand("/bin/bash -l"); //$NON-NLS-1$ + exec.connect(); + return exec; + } catch (JSchException e) { + throw new RemoteConnectionException(e.getMessage()); + } + } +} diff --git a/bundles/org.eclipse.remote.proxy.core/src/org/eclipse/remote/internal/proxy/core/ProxyConnectionProviderService.java b/bundles/org.eclipse.remote.proxy.core/src/org/eclipse/remote/internal/proxy/core/ProxyConnectionProviderService.java new file mode 100644 index 00000000000..3eb5869c757 --- /dev/null +++ b/bundles/org.eclipse.remote.proxy.core/src/org/eclipse/remote/internal/proxy/core/ProxyConnectionProviderService.java @@ -0,0 +1,43 @@ +/******************************************************************************* +* Copyright (c) 2016 Oak Ridge National Laboratory 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 + *******************************************************************************/ +package org.eclipse.remote.internal.proxy.core; + +import org.eclipse.remote.core.IRemoteConnectionProviderService; +import org.eclipse.remote.core.IRemoteConnectionType; +import org.eclipse.remote.core.IRemoteConnectionType.Service; + +public class ProxyConnectionProviderService implements IRemoteConnectionProviderService { + + private IRemoteConnectionType connectionType; + + public static class Factory implements IRemoteConnectionType.Service.Factory { + @SuppressWarnings("unchecked") + @Override + public T getService(IRemoteConnectionType connectionType, Class service) { + if (service.equals(IRemoteConnectionProviderService.class)) { + return (T) new ProxyConnectionProviderService(connectionType); + } + return null; + } + } + + public ProxyConnectionProviderService(IRemoteConnectionType connectionType) { + this.connectionType = connectionType; + } + + @Override + public void init() { + // Nothing + } + + @Override + public IRemoteConnectionType getConnectionType() { + return connectionType; + } + +} diff --git a/bundles/org.eclipse.remote.proxy.core/src/org/eclipse/remote/internal/proxy/core/ProxyFileManager.java b/bundles/org.eclipse.remote.proxy.core/src/org/eclipse/remote/internal/proxy/core/ProxyFileManager.java new file mode 100644 index 00000000000..ea57924cd46 --- /dev/null +++ b/bundles/org.eclipse.remote.proxy.core/src/org/eclipse/remote/internal/proxy/core/ProxyFileManager.java @@ -0,0 +1,85 @@ +/******************************************************************************* + * Copyright (c) 2016 Oak Ridge National Laboratory 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 + *******************************************************************************/ +package org.eclipse.remote.internal.proxy.core; + +import java.net.URI; + +import org.eclipse.core.filesystem.IFileStore; +import org.eclipse.core.runtime.IPath; +import org.eclipse.remote.core.IRemoteConnection; +import org.eclipse.remote.core.IRemoteConnection.Service; +import org.eclipse.remote.core.IRemoteFileService; +import org.eclipse.remote.core.IRemoteProcessService; +import org.eclipse.remote.core.RemoteServicesUtils; + +public class ProxyFileManager implements IRemoteFileService { + private final IRemoteConnection fConnection; + + private ProxyFileManager(IRemoteConnection connection) { + fConnection = connection; + } + + public static class Factory implements IRemoteFileService.Factory { + @SuppressWarnings("unchecked") + @Override + public T getService(IRemoteConnection remoteConnection, Class service) { + if (IRemoteFileService.class.equals(service)) { + return (T) new ProxyFileManager(remoteConnection); + } + return null; + } + } + + @Override + public IRemoteConnection getRemoteConnection() { + return fConnection; + } + + @Override + public String getDirectorySeparator() { + return "/"; //$NON-NLS-1$ + } + + @Override + public IFileStore getResource(String pathStr) { + IPath path = RemoteServicesUtils.posixPath(pathStr); + if (!path.isAbsolute()) { + path = RemoteServicesUtils.posixPath(getBaseDirectory()).append(path); + } + return ProxyFileStore.getInstance(ProxyFileSystem.getURIFor(fConnection.getName(), path.toString())); + } + + @Override + public String getBaseDirectory() { + return fConnection.getService(IRemoteProcessService.class).getWorkingDirectory(); + } + + @Override + public void setBaseDirectory(String path) { + fConnection.getService(IRemoteProcessService.class).setWorkingDirectory(path); + } + + @Override + public String toPath(URI uri) { + return uri.getPath(); + } + + @Override + public URI toURI(IPath path) { + try { + return ProxyFileSystem.getURIFor(fConnection.getName(), path.toString()); + } catch (Exception e) { + return null; + } + } + + @Override + public URI toURI(String path) { + return toURI(RemoteServicesUtils.posixPath(path)); + } +} diff --git a/bundles/org.eclipse.remote.proxy.core/src/org/eclipse/remote/internal/proxy/core/ProxyFileStore.java b/bundles/org.eclipse.remote.proxy.core/src/org/eclipse/remote/internal/proxy/core/ProxyFileStore.java new file mode 100644 index 00000000000..09ce3a47914 --- /dev/null +++ b/bundles/org.eclipse.remote.proxy.core/src/org/eclipse/remote/internal/proxy/core/ProxyFileStore.java @@ -0,0 +1,356 @@ +/******************************************************************************* + * Copyright (c) 2016 Oak Ridge National Laboratory 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 + *******************************************************************************/ +package org.eclipse.remote.internal.proxy.core; + +import java.io.InputStream; +import java.io.OutputStream; +import java.net.URI; +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.core.filesystem.EFS; +import org.eclipse.core.filesystem.IFileInfo; +import org.eclipse.core.filesystem.IFileStore; +import org.eclipse.core.filesystem.provider.FileStore; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; +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.osgi.util.NLS; +import org.eclipse.remote.core.IRemoteConnection; +import org.eclipse.remote.core.IRemoteConnectionType; +import org.eclipse.remote.core.IRemoteServicesManager; +import org.eclipse.remote.core.RemoteServicesUtils; +import org.eclipse.remote.core.exception.RemoteConnectionException; +import org.eclipse.remote.internal.proxy.core.commands.ChildInfosCommand; +import org.eclipse.remote.internal.proxy.core.commands.DeleteCommand; +import org.eclipse.remote.internal.proxy.core.commands.FetchInfoCommand; +import org.eclipse.remote.internal.proxy.core.commands.GetInputStreamCommand; +import org.eclipse.remote.internal.proxy.core.commands.GetOutputStreamCommand; +import org.eclipse.remote.internal.proxy.core.commands.MkdirCommand; +import org.eclipse.remote.internal.proxy.core.commands.PutInfoCommand; +import org.eclipse.remote.internal.proxy.core.messages.Messages; +import org.eclipse.remote.proxy.protocol.core.exceptions.ProxyException; + +public class ProxyFileStore extends FileStore { + /** + * Public factory method for obtaining ProxyFileStore instances. + * + * @param uri + * URI to get a fileStore for + * @return an ProxyFileStore instance for the URI. + */ + public static ProxyFileStore getInstance(URI uri) { + synchronized (instanceMap) { + ProxyFileStore store = instanceMap.get(uri.toString()); + if (store == null) { + store = new ProxyFileStore(uri); + instanceMap.put(uri.toString(), store); + } + return store; + } + } + + private static Map instanceMap = new HashMap(); + + private final IPath fRemotePath; + private final URI fURI; + + private ProxyFileStore(URI uri) { + fURI = uri; + fRemotePath = RemoteServicesUtils.posixPath(uri.getPath()); + } + + private ProxyConnection checkConnection(IProgressMonitor monitor) throws RemoteConnectionException { + IRemoteServicesManager manager = Activator.getService(IRemoteServicesManager.class); + IRemoteConnectionType connectionType = manager.getConnectionType(fURI); + if (connectionType == null) { + throw new RemoteConnectionException(NLS.bind(Messages.ProxyFileStore_0, fURI)); + } + + try { + IRemoteConnection connection = connectionType.getConnection(fURI); + if (connection == null) { + throw new RemoteConnectionException(NLS.bind(Messages.ProxyFileStore_1, fURI)); + } + if (!connection.isOpen()) { + connection.open(monitor); + if (!connection.isOpen()) { + throw new RemoteConnectionException(Messages.ProxyFileStore_2); + } + } + return connection.getService(ProxyConnection.class); + } catch (CoreException e) { + throw new RemoteConnectionException(e); + } + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.core.filesystem.provider.FileStore#childInfos(int, + * org.eclipse.core.runtime.IProgressMonitor) + */ + @Override + public IFileInfo[] childInfos(int options, IProgressMonitor monitor) throws CoreException { + SubMonitor subMon = SubMonitor.convert(monitor, 10); + ProxyConnection connection = checkConnection(subMon.newChild(1)); + ChildInfosCommand command = new ChildInfosCommand(connection, fRemotePath.toString()); + try { + return command.getResult(subMon.newChild(9)); + } catch (ProxyException e) { + throw new CoreException(new Status(IStatus.ERROR, Activator.getUniqueIdentifier(), e.getMessage())); + } + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.core.filesystem.provider.FileStore#childNames(int, + * org.eclipse.core.runtime.IProgressMonitor) + */ + @Override + public String[] childNames(int options, IProgressMonitor monitor) throws CoreException { + SubMonitor subMon = SubMonitor.convert(monitor, 10); + IFileInfo[] infos = childInfos(options, subMon.newChild(10)); + String[] names = new String[infos.length]; + for (int i = 0; i < infos.length; i++) { + names[i] = infos[i].getName(); + } + return names; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.core.filesystem.provider.FileStore#delete(int, + * org.eclipse.core.runtime.IProgressMonitor) + */ + @Override + public void delete(int options, IProgressMonitor monitor) throws CoreException { + SubMonitor subMon = SubMonitor.convert(monitor, 20); + ProxyConnection connection = checkConnection(subMon.newChild(1)); + IFileInfo info = fetchInfo(EFS.NONE, subMon.newChild(9)); + if (!subMon.isCanceled() && info.exists()) { + DeleteCommand command = new DeleteCommand(connection, options, fRemotePath.toString()); + try { + command.getResult(subMon.newChild(10)); + } catch (ProxyException e) { + throw new CoreException(new Status(IStatus.ERROR, Activator.getUniqueIdentifier(), e.getMessage())); + } + } + subMon.setWorkRemaining(0); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.core.filesystem.provider.FileStore#fetchInfo(int, + * org.eclipse.core.runtime.IProgressMonitor) + */ + @Override + public IFileInfo fetchInfo(int options, IProgressMonitor monitor) throws CoreException { + SubMonitor subMon = SubMonitor.convert(monitor, 10); + ProxyConnection connection = checkConnection(subMon.newChild(1)); + FetchInfoCommand command = new FetchInfoCommand(connection, fRemotePath.toString()); + try { + return command.getResult(subMon.newChild(9)); + } catch (ProxyException e) { + throw new CoreException(new Status(IStatus.ERROR, Activator.getUniqueIdentifier(), e.getMessage())); + } + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.core.filesystem.provider.FileStore#getChild(java.lang.String) + */ + @Override + public IFileStore getChild(String name) { + URI uri = ProxyFileSystem.getURIFor(ProxyFileSystem.getConnectionNameFor(fURI), fRemotePath.append(name).toString()); + return getInstance(uri); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.core.filesystem.provider.FileStore#getName() + */ + @Override + public String getName() { + return getNameFromPath(fRemotePath); + } + + /** + * Utility routing to get the file name from an absolute path. + * + * @param path + * path to extract file name from + * @return last segment of path, or the full path if it is root + */ + private String getNameFromPath(IPath path) { + if (path.isRoot()) { + return path.toString(); + } + return path.lastSegment(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.core.filesystem.provider.FileStore#getParent() + */ + @Override + public IFileStore getParent() { + if (fRemotePath.isRoot()) { + return null; + } + String parentPath = fRemotePath.toString(); + if (fRemotePath.segmentCount() > 0) { + parentPath = fRemotePath.removeLastSegments(1).toString(); + } + return getInstance(ProxyFileSystem.getURIFor(ProxyFileSystem.getConnectionNameFor(fURI), parentPath)); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.core.filesystem.provider.FileStore#mkdir(int, + * org.eclipse.core.runtime.IProgressMonitor) + */ + @Override + public IFileStore mkdir(int options, IProgressMonitor monitor) throws CoreException { + SubMonitor subMon = SubMonitor.convert(monitor, 16); + ProxyConnection connection = checkConnection(subMon.newChild(1)); + + if ((options & EFS.SHALLOW) == EFS.SHALLOW) { + IFileStore parent = getParent(); + if (parent != null && !parent.fetchInfo(EFS.NONE, subMon.newChild(5)).exists()) { + throw new CoreException(new Status(IStatus.ERROR, Activator.getUniqueIdentifier(), EFS.ERROR_WRITE, + NLS.bind(Messages.ProxyFileStore_3, fRemotePath.toString()), null)); + } + if (subMon.isCanceled()) { + return this; + } + } + subMon.setWorkRemaining(10); + + try { + MkdirCommand command = new MkdirCommand(connection, options, fRemotePath.toString()); + command.getResult(subMon.newChild(5)); + } catch (Exception e) { + // Ignore any exceptions + } + if (!subMon.isCanceled()) { + /* + * Check if the result exists and is a directory, throw an exception if neither. + */ + IFileInfo info = fetchInfo(EFS.NONE, subMon.newChild(5)); + if (!subMon.isCanceled()) { + if (!info.exists()) { + throw new CoreException(new Status(IStatus.ERROR, Activator.getUniqueIdentifier(), EFS.ERROR_WRITE, + NLS.bind(Messages.ProxyFileStore_4, fRemotePath.toString()), null)); + } + if (!info.isDirectory()) { + throw new CoreException(new Status(IStatus.ERROR, Activator.getUniqueIdentifier(), EFS.ERROR_WRONG_TYPE, + NLS.bind(Messages.ProxyFileStore_5, fRemotePath.toString()), null)); + } + } + } + + return this; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.core.filesystem.provider.FileStore#openInputStream(int, + * org.eclipse.core.runtime.IProgressMonitor) + */ + @Override + public InputStream openInputStream(int options, IProgressMonitor monitor) throws CoreException { + SubMonitor subMon = SubMonitor.convert(monitor, 20); + ProxyConnection connection = checkConnection(subMon.newChild(1)); + IFileInfo info = fetchInfo(EFS.NONE, subMon.newChild(9)); + if (!subMon.isCanceled()) { + if (!info.exists()) { + throw new CoreException(new Status(IStatus.ERROR, Activator.getUniqueIdentifier(), EFS.ERROR_READ, + NLS.bind(Messages.ProxyFileStore_6, fRemotePath.toString()), null)); + } + if (info.isDirectory()) { + throw new CoreException(new Status(IStatus.ERROR, Activator.getUniqueIdentifier(), EFS.ERROR_WRONG_TYPE, + NLS.bind(Messages.ProxyFileStore_7, fRemotePath.toString()), null)); + } + GetInputStreamCommand command = new GetInputStreamCommand(connection, options, fRemotePath.toString()); + try { + return command.getResult(subMon.newChild(10)); + } catch (ProxyException e) { + throw new CoreException(new Status(IStatus.ERROR, Activator.getUniqueIdentifier(), e.getMessage())); + } + } + return null; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.core.filesystem.provider.FileStore#openOutputStream(int, + * org.eclipse.core.runtime.IProgressMonitor) + */ + @Override + public OutputStream openOutputStream(int options, IProgressMonitor monitor) throws CoreException { + SubMonitor subMon = SubMonitor.convert(monitor, 20); + ProxyConnection connection = checkConnection(subMon.newChild(1)); + IFileInfo info = fetchInfo(EFS.NONE, subMon.newChild(9)); + if (!subMon.isCanceled()) { + if (info.isDirectory()) { + throw new CoreException(new Status(IStatus.ERROR, Activator.getUniqueIdentifier(), EFS.ERROR_WRONG_TYPE, + NLS.bind(Messages.ProxyFileStore_7, fRemotePath.toString()), null)); + } + GetOutputStreamCommand command = new GetOutputStreamCommand(connection, options, fRemotePath.toString()); + try { + return command.getResult(subMon.newChild(10)); + } catch (ProxyException e) { + throw new CoreException(new Status(IStatus.ERROR, Activator.getUniqueIdentifier(), e.getMessage())); + } + } + return null; + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.core.filesystem.provider.FileStore#putInfo(org.eclipse.core + * .filesystem.IFileInfo, int, org.eclipse.core.runtime.IProgressMonitor) + */ + @Override + public void putInfo(IFileInfo info, int options, IProgressMonitor monitor) throws CoreException { + SubMonitor subMon = SubMonitor.convert(monitor, 10); + ProxyConnection connection = checkConnection(subMon.newChild(1)); + PutInfoCommand command = new PutInfoCommand(connection, info, options, fRemotePath.toString()); + try { + command.getResult(subMon.newChild(9)); + } catch (ProxyException e) { + throw new CoreException(new Status(IStatus.ERROR, Activator.getUniqueIdentifier(), e.getMessage())); + } + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.core.filesystem.provider.FileStore#toURI() + */ + @Override + public URI toURI() { + return fURI; + } +} diff --git a/bundles/org.eclipse.remote.proxy.core/src/org/eclipse/remote/internal/proxy/core/ProxyFileSystem.java b/bundles/org.eclipse.remote.proxy.core/src/org/eclipse/remote/internal/proxy/core/ProxyFileSystem.java new file mode 100644 index 00000000000..e800594caca --- /dev/null +++ b/bundles/org.eclipse.remote.proxy.core/src/org/eclipse/remote/internal/proxy/core/ProxyFileSystem.java @@ -0,0 +1,112 @@ +/******************************************************************************** + * Copyright (c) 2016 Oak Ridge National Laboratory and others. + * 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 + ********************************************************************************/ + +package org.eclipse.remote.internal.proxy.core; + +import java.net.URI; +import java.net.URISyntaxException; + +import org.eclipse.core.filesystem.EFS; +import org.eclipse.core.filesystem.IFileStore; +import org.eclipse.core.filesystem.provider.FileSystem; +import org.eclipse.core.runtime.IPath; + +public class ProxyFileSystem extends FileSystem { + /** + * Return the connection name encoded in the URI. + * + * @param uri + * URI specifying a remote tools connection + * @return name of the connection or null if the URI is invalid + * @since 4.0 + */ + public static String getConnectionNameFor(URI uri) { + return uri.getAuthority(); + } + + /** + * Return an URI uniquely naming a remote tools remote resource. + * + * @param connectionName + * remote tools connection name + * @param path + * absolute path to resource as valid on the remote system + * @return an URI uniquely naming the remote resource. + */ + public static URI getURIFor(String connectionName, String path) { + try { + return new URI("proxy", connectionName, path, null, null); //$NON-NLS-1$ + } catch (URISyntaxException e) { + throw new RuntimeException(e); + } + } + + /** + * Default constructor. + */ + public ProxyFileSystem() { + super(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.core.filesystem.IFileSystem#attributes() + */ + @Override + public int attributes() { + // Attributes supported by JSch IFileService + return EFS.ATTRIBUTE_READ_ONLY | EFS.ATTRIBUTE_EXECUTABLE | EFS.ATTRIBUTE_SYMLINK | EFS.ATTRIBUTE_LINK_TARGET; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.core.filesystem.provider.FileSystem#canDelete() + */ + @Override + public boolean canDelete() { + return true; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.core.filesystem.provider.FileSystem#canWrite() + */ + @Override + public boolean canWrite() { + return true; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.core.filesystem.provider.FileSystem#getStore(org.eclipse.core.runtime.IPath) + */ + @Override + public IFileStore getStore(IPath path) { + return EFS.getNullFileSystem().getStore(path); + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.core.filesystem.provider.FileSystem#getStore(java.net.URI) + */ + @Override + public IFileStore getStore(URI uri) { + try { + return ProxyFileStore.getInstance(uri); + } catch (Exception e) { + // Could be an URI format exception + Activator.log(e); + return EFS.getNullFileSystem().getStore(uri); + } + } +} \ No newline at end of file diff --git a/bundles/org.eclipse.remote.proxy.core/src/org/eclipse/remote/internal/proxy/core/ProxyProcess.java b/bundles/org.eclipse.remote.proxy.core/src/org/eclipse/remote/internal/proxy/core/ProxyProcess.java new file mode 100644 index 00000000000..95cd5a9de16 --- /dev/null +++ b/bundles/org.eclipse.remote.proxy.core/src/org/eclipse/remote/internal/proxy/core/ProxyProcess.java @@ -0,0 +1,211 @@ +/******************************************************************************* + * Copyright (c) 2016 Oak Ridge National Laboratory 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 + *******************************************************************************/ +package org.eclipse.remote.internal.proxy.core; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.List; + +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.proxy.protocol.core.Protocol; +import org.eclipse.remote.proxy.protocol.core.StreamChannel; + +public class ProxyProcess implements IRemoteProcessControlService, IRemoteProcessTerminalService { + private IRemoteProcess remoteProcess; + + private final StreamChannel stdIOChan; + private final StreamChannel stdErrChan; + private final StreamChannel controlChan; + private final DataOutputStream cmdStream; + private final DataInputStream resultStream; + private final Thread cmdThread; + + private volatile int exitValue; + 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) { + if (ProxyProcess.class.equals(service)) { + return (T) new ProxyProcess(remoteProcess); + } + if (IRemoteProcessControlService.class.equals(service) || IRemoteProcessSignalService.class.equals(service) + || IRemoteProcessTerminalService.class.equals(service)) { + return (T) remoteProcess.getService(ProxyProcess.class); + } + return null; + } + } + + protected ProxyProcess(IRemoteProcess process) { + remoteProcess = process; + ProxyProcessBuilder builder = (ProxyProcessBuilder)process.getProcessBuilder(); + List streams = builder.getStreams(); + controlChan = streams.get(0); + stdIOChan = streams.get(1); + stdErrChan = streams.size() > 2 ? streams.get(2) : null; + cmdStream = new DataOutputStream(controlChan.getOutputStream()); + resultStream = new DataInputStream(controlChan.getInputStream()); + isCompleted = false; + exitValue = 0; + + cmdThread = new Thread("process result reader") { //$NON-NLS-1$ + @Override + public void run() { + try { + exitValue = resultStream.readInt(); + } catch (IOException e) { + // Finish + } + isCompleted = true; + try { + stdIOChan.close(); + } catch (IOException e1) { + // Ignore + } + try { + if (stdErrChan != null) { + stdErrChan.close(); + } + } catch (IOException e1) { + // Ignore + } + try { + controlChan.close(); + } catch (IOException e) { + // Ignore + } + } + }; + cmdThread.start(); + } + + /* + * (non-Javadoc) + * + * @see java.lang.Process#destroy() + */ + @Override + public void destroy() { + try { + cmdStream.writeByte(Protocol.CONTROL_KILL); + cmdStream.flush(); + } catch (IOException e) { + isCompleted = true; + } + } + + /* + * (non-Javadoc) + * + * @see java.lang.Process#exitValue() + */ + @Override + public int exitValue() { + if (!isCompleted) { + throw new IllegalThreadStateException(); + } + return exitValue; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Process#getErrorStream() + */ + @Override + public InputStream getErrorStream() { + if (stdErrChan == null) { + return new InputStream() { + @Override + public int read() throws IOException { + return -1; + } + + @Override + public int available() { + return 0; + } + }; + } + return stdErrChan.getInputStream(); + } + + /* + * (non-Javadoc) + * + * @see java.lang.Process#getInputStream() + */ + @Override + public InputStream getInputStream() { + return stdIOChan.getInputStream(); + } + + /* + * (non-Javadoc) + * + * @see java.lang.Process#getOutputStream() + */ + @Override + public OutputStream getOutputStream() { + return stdIOChan.getOutputStream(); + } + + /* + * (non-Javadoc) + * + * @see java.lang.Process#waitFor() + */ + @Override + public int waitFor() throws InterruptedException { + cmdThread.join(); + return exitValue; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.remote.core.RemoteProcess#isCompleted() + */ + @Override + public boolean isCompleted() { + return isCompleted; + } + + @Override + public IRemoteProcess getRemoteProcess() { + return remoteProcess; + } + + @Override + public void setTerminalSize(int cols, int rows, int pwidth, int pheight) { + try { + cmdStream.writeByte(Protocol.CONTROL_SETTERMINALSIZE); + cmdStream.writeInt(cols); + cmdStream.writeInt(rows); + cmdStream.writeInt(pwidth); + cmdStream.writeInt(pheight); + cmdStream.flush(); + } catch (IOException e) { + // Dealt with somewhere else hopefully + } + } +} diff --git a/bundles/org.eclipse.remote.proxy.core/src/org/eclipse/remote/internal/proxy/core/ProxyProcessBuilder.java b/bundles/org.eclipse.remote.proxy.core/src/org/eclipse/remote/internal/proxy/core/ProxyProcessBuilder.java new file mode 100644 index 00000000000..024119405a7 --- /dev/null +++ b/bundles/org.eclipse.remote.proxy.core/src/org/eclipse/remote/internal/proxy/core/ProxyProcessBuilder.java @@ -0,0 +1,169 @@ +/******************************************************************************* + * Copyright (c) 2016 Oak Ridge National Laboratory 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 + *******************************************************************************/ +package org.eclipse.remote.internal.proxy.core; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.remote.core.AbstractRemoteProcessBuilder; +import org.eclipse.remote.core.IRemoteFileService; +import org.eclipse.remote.core.IRemoteProcess; +import org.eclipse.remote.core.IRemoteProcessBuilder; +import org.eclipse.remote.internal.proxy.core.commands.ExecCommand; +import org.eclipse.remote.internal.proxy.core.commands.ShellCommand; +import org.eclipse.remote.internal.proxy.core.messages.Messages; +import org.eclipse.remote.proxy.protocol.core.StreamChannel; +import org.eclipse.remote.proxy.protocol.core.exceptions.ProxyException; + +public class ProxyProcessBuilder extends AbstractRemoteProcessBuilder { + private final ProxyConnection proxyConnection; + private Map remoteEnv; + private List streams = new ArrayList<>(); + + public ProxyProcessBuilder(ProxyConnection connection, List command) { + super(connection.getRemoteConnection(), command); + proxyConnection = connection; + IRemoteFileService fileSvc = proxyConnection.getRemoteConnection().getService(IRemoteFileService.class); + if (fileSvc != null) { + directory(fileSvc.getResource(proxyConnection.getWorkingDirectory())); + } + } + + public ProxyProcessBuilder(ProxyConnection connection, String... command) { + this(connection, Arrays.asList(command)); + } + + /** + * Constructor for creating command shell + * @param connection + */ + public ProxyProcessBuilder(ProxyConnection connection) { + super(connection.getRemoteConnection(), (List)null); + proxyConnection = connection; + redirectErrorStream(true); + } + + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.remote.core.AbstractRemoteProcessBuilder#environment() + */ + @Override + public Map environment() { + if (remoteEnv == null) { + remoteEnv = new HashMap(proxyConnection.getEnv()); + } + return remoteEnv; + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.remote.core.AbstractRemoteProcessBuilder#getSupportedFlags + * () + */ + @Override + public int getSupportedFlags() { + return NONE; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.remote.core.IRemoteProcessBuilder#start(int) + */ + @Override + public IRemoteProcess start(int flags) throws IOException { + final ProxyConnection conn = getRemoteConnection().getService(ProxyConnection.class); + if (conn == null) { + throw new IOException(Messages.ProxyProcessBuilder_0); + } + + Job job; + + final List cmdArgs = command(); + if (cmdArgs != null) { + if (cmdArgs.size() < 1) { + throw new IOException(Messages.ProxyProcessBuilder_1); + } + /* + * If environment has not been touched, then don't send anything + */ + final Map env = new HashMap(); + if (remoteEnv != null) { + env.putAll(remoteEnv); + } + + final boolean append = (flags & IRemoteProcessBuilder.APPEND_ENVIRONMENT) != 0 || remoteEnv == null; + + streams.add(conn.openChannel()); + streams.add(conn.openChannel()); + streams.add(conn.openChannel()); + + job = new Job("process executor") { //$NON-NLS-1$ + @Override + protected IStatus run(IProgressMonitor monitor) { + ExecCommand cmd = new ExecCommand(conn, cmdArgs, env, directory().toURI().getPath(), redirectErrorStream(), append, + streams.get(0).getId(), streams.get(1).getId(), streams.get(2).getId()); + try { + cmd.getResult(monitor); + } catch (ProxyException e) { + return new Status(IStatus.ERROR, Activator.getUniqueIdentifier(), e.getMessage()); + } + return monitor.isCanceled() ? Status.CANCEL_STATUS : Status.OK_STATUS; + } + }; + } else { + /* + * Start command shell + */ + streams.add(conn.openChannel()); + streams.add(conn.openChannel()); + + job = new Job("process executor") { //$NON-NLS-1$ + @Override + protected IStatus run(IProgressMonitor monitor) { + ShellCommand cmd = new ShellCommand(conn, streams.get(0).getId(), streams.get(1).getId()); + try { + cmd.getResult(monitor); + } catch (ProxyException e) { + return new Status(IStatus.ERROR, Activator.getUniqueIdentifier(), e.getMessage()); + } + return monitor.isCanceled() ? Status.CANCEL_STATUS : Status.OK_STATUS; + } + }; + } + + job.schedule(); + try { + job.join(); + } catch (InterruptedException e) { + throw new IOException(e.getMessage()); + } + if (!job.getResult().isOK()) { + throw new IOException(job.getResult().getMessage()); + } + + return newRemoteProcess(); + } + + public List getStreams() { + return streams; + } +} diff --git a/bundles/org.eclipse.remote.proxy.core/src/org/eclipse/remote/internal/proxy/core/commands/AbstractCommand.java b/bundles/org.eclipse.remote.proxy.core/src/org/eclipse/remote/internal/proxy/core/commands/AbstractCommand.java new file mode 100644 index 00000000000..dec2d98c77c --- /dev/null +++ b/bundles/org.eclipse.remote.proxy.core/src/org/eclipse/remote/internal/proxy/core/commands/AbstractCommand.java @@ -0,0 +1,84 @@ +/******************************************************************************* + * Copyright (c) 2016 Oak Ridge National Laboratory 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 + *******************************************************************************/ +package org.eclipse.remote.internal.proxy.core.commands; + +import java.io.IOException; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.SubMonitor; +import org.eclipse.remote.internal.proxy.core.ProxyConnection; +import org.eclipse.remote.internal.proxy.core.messages.Messages; +import org.eclipse.remote.proxy.protocol.core.StreamChannel; +import org.eclipse.remote.proxy.protocol.core.exceptions.ProxyException; + +public abstract class AbstractCommand implements Callable { + private IProgressMonitor progressMonitor; + + private static ExecutorService executors = Executors.newSingleThreadExecutor(); + + private final ProxyConnection connection; + + private Future asyncCmdInThread() throws ProxyException { + return executors.submit(this); + } + + public StreamChannel openChannel() throws IOException { + return connection.openChannel(); + } + + public IProgressMonitor getProgressMonitor() { + return progressMonitor; + } + + /** + * Function opens exec channel and then executes the exec operation. If + * run on the main thread it executes it on a separate thread + */ + public T getResult(IProgressMonitor monitor) throws ProxyException { + Future future = null; + progressMonitor = SubMonitor.convert(monitor, 10); + future = asyncCmdInThread(); + return waitCmdInThread(future); + } + + private T waitCmdInThread(Future future) throws ProxyException { + boolean bInterrupted = Thread.interrupted(); + while (!getProgressMonitor().isCanceled()) { + try { + return future.get(100, TimeUnit.MILLISECONDS); + } catch (InterruptedException e) { + bInterrupted = true; + } catch (TimeoutException e) { + // ignore + } catch (ExecutionException e) { + throw new ProxyException(e.getMessage()); + } + getProgressMonitor().worked(1); + } + if (bInterrupted) { + Thread.currentThread().interrupt(); // set current thread flag + } + future.cancel(true); + throw new ProxyException(Messages.AbstractCommand_0); + } + + @Override + public abstract T call() throws ProxyException; + + public AbstractCommand(ProxyConnection conn) { + this.connection = conn; + } +} + diff --git a/bundles/org.eclipse.remote.proxy.core/src/org/eclipse/remote/internal/proxy/core/commands/ChildInfosCommand.java b/bundles/org.eclipse.remote.proxy.core/src/org/eclipse/remote/internal/proxy/core/commands/ChildInfosCommand.java new file mode 100644 index 00000000000..3e6af47c3f0 --- /dev/null +++ b/bundles/org.eclipse.remote.proxy.core/src/org/eclipse/remote/internal/proxy/core/commands/ChildInfosCommand.java @@ -0,0 +1,64 @@ +/******************************************************************************* + * Copyright (c) 2016 Oak Ridge National Laboratory 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 + *******************************************************************************/ +package org.eclipse.remote.internal.proxy.core.commands; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.eclipse.core.filesystem.IFileInfo; +import org.eclipse.remote.internal.proxy.core.ProxyConnection; +import org.eclipse.remote.proxy.protocol.core.Protocol; +import org.eclipse.remote.proxy.protocol.core.SerializableFileInfo; +import org.eclipse.remote.proxy.protocol.core.StreamChannel; +import org.eclipse.remote.proxy.protocol.core.exceptions.ProxyException; + +public class ChildInfosCommand extends AbstractCommand { + + private final DataOutputStream out; + private final DataInputStream in; + private final String path; + + public ChildInfosCommand(ProxyConnection conn, String path) { + super(conn); + this.out = new DataOutputStream(conn.getCommandChannel().getOutputStream()); + this.in = new DataInputStream(conn.getCommandChannel().getInputStream()); + this.path = path; + } + + public IFileInfo[] call() throws ProxyException { + try { + final StreamChannel chan = openChannel(); + + out.writeByte(Protocol.PROTO_COMMAND); + out.writeShort(Protocol.CMD_CHILDINFOS); + out.writeByte(chan.getId()); + out.writeUTF(path); + out.flush(); + + byte res = in.readByte(); + if (res != Protocol.PROTO_OK) { + String errMsg = in.readUTF(); + throw new ProxyException(errMsg); + } + + DataInputStream resultStream = new DataInputStream(chan.getInputStream()); + int length = resultStream.readInt(); + SerializableFileInfo sInfo = new SerializableFileInfo(); + IFileInfo[] infos = new IFileInfo[length]; + for (int i = 0; i < length; i++) { + sInfo.readObject(resultStream); + infos[i] = sInfo.getIFileInfo(); + } + chan.close(); + return infos; + } catch (IOException e) { + throw new ProxyException(e.getMessage()); + } + } +} diff --git a/bundles/org.eclipse.remote.proxy.core/src/org/eclipse/remote/internal/proxy/core/commands/DeleteCommand.java b/bundles/org.eclipse.remote.proxy.core/src/org/eclipse/remote/internal/proxy/core/commands/DeleteCommand.java new file mode 100644 index 00000000000..bd7463c8f16 --- /dev/null +++ b/bundles/org.eclipse.remote.proxy.core/src/org/eclipse/remote/internal/proxy/core/commands/DeleteCommand.java @@ -0,0 +1,51 @@ +/******************************************************************************* + * Copyright (c) 2016 Oak Ridge National Laboratory 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 + *******************************************************************************/ +package org.eclipse.remote.internal.proxy.core.commands; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.eclipse.remote.internal.proxy.core.ProxyConnection; +import org.eclipse.remote.proxy.protocol.core.Protocol; +import org.eclipse.remote.proxy.protocol.core.exceptions.ProxyException; + +public class DeleteCommand extends AbstractCommand { + + private final DataOutputStream out; + private final DataInputStream in; + private final int options; + private final String path; + + public DeleteCommand(ProxyConnection conn, int options, String path) { + super(conn); + this.out = new DataOutputStream(conn.getCommandChannel().getOutputStream()); + this.in = new DataInputStream(conn.getCommandChannel().getInputStream()); + this.options = options; + this.path = path; + } + + public Void call() throws ProxyException { + try { + out.writeByte(Protocol.PROTO_COMMAND); + out.writeShort(Protocol.CMD_DELETE); + out.writeInt(options); + out.writeUTF(path); + out.flush(); + + byte res = in.readByte(); + if (res != Protocol.PROTO_OK) { + String errMsg = in.readUTF(); + throw new ProxyException(errMsg); + } + return null; + } catch (IOException e) { + throw new ProxyException(e.getMessage()); + } + } +} diff --git a/bundles/org.eclipse.remote.proxy.core/src/org/eclipse/remote/internal/proxy/core/commands/ExecCommand.java b/bundles/org.eclipse.remote.proxy.core/src/org/eclipse/remote/internal/proxy/core/commands/ExecCommand.java new file mode 100644 index 00000000000..c03decd2e73 --- /dev/null +++ b/bundles/org.eclipse.remote.proxy.core/src/org/eclipse/remote/internal/proxy/core/commands/ExecCommand.java @@ -0,0 +1,79 @@ +/******************************************************************************* + * Copyright (c) 2016 Oak Ridge National Laboratory 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 + *******************************************************************************/ +package org.eclipse.remote.internal.proxy.core.commands; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.List; +import java.util.Map; + +import org.eclipse.remote.internal.proxy.core.ProxyConnection; +import org.eclipse.remote.proxy.protocol.core.Protocol; +import org.eclipse.remote.proxy.protocol.core.exceptions.ProxyException; + +public class ExecCommand extends AbstractCommand { + + private final DataOutputStream out; + private final DataInputStream in; + private final List command; + private final Map env; + private final String directory; + private final boolean appendEnv; + private final boolean redirect; + private final int cmdChan; + private final int ioChan; + private final int errChan; + + public ExecCommand(ProxyConnection conn, List command, Map env, String directory, boolean redirect, boolean appendEnv, + int cmdChan, int ioChan, int errChan) { + super(conn); + this.out = new DataOutputStream(conn.getCommandChannel().getOutputStream()); + this.in = new DataInputStream(conn.getCommandChannel().getInputStream()); + this.command = command; + this.env = env; + this.directory = directory; + this.redirect = redirect; + this.appendEnv = appendEnv; + this.cmdChan = cmdChan; + this.ioChan = ioChan; + this.errChan = errChan; + } + + public Void call() throws ProxyException { + try { + out.writeByte(Protocol.PROTO_COMMAND); + out.writeShort(Protocol.CMD_EXEC); + out.writeByte(cmdChan); + out.writeByte(ioChan); + out.writeByte(errChan); + out.writeInt(command.size()); + for (String arg : command) { + out.writeUTF(arg); + } + out.writeInt(env.size()); + for (Map.Entry entry : env.entrySet()) { + out.writeUTF(entry.getKey()); + out.writeUTF(entry.getValue()); + } + out.writeUTF(directory); + out.writeBoolean(redirect); + out.writeBoolean(appendEnv); + out.flush(); + + byte res = in.readByte(); + if (res != Protocol.PROTO_OK) { + String errMsg = in.readUTF(); + throw new ProxyException(errMsg); + } + } catch (IOException e) { + throw new ProxyException(e.getMessage()); + } + return null; + } +} diff --git a/bundles/org.eclipse.remote.proxy.core/src/org/eclipse/remote/internal/proxy/core/commands/FetchInfoCommand.java b/bundles/org.eclipse.remote.proxy.core/src/org/eclipse/remote/internal/proxy/core/commands/FetchInfoCommand.java new file mode 100644 index 00000000000..06163711351 --- /dev/null +++ b/bundles/org.eclipse.remote.proxy.core/src/org/eclipse/remote/internal/proxy/core/commands/FetchInfoCommand.java @@ -0,0 +1,59 @@ +/******************************************************************************* + * Copyright (c) 2016 Oak Ridge National Laboratory 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 + *******************************************************************************/ +package org.eclipse.remote.internal.proxy.core.commands; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.eclipse.core.filesystem.IFileInfo; +import org.eclipse.remote.internal.proxy.core.ProxyConnection; +import org.eclipse.remote.proxy.protocol.core.Protocol; +import org.eclipse.remote.proxy.protocol.core.SerializableFileInfo; +import org.eclipse.remote.proxy.protocol.core.StreamChannel; +import org.eclipse.remote.proxy.protocol.core.exceptions.ProxyException; + +public class FetchInfoCommand extends AbstractCommand { + + private final DataOutputStream out; + private final DataInputStream in; + private final String path; + + public FetchInfoCommand(ProxyConnection conn, String path) { + super(conn); + this.out = new DataOutputStream(conn.getCommandChannel().getOutputStream()); + this.in = new DataInputStream(conn.getCommandChannel().getInputStream()); + this.path = path; + } + + public IFileInfo call() throws ProxyException { + try { + final StreamChannel chan = openChannel(); + + out.writeByte(Protocol.PROTO_COMMAND); + out.writeShort(Protocol.CMD_FETCHINFO); + out.writeByte(chan.getId()); + out.writeUTF(path); + out.flush(); + + byte res = in.readByte(); + if (res != Protocol.PROTO_OK) { + String errMsg = in.readUTF(); + throw new ProxyException(errMsg); + } + + DataInputStream resultStream = new DataInputStream(chan.getInputStream()); + SerializableFileInfo info = new SerializableFileInfo(); + info.readObject(resultStream); + chan.close(); + return info.getIFileInfo(); + } catch (IOException e) { + throw new ProxyException(e.getMessage()); + } + } +} diff --git a/bundles/org.eclipse.remote.proxy.core/src/org/eclipse/remote/internal/proxy/core/commands/GetCwdCommand.java b/bundles/org.eclipse.remote.proxy.core/src/org/eclipse/remote/internal/proxy/core/commands/GetCwdCommand.java new file mode 100644 index 00000000000..99a373cae13 --- /dev/null +++ b/bundles/org.eclipse.remote.proxy.core/src/org/eclipse/remote/internal/proxy/core/commands/GetCwdCommand.java @@ -0,0 +1,53 @@ +/******************************************************************************* + * Copyright (c) 2016 Oak Ridge National Laboratory 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 + *******************************************************************************/ +package org.eclipse.remote.internal.proxy.core.commands; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.eclipse.remote.internal.proxy.core.ProxyConnection; +import org.eclipse.remote.proxy.protocol.core.Protocol; +import org.eclipse.remote.proxy.protocol.core.StreamChannel; +import org.eclipse.remote.proxy.protocol.core.exceptions.ProxyException; + +public class GetCwdCommand extends AbstractCommand { + + private final DataOutputStream out; + private final DataInputStream in; + + public GetCwdCommand(ProxyConnection conn) { + super(conn); + this.out = new DataOutputStream(conn.getCommandChannel().getOutputStream()); + this.in = new DataInputStream(conn.getCommandChannel().getInputStream()); + } + + public String call() throws ProxyException { + try { + final StreamChannel chan = openChannel(); + DataInputStream resultStream = new DataInputStream(chan.getInputStream()); + + out.writeByte(Protocol.PROTO_COMMAND); + out.writeShort(Protocol.CMD_GETCWD); + out.writeByte(chan.getId()); + out.flush(); + + byte res = in.readByte(); + if (res != Protocol.PROTO_OK) { + String errMsg = in.readUTF(); + throw new ProxyException(errMsg); + } + + String cwd = resultStream.readUTF(); + chan.close(); + return cwd; + } catch (IOException e) { + throw new ProxyException(e.getMessage()); + } + } +} diff --git a/bundles/org.eclipse.remote.proxy.core/src/org/eclipse/remote/internal/proxy/core/commands/GetEnvCommand.java b/bundles/org.eclipse.remote.proxy.core/src/org/eclipse/remote/internal/proxy/core/commands/GetEnvCommand.java new file mode 100644 index 00000000000..773f39f3f42 --- /dev/null +++ b/bundles/org.eclipse.remote.proxy.core/src/org/eclipse/remote/internal/proxy/core/commands/GetEnvCommand.java @@ -0,0 +1,61 @@ +/******************************************************************************* + * Copyright (c) 2016 Oak Ridge National Laboratory 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 + *******************************************************************************/ +package org.eclipse.remote.internal.proxy.core.commands; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.remote.internal.proxy.core.ProxyConnection; +import org.eclipse.remote.proxy.protocol.core.Protocol; +import org.eclipse.remote.proxy.protocol.core.StreamChannel; +import org.eclipse.remote.proxy.protocol.core.exceptions.ProxyException; + +public class GetEnvCommand extends AbstractCommand> { + + private final DataOutputStream out; + private final DataInputStream in; + + public GetEnvCommand(ProxyConnection conn) { + super(conn); + this.out = new DataOutputStream(conn.getCommandChannel().getOutputStream()); + this.in = new DataInputStream(conn.getCommandChannel().getInputStream()); + } + + public Map call() throws ProxyException { + try { + final StreamChannel chan = openChannel(); + DataInputStream resultStream = new DataInputStream(chan.getInputStream()); + + out.writeByte(Protocol.PROTO_COMMAND); + out.writeShort(Protocol.CMD_GETENV); + out.writeByte(chan.getId()); + out.flush(); + + byte res = in.readByte(); + if (res != Protocol.PROTO_OK) { + String errMsg = in.readUTF(); + throw new ProxyException(errMsg); + } + + int len = resultStream.readInt(); + Map env = new HashMap(len); + for (int i = 0; i < len; i++) { + String key = resultStream.readUTF(); + String value = resultStream.readUTF(); + env.put(key, value); + } + chan.close(); + return env; + } catch (IOException e) { + throw new ProxyException(e.getMessage()); + } + } +} diff --git a/bundles/org.eclipse.remote.proxy.core/src/org/eclipse/remote/internal/proxy/core/commands/GetInputStreamCommand.java b/bundles/org.eclipse.remote.proxy.core/src/org/eclipse/remote/internal/proxy/core/commands/GetInputStreamCommand.java new file mode 100644 index 00000000000..b93b695b729 --- /dev/null +++ b/bundles/org.eclipse.remote.proxy.core/src/org/eclipse/remote/internal/proxy/core/commands/GetInputStreamCommand.java @@ -0,0 +1,58 @@ +/******************************************************************************* + * Copyright (c) 2016 Oak Ridge National Laboratory 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 + *******************************************************************************/ +package org.eclipse.remote.internal.proxy.core.commands; + +import java.io.BufferedInputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.InputStream; + +import org.eclipse.remote.internal.proxy.core.ProxyConnection; +import org.eclipse.remote.proxy.protocol.core.Protocol; +import org.eclipse.remote.proxy.protocol.core.StreamChannel; +import org.eclipse.remote.proxy.protocol.core.exceptions.ProxyException; + +public class GetInputStreamCommand extends AbstractCommand { + + private final DataOutputStream out; + private final DataInputStream in; + private final int options; + private final String path; + + public GetInputStreamCommand(ProxyConnection conn, int options, String path) { + super(conn); + this.out = new DataOutputStream(conn.getCommandChannel().getOutputStream()); + this.in = new DataInputStream(conn.getCommandChannel().getInputStream()); + this.options = options; + this.path = path; + } + + public InputStream call() throws ProxyException { + try { + StreamChannel chan = openChannel(); + + out.writeByte(Protocol.PROTO_COMMAND); + out.writeShort(Protocol.CMD_GETINPUTSTREAM); + out.writeByte(chan.getId()); + out.writeInt(options); + out.writeUTF(path); + out.flush(); + + byte res = in.readByte(); + if (res != Protocol.PROTO_OK) { + String errMsg = in.readUTF(); + throw new ProxyException(errMsg); + } + + return new BufferedInputStream(chan.getInputStream()); + } catch (IOException e) { + throw new ProxyException(e.getMessage()); + } + } +} diff --git a/bundles/org.eclipse.remote.proxy.core/src/org/eclipse/remote/internal/proxy/core/commands/GetOutputStreamCommand.java b/bundles/org.eclipse.remote.proxy.core/src/org/eclipse/remote/internal/proxy/core/commands/GetOutputStreamCommand.java new file mode 100644 index 00000000000..c1fc27719bd --- /dev/null +++ b/bundles/org.eclipse.remote.proxy.core/src/org/eclipse/remote/internal/proxy/core/commands/GetOutputStreamCommand.java @@ -0,0 +1,58 @@ +/******************************************************************************* + * Copyright (c) 2016 Oak Ridge National Laboratory 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 + *******************************************************************************/ +package org.eclipse.remote.internal.proxy.core.commands; + +import java.io.BufferedOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +import org.eclipse.remote.internal.proxy.core.ProxyConnection; +import org.eclipse.remote.proxy.protocol.core.Protocol; +import org.eclipse.remote.proxy.protocol.core.StreamChannel; +import org.eclipse.remote.proxy.protocol.core.exceptions.ProxyException; + +public class GetOutputStreamCommand extends AbstractCommand { + + private final DataOutputStream out; + private final DataInputStream in; + private final int options; + private final String path; + + public GetOutputStreamCommand(ProxyConnection conn, int options, String path) { + super(conn); + this.out = new DataOutputStream(conn.getCommandChannel().getOutputStream()); + this.in = new DataInputStream(conn.getCommandChannel().getInputStream()); + this.options = options; + this.path = path; + } + + public OutputStream call() throws ProxyException { + try { + StreamChannel chan = openChannel(); + + out.writeByte(Protocol.PROTO_COMMAND); + out.writeShort(Protocol.CMD_GETOUTPUTSTREAM); + out.writeByte(chan.getId()); + out.writeInt(options); + out.writeUTF(path); + out.flush(); + + byte res = in.readByte(); + if (res != Protocol.PROTO_OK) { + String errMsg = in.readUTF(); + throw new ProxyException(errMsg); + } + + return new BufferedOutputStream(chan.getOutputStream()); + } catch (IOException e) { + throw new ProxyException(e.getMessage()); + } + } +} diff --git a/bundles/org.eclipse.remote.proxy.core/src/org/eclipse/remote/internal/proxy/core/commands/GetPropertiesCommand.java b/bundles/org.eclipse.remote.proxy.core/src/org/eclipse/remote/internal/proxy/core/commands/GetPropertiesCommand.java new file mode 100644 index 00000000000..ad77868ad45 --- /dev/null +++ b/bundles/org.eclipse.remote.proxy.core/src/org/eclipse/remote/internal/proxy/core/commands/GetPropertiesCommand.java @@ -0,0 +1,61 @@ +/******************************************************************************* + * Copyright (c) 2016 Oak Ridge National Laboratory 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 + *******************************************************************************/ +package org.eclipse.remote.internal.proxy.core.commands; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.remote.internal.proxy.core.ProxyConnection; +import org.eclipse.remote.proxy.protocol.core.Protocol; +import org.eclipse.remote.proxy.protocol.core.StreamChannel; +import org.eclipse.remote.proxy.protocol.core.exceptions.ProxyException; + +public class GetPropertiesCommand extends AbstractCommand> { + + private final DataOutputStream out; + private final DataInputStream in; + + public GetPropertiesCommand(ProxyConnection conn) { + super(conn); + this.out = new DataOutputStream(conn.getCommandChannel().getOutputStream()); + this.in = new DataInputStream(conn.getCommandChannel().getInputStream()); + } + + public Map call() throws ProxyException { + try { + final StreamChannel chan = openChannel(); + DataInputStream resultStream = new DataInputStream(chan.getInputStream()); + + out.writeByte(Protocol.PROTO_COMMAND); + out.writeShort(Protocol.CMD_GETPROPERTIES); + out.writeByte(chan.getId()); + out.flush(); + + byte res = in.readByte(); + if (res != Protocol.PROTO_OK) { + String errMsg = in.readUTF(); + throw new ProxyException(errMsg); + } + + int len = resultStream.readInt(); + Map props = new HashMap(len); + for (int i = 0; i < len; i++) { + String key = resultStream.readUTF(); + String value = resultStream.readUTF(); + props.put(key, value); + } + chan.close(); + return props; + } catch (IOException e) { + throw new ProxyException(e.getMessage()); + } + } +} diff --git a/bundles/org.eclipse.remote.proxy.core/src/org/eclipse/remote/internal/proxy/core/commands/MkdirCommand.java b/bundles/org.eclipse.remote.proxy.core/src/org/eclipse/remote/internal/proxy/core/commands/MkdirCommand.java new file mode 100644 index 00000000000..eebb748f543 --- /dev/null +++ b/bundles/org.eclipse.remote.proxy.core/src/org/eclipse/remote/internal/proxy/core/commands/MkdirCommand.java @@ -0,0 +1,51 @@ +/******************************************************************************* + * Copyright (c) 2016 Oak Ridge National Laboratory 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 + *******************************************************************************/ +package org.eclipse.remote.internal.proxy.core.commands; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.eclipse.remote.internal.proxy.core.ProxyConnection; +import org.eclipse.remote.proxy.protocol.core.Protocol; +import org.eclipse.remote.proxy.protocol.core.exceptions.ProxyException; + +public class MkdirCommand extends AbstractCommand { + + private final DataOutputStream out; + private final DataInputStream in; + private final int options; + private final String path; + + public MkdirCommand(ProxyConnection conn, int options, String path) { + super(conn); + this.out = new DataOutputStream(conn.getCommandChannel().getOutputStream()); + this.in = new DataInputStream(conn.getCommandChannel().getInputStream()); + this.options = options; + this.path = path; + } + + public Void call() throws ProxyException { + try { + out.writeByte(Protocol.PROTO_COMMAND); + out.writeShort(Protocol.CMD_MKDIR); + out.writeInt(options); + out.writeUTF(path); + out.flush(); + + byte res = in.readByte(); + if (res != Protocol.PROTO_OK) { + String errMsg = in.readUTF(); + throw new ProxyException(errMsg); + } + return null; + } catch (IOException e) { + throw new ProxyException(e.getMessage()); + } + } +} diff --git a/bundles/org.eclipse.remote.proxy.core/src/org/eclipse/remote/internal/proxy/core/commands/PutInfoCommand.java b/bundles/org.eclipse.remote.proxy.core/src/org/eclipse/remote/internal/proxy/core/commands/PutInfoCommand.java new file mode 100644 index 00000000000..d4a61492c08 --- /dev/null +++ b/bundles/org.eclipse.remote.proxy.core/src/org/eclipse/remote/internal/proxy/core/commands/PutInfoCommand.java @@ -0,0 +1,57 @@ +/******************************************************************************* + * Copyright (c) 2016 Oak Ridge National Laboratory 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 + *******************************************************************************/ +package org.eclipse.remote.internal.proxy.core.commands; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.eclipse.core.filesystem.IFileInfo; +import org.eclipse.remote.internal.proxy.core.ProxyConnection; +import org.eclipse.remote.proxy.protocol.core.Protocol; +import org.eclipse.remote.proxy.protocol.core.SerializableFileInfo; +import org.eclipse.remote.proxy.protocol.core.exceptions.ProxyException; + +public class PutInfoCommand extends AbstractCommand { + + private final DataOutputStream out; + private final DataInputStream in; + private final IFileInfo info; + private final int options; + private final String path; + + public PutInfoCommand(ProxyConnection conn, IFileInfo info, int options, String path) { + super(conn); + this.out = new DataOutputStream(conn.getCommandChannel().getOutputStream()); + this.in = new DataInputStream(conn.getCommandChannel().getInputStream()); + this.info = info; + this.options = options; + this.path = path; + } + + public Void call() throws ProxyException { + try { + out.writeByte(Protocol.PROTO_COMMAND); + out.writeShort(Protocol.CMD_PUTINFO); + out.writeInt(options); + out.writeUTF(path); + SerializableFileInfo sInfo = new SerializableFileInfo(info); + sInfo.writeObject(out); + out.flush(); + + byte res = in.readByte(); + if (res != Protocol.PROTO_OK) { + String errMsg = in.readUTF(); + throw new ProxyException(errMsg); + } + return null; + } catch (IOException e) { + throw new ProxyException(e.getMessage()); + } + } +} diff --git a/bundles/org.eclipse.remote.proxy.core/src/org/eclipse/remote/internal/proxy/core/commands/ShellCommand.java b/bundles/org.eclipse.remote.proxy.core/src/org/eclipse/remote/internal/proxy/core/commands/ShellCommand.java new file mode 100644 index 00000000000..66a10884142 --- /dev/null +++ b/bundles/org.eclipse.remote.proxy.core/src/org/eclipse/remote/internal/proxy/core/commands/ShellCommand.java @@ -0,0 +1,51 @@ +/******************************************************************************* + * Copyright (c) 2016 Oak Ridge National Laboratory 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 + *******************************************************************************/ +package org.eclipse.remote.internal.proxy.core.commands; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.eclipse.remote.internal.proxy.core.ProxyConnection; +import org.eclipse.remote.proxy.protocol.core.Protocol; +import org.eclipse.remote.proxy.protocol.core.exceptions.ProxyException; + +public class ShellCommand extends AbstractCommand { + + private final DataOutputStream out; + private final DataInputStream in; + private final int cmdChan; + private final int ioChan; + + public ShellCommand(ProxyConnection conn, int cmdChan, int ioChan) { + super(conn); + this.out = new DataOutputStream(conn.getCommandChannel().getOutputStream()); + this.in = new DataInputStream(conn.getCommandChannel().getInputStream()); + this.cmdChan = cmdChan; + this.ioChan = ioChan; + } + + public Void call() throws ProxyException { + try { + out.writeByte(Protocol.PROTO_COMMAND); + out.writeShort(Protocol.CMD_SHELL); + out.writeByte(cmdChan); + out.writeByte(ioChan); + out.flush(); + + byte res = in.readByte(); + if (res != Protocol.PROTO_OK) { + String errMsg = in.readUTF(); + throw new ProxyException(errMsg); + } + } catch (IOException e) { + throw new ProxyException(e.getMessage()); + } + return null; + } +} diff --git a/bundles/org.eclipse.remote.proxy.core/src/org/eclipse/remote/internal/proxy/core/messages/Messages.java b/bundles/org.eclipse.remote.proxy.core/src/org/eclipse/remote/internal/proxy/core/messages/Messages.java new file mode 100755 index 00000000000..6d7c896a54f --- /dev/null +++ b/bundles/org.eclipse.remote.proxy.core/src/org/eclipse/remote/internal/proxy/core/messages/Messages.java @@ -0,0 +1,115 @@ +/** + * Copyright (c) 2013 IBM Corporation. + * 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 Implementation + * + */ +package org.eclipse.remote.internal.proxy.core.messages; + +import org.eclipse.osgi.util.NLS; + +public class Messages extends NLS { + private static final String BUNDLE_ID = "org.eclipse.remote.internal.proxy.core.messages.messages"; //$NON-NLS-1$ + + public static String AbstractCommand_0; + + public static String AbstractRemoteCommand_format1; + public static String AbstractRemoteCommand_format2; + public static String AbstractRemoteCommand_Get_symlink_target; + public static String AbstractRemoteCommand_Operation_cancelled_by_user; + public static String AuthInfo_Authentication_message; + public static String ExecCommand_Exec_command; + + public static String GetInputStreamCommand_Receiving; + + public static String GetOutputStreamCommand_Sending; + public static String JSchConnection_0; + + public static String JSchConnection_Connection_was_cancelled; + public static String JSchConnection_connectionNotOpen; + public static String JSchConnection_Executing_command; + public static String JSchConnection_remote_address_must_be_set; + public static String JSchConnection_remotePort; + public static String JSchConnection_forwarding; + public static String JSchConnection_Remote_host_does_not_support_sftp; + public static String JSchConnection_Unable_to_open_sftp_channel; + public static String JSchConnection_username_must_be_set; + public static String JSchConnectionManager_connection_with_name_exists; + public static String JSchConnectionManager_cannotRemoveOpenConnection; + public static String JSchConnectionManager_invalidConnectionType; + public static String JSchConnectionProxyFactory_failed; + public static String JSchConnectionProxyFactory_ProxyCommandFailed; + public static String JSchConnectionProxyFactory_timedOut; + public static String JSchConnectionProxyFactory_wasCanceled; + public static String JSchProcess_exitValue_exception_msg; + public static String JSchProcessBuilder_Connection_is_not_open; + public static String JschFileStore_Connection_is_not_open; + public static String JschFileStore_File_doesnt_exist; + public static String JschFileStore_Invalid_connection_for_URI; + public static String JschFileStore_Is_a_directory; + public static String JschFileStore_No_remote_services_found_for_URI; + public static String JschFileStore_The_directory_could_not_be_created; + + public static String JschFileStore_A_file_of_name_already_exists; + public static String JschFileStore_The_parent_of_directory_does_not_exist; + + public static String ProxyCommandShell_0; + + public static String ProxyConnection_0; + + public static String ProxyConnection_2; + + public static String ProxyConnectionBootstrap_0; + + public static String ProxyConnectionBootstrap_1; + + public static String ProxyConnectionBootstrap_2; + + public static String ProxyConnectionBootstrap_3; + + public static String ProxyConnectionBootstrap_4; + + public static String ProxyConnectionBootstrap_5; + + public static String ProxyConnectionBootstrap_6; + + public static String ProxyConnectionBootstrap_7; + + public static String ProxyConnectionBootstrap_8; + + public static String ProxyConnectionBootstrap_9; + + public static String ProxyFileStore_0; + + public static String ProxyFileStore_1; + + public static String ProxyFileStore_2; + + public static String ProxyFileStore_3; + + public static String ProxyFileStore_4; + + public static String ProxyFileStore_5; + + public static String ProxyFileStore_6; + + public static String ProxyFileStore_7; + + public static String ProxyProcessBuilder_0; + + public static String ProxyProcessBuilder_1; + + static { + // load message values from bundle file + NLS.initializeMessages(BUNDLE_ID, Messages.class); + } + + private Messages() { + // cannot create new instance + } +} diff --git a/bundles/org.eclipse.remote.proxy.core/src/org/eclipse/remote/internal/proxy/core/messages/messages.properties b/bundles/org.eclipse.remote.proxy.core/src/org/eclipse/remote/internal/proxy/core/messages/messages.properties new file mode 100755 index 00000000000..d96b42bbd0c --- /dev/null +++ b/bundles/org.eclipse.remote.proxy.core/src/org/eclipse/remote/internal/proxy/core/messages/messages.properties @@ -0,0 +1,69 @@ +############################################################################### +# Copyright (c) 2013 IBM Corporation. +# 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 implementation +############################################################################### +AbstractCommand_0=Operation cancelled by user +AbstractRemoteCommand_format1={0,number,integer} {1} completed +AbstractRemoteCommand_format2={0,number,integer} {1} of {2,number,integer} {3} complete ({4,number,percent}) +AbstractRemoteCommand_Get_symlink_target=Get symlink target +AbstractRemoteCommand_Operation_cancelled_by_user=Operation cancelled by user +AuthInfo_Authentication_message=Authentication Message +ExecCommand_Exec_command=Executing command "{0}" +GetInputStreamCommand_Receiving=Receiving {0}: +GetOutputStreamCommand_Sending=Sending {0}: +JSchConnection_0=Connection canceled by user +JSchConnection_Connection_was_cancelled=Connection was cancelled +JSchConnection_connectionNotOpen=Connection is not open +JSchConnection_Executing_command=Executing command "{0}" +JSchConnection_remote_address_must_be_set=Remote address must be set before opening connection +JSchConnection_remotePort=Could not allocate remote port +JSchConnection_forwarding=Setting up remote forwarding +JSchConnection_Remote_host_does_not_support_sftp=Remote host does not support sftp. Remote functionality requires sftp to be enabled +JSchConnection_Unable_to_open_sftp_channel=Unable to open sftp channel: check sftp is enabled on remote host +JSchConnection_username_must_be_set=Username must be set before opening connection +JSchConnectionManager_connection_with_name_exists=A connection with name \"{0}\" already exists +JSchConnectionManager_cannotRemoveOpenConnection=Cannot remove an open connection +JSchConnectionManager_invalidConnectionType=Invalid connection type +JSchConnectionProxyFactory_failed=failed +JSchConnectionProxyFactory_ProxyCommandFailed=Proxy command "{0}" {1} and printed message "{2}" +JSchConnectionProxyFactory_timedOut=timed out +JSchConnectionProxyFactory_wasCanceled=was canceled +JSchProcess_exitValue_exception_msg=process has not exited +JSchProcessBuilder_Connection_is_not_open=Connection is not open +JschFileStore_Connection_is_not_open=Connection is not open +JschFileStore_File_doesnt_exist=File {0} doesn't exist +JschFileStore_Invalid_connection_for_URI=Invalid connection for URI: "{0}" +JschFileStore_Is_a_directory={0} is a directory +JschFileStore_No_remote_services_found_for_URI=No remote services found for URI: "{0}" +JschFileStore_The_directory_could_not_be_created=The directory {0} could not be created +JschFileStore_A_file_of_name_already_exists=A file of name {0} already exists +JschFileStore_The_parent_of_directory_does_not_exist=The parent of directory {0} does not exist +ProxyCommandShell_0=Unable to locate connection for command shell +ProxyConnection_0=Opening connection... +ProxyConnection_2=User canceled opening connection +ProxyConnectionBootstrap_0=Initializing +ProxyConnectionBootstrap_1=Validating environment +ProxyConnectionBootstrap_2=Unable to locate server bundle {0} +ProxyConnectionBootstrap_3=Updating server proxy +ProxyConnectionBootstrap_4=Starting server +ProxyConnectionBootstrap_5=Checking server installation +ProxyConnectionBootstrap_6=Unable to locate bootstrap shell +ProxyConnectionBootstrap_7=Unable to start server: {0} +ProxyConnectionBootstrap_8=User canceled connection open +ProxyConnectionBootstrap_9=Loading bootstrap shell +ProxyFileStore_0=No remote services found for URI {0} +ProxyFileStore_1=Invalid connection for URI {0} +ProxyFileStore_2=Connection is not open +ProxyFileStore_3=The parent of directory {0} does not exist +ProxyFileStore_4=The directory {0} could not be created +ProxyFileStore_5=A file of name {0} already exists +ProxyFileStore_6=File {0} does not exist +ProxyFileStore_7={0} is a directory +ProxyProcessBuilder_0=Unable to located connection for this process +ProxyProcessBuilder_1=No command to run\! diff --git a/bundles/org.eclipse.remote.proxy.protocol.core/.classpath b/bundles/org.eclipse.remote.proxy.protocol.core/.classpath new file mode 100644 index 00000000000..eca7bdba8f0 --- /dev/null +++ b/bundles/org.eclipse.remote.proxy.protocol.core/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/bundles/org.eclipse.remote.proxy.protocol.core/.gitignore b/bundles/org.eclipse.remote.proxy.protocol.core/.gitignore new file mode 100644 index 00000000000..5e56e040ec0 --- /dev/null +++ b/bundles/org.eclipse.remote.proxy.protocol.core/.gitignore @@ -0,0 +1 @@ +/bin diff --git a/bundles/org.eclipse.remote.proxy.protocol.core/.project b/bundles/org.eclipse.remote.proxy.protocol.core/.project new file mode 100644 index 00000000000..8a48fee1d62 --- /dev/null +++ b/bundles/org.eclipse.remote.proxy.protocol.core/.project @@ -0,0 +1,34 @@ + + + org.eclipse.remote.proxy.protocol.core + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + org.eclipse.pde.api.tools.apiAnalysisBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + org.eclipse.pde.api.tools.apiAnalysisNature + + diff --git a/bundles/org.eclipse.remote.proxy.protocol.core/.settings/org.eclipse.jdt.core.prefs b/bundles/org.eclipse.remote.proxy.protocol.core/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 00000000000..3a21537071b --- /dev/null +++ b/bundles/org.eclipse.remote.proxy.protocol.core/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,11 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/bundles/org.eclipse.remote.proxy.protocol.core/META-INF/MANIFEST.MF b/bundles/org.eclipse.remote.proxy.protocol.core/META-INF/MANIFEST.MF new file mode 100644 index 00000000000..fdfcbeb9b3b --- /dev/null +++ b/bundles/org.eclipse.remote.proxy.protocol.core/META-INF/MANIFEST.MF @@ -0,0 +1,16 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: %pluginName +Bundle-SymbolicName: org.eclipse.remote.proxy.protocol.core;singleton:=true +Bundle-Version: 2.0.0.qualifier +Bundle-Activator: org.eclipse.remote.internal.proxy.protocol.core.Activator +Bundle-Vendor: %pluginProvider +Bundle-ActivationPolicy: lazy +Export-Package: org.eclipse.remote.proxy.protocol.core, + org.eclipse.remote.proxy.protocol.core.exceptions +Bundle-Localization: plugin +Bundle-RequiredExecutionEnvironment: JavaSE-1.8 +Import-Package: org.eclipse.core.filesystem, + org.eclipse.core.filesystem.provider, + org.eclipse.core.runtime, + org.osgi.framework diff --git a/bundles/org.eclipse.remote.proxy.protocol.core/about.html b/bundles/org.eclipse.remote.proxy.protocol.core/about.html new file mode 100644 index 00000000000..3f810933b39 --- /dev/null +++ b/bundles/org.eclipse.remote.proxy.protocol.core/about.html @@ -0,0 +1,22 @@ + + + +About + + + +

About This Content

+ +

May 2, 2006

+

License

+ +

The Eclipse Foundation makes available all content in this plug-in ("Content"). Unless otherwise indicated below, the Content is provided to you under the terms and conditions of the +Eclipse Public License Version 1.0 ("EPL"). A copy of the EPL is available at http://www.eclipse.org/legal/epl-v10.html. +For purposes of the EPL, "Program" will mean the Content.

+ +

If you did not receive this Content directly from the Eclipse Foundation, the Content is being redistributed by another party ("Redistributor") and different terms and conditions may +apply to your use of any object code in the Content. Check the Redistributor's license that was provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise +indicated below, the terms and conditions of the EPL still apply to any source code in the Content and such source code may be obtained at http://www.eclipse.org.

+ + + \ No newline at end of file diff --git a/bundles/org.eclipse.remote.proxy.protocol.core/build.properties b/bundles/org.eclipse.remote.proxy.protocol.core/build.properties new file mode 100644 index 00000000000..47b4c86905e --- /dev/null +++ b/bundles/org.eclipse.remote.proxy.protocol.core/build.properties @@ -0,0 +1,8 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + .,\ + plugin.properties,\ + about.html + + diff --git a/bundles/org.eclipse.remote.proxy.protocol.core/plugin.properties b/bundles/org.eclipse.remote.proxy.protocol.core/plugin.properties new file mode 100644 index 00000000000..35d5c536b23 --- /dev/null +++ b/bundles/org.eclipse.remote.proxy.protocol.core/plugin.properties @@ -0,0 +1,11 @@ +############################################################################### +# Copyright (c) 2016 Oak Ridge National Laboratory 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 +# +############################################################################### + +pluginName=Remote Proxy Protocol Support +pluginProvider=Eclipse PTP diff --git a/bundles/org.eclipse.remote.proxy.protocol.core/pom.xml b/bundles/org.eclipse.remote.proxy.protocol.core/pom.xml new file mode 100644 index 00000000000..ac47f7a1cda --- /dev/null +++ b/bundles/org.eclipse.remote.proxy.protocol.core/pom.xml @@ -0,0 +1,16 @@ + + + 4.0.0 + + + org.eclipse.remote + remote-parent + 3.0.0-SNAPSHOT + ../../releng/org.eclipse.remote.build/pom.xml + + + org.eclipse.remote.proxy.protocol.core + eclipse-plugin +2.0.0-SNAPSHOT + diff --git a/bundles/org.eclipse.remote.proxy.protocol.core/src/org/eclipse/remote/internal/proxy/protocol/core/Activator.java b/bundles/org.eclipse.remote.proxy.protocol.core/src/org/eclipse/remote/internal/proxy/protocol/core/Activator.java new file mode 100644 index 00000000000..b9ec18b23af --- /dev/null +++ b/bundles/org.eclipse.remote.proxy.protocol.core/src/org/eclipse/remote/internal/proxy/protocol/core/Activator.java @@ -0,0 +1,116 @@ +package org.eclipse.remote.internal.proxy.protocol.core; + +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Plugin; +import org.eclipse.core.runtime.Status; +import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceReference; + +/** + * The activator class controls the plug-in life cycle + */ +public class Activator extends Plugin { + + // The plug-in ID + public static final String PLUGIN_ID = "org.eclipse.remote.proxy.protocol.core"; //$NON-NLS-1$ + + // The shared instance + private static Activator plugin; + + /** + * Returns the shared instance + * + * @return the shared instance + */ + public static Activator getDefault() { + return plugin; + } + + /** + * Get unique identifier + * + * @return + * @since 5.0 + */ + public static String getUniqueIdentifier() { + if (getDefault() == null) { + return PLUGIN_ID; + } + return getDefault().getBundle().getSymbolicName(); + } + + /** + * Logs the specified status with this plug-in's log. + * + * @param status + * status to log + */ + public static void log(IStatus status) { + getDefault().getLog().log(status); + } + + /** + * Logs an internal error with the specified message. + * + * @param message + * the error message to log + */ + public static void log(String message) { + log(new Status(IStatus.ERROR, getUniqueIdentifier(), IStatus.ERROR, message, null)); + } + + /** + * Logs an internal error with the specified throwable + * + * @param e + * the exception to be logged + */ + public static void log(Throwable e) { + log(new Status(IStatus.ERROR, getUniqueIdentifier(), IStatus.ERROR, e.getMessage(), e)); + } + + + /** + * The constructor + */ + public Activator() { + } + + /** + * Return the OSGi service with the given service interface. + * + * @param service service interface + * @return the specified service or null if it's not registered + */ + public static T getService(Class service) { + BundleContext context = plugin.getBundle().getBundleContext(); + ServiceReference ref = context.getServiceReference(service); + return ref != null ? context.getService(ref) : null; + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext + * ) + */ + @Override + public void start(BundleContext context) throws Exception { + super.start(context); + plugin = this; + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext + * ) + */ + @Override + public void stop(BundleContext context) throws Exception { + plugin = null; + super.stop(context); + } +} diff --git a/bundles/org.eclipse.remote.proxy.protocol.core/src/org/eclipse/remote/proxy/protocol/core/Protocol.java b/bundles/org.eclipse.remote.proxy.protocol.core/src/org/eclipse/remote/proxy/protocol/core/Protocol.java new file mode 100644 index 00000000000..0e7257e9d26 --- /dev/null +++ b/bundles/org.eclipse.remote.proxy.protocol.core/src/org/eclipse/remote/proxy/protocol/core/Protocol.java @@ -0,0 +1,41 @@ +/******************************************************************************* + * Copyright (c) 2016 Oak Ridge National Laboratory 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 + *******************************************************************************/ +package org.eclipse.remote.proxy.protocol.core; + +public class Protocol { + public static final int MAGIC = 0xAFFA; + + public final static byte PROTO_COMMAND = 1; + public final static byte PROTO_SHUTDOWN = 2; + public final static byte PROTO_ERROR = 126; + public final static byte PROTO_OK = 0; + + public final static short CmdBase = 100; + + public final static short CMD_EXEC = CmdBase + 1; + public final static short CMD_SHELL = CmdBase + 2; + public final static short CMD_GETCWD = CmdBase + 3; + public final static short CMD_GETENV = CmdBase + 4; + public final static short CMD_CHILDINFOS = CmdBase + 5; + public final static short CMD_DELETE = CmdBase + 6; + public final static short CMD_FETCHINFO = CmdBase + 7; + public final static short CMD_GETINPUTSTREAM = CmdBase + 8; + public final static short CMD_GETOUTPUTSTREAM = CmdBase + 9; + public final static short CMD_MKDIR = CmdBase + 10; + public final static short CMD_PUTINFO = CmdBase + 11; + public final static short CMD_GETPROPERTIES = CmdBase + 12; + + /** + * @since 2.0 + */ + public final static byte CONTROL_KILL = 0; + /** + * @since 2.0 + */ + public final static byte CONTROL_SETTERMINALSIZE = 1; +} diff --git a/bundles/org.eclipse.remote.proxy.protocol.core/src/org/eclipse/remote/proxy/protocol/core/SerializableFileInfo.java b/bundles/org.eclipse.remote.proxy.protocol.core/src/org/eclipse/remote/proxy/protocol/core/SerializableFileInfo.java new file mode 100644 index 00000000000..22c2488adf7 --- /dev/null +++ b/bundles/org.eclipse.remote.proxy.protocol.core/src/org/eclipse/remote/proxy/protocol/core/SerializableFileInfo.java @@ -0,0 +1,90 @@ +/******************************************************************************* + * Copyright (c) 2016 Oak Ridge National Laboratory 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 + *******************************************************************************/ +package org.eclipse.remote.proxy.protocol.core; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.Serializable; + +import org.eclipse.core.filesystem.EFS; +import org.eclipse.core.filesystem.IFileInfo; +import org.eclipse.core.filesystem.provider.FileInfo; + +public class SerializableFileInfo implements Serializable { + private static final long serialVersionUID = -1986643088683154145L; + + private IFileInfo info; + + public SerializableFileInfo() { + } + + public SerializableFileInfo(IFileInfo info) { + setIFileInfo(info); + } + + public void setIFileInfo(IFileInfo info) { + this.info = info; + } + + public IFileInfo getIFileInfo() { + return info; + } + + public void writeObject(DataOutputStream out) throws IOException { + out.writeUTF(info.getName()); + boolean symlink = info.getAttribute(EFS.ATTRIBUTE_SYMLINK); + out.writeBoolean(symlink); + if (symlink) { + out.writeUTF(info.getStringAttribute(EFS.ATTRIBUTE_LINK_TARGET)); + } + out.writeBoolean(info.exists()); + out.writeLong(info.getLastModified()); + out.writeLong(info.getLength()); + out.writeBoolean(info.isDirectory()); + out.writeBoolean(info.getAttribute(EFS.ATTRIBUTE_GROUP_READ)); + out.writeBoolean(info.getAttribute(EFS.ATTRIBUTE_GROUP_WRITE)); + out.writeBoolean(info.getAttribute(EFS.ATTRIBUTE_GROUP_EXECUTE)); + out.writeBoolean(info.getAttribute(EFS.ATTRIBUTE_OTHER_READ)); + out.writeBoolean(info.getAttribute(EFS.ATTRIBUTE_OTHER_WRITE)); + out.writeBoolean(info.getAttribute(EFS.ATTRIBUTE_OTHER_EXECUTE)); + out.writeBoolean(info.getAttribute(EFS.ATTRIBUTE_OWNER_READ)); + out.writeBoolean(info.getAttribute(EFS.ATTRIBUTE_OWNER_WRITE)); + out.writeBoolean(info.getAttribute(EFS.ATTRIBUTE_OWNER_EXECUTE)); + } + + public void readObject(DataInputStream in) throws IOException { + FileInfo newInfo = new FileInfo(); + + try { + newInfo.setName(in.readUTF()); + boolean symlink = in.readBoolean(); + newInfo.setAttribute(EFS.ATTRIBUTE_SYMLINK, symlink); + if (symlink) { + newInfo.setStringAttribute(EFS.ATTRIBUTE_LINK_TARGET, in.readUTF()); + } + newInfo.setExists(in.readBoolean()); + newInfo.setLastModified(in.readLong()); + newInfo.setLength(in.readLong()); + newInfo.setDirectory(in.readBoolean()); + newInfo.setAttribute(EFS.ATTRIBUTE_GROUP_READ, in.readBoolean()); + newInfo.setAttribute(EFS.ATTRIBUTE_GROUP_WRITE, in.readBoolean()); + newInfo.setAttribute(EFS.ATTRIBUTE_GROUP_EXECUTE, in.readBoolean()); + newInfo.setAttribute(EFS.ATTRIBUTE_OTHER_READ, in.readBoolean()); + newInfo.setAttribute(EFS.ATTRIBUTE_OTHER_WRITE, in.readBoolean()); + newInfo.setAttribute(EFS.ATTRIBUTE_OTHER_EXECUTE, in.readBoolean()); + newInfo.setAttribute(EFS.ATTRIBUTE_OWNER_READ, in.readBoolean()); + newInfo.setAttribute(EFS.ATTRIBUTE_OWNER_WRITE, in.readBoolean()); + newInfo.setAttribute(EFS.ATTRIBUTE_OWNER_EXECUTE, in.readBoolean()); + } catch (IOException e) { + newInfo.setError(IFileInfo.IO_ERROR); + } + + setIFileInfo(newInfo); + } +} diff --git a/bundles/org.eclipse.remote.proxy.protocol.core/src/org/eclipse/remote/proxy/protocol/core/StreamChannel.java b/bundles/org.eclipse.remote.proxy.protocol.core/src/org/eclipse/remote/proxy/protocol/core/StreamChannel.java new file mode 100644 index 00000000000..b124fed2b4e --- /dev/null +++ b/bundles/org.eclipse.remote.proxy.protocol.core/src/org/eclipse/remote/proxy/protocol/core/StreamChannel.java @@ -0,0 +1,365 @@ +/******************************************************************************* + * Copyright (c) 2016 Oak Ridge National Laboratory 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 + * + *******************************************************************************/ +package org.eclipse.remote.proxy.protocol.core; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +public class StreamChannel { + public static final int CAPACITY = 8192; + + private class ChannelInputStream extends InputStream { + private final Lock lock = new ReentrantLock(); + private final Condition cond = lock.newCondition(); + private final StreamChannel channel; + + private int currentPos; + private int currentSize; + private boolean connected = true; + private int inputRequestCount; + private byte[] buffer = new byte[CAPACITY]; + + public ChannelInputStream(StreamChannel channel) { + this.channel = channel; + } + + @Override + public synchronized int read() throws IOException { + byte[] b = new byte[1]; + if (read(b, 0, 1) != 1) { + return -1; + } + return b[0] & 0xff; + } + + @Override + public int available() throws IOException { + lock.lock(); + try { + return currentSize - currentPos; + } finally { + lock.unlock(); + } + } + + public synchronized int read(byte b[], int off, int len) throws IOException { + if (len <= 0) { + return 0; + } + int moreSpace; + lock.lock(); + try { + if (currentPos >= currentSize) { + currentPos = currentSize = 0; + } else if (currentPos >= CAPACITY/2) { + System.arraycopy(buffer, currentPos, buffer, 0, currentSize - currentPos); + currentSize -= currentPos; + currentPos = 0; + } + int freeSpace = CAPACITY - currentSize; + moreSpace = Math.max(freeSpace - inputRequestCount, 0); + } finally { + lock.unlock(); + } + if (moreSpace > 0) { + mux.sendRequestCmd(StreamChannel.this, moreSpace); + } + lock.lock(); + try { + inputRequestCount += moreSpace; + while (currentPos >= currentSize && connected) { + try { + cond.await(); + } catch (InterruptedException e) { + } + } + if (!connected && currentPos >= currentSize) { + return -1; + } + + int available = currentSize - currentPos; + if (len < available) { + System.arraycopy(buffer, currentPos, b, off, len); + currentPos += len; + return len; + } else { + System.arraycopy(buffer, currentPos, b, off, available); + currentPos = currentSize = 0; + return available; + } + } finally { + lock.unlock(); + } + } + + @Override + public void close() throws IOException { + channel.closeOutput(); + disconnect(); + } + + void receive(byte[] buf, int len) throws IOException { + lock.lock(); + try { + if (currentPos > 0 && (CAPACITY - currentSize) < len) { + System.arraycopy(buffer, currentPos, buffer, 0, currentSize - currentPos); + currentSize -= currentPos; + currentPos = 0; + } + if (CAPACITY - currentSize < len) { + throw new IOException("Receive buffer overflow"); + } + System.arraycopy(buf, 0, buffer, currentSize, len); + currentSize += len; + inputRequestCount -= len; + cond.signalAll(); + } finally { + lock.unlock(); + } + } + + void disconnect() { + lock.lock(); + try { + connected = false; + cond.signalAll(); + } finally { + lock.unlock(); + } + } + + boolean isConnected() { + lock.lock(); + try { + return connected; + } finally { + lock.unlock(); + } + } + } + + private class ChannelOutputStream extends OutputStream { + private final Lock lock = new ReentrantLock(); + private final Condition cond = lock.newCondition(); + private final StreamChannel channel; + + private int currentPos; + private byte[] buffer = new byte[CAPACITY]; + private boolean connected = true; + private int outputRequestCount; + + public ChannelOutputStream(StreamChannel channel) { + this.channel = channel; + } + + @Override + public synchronized void write(int b) throws IOException { + while (currentPos >= CAPACITY) { + send(); + } + buffer[currentPos++] = (byte)b; + } + + @Override + public synchronized void flush() throws IOException { + while (currentPos > 0) { + send(); + } + } + + @Override + public synchronized void write(byte[] b, int off, int len) throws IOException { + if (len <= 0) { + return; + } + if (len <= CAPACITY - currentPos) { + System.arraycopy(b, off, buffer, currentPos, len); + currentPos += len; + return; + } + flush(); + int canSend; + while (true) { + lock.lock(); + try { + while ((canSend = outputRequestCount) == 0 && connected) { + try { + cond.await(); + } catch (InterruptedException e) { + } + } + if (!connected) { + throw new IOException("channel closed"); + } + } finally { + lock.unlock(); + } + + if (canSend < len) { + mux.sendTransmitCmd(StreamChannel.this, b, off, canSend); + off += canSend; + len -= canSend; + lock.lock(); + outputRequestCount -= canSend; + lock.unlock(); + } else { + mux.sendTransmitCmd(StreamChannel.this, b, off, len); + lock.lock(); + outputRequestCount -= len; + lock.unlock(); + break; + } + } + } + + void send() throws IOException { + int canSend; + lock.lock(); + try { + while ((canSend = outputRequestCount) == 0 && connected) { + try { + cond.await(); + } catch (InterruptedException e) { + } + } + if (!connected) { + throw new IOException("channel closed"); + } + } finally { + lock.unlock(); + } + if (canSend < currentPos) { + mux.sendTransmitCmd(StreamChannel.this, buffer, 0, canSend); + currentPos -= canSend; + System.arraycopy(buffer, canSend, buffer, 0, currentPos); + lock.lock(); + outputRequestCount -= canSend; + lock.unlock(); + } else { + mux.sendTransmitCmd(StreamChannel.this, buffer, 0, currentPos); + lock.lock(); + outputRequestCount -= currentPos; + lock.unlock(); + currentPos = 0; + } + } + + @Override + public void close() throws IOException { + flush(); + channel.closeInput(); + disconnect(); + } + + void request(int len) { + lock.lock(); + outputRequestCount += len; + cond.signalAll(); + lock.unlock(); + } + + void disconnect() { + lock.lock(); + try { + connected = false; + cond.signalAll(); + } finally { + lock.unlock(); + } + } + + boolean isConnected() { + lock.lock(); + try { + return connected; + } finally { + lock.unlock(); + } + + } + } + + private final StreamChannelManager mux; + private final int channelId; + private final ChannelInputStream min = new ChannelInputStream(this); + private final ChannelOutputStream mout = new ChannelOutputStream(this); + + private boolean open; + + public StreamChannel(StreamChannelManager mux, int id) { + this.mux = mux; + channelId = id; + open = true; + } + + public int getId() { + return channelId; + } + + public InputStream getInputStream() { + return min; + } + + public OutputStream getOutputStream() { + return mout; + } + + public boolean isOpen() { + return open; + } + + public void close() throws IOException { + mux.sendCloseCmd(this); + } + + void receive(byte[] buf, int len) throws IOException { + min.receive(buf, len); + } + + void request(int len) { + mout.request(len); + } + + void disconnect() { + min.disconnect(); + mout.disconnect(); + } + + void setClosed() { + open = false; + } + + void disconnectInput() { + min.disconnect(); + } + + void disconnectOutput() { + mout.disconnect(); + } + + void closeInput() throws IOException { + mux.sendCloseInputCmd(this); + } + + void closeOutput() throws IOException { + mux.sendCloseOutputCmd(this); + } + + boolean isInputConnected() { + return min.isConnected(); + } + + boolean isOutputConnected() { + return mout.isConnected(); + } +} diff --git a/bundles/org.eclipse.remote.proxy.protocol.core/src/org/eclipse/remote/proxy/protocol/core/StreamChannelManager.java b/bundles/org.eclipse.remote.proxy.protocol.core/src/org/eclipse/remote/proxy/protocol/core/StreamChannelManager.java new file mode 100644 index 00000000000..4b31d566e45 --- /dev/null +++ b/bundles/org.eclipse.remote.proxy.protocol.core/src/org/eclipse/remote/proxy/protocol/core/StreamChannelManager.java @@ -0,0 +1,562 @@ +/******************************************************************************* + * Copyright (c) 2016 Oak Ridge National Laboratory 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 + * + *******************************************************************************/ +package org.eclipse.remote.proxy.protocol.core; + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.EOFException; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; + +public class StreamChannelManager implements Runnable { + public interface IChannelListener { + public void newChannel(StreamChannel chan); + public void closeChannel(StreamChannel chan); + } + + private class Sender implements Runnable { + private OutputStream out; + private BlockingQueue queue = new LinkedBlockingQueue(); + private boolean running = true; + + public Sender(OutputStream out) { + this.out = out; + } + + public void sendOpenCmd(int id) throws IOException { + ByteArrayOutputStream bytes = new ByteArrayOutputStream(); + DataOutputStream data = new DataOutputStream(bytes); + data.writeByte(CMD_OPEN); + data.writeByte(id); + try { + queue.put(bytes); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + public void sendTransmitCmd(int id, byte buf[], int off, int len) throws IOException { + ByteArrayOutputStream bytes = new ByteArrayOutputStream(); + DataOutputStream data = new DataOutputStream(bytes); + data.writeByte(CMD_TRANSMIT); + data.writeByte(id); + data.writeInt(len); + data.write(buf, off, len); + try { + queue.put(bytes); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + public void sendCloseCmd(int id) throws IOException { + ByteArrayOutputStream bytes = new ByteArrayOutputStream(); + DataOutputStream data = new DataOutputStream(bytes); + data.writeByte(CMD_CLOSE); + data.writeByte(id); + try { + queue.put(bytes); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + public void sendCloseAckCmd(int id) throws IOException { + ByteArrayOutputStream bytes = new ByteArrayOutputStream(); + DataOutputStream data = new DataOutputStream(bytes); + data.writeByte(CMD_CLOSEACK); + data.writeByte(id); + try { + queue.put(bytes); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + public void sendRequestCmd(int id, int len) throws IOException { + ByteArrayOutputStream bytes = new ByteArrayOutputStream(); + DataOutputStream data = new DataOutputStream(bytes); + data.writeByte(CMD_REQUEST); + data.writeByte(id); + data.writeInt(len); + try { + queue.put(bytes); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + public void sendCloseInputCmd(int id) throws IOException { + ByteArrayOutputStream bytes = new ByteArrayOutputStream(); + DataOutputStream data = new DataOutputStream(bytes); + data.writeByte(CMD_CLOSE_INPUT); + data.writeByte(id); + try { + queue.put(bytes); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + public void sendCloseOutputCmd(int id) throws IOException { + ByteArrayOutputStream bytes = new ByteArrayOutputStream(); + DataOutputStream data = new DataOutputStream(bytes); + data.writeByte(CMD_CLOSE_OUTPUT); + data.writeByte(id); + try { + queue.put(bytes); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + public void shutdown() { + running = false; + try { + queue.put(new ByteArrayOutputStream()); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + @Override + public void run() { + try { + while (running) { + ByteArrayOutputStream bytes = queue.take(); + if (bytes != null) { + bytes.writeTo(out); + out.flush(); + } + } + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + } + + private boolean isMyChannel(int id) { + return !(isServer ^ ((id & SERVER_ID_MASK) == SERVER_ID_MASK)); + } + + private class Receiver implements Runnable { + private DataInputStream dataIn; + + public Receiver(InputStream in) { + this.dataIn = new DataInputStream(in); + } + + @Override + public void run() { + StreamChannel chan; + running = true; + try { + while (true) { + debugPrint("start read"); + int cmd = dataIn.readByte() & 0xff; + int id = dataIn.readByte() & 0xff; + + switch (cmd) { + case CMD_OPEN: + debugPrint("received cmd=OPEN id="+id); + chan = channels.get(id); + if (chan != null) { + throw new IOException("Channel already exists"); + } + if (!isServer && (id & SERVER_ID_MASK) != SERVER_ID_MASK) { + throw new IOException("Client received invalid server channel id: " + id); + } + if (isServer && (id & SERVER_ID_MASK) == SERVER_ID_MASK) { + throw new IOException("Server received invalid client channel id: " + id); + } + chan = new StreamChannel(StreamChannelManager.this, id); + channels.put(id, chan); + newChannelCallback(chan); + break; + + case CMD_CLOSE: + /* + * Received a command to close the channel. + * Clean up channel and free channel ID if we allocated it. + */ + debugPrint("received cmd=CLOSE id="+id); + chan = channels.get(id); + if (chan == null) { + throw new IOException("CLOSE: Invalid channel id: " + id); + } + chan.disconnect(); + if (chan.isOpen()) { + sendCloseAckCmd(chan); + } + closeChannelCallback(chan); + channels.remove(id); + if (isMyChannel(id)) { + freeId(id); + } + break; + + case CMD_CLOSEACK: + /* + * Received acknowledgement for our close command. + * Clean up channel and free channel ID if we allocated it. + */ + debugPrint("received cmd=CLOSEACK id="+id); + chan = channels.get(id); + if (chan == null) { + throw new IOException("CLOSEACK: Invalid channel id"); + } + if (chan.isOpen()) { + throw new IOException("Channel is still open"); + } + chan.disconnect(); + channels.remove(id); + if (isMyChannel(id)) { + freeId(id); + } + break; + + case CMD_TRANSMIT: + debugPrint("received cmd=TRANSMIT id="+id); + chan = channels.get(id); + if (chan == null) { + throw new IOException("TRANSMIT: Invalid channel id: " + id); + } + int len = dataIn.readInt(); + byte[] buf = new byte[len]; + dataIn.readFully(buf, 0, len); + chan.receive(buf, len); + break; + + case CMD_REQUEST: + chan = channels.get(id); + if (chan == null) { + throw new IOException("REQUEST: Invalid channel id: " + id); + } + int req = dataIn.readInt(); + debugPrint("received cmd=REQUEST id="+id+ " len="+req); + chan.request(req); + break; + + case CMD_CLOSE_INPUT: + /* + * Received a command to close the input side of the channel. + */ + debugPrint("received cmd=CLOSE_INPUT id="+id); + chan = channels.get(id); + if (chan == null) { + throw new IOException("CLOSE: Invalid channel id: " + id); + } + chan.disconnectInput(); + break; + + + case CMD_CLOSE_OUTPUT: + /* + * Received a command to close the output side of the channel. + */ + debugPrint("received cmd=CLOSE_OUTPUT id="+id); + chan = channels.get(id); + if (chan == null) { + throw new IOException("CLOSE: Invalid channel id: " + id); + } + chan.disconnectOutput(); + break; + + default: + synchronized (System.err) { + System.err.print("invalid command: "+ dump_byte((byte)cmd) + dump_byte((byte)id)); + } + try { + while (true) { + byte b = dataIn.readByte(); + System.err.print(dump_byte(b)); + } + } catch (Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + throw new IOException("Invalid command: " + cmd); + } + } + } catch (EOFException e) { + // Finish + } catch (Exception e) { + e.printStackTrace(); + debugPrint("run got exception:" + e.getMessage()); + } finally { + debugPrint("shutting down manager"); + StreamChannelManager.this.shutdown(); + } + } + + public void shutdown() { + try { + dataIn.close(); + } catch (IOException e) { + // Ignore + } + } + } + + private final static int CMD_OPEN = 0xA1; // Open a new channel + private final static int CMD_CLOSE = 0xA2; // Close a channel; acknowledgement required + private final static int CMD_CLOSEACK = 0xA3; // Channel close acknowledgement + private final static int CMD_REQUEST = 0xA4; // Request buffer space + private final static int CMD_TRANSMIT = 0xA5; // Transmit a buffer + private final static int CMD_CLOSE_INPUT = 0xA6; // Close input side of the channel; no acknowledgement required + private final static int CMD_CLOSE_OUTPUT = 0xA7; // Close output side of the channel; no acknowledgement required + + private final static int SERVER_ID_MASK = 1 << 15; + private final static int MAX_CHANNELS = SERVER_ID_MASK >> 1; + + private final Map channels = (Map) Collections.synchronizedMap(new HashMap()); + private final List listeners = (List)Collections.synchronizedList(new ArrayList()); + + private Set usedIds = new HashSet<>(); + private int nextUnusedChannelId; + private boolean isServer; + + private volatile boolean running = true; + + private Sender sender; + private Receiver receiver; + + private boolean debug = false; + + public StreamChannelManager(InputStream in, OutputStream out) { + sender = new Sender(new BufferedOutputStream(out)); + receiver = new Receiver(new BufferedInputStream(in)); + } + + /** + * Clients allocate IDs with leading bit 0 + * Servers allocate IDs with leading bit 1 + * + * Reuse an ID if it is not longer being used. + * + * @return new ID + */ + synchronized int newId() throws IOException { + if (!usedIds.isEmpty()) { + Short id = usedIds.iterator().next(); + usedIds.remove(id); + debugPrint("recover id="+id); + return id; + } + int nextId = nextUnusedChannelId; + if (nextUnusedChannelId++ > (MAX_CHANNELS - 1)) { + throw new IOException("Maximum number of channels exceeded"); + } + return nextId | (isServer ? SERVER_ID_MASK : 0); + } + + synchronized void freeId(int id) { + debugPrint("free id="+id); + usedIds.add((short)id); + } + + void dump_buf(String pref, byte[] b, int off, int len) { + System.err.print(pref + ": "); + for (int i = off; i < len+off; i++) { + if (b[i] <= 32 || b[i] > 126) { + System.err.print(String.format(" 0x%02x ", b[i])); + } else { + System.err.print((char)b[i]); + } + } + System.err.println(); + } + + public boolean isServer() { + return isServer; + } + + public void setServer(boolean server) { + isServer = server; + } + + public void addListener(IChannelListener listener) { + if (!listeners.contains(listener)) { + listeners.add(listener); + } + } + + public void removeListener(IChannelListener listener) { + if (listeners.contains(listener)) { + listeners.remove(listener); + } + } + + protected void newChannelCallback(StreamChannel chan) { + for (IChannelListener listener : listeners.toArray(new IChannelListener[listeners.size()])) { + listener.newChannel(chan); + } + } + + protected void closeChannelCallback(StreamChannel chan) { + for (IChannelListener listener : listeners.toArray(new IChannelListener[listeners.size()])) { + listener.closeChannel(chan); + } + } + + public String dump_byte(byte b) { + if (b <= 32 || b > 126) { + return String.format(" 0x%02x ", b); + } + + return String.valueOf((char)b); + } + + public StreamChannel openChannel() throws IOException { + if (!running) { + throw new IOException("Multiplexer is not running"); + } + + StreamChannel chan = new StreamChannel(this, newId()); + channels.put(chan.getId(), chan); + + debugPrint("send cmd=OPEN id="+chan.getId()); + sender.sendOpenCmd(chan.getId()); + + return chan; + } + + synchronized void sendTransmitCmd(StreamChannel chan, byte buf[], int off, int len) throws IOException { + if (running && chan.isOpen()) { + debugPrint("send cmd=TRANSMIT id="+chan.getId()+" len="+len + " off=" + off + " buflen="+buf.length); + sender.sendTransmitCmd(chan.getId(), buf, off, len); + } + } + + synchronized void sendCloseCmd(StreamChannel chan) throws IOException { + if (running && chan.isOpen()) { + debugPrint("send cmd=CLOSE id="+chan.getId()); + chan.disconnect(); + sender.sendCloseCmd(chan.getId()); + chan.setClosed(); + } + } + + synchronized void sendCloseAckCmd(StreamChannel chan) throws IOException { + if (running && chan.isOpen()) { + debugPrint("send cmd=CLOSEACK id="+chan.getId()); + sender.sendCloseAckCmd(chan.getId()); + chan.setClosed(); + } + } + + synchronized void sendRequestCmd(StreamChannel chan, int len) throws IOException { + if (running && chan.isOpen()) { + debugPrint("send cmd=REQUEST id="+chan.getId()+" len="+len); + sender.sendRequestCmd(chan.getId(), len); + } + } + + synchronized void sendCloseInputCmd(StreamChannel chan) throws IOException { + if (running && chan.isOpen()) { + if (!chan.isOutputConnected()) { + sendCloseCmd(chan); + } else { + debugPrint("send cmd=CLOSE_INPUT id="+chan.getId()); + sender.sendCloseInputCmd(chan.getId()); + } + } + } + + synchronized void sendCloseOutputCmd(StreamChannel chan) throws IOException { + if (running && chan.isOpen()) { + if (!chan.isInputConnected()) { + sendCloseCmd(chan); + } else { + debugPrint("send cmd=CLOSE_OUTPUT id="+chan.getId()); + sender.sendCloseOutputCmd(chan.getId()); + } + } + } + + public void debugPrint(String x) { + if (debug) { + synchronized (System.err) { + System.err.println(x); + } + } + } + + public void shutdown() { + if (!running) { + return; + } + running = false; + + synchronized (channels) { + for (StreamChannel c : channels.values()) { + c.disconnect(); + } + } + channels.clear(); + + sender.shutdown(); + receiver.shutdown(); + debugPrint("chan mpx stopped"); + // Should in and out be closed also? + } + + private String asString(int v) { + switch (v) { + case CMD_OPEN: + return "OPEN"; + + case CMD_CLOSE: + return "CLOSE"; + + case CMD_CLOSEACK: + return "CLOSEACK"; + + case CMD_TRANSMIT: + return "TRANSMIT"; + + case CMD_REQUEST: + return "REQUEST"; + } + return ""; + } + + @Override + public void run() { + debugPrint("mux starting"); + new Thread(sender, "mux sender").start(); + receiver.run(); + } +} diff --git a/bundles/org.eclipse.remote.proxy.protocol.core/src/org/eclipse/remote/proxy/protocol/core/exceptions/ProxyException.java b/bundles/org.eclipse.remote.proxy.protocol.core/src/org/eclipse/remote/proxy/protocol/core/exceptions/ProxyException.java new file mode 100644 index 00000000000..b64890a6e6d --- /dev/null +++ b/bundles/org.eclipse.remote.proxy.protocol.core/src/org/eclipse/remote/proxy/protocol/core/exceptions/ProxyException.java @@ -0,0 +1,17 @@ +/******************************************************************************* + * Copyright (c) 2016 Oak Ridge National Laboratory 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 + *******************************************************************************/ +package org.eclipse.remote.proxy.protocol.core.exceptions; + +public class ProxyException extends Exception { + + private static final long serialVersionUID = 1L; + + public ProxyException(String message) { + super(message); + } +} diff --git a/bundles/org.eclipse.remote.proxy.server.core/.classpath b/bundles/org.eclipse.remote.proxy.server.core/.classpath new file mode 100644 index 00000000000..eca7bdba8f0 --- /dev/null +++ b/bundles/org.eclipse.remote.proxy.server.core/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/bundles/org.eclipse.remote.proxy.server.core/.gitignore b/bundles/org.eclipse.remote.proxy.server.core/.gitignore new file mode 100644 index 00000000000..ae3c1726048 --- /dev/null +++ b/bundles/org.eclipse.remote.proxy.server.core/.gitignore @@ -0,0 +1 @@ +/bin/ diff --git a/bundles/org.eclipse.remote.proxy.server.core/.project b/bundles/org.eclipse.remote.proxy.server.core/.project new file mode 100644 index 00000000000..f1d580cb599 --- /dev/null +++ b/bundles/org.eclipse.remote.proxy.server.core/.project @@ -0,0 +1,28 @@ + + + org.eclipse.remote.proxy.server.core + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/bundles/org.eclipse.remote.proxy.server.core/.settings/org.eclipse.jdt.core.prefs b/bundles/org.eclipse.remote.proxy.server.core/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 00000000000..a698e59674f --- /dev/null +++ b/bundles/org.eclipse.remote.proxy.server.core/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,12 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/bundles/org.eclipse.remote.proxy.server.core/.settings/org.eclipse.jdt.ui.prefs b/bundles/org.eclipse.remote.proxy.server.core/.settings/org.eclipse.jdt.ui.prefs new file mode 100644 index 00000000000..44ccb79db9a --- /dev/null +++ b/bundles/org.eclipse.remote.proxy.server.core/.settings/org.eclipse.jdt.ui.prefs @@ -0,0 +1,59 @@ +eclipse.preferences.version=1 +editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true +sp_cleanup.add_default_serial_version_id=true +sp_cleanup.add_generated_serial_version_id=false +sp_cleanup.add_missing_annotations=true +sp_cleanup.add_missing_deprecated_annotations=true +sp_cleanup.add_missing_methods=false +sp_cleanup.add_missing_nls_tags=false +sp_cleanup.add_missing_override_annotations=true +sp_cleanup.add_missing_override_annotations_interface_methods=true +sp_cleanup.add_serial_version_id=false +sp_cleanup.always_use_blocks=true +sp_cleanup.always_use_parentheses_in_expressions=false +sp_cleanup.always_use_this_for_non_static_field_access=false +sp_cleanup.always_use_this_for_non_static_method_access=false +sp_cleanup.convert_functional_interfaces=false +sp_cleanup.convert_to_enhanced_for_loop=false +sp_cleanup.correct_indentation=false +sp_cleanup.format_source_code=false +sp_cleanup.format_source_code_changes_only=false +sp_cleanup.insert_inferred_type_arguments=false +sp_cleanup.make_local_variable_final=true +sp_cleanup.make_parameters_final=false +sp_cleanup.make_private_fields_final=true +sp_cleanup.make_type_abstract_if_missing_method=false +sp_cleanup.make_variable_declarations_final=false +sp_cleanup.never_use_blocks=false +sp_cleanup.never_use_parentheses_in_expressions=true +sp_cleanup.on_save_use_additional_actions=false +sp_cleanup.organize_imports=true +sp_cleanup.qualify_static_field_accesses_with_declaring_class=false +sp_cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true +sp_cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=true +sp_cleanup.qualify_static_member_accesses_with_declaring_class=false +sp_cleanup.qualify_static_method_accesses_with_declaring_class=false +sp_cleanup.remove_private_constructors=true +sp_cleanup.remove_redundant_type_arguments=false +sp_cleanup.remove_trailing_whitespaces=false +sp_cleanup.remove_trailing_whitespaces_all=true +sp_cleanup.remove_trailing_whitespaces_ignore_empty=false +sp_cleanup.remove_unnecessary_casts=true +sp_cleanup.remove_unnecessary_nls_tags=false +sp_cleanup.remove_unused_imports=false +sp_cleanup.remove_unused_local_variables=false +sp_cleanup.remove_unused_private_fields=true +sp_cleanup.remove_unused_private_members=false +sp_cleanup.remove_unused_private_methods=true +sp_cleanup.remove_unused_private_types=true +sp_cleanup.sort_members=false +sp_cleanup.sort_members_all=false +sp_cleanup.use_anonymous_class_creation=false +sp_cleanup.use_blocks=false +sp_cleanup.use_blocks_only_for_return_and_throw=false +sp_cleanup.use_lambda=true +sp_cleanup.use_parentheses_in_expressions=false +sp_cleanup.use_this_for_non_static_field_access=false +sp_cleanup.use_this_for_non_static_field_access_only_if_necessary=true +sp_cleanup.use_this_for_non_static_method_access=false +sp_cleanup.use_this_for_non_static_method_access_only_if_necessary=true diff --git a/bundles/org.eclipse.remote.proxy.server.core/.settings/org.eclipse.pde.core.prefs b/bundles/org.eclipse.remote.proxy.server.core/.settings/org.eclipse.pde.core.prefs new file mode 100644 index 00000000000..d40b9600d07 --- /dev/null +++ b/bundles/org.eclipse.remote.proxy.server.core/.settings/org.eclipse.pde.core.prefs @@ -0,0 +1,4 @@ +eclipse.preferences.version=1 +pluginProject.equinox=false +pluginProject.extensions=true +resolve.requirebundle=false diff --git a/bundles/org.eclipse.remote.proxy.server.core/META-INF/MANIFEST.MF b/bundles/org.eclipse.remote.proxy.server.core/META-INF/MANIFEST.MF new file mode 100644 index 00000000000..e20134257e4 --- /dev/null +++ b/bundles/org.eclipse.remote.proxy.server.core/META-INF/MANIFEST.MF @@ -0,0 +1,18 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: %pluginName +Bundle-SymbolicName: org.eclipse.remote.proxy.server.core;singleton:=true +Bundle-Version: 1.0.0.qualifier +Bundle-RequiredExecutionEnvironment: JavaSE-1.8 +Import-Package: org.eclipse.core.filesystem, + org.eclipse.core.runtime, + org.eclipse.core.runtime.adaptor, + org.eclipse.equinox.app, + org.eclipse.remote.core, + org.eclipse.remote.proxy.protocol.core, + org.eclipse.remote.proxy.protocol.core.exceptions, + org.osgi.framework, + org.osgi.framework.launch +Bundle-Vendor: %pluginProvider +Bundle-Localization: plugin +Require-Bundle: org.eclipse.cdt.core.native diff --git a/bundles/org.eclipse.remote.proxy.server.core/about.html b/bundles/org.eclipse.remote.proxy.server.core/about.html new file mode 100644 index 00000000000..3f810933b39 --- /dev/null +++ b/bundles/org.eclipse.remote.proxy.server.core/about.html @@ -0,0 +1,22 @@ + + + +About + + + +

About This Content

+ +

May 2, 2006

+

License

+ +

The Eclipse Foundation makes available all content in this plug-in ("Content"). Unless otherwise indicated below, the Content is provided to you under the terms and conditions of the +Eclipse Public License Version 1.0 ("EPL"). A copy of the EPL is available at http://www.eclipse.org/legal/epl-v10.html. +For purposes of the EPL, "Program" will mean the Content.

+ +

If you did not receive this Content directly from the Eclipse Foundation, the Content is being redistributed by another party ("Redistributor") and different terms and conditions may +apply to your use of any object code in the Content. Check the Redistributor's license that was provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise +indicated below, the terms and conditions of the EPL still apply to any source code in the Content and such source code may be obtained at http://www.eclipse.org.

+ + + \ No newline at end of file diff --git a/bundles/org.eclipse.remote.proxy.server.core/build.properties b/bundles/org.eclipse.remote.proxy.server.core/build.properties new file mode 100644 index 00000000000..bc3b0f2bf1f --- /dev/null +++ b/bundles/org.eclipse.remote.proxy.server.core/build.properties @@ -0,0 +1,7 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + .,\ + plugin.xml,\ + plugin.properties,\ + about.html diff --git a/bundles/org.eclipse.remote.proxy.server.core/plugin.properties b/bundles/org.eclipse.remote.proxy.server.core/plugin.properties new file mode 100644 index 00000000000..a7ad218f8f5 --- /dev/null +++ b/bundles/org.eclipse.remote.proxy.server.core/plugin.properties @@ -0,0 +1,11 @@ +############################################################################### +# Copyright (c) 2016 Oak Ridge National Laboratory 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 +# +############################################################################### + +pluginName=Remote Proxy Server Support +pluginProvider=Eclipse PTP diff --git a/bundles/org.eclipse.remote.proxy.server.core/plugin.xml b/bundles/org.eclipse.remote.proxy.server.core/plugin.xml new file mode 100644 index 00000000000..43ce2939415 --- /dev/null +++ b/bundles/org.eclipse.remote.proxy.server.core/plugin.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + diff --git a/bundles/org.eclipse.remote.proxy.server.core/pom.xml b/bundles/org.eclipse.remote.proxy.server.core/pom.xml new file mode 100644 index 00000000000..12d51837818 --- /dev/null +++ b/bundles/org.eclipse.remote.proxy.server.core/pom.xml @@ -0,0 +1,16 @@ + + + 4.0.0 + + + org.eclipse.remote + remote-parent + 3.0.0-SNAPSHOT + ../../releng/org.eclipse.remote.build/pom.xml + + + org.eclipse.remote.proxy.server.core + eclipse-plugin +1.0.0-SNAPSHOT + diff --git a/bundles/org.eclipse.remote.proxy.server.core/src/org/eclipse/remote/internal/proxy/server/core/Application.java b/bundles/org.eclipse.remote.proxy.server.core/src/org/eclipse/remote/internal/proxy/server/core/Application.java new file mode 100644 index 00000000000..0ad311029cd --- /dev/null +++ b/bundles/org.eclipse.remote.proxy.server.core/src/org/eclipse/remote/internal/proxy/server/core/Application.java @@ -0,0 +1,45 @@ +/******************************************************************************* + * Copyright (c) 2016 Oak Ridge National Laboratory 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 + *******************************************************************************/ +package org.eclipse.remote.internal.proxy.server.core; + +import java.nio.ByteBuffer; + +import org.eclipse.equinox.app.IApplication; +import org.eclipse.equinox.app.IApplicationContext; +import org.eclipse.remote.proxy.protocol.core.Protocol; + +/** + * This class controls all aspects of the application's execution + */ +public class Application implements IApplication { + private Server server = new Server(); + + /* (non-Javadoc) + * @see org.eclipse.equinox.app.IApplication#start(org.eclipse.equinox.app.IApplicationContext) + */ + public Object start(IApplicationContext context) throws Exception { + String[] args = (String[])context.getArguments().get(IApplicationContext.APPLICATION_ARGS); + for (String arg : args) { + if (arg.equals("-magic")) { //$NON-NLS-1$ + ByteBuffer b = ByteBuffer.allocate(4); + b.putInt(Protocol.MAGIC); + System.out.write(b.array()); + }; + } + server.start(); + server.waitFor(); + return IApplication.EXIT_OK; + } + + /* (non-Javadoc) + * @see org.eclipse.equinox.app.IApplication#stop() + */ + public void stop() { + // Nothing + } +} diff --git a/bundles/org.eclipse.remote.proxy.server.core/src/org/eclipse/remote/internal/proxy/server/core/CommandServer.java b/bundles/org.eclipse.remote.proxy.server.core/src/org/eclipse/remote/internal/proxy/server/core/CommandServer.java new file mode 100644 index 00000000000..e600a47c471 --- /dev/null +++ b/bundles/org.eclipse.remote.proxy.server.core/src/org/eclipse/remote/internal/proxy/server/core/CommandServer.java @@ -0,0 +1,291 @@ +/******************************************************************************* + * Copyright (c) 2016 Oak Ridge National Laboratory 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 + *******************************************************************************/ +package org.eclipse.remote.internal.proxy.server.core; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.EOFException; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.eclipse.remote.internal.proxy.server.core.commands.AbstractServerCommand; +import org.eclipse.remote.internal.proxy.server.core.commands.ServerChildInfosCommand; +import org.eclipse.remote.internal.proxy.server.core.commands.ServerDeleteCommand; +import org.eclipse.remote.internal.proxy.server.core.commands.ServerExecCommand; +import org.eclipse.remote.internal.proxy.server.core.commands.ServerFetchInfoCommand; +import org.eclipse.remote.internal.proxy.server.core.commands.ServerGetCwdCommand; +import org.eclipse.remote.internal.proxy.server.core.commands.ServerGetEnvCommand; +import org.eclipse.remote.internal.proxy.server.core.commands.ServerGetInputStreamCommand; +import org.eclipse.remote.internal.proxy.server.core.commands.ServerGetOutputStreamCommand; +import org.eclipse.remote.internal.proxy.server.core.commands.ServerGetPropertiesCommand; +import org.eclipse.remote.internal.proxy.server.core.commands.ServerMkdirCommand; +import org.eclipse.remote.internal.proxy.server.core.commands.ServerPutInfoCommand; +import org.eclipse.remote.internal.proxy.server.core.commands.ServerShellCommand; +import org.eclipse.remote.proxy.protocol.core.Protocol; +import org.eclipse.remote.proxy.protocol.core.SerializableFileInfo; +import org.eclipse.remote.proxy.protocol.core.StreamChannel; +import org.eclipse.remote.proxy.protocol.core.exceptions.ProxyException; + +public class CommandServer implements Runnable { + private Server server; + private DataInputStream cmdIn; + private DataOutputStream cmdOut; + private boolean running = true; + private StreamChannel chan; + + public CommandServer(StreamChannel chan, Server server) { + this.chan = chan; + this.server = server; + this.cmdIn = new DataInputStream(chan.getInputStream()); + this.cmdOut = new DataOutputStream(chan.getOutputStream()); + } + + public void run() { + new Thread("cmd reader") { //$NON-NLS-1$ + @Override + public void run() { + try { + while (running) { + byte proto = cmdIn.readByte(); + switch (proto) { + case Protocol.PROTO_COMMAND: + try { + dispatchCommand(cmdIn); + sendOKResult(); + } catch (ProxyException e) { + sendErrorResult(e.getMessage()); + } + break; + + case Protocol.PROTO_SHUTDOWN: + running = false; + break; + + default: + System.err.println("Invalid protocol ID: " + proto); + break; + } + } + } catch (EOFException e) { + // Exit server + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } finally { + running = false; + } + } + }.start(); + } + + private void sendOKResult() throws IOException { + cmdOut.writeByte(Protocol.PROTO_OK); + cmdOut.flush(); + } + + private void sendErrorResult(String error) throws IOException { + cmdOut.writeByte(Protocol.PROTO_ERROR); + cmdOut.writeUTF(error); + cmdOut.flush(); + } + + + /** + * TODO replace with dynamic dispatcher + */ + private void dispatchCommand(DataInputStream in) throws ProxyException, IOException { + AbstractServerCommand serverCmd; + + short cmd = in.readShort(); + switch (cmd) { + case Protocol.CMD_CHILDINFOS: + serverCmd = cmdChildInfos(in); + break; + + case Protocol.CMD_DELETE: + serverCmd = cmdDelete(in); + break; + + case Protocol.CMD_EXEC: + serverCmd = cmdExec(in); + break; + + case Protocol.CMD_SHELL: + serverCmd = cmdShell(in); + break; + + case Protocol.CMD_FETCHINFO: + serverCmd = cmdFetchInfo(in); + break; + + case Protocol.CMD_GETCWD: + serverCmd = cmdGetCwd(in); + break; + + case Protocol.CMD_GETENV: + serverCmd = cmdGetEnv(in); + break; + + case Protocol.CMD_GETINPUTSTREAM: + serverCmd = cmdGetInputStream(in); + break; + + case Protocol.CMD_GETOUTPUTSTREAM: + serverCmd = cmdGetOutputStream(in); + break; + + case Protocol.CMD_GETPROPERTIES: + serverCmd = cmdGetProperties(in); + break; + + case Protocol.CMD_MKDIR: + serverCmd = cmdMkdir(in); + break; + + case Protocol.CMD_PUTINFO: + serverCmd = cmdPutInfo(in); + break; + + default: + System.err.println("Invalid command ID: " + cmd); + throw new ProxyException("Invalid command ID: " + cmd); //$NON-NLS-1$ + } + + serverCmd.exec(); + } + + private AbstractServerCommand cmdExec(DataInputStream in) throws ProxyException, IOException { + int cmdChanId = in.readByte(); + int ioChanId = in.readByte(); + int errChanId = in.readByte(); + int length = in.readInt(); + List command = new ArrayList(length); + for (int i = 0; i < length; i++) { + command.add(in.readUTF()); + } + length = in.readInt(); + Map env = new HashMap(length); + for (int i = 0; i < length; i++) { + String key = in.readUTF(); + String val = in.readUTF(); + env.put(key, val); + } + String dir = in.readUTF(); + boolean redirect = in.readBoolean(); + boolean appendEnv = in.readBoolean(); + StreamChannel cmdChan = server.getChannel(cmdChanId); + StreamChannel ioChan = server.getChannel(ioChanId); + StreamChannel errChan= server.getChannel(errChanId); + if (cmdChan == null || ioChan == null || errChan == null) { + throw new ProxyException("Unable to locate channels for command"); //$NON-NLS-1$ + } + return new ServerExecCommand(command, env, dir, redirect, appendEnv, cmdChan, ioChan, errChan); + } + + private AbstractServerCommand cmdShell(DataInputStream in) throws ProxyException, IOException { + int cmdChanId = in.readByte(); + int ioChanId = in.readByte(); + StreamChannel cmdChan = server.getChannel(cmdChanId); + StreamChannel ioChan = server.getChannel(ioChanId); + if (cmdChan == null || ioChan == null) { + throw new ProxyException("Unable to locate channels for command"); //$NON-NLS-1$ + } + return new ServerShellCommand(cmdChan, ioChan); + } + private AbstractServerCommand cmdGetCwd(DataInputStream in) throws ProxyException, IOException { + int chanId = in.readByte(); + StreamChannel chan = server.getChannel(chanId); + if (chan == null) { + throw new ProxyException("Unable to locate channel for command"); //$NON-NLS-1$ + } + return new ServerGetCwdCommand(chan); + } + + private AbstractServerCommand cmdGetEnv(DataInputStream in) throws ProxyException, IOException { + int chanId = in.readByte(); + StreamChannel chan = server.getChannel(chanId); + if (chan == null) { + throw new ProxyException("Unable to locate channel for command"); //$NON-NLS-1$ + } + return new ServerGetEnvCommand(chan); + } + + private AbstractServerCommand cmdGetProperties(DataInputStream in) throws ProxyException, IOException { + int chanId = in.readByte(); + StreamChannel chan = server.getChannel(chanId); + if (chan == null) { + throw new ProxyException("Unable to locate channel for command"); //$NON-NLS-1$ + } + return new ServerGetPropertiesCommand(chan); + } + + private AbstractServerCommand cmdChildInfos(DataInputStream in) throws ProxyException, IOException { + int chanId = in.readByte(); + StreamChannel chan = server.getChannel(chanId); + if (chan == null) { + throw new ProxyException("Unable to locate channel for command"); //$NON-NLS-1$ + } + String path = in.readUTF(); + return new ServerChildInfosCommand(chan, path); + } + + private AbstractServerCommand cmdFetchInfo(DataInputStream in) throws ProxyException, IOException { + int chanId = in.readByte(); + StreamChannel chan = server.getChannel(chanId); + if (chan == null) { + throw new ProxyException("Unable to locate channel for command"); //$NON-NLS-1$ + } + String path = in.readUTF(); + return new ServerFetchInfoCommand(chan, path); + } + + private AbstractServerCommand cmdGetInputStream(DataInputStream in) throws ProxyException, IOException { + int chanId = in.readByte(); + StreamChannel chan = server.getChannel(chanId); + if (chan == null) { + throw new ProxyException("Unable to locate channel for command"); //$NON-NLS-1$ + } + int options = in.readInt(); + String path = in.readUTF(); + return new ServerGetInputStreamCommand(chan, options, path); + } + + private AbstractServerCommand cmdGetOutputStream(DataInputStream in) throws ProxyException, IOException { + int chanId = in.readByte(); + StreamChannel chan = server.getChannel(chanId); + if (chan == null) { + throw new ProxyException("Unable to locate channel for command"); //$NON-NLS-1$ + } + int options = in.readInt(); + String path = in.readUTF(); + return new ServerGetOutputStreamCommand(chan, options, path); + } + + private AbstractServerCommand cmdDelete(DataInputStream in) throws ProxyException, IOException { + int options = in.readInt(); + String path = in.readUTF(); + return new ServerDeleteCommand(options, path); + } + + private AbstractServerCommand cmdMkdir(DataInputStream in) throws ProxyException, IOException { + int options = in.readInt(); + String path = in.readUTF(); + return new ServerMkdirCommand(options, path); + } + + private AbstractServerCommand cmdPutInfo(DataInputStream in) throws ProxyException, IOException { + int options = in.readInt(); + String path = in.readUTF(); + SerializableFileInfo info = new SerializableFileInfo(); + info.readObject(in); + return new ServerPutInfoCommand(info.getIFileInfo(), options, path); + } +} diff --git a/bundles/org.eclipse.remote.proxy.server.core/src/org/eclipse/remote/internal/proxy/server/core/Server.java b/bundles/org.eclipse.remote.proxy.server.core/src/org/eclipse/remote/internal/proxy/server/core/Server.java new file mode 100644 index 00000000000..19fbdbea4b3 --- /dev/null +++ b/bundles/org.eclipse.remote.proxy.server.core/src/org/eclipse/remote/internal/proxy/server/core/Server.java @@ -0,0 +1,76 @@ +/******************************************************************************* + * Copyright (c) 2016 Oak Ridge National Laboratory 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 + *******************************************************************************/ +package org.eclipse.remote.internal.proxy.server.core; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.remote.proxy.protocol.core.StreamChannelManager; +import org.eclipse.remote.proxy.protocol.core.StreamChannelManager.IChannelListener; +import org.eclipse.remote.proxy.protocol.core.StreamChannel; + +public class Server { + private volatile boolean running; + private Thread serverThread; + private StreamChannel cmdChannel; + private Map auxChannel = Collections.synchronizedMap(new HashMap()); + + + public void start() { + final StreamChannelManager mux = new StreamChannelManager(System.in, System.out); + mux.setServer(true); + mux.addListener(new IChannelListener() { + + @Override + public void newChannel(StreamChannel chan) { + Runnable runnable; + System.err.println("newChannel: " + chan.getId()); + // First channel opened becomes command channel + if (cmdChannel == null) { + cmdChannel = chan; + runnable = new CommandServer(chan, Server.this); + new Thread(runnable).start(); + } else { + auxChannel.put(chan.getId(), chan); + } + } + + @Override + public void closeChannel(StreamChannel chan) { + System.err.println("closeChannel: " + chan.getId()); + auxChannel.remove(chan.getId()); + } + + }); + serverThread = new Thread(mux) { + @Override + public void run() { + running = true; + mux.run(); + running = false; + } + }; + serverThread.start(); + } + + public StreamChannel getChannel(int id) { + System.err.println("getChannel: "+id); + return auxChannel.get(id); + } + + public void waitFor() { + if (running && serverThread != null) { + try { + serverThread.join(); + } catch (InterruptedException e) { + // Ignore + } + } + } +} diff --git a/bundles/org.eclipse.remote.proxy.server.core/src/org/eclipse/remote/internal/proxy/server/core/commands/AbstractServerCommand.java b/bundles/org.eclipse.remote.proxy.server.core/src/org/eclipse/remote/internal/proxy/server/core/commands/AbstractServerCommand.java new file mode 100644 index 00000000000..c25198a9140 --- /dev/null +++ b/bundles/org.eclipse.remote.proxy.server.core/src/org/eclipse/remote/internal/proxy/server/core/commands/AbstractServerCommand.java @@ -0,0 +1,14 @@ +/******************************************************************************* + * Copyright (c) 2016 Oak Ridge National Laboratory 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 + *******************************************************************************/ +package org.eclipse.remote.internal.proxy.server.core.commands; + +import org.eclipse.remote.proxy.protocol.core.exceptions.ProxyException; + +public abstract class AbstractServerCommand { + public abstract void exec() throws ProxyException; +} diff --git a/bundles/org.eclipse.remote.proxy.server.core/src/org/eclipse/remote/internal/proxy/server/core/commands/AbstractServerExecCommand.java b/bundles/org.eclipse.remote.proxy.server.core/src/org/eclipse/remote/internal/proxy/server/core/commands/AbstractServerExecCommand.java new file mode 100644 index 00000000000..9fc61b1d259 --- /dev/null +++ b/bundles/org.eclipse.remote.proxy.server.core/src/org/eclipse/remote/internal/proxy/server/core/commands/AbstractServerExecCommand.java @@ -0,0 +1,232 @@ +/******************************************************************************* + * Copyright (c) 2016 Oak Ridge National Laboratory 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 + *******************************************************************************/ +package org.eclipse.remote.internal.proxy.server.core.commands; + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.BufferedWriter; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.util.List; +import java.util.Map; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +import org.eclipse.remote.proxy.protocol.core.Protocol; +import org.eclipse.remote.proxy.protocol.core.StreamChannel; +import org.eclipse.remote.proxy.protocol.core.exceptions.ProxyException; + +public abstract class AbstractServerExecCommand extends AbstractServerCommand { + + private class CommandRunner implements Runnable { + @Override + public void run() { + try { + int exit = 0; + try { + proc = doRun(); + Forwarder stdoutFwd = startForwarder("stdout", proc.getInputStream(), stdoutChan); //$NON-NLS-1$ + Forwarder stderrFwd = null; + if (!redirect) { + stderrFwd = startForwarder("stderr", proc.getErrorStream(), stderrChan); //$NON-NLS-1$ + } + startForwarder("stdin", stdinChan, proc.getOutputStream()); //$NON-NLS-1$ + new Thread(new ProcMonitor(), "process monitor").start(); //$NON-NLS-1$ + exit = proc.waitFor(); + /* + * After the process has finished, wait for the stdout and stderr forwarders to finish to + * ensure that all output is flushed. + */ + stdoutFwd.waitFor(); + if (stderrFwd != null) { + stderrFwd.waitFor(); + } + } catch (IOException e) { + BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(stderrChan)); + try { + writer.write(e.getMessage()); + writer.flush(); + } catch (IOException e1) { + // Things look pretty hopeless + } + exit = -1; + } + try { + resultStream.writeInt(exit); + resultStream.flush(); + } catch (IOException e) { + // We're finished anyway + } + } catch (InterruptedException e) { + // Ignore? + } + } + } + + private class ProcMonitor implements Runnable { + @Override + public void run() { + try { + switch (cmdStream.readByte()) { + case Protocol.CONTROL_KILL: + doKill(proc); + break; + case Protocol.CONTROL_SETTERMINALSIZE: + int cols = cmdStream.readInt(); + int rows = cmdStream.readInt(); + cmdStream.readInt(); // pixel dimensions not supported + cmdStream.readInt(); // pixel dimensions not supported + doSetTerminalSize(proc, cols, rows); + break; + } + } catch (IOException e) { + // Finish + } + } + } + + private class Forwarder implements Runnable { + private final InputStream in; + private final OutputStream out; + private final String name; + + private boolean running = true; + + private final Lock lock = new ReentrantLock(); + private final Condition cond = lock.newCondition(); + + public Forwarder(String name, InputStream in, OutputStream out) { + this.name = name; + this.in = new BufferedInputStream(in); + this.out = new BufferedOutputStream(out); + } + + @Override + public void run() { + byte[] buf = new byte[8192]; + int n; + try { + while (running) { + n = in.read(buf); + if (n > 0) { + out.write(buf, 0, n); + out.flush(); + } + if (n < 0) break; + } + } catch (IOException e) { + // Finish + } + + lock.lock(); + try { + running = false; + try { + out.close(); + } catch (IOException e) { + // Best effort + } + cond.signalAll(); + } finally { + lock.unlock(); + } + } + + public String getName() { + return name; + } + + public synchronized void waitFor() { + lock.lock(); + try { + while (running) { + try { + cond.await(); + } catch (InterruptedException e) { + // Check terminated flag + } + } + } finally { + lock.unlock(); + } + } + } + + private final List command; + private final Map env; + private final boolean redirect; + private final boolean appendEnv; + private final String directory; + + private final InputStream stdinChan; + private final OutputStream stdoutChan; + private final OutputStream stderrChan; + + private final DataInputStream cmdStream; + private final DataOutputStream resultStream; + + private Process proc; + + public AbstractServerExecCommand(List command, Map env, String directory, boolean redirect, boolean appendEnv, StreamChannel cmdChan, StreamChannel ioChan, StreamChannel errChan) { + this.command = command; + this.env = env; + this.directory = directory; + this.redirect = redirect; + this.appendEnv = appendEnv; + + this.stdinChan = ioChan.getInputStream(); + this.stdoutChan = ioChan.getOutputStream(); + + this.stderrChan = errChan != null ? errChan.getOutputStream() : this.stdoutChan; + + this.resultStream = new DataOutputStream(cmdChan.getOutputStream()); + this.cmdStream = new DataInputStream(cmdChan.getInputStream()); + } + + protected abstract Process doRun() throws IOException; + + protected abstract void doKill(Process proc); + + protected abstract void doSetTerminalSize(Process proc, int col, int rows); + + protected List getCommand() { + return command; + } + + protected Map getEnv() { + return env; + } + + protected boolean isRedirect() { + return redirect; + } + + protected boolean isAppendEnv() { + return appendEnv; + } + + protected String getDirectory() { + return directory; + } + + public void exec() throws ProxyException { + new Thread(new CommandRunner()).start(); + } + + private Forwarder startForwarder(String name, InputStream in, OutputStream out) { + Forwarder forwarder = new Forwarder(name, in, out); + Thread thread = new Thread(forwarder, forwarder.getName()); + thread.start(); + return forwarder; + } +} diff --git a/bundles/org.eclipse.remote.proxy.server.core/src/org/eclipse/remote/internal/proxy/server/core/commands/ServerChildInfosCommand.java b/bundles/org.eclipse.remote.proxy.server.core/src/org/eclipse/remote/internal/proxy/server/core/commands/ServerChildInfosCommand.java new file mode 100644 index 00000000000..7f471e1da34 --- /dev/null +++ b/bundles/org.eclipse.remote.proxy.server.core/src/org/eclipse/remote/internal/proxy/server/core/commands/ServerChildInfosCommand.java @@ -0,0 +1,59 @@ +/******************************************************************************* + * Copyright (c) 2016 Oak Ridge National Laboratory 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 + *******************************************************************************/ +package org.eclipse.remote.internal.proxy.server.core.commands; + +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.net.URI; + +import org.eclipse.core.filesystem.EFS; +import org.eclipse.core.filesystem.IFileInfo; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.remote.proxy.protocol.core.SerializableFileInfo; +import org.eclipse.remote.proxy.protocol.core.StreamChannel; +import org.eclipse.remote.proxy.protocol.core.exceptions.ProxyException; + +public class ServerChildInfosCommand extends AbstractServerCommand { + private IFileInfo[] infos; + + private final URI uri; + private final OutputStream out; + + private class CommandRunner implements Runnable { + @Override + public void run() { + try { + DataOutputStream result = new DataOutputStream(out); + result.writeInt(infos.length); + for (int i = 0; i < infos.length; i++) { + SerializableFileInfo sInfo = new SerializableFileInfo(infos[i]); + sInfo.writeObject(result); + } + result.flush(); + } catch (IOException e) { + // Failed + e.printStackTrace(); + } + } + } + + public ServerChildInfosCommand(StreamChannel chan, String path) { + this.out = chan.getOutputStream(); + this.uri = URI.create("file:" + path); //$NON-NLS-1$ + } + + public void exec() throws ProxyException { + try { + infos = EFS.getStore(uri).childInfos(EFS.NONE, null); + } catch (CoreException e) { + throw new ProxyException(e.getMessage()); + } + new Thread(new CommandRunner()).start(); + } +} diff --git a/bundles/org.eclipse.remote.proxy.server.core/src/org/eclipse/remote/internal/proxy/server/core/commands/ServerDeleteCommand.java b/bundles/org.eclipse.remote.proxy.server.core/src/org/eclipse/remote/internal/proxy/server/core/commands/ServerDeleteCommand.java new file mode 100644 index 00000000000..a259e779187 --- /dev/null +++ b/bundles/org.eclipse.remote.proxy.server.core/src/org/eclipse/remote/internal/proxy/server/core/commands/ServerDeleteCommand.java @@ -0,0 +1,33 @@ +/******************************************************************************* + * Copyright (c) 2016 Oak Ridge National Laboratory 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 + *******************************************************************************/ +package org.eclipse.remote.internal.proxy.server.core.commands; + +import java.net.URI; + +import org.eclipse.core.filesystem.EFS; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.remote.proxy.protocol.core.exceptions.ProxyException; + +public class ServerDeleteCommand extends AbstractServerCommand { + private final int options; + private final URI uri; + + public ServerDeleteCommand(int options, String path) { + this.options = options; + this.uri = URI.create("file:" + path); //$NON-NLS-1$ + } + + public void exec() throws ProxyException { + try { + EFS.getStore(uri).delete(options, new NullProgressMonitor()); + } catch (CoreException e) { + throw new ProxyException(e.getMessage()); + } + } +} diff --git a/bundles/org.eclipse.remote.proxy.server.core/src/org/eclipse/remote/internal/proxy/server/core/commands/ServerExecCommand.java b/bundles/org.eclipse.remote.proxy.server.core/src/org/eclipse/remote/internal/proxy/server/core/commands/ServerExecCommand.java new file mode 100644 index 00000000000..f56a64188a6 --- /dev/null +++ b/bundles/org.eclipse.remote.proxy.server.core/src/org/eclipse/remote/internal/proxy/server/core/commands/ServerExecCommand.java @@ -0,0 +1,65 @@ +/******************************************************************************* + * Copyright (c) 2016 Oak Ridge National Laboratory 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 + *******************************************************************************/ +package org.eclipse.remote.internal.proxy.server.core.commands; + +import java.io.File; +import java.io.IOException; +import java.util.List; +import java.util.Map; + +import org.eclipse.remote.proxy.protocol.core.StreamChannel; + +/** + * TODO: Fix hang if command fails... + * + */ +public class ServerExecCommand extends AbstractServerExecCommand { + public Process doRun() throws IOException { + System.err.print("exec: "); + for (String arg:getCommand()) { + System.err.print(arg + " "); + } + System.err.println(); + ProcessBuilder builder = new ProcessBuilder(getCommand()); + try { + if (!isAppendEnv()) { + builder.environment().clear(); + builder.environment().putAll(getEnv()); + } else { + for (Map.Entry entry : getEnv().entrySet()) { + String val = builder.environment().get(entry.getKey()); + if (val == null || !val.equals(entry.getValue())) { + builder.environment().put(entry.getKey(), entry.getValue()); + } + } + } + } catch (UnsupportedOperationException | IllegalArgumentException e) { + // Leave environment untouched + } + File dir = new File(getDirectory()); + if (dir.exists() && dir.isAbsolute()) { + builder.directory(dir); + } + builder.redirectErrorStream(isRedirect()); + return builder.start(); + } + + protected void doKill(Process proc) { + if (proc.isAlive()) { + proc.destroyForcibly(); + } + } + + protected void doSetTerminalSize(Process proc, int cols, int rows) { + // Not supported + } + + public ServerExecCommand(List command, Map env, String directory, boolean redirect, boolean appendEnv, StreamChannel cmdChan, StreamChannel ioChan, StreamChannel errChan) { + super(command, env, directory, redirect, appendEnv, cmdChan, ioChan, errChan); + } +} diff --git a/bundles/org.eclipse.remote.proxy.server.core/src/org/eclipse/remote/internal/proxy/server/core/commands/ServerFetchInfoCommand.java b/bundles/org.eclipse.remote.proxy.server.core/src/org/eclipse/remote/internal/proxy/server/core/commands/ServerFetchInfoCommand.java new file mode 100644 index 00000000000..d03b01626a1 --- /dev/null +++ b/bundles/org.eclipse.remote.proxy.server.core/src/org/eclipse/remote/internal/proxy/server/core/commands/ServerFetchInfoCommand.java @@ -0,0 +1,56 @@ +/******************************************************************************* + * Copyright (c) 2016 Oak Ridge National Laboratory 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 + *******************************************************************************/ +package org.eclipse.remote.internal.proxy.server.core.commands; + +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.net.URI; + +import org.eclipse.core.filesystem.EFS; +import org.eclipse.core.filesystem.IFileInfo; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.remote.proxy.protocol.core.SerializableFileInfo; +import org.eclipse.remote.proxy.protocol.core.StreamChannel; +import org.eclipse.remote.proxy.protocol.core.exceptions.ProxyException; + +public class ServerFetchInfoCommand extends AbstractServerCommand { + private IFileInfo info; + + private final URI uri; + private final OutputStream out; + + private class CommandRunner implements Runnable { + @Override + public void run() { + try { + DataOutputStream result = new DataOutputStream(out); + SerializableFileInfo sInfo = new SerializableFileInfo(info); + sInfo.writeObject(result); + result.flush(); + } catch (IOException e) { + // Failed + e.printStackTrace(); + } + } + } + + public ServerFetchInfoCommand(StreamChannel chan, String path) { + this.out = chan.getOutputStream(); + this.uri = URI.create("file:" + path); //$NON-NLS-1$ + } + + public void exec() throws ProxyException { + try { + info = EFS.getStore(uri).fetchInfo(); + } catch (CoreException e) { + throw new ProxyException(e.getMessage()); + } + new Thread(new CommandRunner()).start(); + } +} diff --git a/bundles/org.eclipse.remote.proxy.server.core/src/org/eclipse/remote/internal/proxy/server/core/commands/ServerGetCwdCommand.java b/bundles/org.eclipse.remote.proxy.server.core/src/org/eclipse/remote/internal/proxy/server/core/commands/ServerGetCwdCommand.java new file mode 100644 index 00000000000..9bc2a5f4d2d --- /dev/null +++ b/bundles/org.eclipse.remote.proxy.server.core/src/org/eclipse/remote/internal/proxy/server/core/commands/ServerGetCwdCommand.java @@ -0,0 +1,41 @@ +/******************************************************************************* + * Copyright (c) 2016 Oak Ridge National Laboratory 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 + *******************************************************************************/ +package org.eclipse.remote.internal.proxy.server.core.commands; + +import java.io.DataOutputStream; +import java.io.IOException; + +import org.eclipse.remote.proxy.protocol.core.StreamChannel; +import org.eclipse.remote.proxy.protocol.core.exceptions.ProxyException; + +public class ServerGetCwdCommand extends AbstractServerCommand { + + private String cwd; + private final DataOutputStream result; + + private class CommandRunner implements Runnable { + @Override + public void run() { + try { + result.writeUTF(cwd); + result.flush(); + } catch (IOException e) { + // Failed + } + } + } + + public ServerGetCwdCommand(StreamChannel chan) { + this.result = new DataOutputStream(chan.getOutputStream()); + } + + public void exec() throws ProxyException { + cwd = System.getProperty("user.dir"); //$NON-NLS-1$ + new Thread(new CommandRunner()).start(); + } +} diff --git a/bundles/org.eclipse.remote.proxy.server.core/src/org/eclipse/remote/internal/proxy/server/core/commands/ServerGetEnvCommand.java b/bundles/org.eclipse.remote.proxy.server.core/src/org/eclipse/remote/internal/proxy/server/core/commands/ServerGetEnvCommand.java new file mode 100644 index 00000000000..624911024e7 --- /dev/null +++ b/bundles/org.eclipse.remote.proxy.server.core/src/org/eclipse/remote/internal/proxy/server/core/commands/ServerGetEnvCommand.java @@ -0,0 +1,45 @@ +/******************************************************************************* + * Copyright (c) 2016 Oak Ridge National Laboratory 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 + *******************************************************************************/ +package org.eclipse.remote.internal.proxy.server.core.commands; + +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.Map; + +import org.eclipse.remote.proxy.protocol.core.StreamChannel; +import org.eclipse.remote.proxy.protocol.core.exceptions.ProxyException; + +public class ServerGetEnvCommand extends AbstractServerCommand { + + private final DataOutputStream result; + + private class CommandRunner implements Runnable { + @Override + public void run() { + try { + Map env = System.getenv(); + result.writeInt(env.size()); + for (Map.Entry entry : env.entrySet()) { + result.writeUTF(entry.getKey()); + result.writeUTF(entry.getValue()); + } + result.flush(); + } catch (IOException e) { + // Failed + } + } + } + + public ServerGetEnvCommand(StreamChannel chan) { + this.result = new DataOutputStream(chan.getOutputStream()); + } + + public void exec() throws ProxyException { + new Thread(new CommandRunner()).start(); + } +} diff --git a/bundles/org.eclipse.remote.proxy.server.core/src/org/eclipse/remote/internal/proxy/server/core/commands/ServerGetInputStreamCommand.java b/bundles/org.eclipse.remote.proxy.server.core/src/org/eclipse/remote/internal/proxy/server/core/commands/ServerGetInputStreamCommand.java new file mode 100644 index 00000000000..6fb283553c0 --- /dev/null +++ b/bundles/org.eclipse.remote.proxy.server.core/src/org/eclipse/remote/internal/proxy/server/core/commands/ServerGetInputStreamCommand.java @@ -0,0 +1,86 @@ +/******************************************************************************* + * Copyright (c) 2016 Oak Ridge National Laboratory 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 + *******************************************************************************/ +package org.eclipse.remote.internal.proxy.server.core.commands; + +import java.io.BufferedInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.URI; + +import org.eclipse.core.filesystem.EFS; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.remote.proxy.protocol.core.StreamChannel; +import org.eclipse.remote.proxy.protocol.core.exceptions.ProxyException; + +/** + * TODO: Fix hang if command fails... + * + */ +public class ServerGetInputStreamCommand extends AbstractServerCommand { + + private final OutputStream out; + private final URI uri; + private final int options; + + private class Forwarder implements Runnable { + private final InputStream in; + private final OutputStream out; + + public Forwarder(InputStream in, OutputStream out) { + this.in = in; + this.out = out; + } + + @Override + public void run() { + byte[] buf = new byte[8192]; + int n; + try { + while ((n = in.read(buf)) >= 0) { + if (n > 0) { + out.write(buf, 0, n); // should block if no-one is reading + out.flush(); + } + } + } catch (IOException e) { + // Finish + } + try { + out.close(); + } catch (IOException e) { + // Ignore + } + try { + in.close(); + } catch (IOException e) { + // Ignore + } + } + } + + public ServerGetInputStreamCommand(StreamChannel chan, int options, String path) { + this.out = chan.getOutputStream(); + this.options = options; + this.uri = URI.create("file:" + path); //$NON-NLS-1$ + } + + public void exec() throws ProxyException { + try { + InputStream in = new BufferedInputStream(EFS.getStore(uri).openInputStream(options, new NullProgressMonitor())); + startForwarder(in, out); + } catch (Exception e) { + throw new ProxyException(e.getMessage()); + } + } + + private void startForwarder(InputStream in, OutputStream out) { + Forwarder forwarder = new Forwarder(in, out); + new Thread(forwarder).start(); + } +} diff --git a/bundles/org.eclipse.remote.proxy.server.core/src/org/eclipse/remote/internal/proxy/server/core/commands/ServerGetOutputStreamCommand.java b/bundles/org.eclipse.remote.proxy.server.core/src/org/eclipse/remote/internal/proxy/server/core/commands/ServerGetOutputStreamCommand.java new file mode 100644 index 00000000000..ab2517e58ee --- /dev/null +++ b/bundles/org.eclipse.remote.proxy.server.core/src/org/eclipse/remote/internal/proxy/server/core/commands/ServerGetOutputStreamCommand.java @@ -0,0 +1,87 @@ +/******************************************************************************* + * Copyright (c) 2016 Oak Ridge National Laboratory 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 + *******************************************************************************/ +package org.eclipse.remote.internal.proxy.server.core.commands; + +import java.io.BufferedOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.URI; + +import org.eclipse.core.filesystem.EFS; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.remote.proxy.protocol.core.StreamChannel; +import org.eclipse.remote.proxy.protocol.core.exceptions.ProxyException; + +/** + * TODO: Fix hang if command fails... + * + */ +public class ServerGetOutputStreamCommand extends AbstractServerCommand { + + private final InputStream in; + private final URI uri; + private final int options; + + private class Forwarder implements Runnable { + private final InputStream in; + private final OutputStream out; + + public Forwarder(InputStream in, OutputStream out) { + this.in = in; + this.out = out; + } + + @Override + public void run() { + byte[] buf = new byte[8192]; + int n; + try { + while ((n = in.read(buf)) >= 0) { + if (n > 0) { + out.write(buf, 0, n); // should block if no-one is reading + } + } + out.flush(); + } catch (IOException e) { + // Finish + } + try { + out.close(); + } catch (IOException e) { + // Ignore + } + try { + in.close(); + } catch (IOException e) { + // Ignore + } + } + } + + public ServerGetOutputStreamCommand(StreamChannel chan, int options, String path) { + this.in = chan.getInputStream(); + this.options = options; + this.uri = URI.create("file:" + path); //$NON-NLS-1$ + } + + public void exec() throws ProxyException { + try { + OutputStream out = new BufferedOutputStream(EFS.getStore(uri).openOutputStream(options, new NullProgressMonitor())); + startForwarder(in, out); + } catch (CoreException e) { + throw new ProxyException(e.getMessage()); + } + } + + private void startForwarder(InputStream in, OutputStream out) { + Forwarder forwarder = new Forwarder(in, out); + new Thread(forwarder).start(); + } +} diff --git a/bundles/org.eclipse.remote.proxy.server.core/src/org/eclipse/remote/internal/proxy/server/core/commands/ServerGetPropertiesCommand.java b/bundles/org.eclipse.remote.proxy.server.core/src/org/eclipse/remote/internal/proxy/server/core/commands/ServerGetPropertiesCommand.java new file mode 100644 index 00000000000..dab727e0123 --- /dev/null +++ b/bundles/org.eclipse.remote.proxy.server.core/src/org/eclipse/remote/internal/proxy/server/core/commands/ServerGetPropertiesCommand.java @@ -0,0 +1,56 @@ +/******************************************************************************* + * Copyright (c) 2016 Oak Ridge National Laboratory 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 + *******************************************************************************/ +package org.eclipse.remote.internal.proxy.server.core.commands; + +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.remote.core.IRemoteConnection; +import org.eclipse.remote.proxy.protocol.core.StreamChannel; +import org.eclipse.remote.proxy.protocol.core.exceptions.ProxyException; + +public class ServerGetPropertiesCommand extends AbstractServerCommand { + + private final DataOutputStream result; + + private class CommandRunner implements Runnable { + @Override + public void run() { + try { + Map props = new HashMap(); + props.put(IRemoteConnection.FILE_SEPARATOR_PROPERTY, System.getProperty(IRemoteConnection.FILE_SEPARATOR_PROPERTY)); + props.put(IRemoteConnection.PATH_SEPARATOR_PROPERTY, System.getProperty(IRemoteConnection.PATH_SEPARATOR_PROPERTY)); + props.put(IRemoteConnection.LINE_SEPARATOR_PROPERTY, System.getProperty(IRemoteConnection.LINE_SEPARATOR_PROPERTY)); + props.put(IRemoteConnection.USER_HOME_PROPERTY, System.getProperty(IRemoteConnection.USER_HOME_PROPERTY)); + props.put(IRemoteConnection.OS_NAME_PROPERTY, System.getProperty(IRemoteConnection.OS_NAME_PROPERTY)); + props.put(IRemoteConnection.OS_VERSION_PROPERTY, System.getProperty(IRemoteConnection.OS_VERSION_PROPERTY)); + props.put(IRemoteConnection.OS_ARCH_PROPERTY, System.getProperty(IRemoteConnection.OS_ARCH_PROPERTY)); + props.put(IRemoteConnection.LOCALE_CHARMAP_PROPERTY, System.getProperty("file.encoding")); //$NON-NLS-1$ + + result.writeInt(props.size()); + for (Map.Entry entry : props.entrySet()) { + result.writeUTF(entry.getKey()); + result.writeUTF(entry.getValue()); + } + result.flush(); + } catch (IOException e) { + // Failed + } + } + } + + public ServerGetPropertiesCommand(StreamChannel chan) { + this.result = new DataOutputStream(chan.getOutputStream()); + } + + public void exec() throws ProxyException { + new Thread(new CommandRunner()).start(); + } +} diff --git a/bundles/org.eclipse.remote.proxy.server.core/src/org/eclipse/remote/internal/proxy/server/core/commands/ServerMkdirCommand.java b/bundles/org.eclipse.remote.proxy.server.core/src/org/eclipse/remote/internal/proxy/server/core/commands/ServerMkdirCommand.java new file mode 100644 index 00000000000..cb3ddb43e6a --- /dev/null +++ b/bundles/org.eclipse.remote.proxy.server.core/src/org/eclipse/remote/internal/proxy/server/core/commands/ServerMkdirCommand.java @@ -0,0 +1,33 @@ +/******************************************************************************* + * Copyright (c) 2016 Oak Ridge National Laboratory 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 + *******************************************************************************/ +package org.eclipse.remote.internal.proxy.server.core.commands; + +import java.net.URI; + +import org.eclipse.core.filesystem.EFS; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.remote.proxy.protocol.core.exceptions.ProxyException; + +public class ServerMkdirCommand extends AbstractServerCommand { + private final int options; + private final URI uri; + + public ServerMkdirCommand(int options, String path) { + this.options = options; + this.uri = URI.create("file:" + path); //$NON-NLS-1$ + } + + public void exec() throws ProxyException { + try { + EFS.getStore(uri).mkdir(options, new NullProgressMonitor()); + } catch (CoreException e) { + throw new ProxyException(e.getMessage()); + } + } +} diff --git a/bundles/org.eclipse.remote.proxy.server.core/src/org/eclipse/remote/internal/proxy/server/core/commands/ServerPutInfoCommand.java b/bundles/org.eclipse.remote.proxy.server.core/src/org/eclipse/remote/internal/proxy/server/core/commands/ServerPutInfoCommand.java new file mode 100644 index 00000000000..61d2abfde37 --- /dev/null +++ b/bundles/org.eclipse.remote.proxy.server.core/src/org/eclipse/remote/internal/proxy/server/core/commands/ServerPutInfoCommand.java @@ -0,0 +1,36 @@ +/******************************************************************************* + * Copyright (c) 2016 Oak Ridge National Laboratory 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 + *******************************************************************************/ +package org.eclipse.remote.internal.proxy.server.core.commands; + +import java.net.URI; + +import org.eclipse.core.filesystem.EFS; +import org.eclipse.core.filesystem.IFileInfo; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.remote.proxy.protocol.core.exceptions.ProxyException; + +public class ServerPutInfoCommand extends AbstractServerCommand { + private final IFileInfo info; + private final int options; + private final URI uri; + + public ServerPutInfoCommand(IFileInfo info, int options, String path) { + this.info = info; + this.options = options; + this.uri = URI.create("file:" + path); //$NON-NLS-1$ + } + + public void exec() throws ProxyException { + try { + EFS.getStore(uri).putInfo(info, options, new NullProgressMonitor());; + } catch (CoreException e) { + throw new ProxyException(e.getMessage()); + } + } +} diff --git a/bundles/org.eclipse.remote.proxy.server.core/src/org/eclipse/remote/internal/proxy/server/core/commands/ServerShellCommand.java b/bundles/org.eclipse.remote.proxy.server.core/src/org/eclipse/remote/internal/proxy/server/core/commands/ServerShellCommand.java new file mode 100644 index 00000000000..74545c63f7f --- /dev/null +++ b/bundles/org.eclipse.remote.proxy.server.core/src/org/eclipse/remote/internal/proxy/server/core/commands/ServerShellCommand.java @@ -0,0 +1,178 @@ +/******************************************************************************* + * Copyright (c) 2016 Oak Ridge National Laboratory 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 + *******************************************************************************/ +package org.eclipse.remote.internal.proxy.server.core.commands; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; + +import org.eclipse.cdt.utils.pty.PTY; +import org.eclipse.cdt.utils.pty.PTY.Mode; +import org.eclipse.cdt.utils.spawner.ProcessFactory; +import org.eclipse.remote.proxy.protocol.core.StreamChannel; + +/** + * TODO: Fix hang if command fails... + * + */ +public class ServerShellCommand extends AbstractServerExecCommand { + private class ShellProcess extends Process { + private final Process proc; + private final PTY pty; + + public ShellProcess(Process proc, PTY pty) { + this.proc = proc; + this.pty = pty; + } + + @Override + public OutputStream getOutputStream() { + if (pty != null) { + return pty.getOutputStream(); + } + return proc.getOutputStream(); + } + + @Override + public InputStream getInputStream() { + if (pty != null) { + return pty.getInputStream(); + } + return proc.getInputStream(); + } + + @Override + public InputStream getErrorStream() { + if (pty != null) { + return pty.getInputStream(); + } + return proc.getErrorStream(); + } + + @Override + public int waitFor() throws InterruptedException { + return proc.waitFor(); + } + + @Override + public int exitValue() { + return proc.exitValue(); + } + + @Override + public void destroy() { + proc.destroy(); + } + + public void setTerminalSize(int cols, int rows) { + if (pty != null) { + pty.setTerminalSize(cols, rows); + } + } + } + + public ServerShellCommand(StreamChannel cmdChan, StreamChannel ioChan) { + super(null, null, null, true, false, cmdChan, ioChan, null); + } + + public Process doRun() throws IOException { + String shell = findLoginShell(); + + if (PTY.isSupported(Mode.TERMINAL)) { + PTY pty = new PTY(Mode.TERMINAL); + Process p = ProcessFactory.getFactory().exec(new String[] {shell, "-l"}, null, null, pty); //$NON-NLS-1$ + return new ShellProcess(p, pty); + } + + return ProcessFactory.getFactory().exec(new String[] {shell, "-l"}, null, null); //$NON-NLS-1$ + } + + protected void doKill(Process proc) { + if (proc.isAlive()) { + proc.destroyForcibly(); + } + } + + protected void doSetTerminalSize(Process proc, int cols, int rows) { + if (proc.isAlive() && proc instanceof ShellProcess) { + ShellProcess shell = (ShellProcess)proc; + shell.setTerminalSize(cols, rows); + } + } + + /** + * Find the login shell. + * + * On Linux, use `getent passwd $USER` + * On Mac OSX, use `dscl . -read /Users/$USER UserShell` + * + * @return + */ + private String findLoginShell() throws IOException { + String res; + + String osName = System.getProperty("os.name"); //$NON-NLS-1$ + String userName = System.getProperty("user.name"); //$NON-NLS-1$ + if (osName == null || userName == null) { + throw new IOException("Unable to obtain information needed to find login shell"); //$NON-NLS-1$ + } + switch (osName) { + case "Mac OS X": //$NON-NLS-1$ + res = executeCommand("dscl . -read /Users/" + userName + " UserShell"); //$NON-NLS-1$ //$NON-NLS-2$ + if (res != null) { + String[] vals = res.split(" "); //$NON-NLS-1$ + if (vals.length == 2) { + return vals[1]; + } + } + break; + case "Linux": //$NON-NLS-1$ + res = executeCommand("getent passwd " + userName); //$NON-NLS-1$ + if (res != null) { + String[] vals = res.split(":"); //$NON-NLS-1$ + if (vals.length == 7) { + return vals[6]; + } + } + break; + default: + break; + } + throw new IOException("Unable to find login shell for os=" + osName + " user=" + userName); //$NON-NLS-1$ //$NON-NLS-2$ + } + + private String executeCommand(String command) throws IOException { + String line; + StringBuffer output = new StringBuffer(); + + Process p; + try { + p = Runtime.getRuntime().exec(command); + } catch (Exception e) { + throw new IOException(e.getMessage()); + } + try { + p.waitFor(); + } catch (InterruptedException e) { + throw new IOException(e.getMessage()); + } + BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream())); + line = reader.readLine(); + while (line != null) { + output.append(line); + line = reader.readLine(); + if (line != null) { + output.append("\n"); //$NON-NLS-1$ + } + } + + return output.toString(); + } +} diff --git a/bundles/org.eclipse.remote.proxy.ui/.classpath b/bundles/org.eclipse.remote.proxy.ui/.classpath new file mode 100644 index 00000000000..eca7bdba8f0 --- /dev/null +++ b/bundles/org.eclipse.remote.proxy.ui/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/bundles/org.eclipse.remote.proxy.ui/.gitignore b/bundles/org.eclipse.remote.proxy.ui/.gitignore new file mode 100644 index 00000000000..5e56e040ec0 --- /dev/null +++ b/bundles/org.eclipse.remote.proxy.ui/.gitignore @@ -0,0 +1 @@ +/bin diff --git a/bundles/org.eclipse.remote.proxy.ui/.project b/bundles/org.eclipse.remote.proxy.ui/.project new file mode 100644 index 00000000000..1979ba08863 --- /dev/null +++ b/bundles/org.eclipse.remote.proxy.ui/.project @@ -0,0 +1,34 @@ + + + org.eclipse.remote.proxy.ui + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + org.eclipse.pde.api.tools.apiAnalysisBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + org.eclipse.pde.api.tools.apiAnalysisNature + + diff --git a/bundles/org.eclipse.remote.proxy.ui/.settings/org.eclipse.jdt.core.prefs b/bundles/org.eclipse.remote.proxy.ui/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 00000000000..3a21537071b --- /dev/null +++ b/bundles/org.eclipse.remote.proxy.ui/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,11 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/bundles/org.eclipse.remote.proxy.ui/META-INF/MANIFEST.MF b/bundles/org.eclipse.remote.proxy.ui/META-INF/MANIFEST.MF new file mode 100644 index 00000000000..9baf5cb30c4 --- /dev/null +++ b/bundles/org.eclipse.remote.proxy.ui/META-INF/MANIFEST.MF @@ -0,0 +1,42 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: %pluginName +Bundle-SymbolicName: org.eclipse.remote.proxy.ui;singleton:=true +Bundle-Version: 1.0.0.qualifier +Bundle-Activator: org.eclipse.remote.internal.proxy.ui.Activator +Bundle-Vendor: %pluginProvider +Bundle-ActivationPolicy: lazy +Export-Package: org.eclipse.remote.internal.proxy.ui;x-internal:=true, + org.eclipse.remote.internal.proxy.ui.messages;x-internal:=true +Bundle-Localization: plugin +Bundle-RequiredExecutionEnvironment: JavaSE-1.8 +Import-Package: com.jcraft.jsch, + org.eclipse.core.filesystem, + org.eclipse.core.runtime, + org.eclipse.jface.dialogs, + org.eclipse.jface.operation, + org.eclipse.jface.preference, + org.eclipse.jface.resource, + org.eclipse.jface.viewers, + org.eclipse.jface.window, + org.eclipse.jface.wizard, + org.eclipse.jsch.core, + org.eclipse.jsch.ui, + org.eclipse.osgi.util, + org.eclipse.remote.core, + org.eclipse.remote.core.exception, + org.eclipse.remote.internal.proxy.core, + org.eclipse.remote.ui, + org.eclipse.remote.ui.dialogs, + org.eclipse.remote.ui.widgets, + org.eclipse.swt, + org.eclipse.swt.events, + org.eclipse.swt.graphics, + org.eclipse.swt.layout, + org.eclipse.swt.widgets, + org.eclipse.ui.dialogs, + org.eclipse.ui.forms.events, + org.eclipse.ui.forms.widgets, + org.eclipse.ui.ide.fileSystem, + org.eclipse.ui.plugin, + org.osgi.framework diff --git a/bundles/org.eclipse.remote.proxy.ui/about.html b/bundles/org.eclipse.remote.proxy.ui/about.html new file mode 100644 index 00000000000..3f810933b39 --- /dev/null +++ b/bundles/org.eclipse.remote.proxy.ui/about.html @@ -0,0 +1,22 @@ + + + +About + + + +

About This Content

+ +

May 2, 2006

+

License

+ +

The Eclipse Foundation makes available all content in this plug-in ("Content"). Unless otherwise indicated below, the Content is provided to you under the terms and conditions of the +Eclipse Public License Version 1.0 ("EPL"). A copy of the EPL is available at http://www.eclipse.org/legal/epl-v10.html. +For purposes of the EPL, "Program" will mean the Content.

+ +

If you did not receive this Content directly from the Eclipse Foundation, the Content is being redistributed by another party ("Redistributor") and different terms and conditions may +apply to your use of any object code in the Content. Check the Redistributor's license that was provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise +indicated below, the terms and conditions of the EPL still apply to any source code in the Content and such source code may be obtained at http://www.eclipse.org.

+ + + \ No newline at end of file diff --git a/bundles/org.eclipse.remote.proxy.ui/build.properties b/bundles/org.eclipse.remote.proxy.ui/build.properties new file mode 100644 index 00000000000..a04702242bd --- /dev/null +++ b/bundles/org.eclipse.remote.proxy.ui/build.properties @@ -0,0 +1,9 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + .,\ + plugin.xml,\ + plugin.properties,\ + about.html,\ + icons/ + diff --git a/bundles/org.eclipse.remote.proxy.ui/icons/full/obj16/connection.gif b/bundles/org.eclipse.remote.proxy.ui/icons/full/obj16/connection.gif new file mode 100644 index 00000000000..870934b6934 Binary files /dev/null and b/bundles/org.eclipse.remote.proxy.ui/icons/full/obj16/connection.gif differ diff --git a/bundles/org.eclipse.remote.proxy.ui/icons/ssh.png b/bundles/org.eclipse.remote.proxy.ui/icons/ssh.png new file mode 100644 index 00000000000..8cbd0a13ba8 Binary files /dev/null and b/bundles/org.eclipse.remote.proxy.ui/icons/ssh.png differ diff --git a/bundles/org.eclipse.remote.proxy.ui/plugin.properties b/bundles/org.eclipse.remote.proxy.ui/plugin.properties new file mode 100644 index 00000000000..01eabd8013a --- /dev/null +++ b/bundles/org.eclipse.remote.proxy.ui/plugin.properties @@ -0,0 +1,13 @@ +############################################################################### +# Copyright (c) 2016 Oak Ridge National Laboratory 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 +# +############################################################################### + +pluginName=Proxy UI Remote Support +pluginProvider=Eclipse PTP +ProxyTransferConnections.name=Remote Connections +ProxyTransferConnections.description=All remote proxy connections \ No newline at end of file diff --git a/bundles/org.eclipse.remote.proxy.ui/plugin.xml b/bundles/org.eclipse.remote.proxy.ui/plugin.xml new file mode 100644 index 00000000000..8c2b5b2704c --- /dev/null +++ b/bundles/org.eclipse.remote.proxy.ui/plugin.xml @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + %ProxyTransferConnections.description + + + + + + + + + + + + + + + + + diff --git a/bundles/org.eclipse.remote.proxy.ui/pom.xml b/bundles/org.eclipse.remote.proxy.ui/pom.xml new file mode 100644 index 00000000000..5d8898e045d --- /dev/null +++ b/bundles/org.eclipse.remote.proxy.ui/pom.xml @@ -0,0 +1,16 @@ + + + 4.0.0 + + + org.eclipse.remote + remote-parent + 3.0.0-SNAPSHOT + ../../releng/org.eclipse.remote.build/pom.xml + + + org.eclipse.remote.proxy.ui + eclipse-plugin +1.0.0-SNAPSHOT + diff --git a/bundles/org.eclipse.remote.proxy.ui/src/org/eclipse/remote/internal/proxy/ui/Activator.java b/bundles/org.eclipse.remote.proxy.ui/src/org/eclipse/remote/internal/proxy/ui/Activator.java new file mode 100644 index 00000000000..034b8a2e134 --- /dev/null +++ b/bundles/org.eclipse.remote.proxy.ui/src/org/eclipse/remote/internal/proxy/ui/Activator.java @@ -0,0 +1,128 @@ +package org.eclipse.remote.internal.proxy.ui; + +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.jsch.core.IJSchService; +import org.eclipse.ui.plugin.AbstractUIPlugin; +import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceReference; + +/** + * The activator class controls the plug-in life cycle + */ +public class Activator extends AbstractUIPlugin { + + // The plug-in ID + private static final String PLUGIN_ID = "org.eclipse.remote.jsch.ui"; //$NON-NLS-1$ + + // Image Keys + public static final String IMG_CONNECTION_TYPE = PLUGIN_ID + ".connectionType"; //$NON-NLS-1$ + + // The shared instance + private static Activator plugin; + + /** + * Returns the shared instance + * + * @return the shared instance + */ + public static Activator getDefault() { + return plugin; + } + + /** + * Get unique identifier + * + * @return + * @since 5.0 + */ + public static String getUniqueIdentifier() { + if (getDefault() == null) { + return PLUGIN_ID; + } + return getDefault().getBundle().getSymbolicName(); + } + + /** + * Logs the specified status with this plug-in's log. + * + * @param status + * status to log + */ + public static void log(IStatus status) { + getDefault().getLog().log(status); + } + + /** + * Logs an internal error with the specified message. + * + * @param message + * the error message to log + */ + public static void log(String message) { + log(new Status(IStatus.ERROR, getUniqueIdentifier(), IStatus.ERROR, message, null)); + } + + /** + * Logs an internal error with the specified throwable + * + * @param e + * the exception to be logged + */ + public static void log(Throwable e) { + log(new Status(IStatus.ERROR, getUniqueIdentifier(), IStatus.ERROR, e.getMessage(), e)); + } + + private IJSchService fJSchService; + + /** + * The constructor + */ + public Activator() { + } + + /** + * Return the OSGi service with the given service interface. + * + * @param service service interface + * @return the specified service or null if it's not registered + */ + public static T getService(Class service) { + BundleContext context = plugin.getBundle().getBundleContext(); + ServiceReference ref = context.getServiceReference(service); + return ref != null ? context.getService(ref) : null; + } + + public IJSchService getService() { + return fJSchService; + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext + * ) + */ + @Override + public void start(BundleContext context) throws Exception { + super.start(context); + plugin = this; + ServiceReference reference = context.getServiceReference(IJSchService.class); + fJSchService = context.getService(reference); + getImageRegistry().put(IMG_CONNECTION_TYPE, imageDescriptorFromPlugin(PLUGIN_ID, "/icons/ssh.png")); //$NON-NLS-1$ + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext + * ) + */ + @Override + public void stop(BundleContext context) throws Exception { + plugin = null; + super.stop(context); + } +} diff --git a/bundles/org.eclipse.remote.proxy.ui/src/org/eclipse/remote/internal/proxy/ui/ProxyFileSystemContributor.java b/bundles/org.eclipse.remote.proxy.ui/src/org/eclipse/remote/internal/proxy/ui/ProxyFileSystemContributor.java new file mode 100644 index 00000000000..9ab44814ea1 --- /dev/null +++ b/bundles/org.eclipse.remote.proxy.ui/src/org/eclipse/remote/internal/proxy/ui/ProxyFileSystemContributor.java @@ -0,0 +1,64 @@ +/******************************************************************************** + * Copyright (c) 2016 Oak Ridge National Laboratory 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 + ********************************************************************************/ + +package org.eclipse.remote.internal.proxy.ui; + +import java.net.URI; +import java.net.URISyntaxException; + +import org.eclipse.remote.core.IRemoteConnection; +import org.eclipse.remote.core.IRemoteConnectionType; +import org.eclipse.remote.core.IRemoteServicesManager; +import org.eclipse.remote.internal.proxy.core.ProxyConnection; +import org.eclipse.remote.internal.proxy.core.ProxyFileSystem; +import org.eclipse.remote.internal.proxy.ui.messages.Messages; +import org.eclipse.remote.ui.IRemoteUIFileService; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.ui.ide.fileSystem.FileSystemContributor; + +public class ProxyFileSystemContributor extends FileSystemContributor { + /* + * (non-Javadoc) + * + * @see + * org.eclipse.ui.ide.fileSystem.FileSystemContributor#browseFileSystem( + * java.lang.String, org.eclipse.swt.widgets.Shell) + */ + @Override + public URI browseFileSystem(String initialPath, Shell shell) { + IRemoteServicesManager manager = Activator.getService(IRemoteServicesManager.class); + IRemoteConnectionType connectionType = manager.getConnectionType(ProxyConnection.JSCH_ID); + IRemoteUIFileService uiFileMgr = connectionType.getService(IRemoteUIFileService.class); + uiFileMgr.showConnections(true); + String path = uiFileMgr.browseDirectory(shell, Messages.ProxyFileSystemContributor_0, initialPath, 0); + if (path != null) { + IRemoteConnection conn = uiFileMgr.getConnection(); + if (conn != null) { + return ProxyFileSystem.getURIFor(conn.getName(), path); + } + } + + return null; + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.ui.ide.fileSystem.FileSystemContributor#getURI(java.lang. + * String) + */ + @Override + public URI getURI(String string) { + try { + return new URI(string); + } catch (URISyntaxException e) { + // Ignore + } + return null; + } +} \ No newline at end of file diff --git a/bundles/org.eclipse.remote.proxy.ui/src/org/eclipse/remote/internal/proxy/ui/ProxyUIConnectionService.java b/bundles/org.eclipse.remote.proxy.ui/src/org/eclipse/remote/internal/proxy/ui/ProxyUIConnectionService.java new file mode 100644 index 00000000000..00017491bb4 --- /dev/null +++ b/bundles/org.eclipse.remote.proxy.ui/src/org/eclipse/remote/internal/proxy/ui/ProxyUIConnectionService.java @@ -0,0 +1,105 @@ +/******************************************************************************* + * Copyright (c) 2016 Oak Ridge National Laboratory 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 + *******************************************************************************/ +package org.eclipse.remote.internal.proxy.ui; + +import java.lang.reflect.InvocationTargetException; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.jface.dialogs.ErrorDialog; +import org.eclipse.jface.dialogs.ProgressMonitorDialog; +import org.eclipse.jface.operation.IRunnableContext; +import org.eclipse.jface.operation.IRunnableWithProgress; +import org.eclipse.jface.viewers.ILabelProvider; +import org.eclipse.remote.core.IRemoteConnection; +import org.eclipse.remote.core.IRemoteConnectionType; +import org.eclipse.remote.core.IRemoteConnectionType.Service; +import org.eclipse.remote.core.exception.RemoteConnectionException; +import org.eclipse.remote.internal.proxy.ui.messages.Messages; +import org.eclipse.remote.internal.proxy.ui.wizards.ProxyConnectionWizard; +import org.eclipse.remote.ui.AbstractRemoteUIConnectionService; +import org.eclipse.remote.ui.IRemoteUIConnectionService; +import org.eclipse.remote.ui.IRemoteUIConnectionWizard; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.widgets.Shell; + +public class ProxyUIConnectionService extends AbstractRemoteUIConnectionService { + + private final IRemoteConnectionType fConnectionType; + + public ProxyUIConnectionService(IRemoteConnectionType connectionType) { + fConnectionType = connectionType; + } + + public static class Factory implements IRemoteConnectionType.Service.Factory { + @SuppressWarnings("unchecked") + @Override + public T getService(IRemoteConnectionType connectionType, Class service) { + if (IRemoteUIConnectionService.class.equals(service)) { + return (T) new ProxyUIConnectionService(connectionType); + } + return null; + } + } + + @Override + public IRemoteConnectionType getConnectionType() { + return fConnectionType; + } + + @Override + public IRemoteUIConnectionWizard getConnectionWizard(Shell shell) { + return new ProxyConnectionWizard(shell, fConnectionType); + } + + @Override + public void openConnectionWithProgress(Shell shell, IRunnableContext context, final IRemoteConnection connection) { + if (!connection.isOpen()) { + IRunnableWithProgress op = new IRunnableWithProgress() { + @Override + public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { + try { + connection.open(monitor); + } catch (RemoteConnectionException e) { + throw new InvocationTargetException(e); + } + if (monitor.isCanceled()) { + throw new InterruptedException(); + } + } + }; + try { + if (context != null) { + context.run(true, true, op); + } else { + new ProgressMonitorDialog(shell).run(true, true, op); + } + } catch (InvocationTargetException e) { + ErrorDialog.openError(shell, Messages.ProxyUIConnectionManager_Connection_Error, + Messages.ProxyUIConnectionManager_Could_not_open_connection, + new Status(IStatus.ERROR, Activator.getUniqueIdentifier(), e.getCause().getMessage())); + } catch (InterruptedException e) { + ErrorDialog.openError(shell, Messages.ProxyUIConnectionManager_Connection_Error, + Messages.ProxyUIConnectionManager_Could_not_open_connection, + new Status(IStatus.ERROR, Activator.getUniqueIdentifier(), e.getMessage())); + } + } + } + + @Override + public ILabelProvider getLabelProvider() { + return new DefaultLabelProvider() { + @Override + public Image getImage(Object element) { + return Activator.getDefault().getImageRegistry().get(Activator.IMG_CONNECTION_TYPE); + } + }; + } + +} diff --git a/bundles/org.eclipse.remote.proxy.ui/src/org/eclipse/remote/internal/proxy/ui/ProxyUserAuthenticator.java b/bundles/org.eclipse.remote.proxy.ui/src/org/eclipse/remote/internal/proxy/ui/ProxyUserAuthenticator.java new file mode 100644 index 00000000000..6146764546c --- /dev/null +++ b/bundles/org.eclipse.remote.proxy.ui/src/org/eclipse/remote/internal/proxy/ui/ProxyUserAuthenticator.java @@ -0,0 +1,117 @@ +/******************************************************************************* + * Copyright (c) 2016 Oak Ridge National Laboratory 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 + *******************************************************************************/ +package org.eclipse.remote.internal.proxy.ui; + +import java.net.PasswordAuthentication; + +import org.eclipse.jface.dialogs.IDialogConstants; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.jsch.ui.UserInfoPrompter; +import org.eclipse.remote.core.IRemoteConnection; +import org.eclipse.remote.core.IRemoteConnectionHostService; +import org.eclipse.remote.core.IUserAuthenticatorService; +import org.eclipse.swt.widgets.Display; + +import com.jcraft.jsch.JSch; +import com.jcraft.jsch.JSchException; + +public class ProxyUserAuthenticator implements IUserAuthenticatorService { + + private final IRemoteConnection remoteConnection; + private UserInfoPrompter prompter; + + public ProxyUserAuthenticator(IRemoteConnection conn) { + this.remoteConnection = conn; + IRemoteConnectionHostService hostService = conn.getService(IRemoteConnectionHostService.class); + if (hostService != null) { + try { + prompter = new UserInfoPrompter(new JSch().getSession(hostService.getUsername(), hostService.getHostname())); + } catch (JSchException e) { + // Not allowed + } + } + } + + @Override + public IRemoteConnection getRemoteConnection() { + return remoteConnection; + } + + @Override + public PasswordAuthentication prompt(String username, String message) { + if (prompter.promptPassword(message)) { + String sessionUserName = prompter.getSession().getUserName(); + if (sessionUserName != null) { + username = sessionUserName; + } + PasswordAuthentication auth = new PasswordAuthentication(username, prompter.getPassword().toCharArray()); + return auth; + } + return null; + } + + @Override + public String[] prompt(String destination, String name, String message, String[] prompt, boolean[] echo) { + return prompter.promptKeyboardInteractive(destination, name, message, prompt, echo); + } + + @Override + public int prompt(final int promptType, final String title, final String message, final int[] promptResponses, + final int defaultResponseIndex) { + final Display display = getDisplay(); + final int[] retval = new int[1]; + final String[] buttons = new String[promptResponses.length]; + for (int i = 0; i < promptResponses.length; i++) { + int prompt = promptResponses[i]; + switch (prompt) { + case IDialogConstants.OK_ID: + buttons[i] = IDialogConstants.OK_LABEL; + break; + case IDialogConstants.CANCEL_ID: + buttons[i] = IDialogConstants.CANCEL_LABEL; + break; + case IDialogConstants.NO_ID: + buttons[i] = IDialogConstants.NO_LABEL; + break; + case IDialogConstants.YES_ID: + buttons[i] = IDialogConstants.YES_LABEL; + break; + } + } + + display.syncExec(new Runnable() { + @Override + public void run() { + final MessageDialog dialog = new MessageDialog(display.getActiveShell(), title, null /* title image */, message, + promptType, buttons, defaultResponseIndex); + retval[0] = dialog.open(); + } + }); + return promptResponses[retval[0]]; + } + + private Display getDisplay() { + Display display = Display.getCurrent(); + if (display == null) { + display = Display.getDefault(); + } + return display; + } + + public static class Factory implements IRemoteConnection.Service.Factory { + @Override + @SuppressWarnings("unchecked") + public T getService(IRemoteConnection connection, Class service) { + if (IUserAuthenticatorService.class.equals(service)) { + return (T) new ProxyUserAuthenticator(connection); + } else { + return null; + } + } + } +} diff --git a/bundles/org.eclipse.remote.proxy.ui/src/org/eclipse/remote/internal/proxy/ui/messages/Messages.java b/bundles/org.eclipse.remote.proxy.ui/src/org/eclipse/remote/internal/proxy/ui/messages/Messages.java new file mode 100755 index 00000000000..f1782fa60a5 --- /dev/null +++ b/bundles/org.eclipse.remote.proxy.ui/src/org/eclipse/remote/internal/proxy/ui/messages/Messages.java @@ -0,0 +1,68 @@ +/** + * Copyright (c) 2013 IBM Corporation. + * 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 Implementation + * + */ +package org.eclipse.remote.internal.proxy.ui.messages; + +import org.eclipse.osgi.util.NLS; + +public class Messages extends NLS { + private static final String BUNDLE_ID = "org.eclipse.remote.internal.proxy.ui.messages.messages"; //$NON-NLS-1$ + + static { + // load message values from bundle file + NLS.initializeMessages(BUNDLE_ID, Messages.class); + } + + public static String ProxyConnectionPage_0; + public static String ProxyConnectionPage_1; + public static String ProxyConnectionPage_2; + public static String ProxyConnectionPage_A_connection_with_that_name_already_exists; + public static String ProxyConnectionPage_Edit_Connection; + public static String ProxyConnectionPage_Edit_properties_of_an_existing_connection; + public static String ProxyConnectionPage_Initial_Message; + public static String ProxyConnectionPage_Proxy; + public static String ProxyConnectionPage_Help; + public static String ProxyConnectionPage_KeysAtSSH2; + public static String ProxyConnectionPage_SelectCommand; + public static String ProxyConnectionPage_SelectConnection; + public static String ProxyConnectionPage_Settings0; + public static String ProxyConnectionPage_selectProxyConnection; + public static String ProxyFileSystemContributor_0; + public static String ProxyNewConnectionPage_Advanced; + public static String ProxyNewConnectionPage_Connection_name; + public static String ProxyNewConnectionPage_File_with_private_key; + public static String ProxyNewConnectionPage_Host; + public static String ProxyNewConnectionPage_Host_information; + public static String ProxyNewConnectionPage_Host_name_cannot_be_empty; + public static String ProxyNewConnectionPage_New_Connection; + public static String ProxyNewConnectionPage_New_connection_properties; + public static String ProxyNewConnectionPage_Passphrase; + public static String ProxyNewConnectionPage_Password; + public static String ProxyNewConnectionPage_Password_based_authentication; + public static String ProxyNewConnectionPage_Please_enter_a_connection_name; + public static String ProxyNewConnectionPage_Port; + public static String ProxyNewConnectionPage_Port_is_not_valid; + public static String ProxyNewConnectionPage_Private_key_file_cannot_be_read; + public static String ProxyNewConnectionPage_Private_key_file_does_not_exist; + public static String ProxyNewConnectionPage_Private_key_file_is_invalid; + public static String ProxyNewConnectionPage_Private_key_path_cannot_be_empty; + public static String ProxyNewConnectionPage_Public_key_based_authentication; + public static String ProxyNewConnectionPage_Timeout; + public static String ProxyNewConnectionPage_Timeout_is_not_valid; + public static String ProxyNewConnectionPage_User; + public static String ProxyNewConnectionPage_User_name_cannot_be_empty; + public static String ProxyUIConnectionManager_Connection_Error; + public static String ProxyUIConnectionManager_Could_not_open_connection; + + private Messages() { + // cannot create new instance + } +} diff --git a/bundles/org.eclipse.remote.proxy.ui/src/org/eclipse/remote/internal/proxy/ui/messages/messages.properties b/bundles/org.eclipse.remote.proxy.ui/src/org/eclipse/remote/internal/proxy/ui/messages/messages.properties new file mode 100755 index 00000000000..84e9f80a41d --- /dev/null +++ b/bundles/org.eclipse.remote.proxy.ui/src/org/eclipse/remote/internal/proxy/ui/messages/messages.properties @@ -0,0 +1,50 @@ +############################################################################### +# Copyright (c) 2013 IBM Corporation. +# 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 implementation +############################################################################### +ProxyConnectionPage_0=Use login shell +ProxyConnectionPage_1=Login shell command +ProxyConnectionPage_2=Login shell command cannot be empty +ProxyConnectionPage_A_connection_with_that_name_already_exists=A connection with that name already exists +ProxyConnectionPage_Edit_Connection=Edit Connection +ProxyConnectionPage_Edit_properties_of_an_existing_connection=Edit properties of an existing connection +ProxyConnectionPage_Initial_Message=Specify properties of a new connection +ProxyConnectionPage_Proxy=SSH Proxy Settings +ProxyConnectionPage_Help=If 'Local' is selected and proxy command is empty, no proxy is used.\nSee Network Connections for SOCKS and HTTP proxy options. +ProxyConnectionPage_KeysAtSSH2=Keys are set at Network Connections, SSH2 +ProxyConnectionPage_SelectCommand=Enter a local or remote command such as 'nc %h %p'. Can be empty for an ssh gateway. +ProxyConnectionPage_SelectConnection=Select 'Remote' for an ssh gateway or a remote proxy command. +ProxyConnectionPage_Settings0=Connection Settings +ProxyConnectionPage_selectProxyConnection=Please select a proxy connection +ProxyFileSystemContributor_0=Browse File System +ProxyNewConnectionPage_Advanced=Advanced +ProxyNewConnectionPage_Connection_name=Connection name: +ProxyNewConnectionPage_File_with_private_key=File with private key: +ProxyNewConnectionPage_Host=Host: +ProxyNewConnectionPage_Host_information=Host information +ProxyNewConnectionPage_Host_name_cannot_be_empty=Host name cannot be empty +ProxyNewConnectionPage_New_Connection=New Connection +ProxyNewConnectionPage_New_connection_properties=New connection properties +ProxyNewConnectionPage_Passphrase=Passphrase: +ProxyNewConnectionPage_Password=Password: +ProxyNewConnectionPage_Password_based_authentication=Password based authentication +ProxyNewConnectionPage_Please_enter_a_connection_name=Please enter a connection name +ProxyNewConnectionPage_Port=Port: +ProxyNewConnectionPage_Port_is_not_valid=Port is not valid +ProxyNewConnectionPage_Private_key_file_cannot_be_read=Private key file cannot be read +ProxyNewConnectionPage_Private_key_file_does_not_exist=Private key file does not exist +ProxyNewConnectionPage_Private_key_file_is_invalid=Private key file is invalid +ProxyNewConnectionPage_Private_key_path_cannot_be_empty=Private key path cannot be empty +ProxyNewConnectionPage_Public_key_based_authentication=Public key based authentication +ProxyNewConnectionPage_Timeout=Timeout: +ProxyNewConnectionPage_Timeout_is_not_valid=Timeout is not valid +ProxyNewConnectionPage_User=User: +ProxyNewConnectionPage_User_name_cannot_be_empty=User name cannot be empty +ProxyUIConnectionManager_Connection_Error=Connection Error +ProxyUIConnectionManager_Could_not_open_connection=Could not open connection diff --git a/bundles/org.eclipse.remote.proxy.ui/src/org/eclipse/remote/internal/proxy/ui/wizards/ProxyConnectionPage.java b/bundles/org.eclipse.remote.proxy.ui/src/org/eclipse/remote/internal/proxy/ui/wizards/ProxyConnectionPage.java new file mode 100755 index 00000000000..a367993df95 --- /dev/null +++ b/bundles/org.eclipse.remote.proxy.ui/src/org/eclipse/remote/internal/proxy/ui/wizards/ProxyConnectionPage.java @@ -0,0 +1,497 @@ +/** + * Copyright (c) 2016 Oak Ridge National Laboratory 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 + */ +package org.eclipse.remote.internal.proxy.ui.wizards; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.jface.preference.PreferenceDialog; +import org.eclipse.jface.wizard.WizardPage; +import org.eclipse.remote.core.IRemoteConnectionType; +import org.eclipse.remote.core.IRemoteConnectionWorkingCopy; +import org.eclipse.remote.core.IRemoteServicesManager; +import org.eclipse.remote.core.exception.RemoteConnectionException; +import org.eclipse.remote.internal.proxy.core.ProxyConnection; +import org.eclipse.remote.internal.proxy.ui.Activator; +import org.eclipse.remote.internal.proxy.ui.messages.Messages; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.ModifyEvent; +import org.eclipse.swt.events.ModifyListener; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.graphics.FontMetrics; +import org.eclipse.swt.graphics.GC; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Group; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Link; +import org.eclipse.swt.widgets.Text; +import org.eclipse.ui.dialogs.PreferencesUtil; +import org.eclipse.ui.forms.events.ExpansionEvent; +import org.eclipse.ui.forms.events.IExpansionListener; +import org.eclipse.ui.forms.widgets.ExpandableComposite; + +public class ProxyConnectionPage extends WizardPage { + + private class DataModifyListener implements ModifyListener { + @Override + public synchronized void modifyText(ModifyEvent e) { + validateFields(); + getContainer().updateButtons(); + } + } + + private Text fConnectionName; + private Button fPasswordButton; + private Button fPublicKeyButton; + private Button fDefaultServerButton; + private Text fHostText; + private Text fUserText; + private Text fPasswordText; + private Text fPassphraseText; + private Text fPortText; + private Text fTimeoutText; + private Text fServerCommandText; + + private String fInitialName = "Remote Host"; //$NON-NLS-1$ + private Set fInvalidConnectionNames; + private final Map fInitialAttributes = new HashMap(); + private IRemoteConnectionWorkingCopy fConnection; + + private final IRemoteConnectionType fConnectionType; + + private final DataModifyListener fDataModifyListener = new DataModifyListener(); + + public ProxyConnectionPage(IRemoteConnectionType connectionType) { + super(Messages.ProxyNewConnectionPage_New_connection_properties); + fConnectionType = connectionType; + setPageComplete(false); + } + + /** + * Create controls for the bottom (hideable) advanced composite + * + * @param mold + * + */ + private void createAdvancedControls(final Composite parent) { + ExpandableComposite expComp = new ExpandableComposite(parent, ExpandableComposite.TWISTIE); + expComp.setText(Messages.ProxyNewConnectionPage_Advanced); + expComp.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); + expComp.setExpanded(false); + expComp.addExpansionListener(new IExpansionListener() { + + @Override + public void expansionStateChanged(ExpansionEvent e) { + for (int i = 0; i < 2; i++) { // sometimes the size compute isn't correct on first try + Point newSize = parent.computeSize(SWT.DEFAULT, SWT.DEFAULT); + Point currentSize = parent.getSize(); + int deltaY = newSize.y - currentSize.y; + Point shellSize = getShell().getSize(); + shellSize.y += deltaY; + getShell().setSize(shellSize); + getShell().layout(true, true); + } + } + + @Override + public void expansionStateChanging(ExpansionEvent e) { + // Ignore + } + }); + + Composite advancedComp = new Composite(expComp, SWT.NONE); + advancedComp.setLayout(new GridLayout(1, false)); + advancedComp.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); + + Group settingsComp = new Group(advancedComp, SWT.NONE); + settingsComp.setText(Messages.ProxyConnectionPage_Settings0); + settingsComp.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1)); + settingsComp.setLayout(new GridLayout(2, false)); + + Label portLabel = new Label(settingsComp, SWT.NONE); + portLabel.setText(Messages.ProxyNewConnectionPage_Port); + fPortText = new Text(settingsComp, SWT.BORDER | SWT.SINGLE); + fPortText.setText(Integer.toString(ProxyConnection.DEFAULT_PORT)); + fPortText.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false)); + setTextFieldWidthInChars(fPortText, 5); + + Label timeoutLabel = new Label(settingsComp, SWT.NONE); + timeoutLabel.setText(Messages.ProxyNewConnectionPage_Timeout); + fTimeoutText = new Text(settingsComp, SWT.BORDER | SWT.SINGLE); + fTimeoutText.setText(Integer.toString(ProxyConnection.DEFAULT_TIMEOUT)); + + fDefaultServerButton = new Button(settingsComp, SWT.CHECK); + fDefaultServerButton.setText("Use default server"); + fDefaultServerButton.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false, 2, 1)); + fDefaultServerButton.addSelectionListener(new SelectionAdapter() { + + /* + * (non-Javadoc) + * + * @see org.eclipse.swt.events.SelectionAdapter#widgetSelected(org.eclipse.swt.events.SelectionEvent) + */ + @Override + public void widgetSelected(SelectionEvent e) { + validateFields(); + updateEnablement(); + } + }); + Label serverLabel = new Label(settingsComp, SWT.NONE); + serverLabel.setText("Server command"); + fServerCommandText = new Text(settingsComp, SWT.BORDER | SWT.SINGLE); + fServerCommandText.setText(ProxyConnection.DEFAULT_SERVER_COMMAND); + fServerCommandText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); + fDefaultServerButton.setSelection(ProxyConnection.DEFAULT_USE_DEFAULT_SERVER); + + expComp.setClient(advancedComp); + } + + private void createAuthControls(Composite parent) { + Composite controls = new Composite(parent, SWT.NONE); + controls.setLayout(new GridLayout(3, false)); + controls.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); + + Label hostLabel = new Label(controls, SWT.NONE); + hostLabel.setText(Messages.ProxyNewConnectionPage_Host); + fHostText = new Text(controls, SWT.BORDER | SWT.SINGLE); + fHostText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 2, 1)); + + Label userLabel = new Label(controls, SWT.NONE); + userLabel.setText(Messages.ProxyNewConnectionPage_User); + fUserText = new Text(controls, SWT.BORDER | SWT.SINGLE); + fUserText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 2, 1)); + + // Key option box + fPublicKeyButton = new Button(controls, SWT.RADIO); + fPublicKeyButton.setText(Messages.ProxyNewConnectionPage_Public_key_based_authentication); + fPublicKeyButton.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false, 2, 1)); + fPublicKeyButton.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + validateFields(); + updateEnablement(); + } + }); + + Link link = new Link(controls, SWT.WRAP); + final GridData linkLayoutData = new GridData(GridData.FILL_HORIZONTAL); + link.setLayoutData(linkLayoutData); + final String PREFS_PAGE_ID_NET_SSH = "org.eclipse.jsch.ui.SSHPreferences"; //$NON-NLS-1$ + link.addSelectionListener(new SelectionListener() { + @Override + public void widgetSelected(SelectionEvent e) { + PreferenceDialog dlg = PreferencesUtil.createPreferenceDialogOn(getShell(), PREFS_PAGE_ID_NET_SSH, + new String[] { PREFS_PAGE_ID_NET_SSH }, null); + dlg.open(); + } + + @Override + public void widgetDefaultSelected(SelectionEvent e) { + // ignore + } + }); + link.setText(Messages.ProxyConnectionPage_KeysAtSSH2); + + // Passphrase field + Label passphraseLabel = new Label(controls, SWT.NONE); + passphraseLabel.setText(Messages.ProxyNewConnectionPage_Passphrase); + fPassphraseText = new Text(controls, SWT.BORDER | SWT.SINGLE | SWT.PASSWORD); + fPassphraseText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 2, 1)); + + // User option box + fPasswordButton = new Button(controls, SWT.RADIO); + fPasswordButton.setText(Messages.ProxyNewConnectionPage_Password_based_authentication); + fPasswordButton.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false, 3, 1)); + fPasswordButton.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + validateFields(); + updateEnablement(); + } + }); + + // Password field + Label passwordLabel = new Label(controls, SWT.NONE); + passwordLabel.setText(Messages.ProxyNewConnectionPage_Password); + fPasswordText = new Text(controls, SWT.BORDER | SWT.SINGLE | SWT.PASSWORD); + fPasswordText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 2, 1)); + + fPasswordButton.setSelection(ProxyConnection.DEFAULT_USE_PASSWORD); + fPublicKeyButton.setSelection(!ProxyConnection.DEFAULT_USE_PASSWORD); + controls.setTabList( + new Control[] { fHostText, fUserText, fPublicKeyButton, fPassphraseText, fPasswordButton, fPasswordText }); + } + + @Override + public void createControl(Composite parent) { + if (fConnection == null) { + setDescription(Messages.ProxyNewConnectionPage_New_connection_properties); + setTitle(Messages.ProxyNewConnectionPage_New_connection_properties); + setMessage(Messages.ProxyConnectionPage_Initial_Message); + } else { + setDescription(Messages.ProxyConnectionPage_Edit_properties_of_an_existing_connection); + setTitle(Messages.ProxyConnectionPage_Edit_Connection); + } + setErrorMessage(null); + + GridLayout topLayout = new GridLayout(2, false); + final Composite topControl = new Composite(parent, SWT.NONE); + setControl(topControl); + topControl.setLayout(topLayout); + + Label label = new Label(topControl, SWT.NONE); + label.setText(Messages.ProxyNewConnectionPage_Connection_name); + + fConnectionName = new Text(topControl, SWT.BORDER | SWT.SINGLE); + fConnectionName.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); + fConnectionName.setEnabled(fConnection == null); + + final Group authGroup = new Group(topControl, SWT.NONE); + authGroup.setText(Messages.ProxyNewConnectionPage_Host_information); + authGroup.setLayout(new GridLayout(1, false)); + authGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1)); + + createAuthControls(authGroup); + createAdvancedControls(authGroup); + + try { + loadValues(); + } catch (CoreException e) { + Activator.log(e.getStatus()); + } + + /* + * Register listeners after loading values so we don't trigger listeners + */ + registerListeners(); + + if (fConnection != null) { + validateFields(); + } + + updateEnablement(); + } + + public IRemoteConnectionWorkingCopy getConnection() { + return fConnection; + } + + /** + * Check if the connection name is invalid. This only applies to new connections (when fConnection is null). + * + * @param name + * connection name + * @return true if the name is invalid, false otherwise + */ + private boolean isInvalidName(String name) { + if (fConnection == null) { + if (fInvalidConnectionNames == null) { + return fConnectionType.getConnection(name) != null; + } + return fInvalidConnectionNames.contains(name); + } + return false; + } + + private void loadValues() throws CoreException { + IRemoteServicesManager manager = Activator.getService(IRemoteServicesManager.class); + if (fConnection != null) { + fConnectionName.setText(fConnection.getName()); + fHostText.setText(fConnection.getAttribute(ProxyConnection.HOSTNAME_ATTR)); + fUserText.setText(fConnection.getAttribute(ProxyConnection.USERNAME_ATTR)); + String portStr = fConnection.getAttribute(ProxyConnection.PORT_ATTR); + fPortText.setText(portStr.isEmpty() ? Integer.toString(ProxyConnection.DEFAULT_PORT) : portStr); + String timeoutStr = fConnection.getAttribute(ProxyConnection.TIMEOUT_ATTR); + fTimeoutText.setText(timeoutStr.isEmpty() ? Integer.toString(ProxyConnection.DEFAULT_TIMEOUT) : timeoutStr); + String isPwdStr = fConnection.getAttribute(ProxyConnection.USE_PASSWORD_ATTR); + boolean isPwd = isPwdStr.isEmpty() ? ProxyConnection.DEFAULT_USE_PASSWORD : Boolean.parseBoolean(isPwdStr); + fPasswordButton.setSelection(isPwd); + fPublicKeyButton.setSelection(!isPwd); + fPasswordText.setText(fConnection.getSecureAttribute(ProxyConnection.PASSWORD_ATTR)); + fPassphraseText.setText(fConnection.getSecureAttribute(ProxyConnection.PASSPHRASE_ATTR)); + String useDefaultServerStr = fConnection.getAttribute(ProxyConnection.USE_DEFAULT_SERVER_ATTR); + boolean useDefaultServer = useDefaultServerStr.isEmpty() ? ProxyConnection.DEFAULT_USE_DEFAULT_SERVER + : Boolean.parseBoolean(useDefaultServerStr); + fDefaultServerButton.setSelection(useDefaultServer); + String serverCommandStr = fConnection.getAttribute(ProxyConnection.SERVER_COMMAND_ATTR); + fServerCommandText.setText(serverCommandStr.isEmpty() ? ProxyConnection.DEFAULT_SERVER_COMMAND : serverCommandStr); + + } else { + fConnectionName.setText(fInitialName); + String host = fInitialAttributes.get(ProxyConnection.HOSTNAME_ATTR); + if (host != null) { + fHostText.setText(host); + } + String username = fInitialAttributes.get(ProxyConnection.USERNAME_ATTR); + if (username != null) { + fUserText.setText(username); + } + String port = fInitialAttributes.get(ProxyConnection.PORT_ATTR); + if (port != null) { + fPortText.setText(port); + } + String timeout = fInitialAttributes.get(ProxyConnection.TIMEOUT_ATTR); + if (timeout != null) { + fTimeoutText.setText(timeout); + } + String isPwd = fInitialAttributes.get(ProxyConnection.USE_PASSWORD_ATTR); + if (isPwd != null) { + fPasswordButton.setSelection(Boolean.parseBoolean(isPwd)); + } + String password = fInitialAttributes.get(ProxyConnection.PASSWORD_ATTR); + if (password != null) { + fPasswordText.setText(password); + } + String passphrase = fInitialAttributes.get(ProxyConnection.PASSPHRASE_ATTR); + if (passphrase != null) { + fPassphraseText.setText(passphrase); + } + String useDefaultServer = fInitialAttributes.get(ProxyConnection.USE_DEFAULT_SERVER_ATTR); + if (useDefaultServer != null) { + fDefaultServerButton.setSelection(Boolean.parseBoolean(useDefaultServer)); + } + String serverCommand = fInitialAttributes.get(ProxyConnection.SERVER_COMMAND_ATTR); + if (serverCommand != null) { + fServerCommandText.setText(serverCommand); + } + } + } + + private void registerListeners() { + fConnectionName.addModifyListener(fDataModifyListener); + fHostText.addModifyListener(fDataModifyListener); + fUserText.addModifyListener(fDataModifyListener); + fPasswordText.addModifyListener(fDataModifyListener); + fPassphraseText.addModifyListener(fDataModifyListener); + fPortText.addModifyListener(fDataModifyListener); + fTimeoutText.addModifyListener(fDataModifyListener); + fServerCommandText.addModifyListener(fDataModifyListener); + } + + public void setAddress(String address) { + fInitialAttributes.put(ProxyConnection.HOSTNAME_ATTR, address); + } + + public void setAttributes(Map attributes) { + fInitialAttributes.putAll(attributes); + } + + public void setConnection(IRemoteConnectionWorkingCopy connection) { + fConnection = connection; + } + + public void setConnectionName(String name) { + fInitialName = name; + } + + public void setInvalidConnectionNames(Set names) { + fInvalidConnectionNames = names; + } + + @Override + public void setPageComplete(boolean complete) { + super.setPageComplete(complete); + if (complete) { + storeValues(); + } + } + + public void setPort(int port) { + fInitialAttributes.put(ProxyConnection.PORT_ATTR, Integer.toString(port)); + } + + private void setTextFieldWidthInChars(Text text, int chars) { + text.setTextLimit(chars); + Object data = text.getLayoutData(); + if (data instanceof GridData) { + GC gc = new GC(text); + FontMetrics fm = gc.getFontMetrics(); + int width = chars * fm.getAverageCharWidth(); + gc.dispose(); + ((GridData) data).widthHint = width; + } + } + + public void setUsername(String username) { + fInitialAttributes.put(ProxyConnection.USERNAME_ATTR, username); + } + + private void storeValues() { + if (fConnection == null) { + try { + fConnection = fConnectionType.newConnection(fConnectionName.getText().trim()); + } catch (RemoteConnectionException e) { + Activator.log(e); + } + } + if (fConnection != null) { + fConnection.setName(fConnectionName.getText().trim()); + fConnection.setAttribute(ProxyConnection.HOSTNAME_ATTR, fHostText.getText().trim()); + fConnection.setAttribute(ProxyConnection.USERNAME_ATTR, fUserText.getText().trim()); + fConnection.setSecureAttribute(ProxyConnection.PASSWORD_ATTR, fPasswordText.getText().trim()); + fConnection.setSecureAttribute(ProxyConnection.PASSPHRASE_ATTR, fPassphraseText.getText().trim()); + fConnection.setAttribute(ProxyConnection.USE_PASSWORD_ATTR, Boolean.toString(fPasswordButton.getSelection())); + fConnection.setAttribute(ProxyConnection.TIMEOUT_ATTR, fTimeoutText.getText().trim()); + fConnection.setAttribute(ProxyConnection.PORT_ATTR, fPortText.getText().trim()); + fConnection.setAttribute(ProxyConnection.USE_DEFAULT_SERVER_ATTR, Boolean.toString(fDefaultServerButton.getSelection())); + fConnection.setAttribute(ProxyConnection.SERVER_COMMAND_ATTR, fServerCommandText.getText().trim()); + } + } + + private void updateEnablement() { + boolean isPasswordAuth = fPasswordButton.getSelection(); + fPasswordText.setEnabled(isPasswordAuth); + fPassphraseText.setEnabled(!isPasswordAuth); + fServerCommandText.setEnabled(!fDefaultServerButton.getSelection()); + } + + private String validateAdvanced() { + try { + Integer.parseInt(fPortText.getText().trim()); + } catch (NumberFormatException ne) { + return Messages.ProxyNewConnectionPage_Port_is_not_valid; + } + try { + Integer.parseInt(fTimeoutText.getText().trim()); + } catch (NumberFormatException ne) { + return Messages.ProxyNewConnectionPage_Timeout_is_not_valid; + } + return null; + } + + private void validateFields() { + String message = null; + if (fConnectionName.getText().trim().length() == 0) { + message = Messages.ProxyNewConnectionPage_Please_enter_a_connection_name; + } else if (isInvalidName(fConnectionName.getText().trim())) { + message = Messages.ProxyConnectionPage_A_connection_with_that_name_already_exists; + } else if (fHostText.getText().trim().length() == 0) { + message = Messages.ProxyNewConnectionPage_Host_name_cannot_be_empty; + } else if (fUserText.getText().trim().length() == 0) { + message = Messages.ProxyNewConnectionPage_User_name_cannot_be_empty; + } else if (!fDefaultServerButton.getSelection() && fServerCommandText.getText().trim().length() == 0) { + message = "Server command cannot be empty"; + } + if (message == null) { + message = validateAdvanced(); + } + + setErrorMessage(message); + setPageComplete(message == null); + } + +} diff --git a/bundles/org.eclipse.remote.proxy.ui/src/org/eclipse/remote/internal/proxy/ui/wizards/ProxyConnectionWizard.java b/bundles/org.eclipse.remote.proxy.ui/src/org/eclipse/remote/internal/proxy/ui/wizards/ProxyConnectionWizard.java new file mode 100755 index 00000000000..b8a0489a281 --- /dev/null +++ b/bundles/org.eclipse.remote.proxy.ui/src/org/eclipse/remote/internal/proxy/ui/wizards/ProxyConnectionWizard.java @@ -0,0 +1,71 @@ +/** + * Copyright (c) 2016 Oak Ridge National Laboratory 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 + */ +package org.eclipse.remote.internal.proxy.ui.wizards; + +import java.util.Set; + +import org.eclipse.jface.wizard.Wizard; +import org.eclipse.jface.wizard.WizardDialog; +import org.eclipse.remote.core.IRemoteConnectionType; +import org.eclipse.remote.core.IRemoteConnectionWorkingCopy; +import org.eclipse.remote.ui.IRemoteUIConnectionWizard; +import org.eclipse.swt.widgets.Shell; + +public class ProxyConnectionWizard extends Wizard implements IRemoteUIConnectionWizard { + + private final Shell fShell; + private final ProxyConnectionPage fPage; + + public ProxyConnectionWizard(Shell shell, IRemoteConnectionType connectionType) { + fShell = shell; + fPage = new ProxyConnectionPage(connectionType); + } + + @Override + public void addPages() { + super.addPages(); + addPage(fPage); + } + + public IRemoteConnectionWorkingCopy open() { + WizardDialog dialog = new WizardDialog(fShell, this); + dialog.setBlockOnOpen(true); + if (dialog.open() == WizardDialog.OK) { + return fPage.getConnection(); + } + return null; + } + + @Override + public IRemoteConnectionWorkingCopy getConnection() { + return fPage.getConnection(); + } + + @Override + public boolean performCancel() { + return true; + } + + @Override + public boolean performFinish() { + return true; + } + + public void setConnection(IRemoteConnectionWorkingCopy connection) { + fPage.setConnection(connection); + } + + public void setConnectionName(String name) { + fPage.setConnectionName(name); + } + + public void setInvalidConnectionNames(Set names) { + fPage.setInvalidConnectionNames(names); + } + +} diff --git a/bundles/org.eclipse.remote.serial.core/pom.xml b/bundles/org.eclipse.remote.serial.core/pom.xml index 0c563f09c58..c2f606df50d 100644 --- a/bundles/org.eclipse.remote.serial.core/pom.xml +++ b/bundles/org.eclipse.remote.serial.core/pom.xml @@ -6,7 +6,7 @@ org.eclipse.remote remote-parent - 2.1.0-SNAPSHOT + 3.0.0-SNAPSHOT ../../releng/org.eclipse.remote.build/pom.xml diff --git a/bundles/org.eclipse.remote.serial.core/src/org/eclipse/remote/serial/core/SerialPortConnection.java b/bundles/org.eclipse.remote.serial.core/src/org/eclipse/remote/serial/core/SerialPortConnection.java index 475bee706d8..e5df667db54 100644 --- a/bundles/org.eclipse.remote.serial.core/src/org/eclipse/remote/serial/core/SerialPortConnection.java +++ b/bundles/org.eclipse.remote.serial.core/src/org/eclipse/remote/serial/core/SerialPortConnection.java @@ -20,7 +20,9 @@ import org.eclipse.cdt.serial.StopBits; import org.eclipse.remote.core.IRemoteCommandShellService; import org.eclipse.remote.core.IRemoteConnection; import org.eclipse.remote.core.IRemoteConnection.Service; +import org.eclipse.remote.core.IRemoteConnectionChangeListener; import org.eclipse.remote.core.IRemoteProcess; +import org.eclipse.remote.core.RemoteConnectionChangeEvent; import org.eclipse.remote.serial.internal.core.Activator; import org.eclipse.remote.serial.internal.core.Messages; @@ -31,6 +33,15 @@ public class SerialPortConnection implements ISerialPortService, IRemoteCommandS private SerialPortConnection(IRemoteConnection remoteConnection) { this.remoteConnection = remoteConnection; + this.remoteConnection.addConnectionChangeListener(new IRemoteConnectionChangeListener() { + + @Override + public void connectionChanged(RemoteConnectionChangeEvent event) { + if (event.getType() == RemoteConnectionChangeEvent.ATTRIBUTES_CHANGED) { + serialPort = null; + } + } + }); } public static class Factory implements IRemoteConnection.Service.Factory { diff --git a/bundles/org.eclipse.remote.serial.ui/pom.xml b/bundles/org.eclipse.remote.serial.ui/pom.xml index cf98fab75fb..8fde0d1f82c 100644 --- a/bundles/org.eclipse.remote.serial.ui/pom.xml +++ b/bundles/org.eclipse.remote.serial.ui/pom.xml @@ -6,7 +6,7 @@ org.eclipse.remote remote-parent - 2.1.0-SNAPSHOT + 3.0.0-SNAPSHOT ../../releng/org.eclipse.remote.build/pom.xml diff --git a/bundles/org.eclipse.remote.telnet.core/pom.xml b/bundles/org.eclipse.remote.telnet.core/pom.xml index bc8b750510f..c96080f21af 100644 --- a/bundles/org.eclipse.remote.telnet.core/pom.xml +++ b/bundles/org.eclipse.remote.telnet.core/pom.xml @@ -6,7 +6,7 @@ org.eclipse.remote remote-parent - 2.1.0-SNAPSHOT + 3.0.0-SNAPSHOT ../../releng/org.eclipse.remote.build/pom.xml diff --git a/bundles/org.eclipse.remote.telnet.ui/pom.xml b/bundles/org.eclipse.remote.telnet.ui/pom.xml index 26c59f69e45..e853e5292da 100644 --- a/bundles/org.eclipse.remote.telnet.ui/pom.xml +++ b/bundles/org.eclipse.remote.telnet.ui/pom.xml @@ -6,7 +6,7 @@ org.eclipse.remote remote-parent - 2.1.0-SNAPSHOT + 3.0.0-SNAPSHOT ../../releng/org.eclipse.remote.build/pom.xml diff --git a/bundles/org.eclipse.remote.ui/pom.xml b/bundles/org.eclipse.remote.ui/pom.xml index 883274ef000..911bd199480 100644 --- a/bundles/org.eclipse.remote.ui/pom.xml +++ b/bundles/org.eclipse.remote.ui/pom.xml @@ -6,7 +6,7 @@ org.eclipse.remote remote-parent - 2.1.0-SNAPSHOT + 3.0.0-SNAPSHOT ../../releng/org.eclipse.remote.build/pom.xml diff --git a/features/org.eclipse.remote-feature/feature.xml b/features/org.eclipse.remote-feature/feature.xml index ee2b54bebec..f551016d33e 100644 --- a/features/org.eclipse.remote-feature/feature.xml +++ b/features/org.eclipse.remote-feature/feature.xml @@ -2,7 +2,7 @@ diff --git a/features/org.eclipse.remote-feature/pom.xml b/features/org.eclipse.remote-feature/pom.xml index 73b067f5b18..ac46a39bbf1 100644 --- a/features/org.eclipse.remote-feature/pom.xml +++ b/features/org.eclipse.remote-feature/pom.xml @@ -6,7 +6,7 @@ org.eclipse.remote remote-parent - 2.1.0-SNAPSHOT + 3.0.0-SNAPSHOT ../../releng/org.eclipse.remote.build/pom.xml diff --git a/features/org.eclipse.remote.console-feature/feature.xml b/features/org.eclipse.remote.console-feature/feature.xml index 49d35e74d2d..58708522d4d 100644 --- a/features/org.eclipse.remote.console-feature/feature.xml +++ b/features/org.eclipse.remote.console-feature/feature.xml @@ -2,7 +2,7 @@ diff --git a/features/org.eclipse.remote.console-feature/pom.xml b/features/org.eclipse.remote.console-feature/pom.xml index 2818106fb72..a6bf2225f3f 100644 --- a/features/org.eclipse.remote.console-feature/pom.xml +++ b/features/org.eclipse.remote.console-feature/pom.xml @@ -6,7 +6,7 @@ org.eclipse.remote remote-parent - 2.1.0-SNAPSHOT + 3.0.0-SNAPSHOT ../../releng/org.eclipse.remote.build/pom.xml diff --git a/features/org.eclipse.remote.proxy-feature/.project b/features/org.eclipse.remote.proxy-feature/.project new file mode 100644 index 00000000000..144e9faeaef --- /dev/null +++ b/features/org.eclipse.remote.proxy-feature/.project @@ -0,0 +1,17 @@ + + + org.eclipse.remote.proxy-feature + + + + + + org.eclipse.pde.FeatureBuilder + + + + + + org.eclipse.pde.FeatureNature + + diff --git a/features/org.eclipse.remote.proxy-feature/build.properties b/features/org.eclipse.remote.proxy-feature/build.properties new file mode 100644 index 00000000000..bb3da8d5adc --- /dev/null +++ b/features/org.eclipse.remote.proxy-feature/build.properties @@ -0,0 +1,4 @@ +bin.includes = feature.xml,\ + feature.properties,\ + eclipse_update_120.jpg,\ + epl-v10.html diff --git a/features/org.eclipse.remote.proxy-feature/eclipse_update_120.jpg b/features/org.eclipse.remote.proxy-feature/eclipse_update_120.jpg new file mode 100644 index 00000000000..bfdf708ad61 Binary files /dev/null and b/features/org.eclipse.remote.proxy-feature/eclipse_update_120.jpg differ diff --git a/features/org.eclipse.remote.proxy-feature/epl-v10.html b/features/org.eclipse.remote.proxy-feature/epl-v10.html new file mode 100644 index 00000000000..ed4b196655e --- /dev/null +++ b/features/org.eclipse.remote.proxy-feature/epl-v10.html @@ -0,0 +1,328 @@ + + + + + + + + +Eclipse Public License - Version 1.0 + + + + + + +
+ +

Eclipse Public License - v 1.0 +

+ +

THE ACCOMPANYING PROGRAM IS PROVIDED UNDER +THE TERMS OF THIS ECLIPSE PUBLIC LICENSE ("AGREEMENT"). ANY USE, +REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE +OF THIS AGREEMENT.

+ +

1. DEFINITIONS

+ +

"Contribution" means:

+ +

a) +in the case of the initial Contributor, the initial code and documentation +distributed under this Agreement, and
+b) in the case of each subsequent Contributor:

+ +

i) +changes to the Program, and

+ +

ii) +additions to the Program;

+ +

where +such changes and/or additions to the Program originate from and are distributed +by that particular Contributor. A Contribution 'originates' from a Contributor +if it was added to the Program by such Contributor itself or anyone acting on +such Contributor's behalf. Contributions do not include additions to the +Program which: (i) are separate modules of software distributed in conjunction +with the Program under their own license agreement, and (ii) are not derivative +works of the Program.

+ +

"Contributor" means any person or +entity that distributes the Program.

+ +

"Licensed Patents " mean patent +claims licensable by a Contributor which are necessarily infringed by the use +or sale of its Contribution alone or when combined with the Program.

+ +

"Program" means the Contributions +distributed in accordance with this Agreement.

+ +

"Recipient" means anyone who +receives the Program under this Agreement, including all Contributors.

+ +

2. GRANT OF RIGHTS

+ +

a) +Subject to the terms of this Agreement, each Contributor hereby grants Recipient +a non-exclusive, worldwide, royalty-free copyright license to reproduce, prepare derivative works of, publicly +display, publicly perform, distribute and sublicense the Contribution of such +Contributor, if any, and such derivative works, in source code and object code +form.

+ +

b) +Subject to the terms of this Agreement, each Contributor hereby grants +Recipient a non-exclusive, worldwide, royalty-free +patent license under Licensed Patents to make, use, sell, offer to sell, import +and otherwise transfer the Contribution of such Contributor, if any, in source +code and object code form. This patent license shall apply to the combination +of the Contribution and the Program if, at the time the Contribution is added +by the Contributor, such addition of the Contribution causes such combination +to be covered by the Licensed Patents. The patent license shall not apply to +any other combinations which include the Contribution. No hardware per se is +licensed hereunder.

+ +

c) +Recipient understands that although each Contributor grants the licenses to its +Contributions set forth herein, no assurances are provided by any Contributor +that the Program does not infringe the patent or other intellectual property +rights of any other entity. Each Contributor disclaims any liability to Recipient +for claims brought by any other entity based on infringement of intellectual +property rights or otherwise. As a condition to exercising the rights and +licenses granted hereunder, each Recipient hereby assumes sole responsibility +to secure any other intellectual property rights needed, if any. For example, +if a third party patent license is required to allow Recipient to distribute +the Program, it is Recipient's responsibility to acquire that license before +distributing the Program.

+ +

d) +Each Contributor represents that to its knowledge it has sufficient copyright +rights in its Contribution, if any, to grant the copyright license set forth in +this Agreement.

+ +

3. REQUIREMENTS

+ +

A Contributor may choose to distribute the +Program in object code form under its own license agreement, provided that: +

+ +

a) +it complies with the terms and conditions of this Agreement; and

+ +

b) +its license agreement:

+ +

i) +effectively disclaims on behalf of all Contributors all warranties and +conditions, express and implied, including warranties or conditions of title +and non-infringement, and implied warranties or conditions of merchantability +and fitness for a particular purpose;

+ +

ii) +effectively excludes on behalf of all Contributors all liability for damages, +including direct, indirect, special, incidental and consequential damages, such +as lost profits;

+ +

iii) +states that any provisions which differ from this Agreement are offered by that +Contributor alone and not by any other party; and

+ +

iv) +states that source code for the Program is available from such Contributor, and +informs licensees how to obtain it in a reasonable manner on or through a +medium customarily used for software exchange.

+ +

When the Program is made available in source +code form:

+ +

a) +it must be made available under this Agreement; and

+ +

b) a +copy of this Agreement must be included with each copy of the Program.

+ +

Contributors may not remove or alter any +copyright notices contained within the Program.

+ +

Each Contributor must identify itself as the +originator of its Contribution, if any, in a manner that reasonably allows +subsequent Recipients to identify the originator of the Contribution.

+ +

4. COMMERCIAL DISTRIBUTION

+ +

Commercial distributors of software may +accept certain responsibilities with respect to end users, business partners +and the like. While this license is intended to facilitate the commercial use +of the Program, the Contributor who includes the Program in a commercial +product offering should do so in a manner which does not create potential +liability for other Contributors. Therefore, if a Contributor includes the +Program in a commercial product offering, such Contributor ("Commercial +Contributor") hereby agrees to defend and indemnify every other +Contributor ("Indemnified Contributor") against any losses, damages and +costs (collectively "Losses") arising from claims, lawsuits and other +legal actions brought by a third party against the Indemnified Contributor to +the extent caused by the acts or omissions of such Commercial Contributor in +connection with its distribution of the Program in a commercial product +offering. The obligations in this section do not apply to any claims or Losses +relating to any actual or alleged intellectual property infringement. In order +to qualify, an Indemnified Contributor must: a) promptly notify the Commercial +Contributor in writing of such claim, and b) allow the Commercial Contributor +to control, and cooperate with the Commercial Contributor in, the defense and +any related settlement negotiations. The Indemnified Contributor may participate +in any such claim at its own expense.

+ +

For example, a Contributor might include the +Program in a commercial product offering, Product X. That Contributor is then a +Commercial Contributor. If that Commercial Contributor then makes performance +claims, or offers warranties related to Product X, those performance claims and +warranties are such Commercial Contributor's responsibility alone. Under this +section, the Commercial Contributor would have to defend claims against the +other Contributors related to those performance claims and warranties, and if a +court requires any other Contributor to pay any damages as a result, the +Commercial Contributor must pay those damages.

+ +

5. NO WARRANTY

+ +

EXCEPT AS EXPRESSLY SET FORTH IN THIS +AGREEMENT, THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT +WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, +WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, +MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely +responsible for determining the appropriateness of using and distributing the +Program and assumes all risks associated with its exercise of rights under this +Agreement , including but not limited to the risks and costs of program errors, +compliance with applicable laws, damage to or loss of data, programs or +equipment, and unavailability or interruption of operations.

+ +

6. DISCLAIMER OF LIABILITY

+ +

EXCEPT AS EXPRESSLY SET FORTH IN THIS +AGREEMENT, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY +OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF +THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGES.

+ +

7. GENERAL

+ +

If any provision of this Agreement is invalid +or unenforceable under applicable law, it shall not affect the validity or +enforceability of the remainder of the terms of this Agreement, and without +further action by the parties hereto, such provision shall be reformed to the +minimum extent necessary to make such provision valid and enforceable.

+ +

If Recipient institutes patent litigation +against any entity (including a cross-claim or counterclaim in a lawsuit) +alleging that the Program itself (excluding combinations of the Program with +other software or hardware) infringes such Recipient's patent(s), then such +Recipient's rights granted under Section 2(b) shall terminate as of the date +such litigation is filed.

+ +

All Recipient's rights under this Agreement +shall terminate if it fails to comply with any of the material terms or +conditions of this Agreement and does not cure such failure in a reasonable +period of time after becoming aware of such noncompliance. If all Recipient's +rights under this Agreement terminate, Recipient agrees to cease use and +distribution of the Program as soon as reasonably practicable. However, +Recipient's obligations under this Agreement and any licenses granted by +Recipient relating to the Program shall continue and survive.

+ +

Everyone is permitted to copy and distribute +copies of this Agreement, but in order to avoid inconsistency the Agreement is +copyrighted and may only be modified in the following manner. The Agreement +Steward reserves the right to publish new versions (including revisions) of +this Agreement from time to time. No one other than the Agreement Steward has +the right to modify this Agreement. The Eclipse Foundation is the initial +Agreement Steward. The Eclipse Foundation may assign the responsibility to +serve as the Agreement Steward to a suitable separate entity. Each new version +of the Agreement will be given a distinguishing version number. The Program +(including Contributions) may always be distributed subject to the version of +the Agreement under which it was received. In addition, after a new version of +the Agreement is published, Contributor may elect to distribute the Program +(including its Contributions) under the new version. Except as expressly stated +in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to +the intellectual property of any Contributor under this Agreement, whether +expressly, by implication, estoppel or otherwise. All rights in the Program not +expressly granted under this Agreement are reserved.

+ +

This Agreement is governed by the laws of the +State of New York and the intellectual property laws of the United States of +America. No party to this Agreement will bring a legal action under this +Agreement more than one year after the cause of action arose. Each party waives +its rights to a jury trial in any resulting litigation.

+ +

 

+ +
+ + + + \ No newline at end of file diff --git a/features/org.eclipse.remote.proxy-feature/feature.properties b/features/org.eclipse.remote.proxy-feature/feature.properties new file mode 100644 index 00000000000..338686bfa76 --- /dev/null +++ b/features/org.eclipse.remote.proxy-feature/feature.properties @@ -0,0 +1,25 @@ +################################################################################# +# Copyright (c) 2016 Oak Ridge National Laborator 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 +################################################################################# + +# "featureName" property - name of the feature +featureName=Remote Services Proxy + +# "providerName" property - name of the company that provides the feature +providerName=Eclipse PTP + +# "description" property - description of the feature +description=Provides a proxy for the remote services framework + +# copyright +copyright=\ +Copyright (c) 2016 Oak Ridge National Laboratory and others.\n\ +All rights reserved. This program and the accompanying materials\n\ +are made available under the terms of the Eclipse Public License v1.0\n\ +which accompanies this distribution, and is available at\n\ +http://www.eclipse.org/legal/epl-v10.html\n + diff --git a/features/org.eclipse.remote.proxy-feature/feature.xml b/features/org.eclipse.remote.proxy-feature/feature.xml new file mode 100644 index 00000000000..526bd557e39 --- /dev/null +++ b/features/org.eclipse.remote.proxy-feature/feature.xml @@ -0,0 +1,68 @@ + + + + + %description + + + + %copyright + + + + %license + + + + + + + + + + + + + + + + + diff --git a/features/org.eclipse.remote.proxy-feature/pom.xml b/features/org.eclipse.remote.proxy-feature/pom.xml new file mode 100644 index 00000000000..5de7d331850 --- /dev/null +++ b/features/org.eclipse.remote.proxy-feature/pom.xml @@ -0,0 +1,55 @@ + + + 4.0.0 + + + org.eclipse.remote + remote-parent + 3.0.0-SNAPSHOT + ../../releng/org.eclipse.remote.build/pom.xml + + + + + + org.eclipse.tycho.extras + tycho-source-feature-plugin + ${tycho-version} + + + source-feature + package + + source-feature + + + + + + + + + + + + + org.eclipse.tycho + tycho-p2-plugin + ${tycho-version} + + + attached-p2-metadata + package + + p2-metadata + + + + + + + + org.eclipse.remote.proxy + eclipse-feature + diff --git a/features/org.eclipse.remote.serial-feature/feature.xml b/features/org.eclipse.remote.serial-feature/feature.xml index db621cca4dc..d9824639efe 100644 --- a/features/org.eclipse.remote.serial-feature/feature.xml +++ b/features/org.eclipse.remote.serial-feature/feature.xml @@ -2,7 +2,7 @@ diff --git a/features/org.eclipse.remote.serial-feature/pom.xml b/features/org.eclipse.remote.serial-feature/pom.xml index b931b8f0d6a..b7e675cb05f 100644 --- a/features/org.eclipse.remote.serial-feature/pom.xml +++ b/features/org.eclipse.remote.serial-feature/pom.xml @@ -6,7 +6,7 @@ org.eclipse.remote remote-parent - 2.1.0-SNAPSHOT + 3.0.0-SNAPSHOT ../../releng/org.eclipse.remote.build/pom.xml diff --git a/features/org.eclipse.remote.telnet-feature/feature.xml b/features/org.eclipse.remote.telnet-feature/feature.xml index 627f31cbe6a..49bfac6b516 100644 --- a/features/org.eclipse.remote.telnet-feature/feature.xml +++ b/features/org.eclipse.remote.telnet-feature/feature.xml @@ -2,7 +2,7 @@ diff --git a/features/org.eclipse.remote.telnet-feature/pom.xml b/features/org.eclipse.remote.telnet-feature/pom.xml index e746681187a..4305e87394e 100644 --- a/features/org.eclipse.remote.telnet-feature/pom.xml +++ b/features/org.eclipse.remote.telnet-feature/pom.xml @@ -6,7 +6,7 @@ org.eclipse.remote remote-parent - 2.1.0-SNAPSHOT + 3.0.0-SNAPSHOT ../../releng/org.eclipse.remote.build/pom.xml diff --git a/releng/org.eclipse.remote.build/pom.xml b/releng/org.eclipse.remote.build/pom.xml index ca8185e8176..1c2c22fd962 100644 --- a/releng/org.eclipse.remote.build/pom.xml +++ b/releng/org.eclipse.remote.build/pom.xml @@ -10,13 +10,13 @@ org.eclipse.remote remote-parent - 2.1.0-SNAPSHOT + 3.0.0-SNAPSHOT pom Remote Parent nightly - 0.24.0 + 0.26.0 ${tycho-version} scm:git:git://git.eclipse.org/gitroot/ptp/org.eclipse.remote.git 4.5 @@ -43,13 +43,24 @@ ../../releng/org.eclipse.remote.target - + ../../bundles/org.eclipse.remote.core ../../bundles/org.eclipse.remote.jsch.core ../../bundles/org.eclipse.remote.jsch.ui ../../bundles/org.eclipse.remote.ui + + ../../bundles/org.eclipse.remote.proxy.core + ../../bundles/org.eclipse.remote.proxy.ui + ../../bundles/org.eclipse.remote.proxy.protocol.core + ../../bundles/org.eclipse.remote.proxy.server.core + ../../releng/org.eclipse.remote.proxy.server.product + ../../releng/org.eclipse.remote.proxy.server.linux.x86_64 + ../../releng/org.eclipse.remote.proxy.server.linux.ppc64le + ../../releng/org.eclipse.remote.proxy.server.macosx.x86_64 + ../../features/org.eclipse.remote-feature - ../../releng/org.eclipse.remote.repo + + ../../features/org.eclipse.remote.proxy-feature ../../bundles/org.eclipse.remote.console ../../features/org.eclipse.remote.console-feature @@ -63,6 +74,8 @@ ../../features/org.eclipse.remote.telnet-feature ../../bundles/org.eclipse.remote.doc.isv + + ../../releng/org.eclipse.remote.repo @@ -114,6 +127,11 @@ gtk x86_64 + + linux + gtk + ppc64le + win32 win32 @@ -143,8 +161,8 @@ org.eclipse.remote org.eclipse.remote.target - 2.1.0-SNAPSHOT - neon + 3.0.0-SNAPSHOT + oxygen @@ -176,6 +194,12 @@ source-feature + + + + + +
diff --git a/releng/org.eclipse.remote.proxy.server.linux.ppc64le/.gitignore b/releng/org.eclipse.remote.proxy.server.linux.ppc64le/.gitignore new file mode 100644 index 00000000000..22ddaadc2eb --- /dev/null +++ b/releng/org.eclipse.remote.proxy.server.linux.ppc64le/.gitignore @@ -0,0 +1 @@ +/proxy.server.tar.gz diff --git a/releng/org.eclipse.remote.proxy.server.linux.ppc64le/.project b/releng/org.eclipse.remote.proxy.server.linux.ppc64le/.project new file mode 100644 index 00000000000..19aa35e59de --- /dev/null +++ b/releng/org.eclipse.remote.proxy.server.linux.ppc64le/.project @@ -0,0 +1,22 @@ + + + org.eclipse.remote.proxy.server.linux.ppc64le + + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + + diff --git a/releng/org.eclipse.remote.proxy.server.linux.ppc64le/.settings/org.eclipse.pde.core.prefs b/releng/org.eclipse.remote.proxy.server.linux.ppc64le/.settings/org.eclipse.pde.core.prefs new file mode 100644 index 00000000000..f29e940a005 --- /dev/null +++ b/releng/org.eclipse.remote.proxy.server.linux.ppc64le/.settings/org.eclipse.pde.core.prefs @@ -0,0 +1,3 @@ +eclipse.preferences.version=1 +pluginProject.extensions=false +resolve.requirebundle=false diff --git a/releng/org.eclipse.remote.proxy.server.linux.ppc64le/META-INF/MANIFEST.MF b/releng/org.eclipse.remote.proxy.server.linux.ppc64le/META-INF/MANIFEST.MF new file mode 100644 index 00000000000..11036c2a1d5 --- /dev/null +++ b/releng/org.eclipse.remote.proxy.server.linux.ppc64le/META-INF/MANIFEST.MF @@ -0,0 +1,7 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: %pluginName +Bundle-SymbolicName: org.eclipse.remote.proxy.server.linux.ppc64le +Bundle-Version: 1.0.0.qualifier +Bundle-Vendor: %pluginProvider +Bundle-Localization: plugin diff --git a/releng/org.eclipse.remote.proxy.server.linux.ppc64le/about.html b/releng/org.eclipse.remote.proxy.server.linux.ppc64le/about.html new file mode 100644 index 00000000000..3f810933b39 --- /dev/null +++ b/releng/org.eclipse.remote.proxy.server.linux.ppc64le/about.html @@ -0,0 +1,22 @@ + + + +About + + + +

About This Content

+ +

May 2, 2006

+

License

+ +

The Eclipse Foundation makes available all content in this plug-in ("Content"). Unless otherwise indicated below, the Content is provided to you under the terms and conditions of the +Eclipse Public License Version 1.0 ("EPL"). A copy of the EPL is available at http://www.eclipse.org/legal/epl-v10.html. +For purposes of the EPL, "Program" will mean the Content.

+ +

If you did not receive this Content directly from the Eclipse Foundation, the Content is being redistributed by another party ("Redistributor") and different terms and conditions may +apply to your use of any object code in the Content. Check the Redistributor's license that was provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise +indicated below, the terms and conditions of the EPL still apply to any source code in the Content and such source code may be obtained at http://www.eclipse.org.

+ + + \ No newline at end of file diff --git a/releng/org.eclipse.remote.proxy.server.linux.ppc64le/build.properties b/releng/org.eclipse.remote.proxy.server.linux.ppc64le/build.properties new file mode 100644 index 00000000000..008b5fb1623 --- /dev/null +++ b/releng/org.eclipse.remote.proxy.server.linux.ppc64le/build.properties @@ -0,0 +1,4 @@ +bin.includes = META-INF/,\ + proxy.server.tar.gz,\ + plugin.properties,\ + about.html diff --git a/releng/org.eclipse.remote.proxy.server.linux.ppc64le/plugin.properties b/releng/org.eclipse.remote.proxy.server.linux.ppc64le/plugin.properties new file mode 100644 index 00000000000..1f736f9a1c7 --- /dev/null +++ b/releng/org.eclipse.remote.proxy.server.linux.ppc64le/plugin.properties @@ -0,0 +1,11 @@ +############################################################################### +# Copyright (c) 2016 Oak Ridge National Laboratory 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 +# +############################################################################### + +pluginName=Remote Proxy Server Linux ppc64le Component +pluginProvider=Eclipse PTP diff --git a/releng/org.eclipse.remote.proxy.server.linux.ppc64le/pom.xml b/releng/org.eclipse.remote.proxy.server.linux.ppc64le/pom.xml new file mode 100644 index 00000000000..d1df30c7c82 --- /dev/null +++ b/releng/org.eclipse.remote.proxy.server.linux.ppc64le/pom.xml @@ -0,0 +1,36 @@ + + + 4.0.0 + + + org.eclipse.remote + remote-parent + 3.0.0-SNAPSHOT + ../../releng/org.eclipse.remote.build/pom.xml + + + org.eclipse.remote.proxy.server.linux.ppc64le + eclipse-plugin + 1.0.0-SNAPSHOT + + + + + org.eclipse.tycho + tycho-source-plugin + ${tycho-version} + + + plugin-source + none + + + attach-source + none + + + + + + diff --git a/releng/org.eclipse.remote.proxy.server.linux.x86_64/.gitignore b/releng/org.eclipse.remote.proxy.server.linux.x86_64/.gitignore new file mode 100644 index 00000000000..22ddaadc2eb --- /dev/null +++ b/releng/org.eclipse.remote.proxy.server.linux.x86_64/.gitignore @@ -0,0 +1 @@ +/proxy.server.tar.gz diff --git a/releng/org.eclipse.remote.proxy.server.linux.x86_64/.project b/releng/org.eclipse.remote.proxy.server.linux.x86_64/.project new file mode 100644 index 00000000000..eb7c18084dd --- /dev/null +++ b/releng/org.eclipse.remote.proxy.server.linux.x86_64/.project @@ -0,0 +1,22 @@ + + + org.eclipse.remote.proxy.server.linux.x86_64 + + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + + diff --git a/releng/org.eclipse.remote.proxy.server.linux.x86_64/.settings/org.eclipse.pde.core.prefs b/releng/org.eclipse.remote.proxy.server.linux.x86_64/.settings/org.eclipse.pde.core.prefs new file mode 100644 index 00000000000..f29e940a005 --- /dev/null +++ b/releng/org.eclipse.remote.proxy.server.linux.x86_64/.settings/org.eclipse.pde.core.prefs @@ -0,0 +1,3 @@ +eclipse.preferences.version=1 +pluginProject.extensions=false +resolve.requirebundle=false diff --git a/releng/org.eclipse.remote.proxy.server.linux.x86_64/META-INF/MANIFEST.MF b/releng/org.eclipse.remote.proxy.server.linux.x86_64/META-INF/MANIFEST.MF new file mode 100644 index 00000000000..aa7dda2dd4b --- /dev/null +++ b/releng/org.eclipse.remote.proxy.server.linux.x86_64/META-INF/MANIFEST.MF @@ -0,0 +1,7 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: %pluginName +Bundle-SymbolicName: org.eclipse.remote.proxy.server.linux.x86_64 +Bundle-Version: 1.0.0.qualifier +Bundle-Vendor: %pluginProvider +Bundle-Localization: plugin diff --git a/releng/org.eclipse.remote.proxy.server.linux.x86_64/about.html b/releng/org.eclipse.remote.proxy.server.linux.x86_64/about.html new file mode 100644 index 00000000000..3f810933b39 --- /dev/null +++ b/releng/org.eclipse.remote.proxy.server.linux.x86_64/about.html @@ -0,0 +1,22 @@ + + + +About + + + +

About This Content

+ +

May 2, 2006

+

License

+ +

The Eclipse Foundation makes available all content in this plug-in ("Content"). Unless otherwise indicated below, the Content is provided to you under the terms and conditions of the +Eclipse Public License Version 1.0 ("EPL"). A copy of the EPL is available at http://www.eclipse.org/legal/epl-v10.html. +For purposes of the EPL, "Program" will mean the Content.

+ +

If you did not receive this Content directly from the Eclipse Foundation, the Content is being redistributed by another party ("Redistributor") and different terms and conditions may +apply to your use of any object code in the Content. Check the Redistributor's license that was provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise +indicated below, the terms and conditions of the EPL still apply to any source code in the Content and such source code may be obtained at http://www.eclipse.org.

+ + + \ No newline at end of file diff --git a/releng/org.eclipse.remote.proxy.server.linux.x86_64/build.properties b/releng/org.eclipse.remote.proxy.server.linux.x86_64/build.properties new file mode 100644 index 00000000000..008b5fb1623 --- /dev/null +++ b/releng/org.eclipse.remote.proxy.server.linux.x86_64/build.properties @@ -0,0 +1,4 @@ +bin.includes = META-INF/,\ + proxy.server.tar.gz,\ + plugin.properties,\ + about.html diff --git a/releng/org.eclipse.remote.proxy.server.linux.x86_64/plugin.properties b/releng/org.eclipse.remote.proxy.server.linux.x86_64/plugin.properties new file mode 100644 index 00000000000..c70a4a752f6 --- /dev/null +++ b/releng/org.eclipse.remote.proxy.server.linux.x86_64/plugin.properties @@ -0,0 +1,11 @@ +############################################################################### +# Copyright (c) 2016 Oak Ridge National Laboratory 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 +# +############################################################################### + +pluginName=Remote Proxy Server Linux x86_64 Component +pluginProvider=Eclipse PTP diff --git a/releng/org.eclipse.remote.proxy.server.linux.x86_64/pom.xml b/releng/org.eclipse.remote.proxy.server.linux.x86_64/pom.xml new file mode 100644 index 00000000000..2cc2434ebb6 --- /dev/null +++ b/releng/org.eclipse.remote.proxy.server.linux.x86_64/pom.xml @@ -0,0 +1,36 @@ + + + 4.0.0 + + + org.eclipse.remote + remote-parent + 3.0.0-SNAPSHOT + ../../releng/org.eclipse.remote.build/pom.xml + + + org.eclipse.remote.proxy.server.linux.x86_64 + eclipse-plugin + 1.0.0-SNAPSHOT + + + + + org.eclipse.tycho + tycho-source-plugin + ${tycho-version} + + + plugin-source + none + + + attach-source + none + + + + + + diff --git a/releng/org.eclipse.remote.proxy.server.macosx.x86_64/.gitignore b/releng/org.eclipse.remote.proxy.server.macosx.x86_64/.gitignore new file mode 100644 index 00000000000..22ddaadc2eb --- /dev/null +++ b/releng/org.eclipse.remote.proxy.server.macosx.x86_64/.gitignore @@ -0,0 +1 @@ +/proxy.server.tar.gz diff --git a/releng/org.eclipse.remote.proxy.server.macosx.x86_64/.project b/releng/org.eclipse.remote.proxy.server.macosx.x86_64/.project new file mode 100644 index 00000000000..1cd20fb4f09 --- /dev/null +++ b/releng/org.eclipse.remote.proxy.server.macosx.x86_64/.project @@ -0,0 +1,22 @@ + + + org.eclipse.remote.proxy.server.macosx.x86_64 + + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + + diff --git a/releng/org.eclipse.remote.proxy.server.macosx.x86_64/.settings/org.eclipse.pde.core.prefs b/releng/org.eclipse.remote.proxy.server.macosx.x86_64/.settings/org.eclipse.pde.core.prefs new file mode 100644 index 00000000000..f29e940a005 --- /dev/null +++ b/releng/org.eclipse.remote.proxy.server.macosx.x86_64/.settings/org.eclipse.pde.core.prefs @@ -0,0 +1,3 @@ +eclipse.preferences.version=1 +pluginProject.extensions=false +resolve.requirebundle=false diff --git a/releng/org.eclipse.remote.proxy.server.macosx.x86_64/META-INF/MANIFEST.MF b/releng/org.eclipse.remote.proxy.server.macosx.x86_64/META-INF/MANIFEST.MF new file mode 100644 index 00000000000..e123a2aa174 --- /dev/null +++ b/releng/org.eclipse.remote.proxy.server.macosx.x86_64/META-INF/MANIFEST.MF @@ -0,0 +1,7 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: %pluginName +Bundle-SymbolicName: org.eclipse.remote.proxy.server.macosx.x86_64 +Bundle-Version: 1.0.0.qualifier +Bundle-Vendor: %pluginProvider +Bundle-Localization: plugin diff --git a/releng/org.eclipse.remote.proxy.server.macosx.x86_64/about.html b/releng/org.eclipse.remote.proxy.server.macosx.x86_64/about.html new file mode 100644 index 00000000000..3f810933b39 --- /dev/null +++ b/releng/org.eclipse.remote.proxy.server.macosx.x86_64/about.html @@ -0,0 +1,22 @@ + + + +About + + + +

About This Content

+ +

May 2, 2006

+

License

+ +

The Eclipse Foundation makes available all content in this plug-in ("Content"). Unless otherwise indicated below, the Content is provided to you under the terms and conditions of the +Eclipse Public License Version 1.0 ("EPL"). A copy of the EPL is available at http://www.eclipse.org/legal/epl-v10.html. +For purposes of the EPL, "Program" will mean the Content.

+ +

If you did not receive this Content directly from the Eclipse Foundation, the Content is being redistributed by another party ("Redistributor") and different terms and conditions may +apply to your use of any object code in the Content. Check the Redistributor's license that was provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise +indicated below, the terms and conditions of the EPL still apply to any source code in the Content and such source code may be obtained at http://www.eclipse.org.

+ + + \ No newline at end of file diff --git a/releng/org.eclipse.remote.proxy.server.macosx.x86_64/build.properties b/releng/org.eclipse.remote.proxy.server.macosx.x86_64/build.properties new file mode 100644 index 00000000000..c437c59c8ec --- /dev/null +++ b/releng/org.eclipse.remote.proxy.server.macosx.x86_64/build.properties @@ -0,0 +1,5 @@ +bin.includes = META-INF/,\ + proxy.server.tar.gz,\ + plugin.properties,\ + about.html + \ No newline at end of file diff --git a/releng/org.eclipse.remote.proxy.server.macosx.x86_64/plugin.properties b/releng/org.eclipse.remote.proxy.server.macosx.x86_64/plugin.properties new file mode 100644 index 00000000000..c6f210a642c --- /dev/null +++ b/releng/org.eclipse.remote.proxy.server.macosx.x86_64/plugin.properties @@ -0,0 +1,11 @@ +############################################################################### +# Copyright (c) 2016 Oak Ridge National Laboratory 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 +# +############################################################################### + +pluginName=Remote Proxy Server Mac OS X x86_64 Component +pluginProvider=Eclipse PTP diff --git a/releng/org.eclipse.remote.proxy.server.macosx.x86_64/pom.xml b/releng/org.eclipse.remote.proxy.server.macosx.x86_64/pom.xml new file mode 100644 index 00000000000..9a05a5b1f90 --- /dev/null +++ b/releng/org.eclipse.remote.proxy.server.macosx.x86_64/pom.xml @@ -0,0 +1,36 @@ + + + 4.0.0 + + + org.eclipse.remote + remote-parent + 3.0.0-SNAPSHOT + ../../releng/org.eclipse.remote.build/pom.xml + + + org.eclipse.remote.proxy.server.macosx.x86_64 + eclipse-plugin + 1.0.0-SNAPSHOT + + + + + org.eclipse.tycho + tycho-source-plugin + ${tycho-version} + + + plugin-source + none + + + attach-source + none + + + + + + diff --git a/releng/org.eclipse.remote.proxy.server.product/.project b/releng/org.eclipse.remote.proxy.server.product/.project new file mode 100644 index 00000000000..cf484fa252c --- /dev/null +++ b/releng/org.eclipse.remote.proxy.server.product/.project @@ -0,0 +1,11 @@ + + + org.eclipse.remote.proxy.server.product + + + + + + + + diff --git a/releng/org.eclipse.remote.proxy.server.product/pom.xml b/releng/org.eclipse.remote.proxy.server.product/pom.xml new file mode 100644 index 00000000000..457342f378e --- /dev/null +++ b/releng/org.eclipse.remote.proxy.server.product/pom.xml @@ -0,0 +1,82 @@ + + + 4.0.0 + + + org.eclipse.remote + remote-parent + 3.0.0-SNAPSHOT + ../../releng/org.eclipse.remote.build/pom.xml + + + org.eclipse.remote.proxy.server.product + 1.0.0-SNAPSHOT + eclipse-repository + + + + + org.eclipse.tycho + tycho-p2-repository-plugin + ${tycho-version} + + false + true + + + + org.eclipse.tycho + tycho-p2-director-plugin + ${tycho-version} + + + zip + tar.gz + tar.gz + + + + proxy.server + proxy + + Proxy.app + + + + + + + create-distributions + + materialize-products + archive-products + + + + + + maven-antrun-plugin + + + deploy + install + + run + + + + + + + + + + + + + + diff --git a/releng/org.eclipse.remote.proxy.server.product/proxy.server.product b/releng/org.eclipse.remote.proxy.server.product/proxy.server.product new file mode 100644 index 00000000000..3376d126d2c --- /dev/null +++ b/releng/org.eclipse.remote.proxy.server.product/proxy.server.product @@ -0,0 +1,73 @@ + + + + + + + + + + -consoleLog + + -Declipse.ignoreApp=true -Dosgi.noShutdown=true + + + + + + + + + + + + + org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/releng/org.eclipse.remote.repo/category.xml b/releng/org.eclipse.remote.repo/category.xml index 677d810d9f0..d3be7727fb7 100644 --- a/releng/org.eclipse.remote.repo/category.xml +++ b/releng/org.eclipse.remote.repo/category.xml @@ -24,4 +24,10 @@ + + + + + + diff --git a/releng/org.eclipse.remote.repo/pom.xml b/releng/org.eclipse.remote.repo/pom.xml index fdfc50f9e13..1657b8439c4 100644 --- a/releng/org.eclipse.remote.repo/pom.xml +++ b/releng/org.eclipse.remote.repo/pom.xml @@ -7,7 +7,7 @@ org.eclipse.remote remote-parent - 2.1.0-SNAPSHOT + 3.0.0-SNAPSHOT ../../releng/org.eclipse.remote.build/pom.xml diff --git a/releng/org.eclipse.remote.target/mars.target b/releng/org.eclipse.remote.target/mars.target index c848db9d253..17f384367f1 100644 --- a/releng/org.eclipse.remote.target/mars.target +++ b/releng/org.eclipse.remote.target/mars.target @@ -1,6 +1,5 @@ - - + diff --git a/releng/org.eclipse.remote.target/neon.target b/releng/org.eclipse.remote.target/neon.target index 04844204ae4..f6329af9b68 100644 --- a/releng/org.eclipse.remote.target/neon.target +++ b/releng/org.eclipse.remote.target/neon.target @@ -1,9 +1,10 @@ - + + diff --git a/releng/org.eclipse.remote.target/oxygen.target b/releng/org.eclipse.remote.target/oxygen.target new file mode 100644 index 00000000000..f3a2707f1bf --- /dev/null +++ b/releng/org.eclipse.remote.target/oxygen.target @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/releng/org.eclipse.remote.target/pom.xml b/releng/org.eclipse.remote.target/pom.xml index a46e09c93ee..b61c33fcf0c 100644 --- a/releng/org.eclipse.remote.target/pom.xml +++ b/releng/org.eclipse.remote.target/pom.xml @@ -7,7 +7,7 @@ org.eclipse.remote remote-parent - 2.1.0-SNAPSHOT + 3.0.0-SNAPSHOT ../org.eclipse.remote.build/pom.xml @@ -30,9 +30,9 @@ - neon.target + oxygen.target target - neon + remote-oxygen diff --git a/tests/org.eclipse.remote.proxy.tests/.classpath b/tests/org.eclipse.remote.proxy.tests/.classpath new file mode 100644 index 00000000000..098194ca4b7 --- /dev/null +++ b/tests/org.eclipse.remote.proxy.tests/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/tests/org.eclipse.remote.proxy.tests/.gitignore b/tests/org.eclipse.remote.proxy.tests/.gitignore new file mode 100644 index 00000000000..ae3c1726048 --- /dev/null +++ b/tests/org.eclipse.remote.proxy.tests/.gitignore @@ -0,0 +1 @@ +/bin/ diff --git a/tests/org.eclipse.remote.proxy.tests/.project b/tests/org.eclipse.remote.proxy.tests/.project new file mode 100644 index 00000000000..41c1372aa28 --- /dev/null +++ b/tests/org.eclipse.remote.proxy.tests/.project @@ -0,0 +1,28 @@ + + + org.eclipse.remote.proxy.tests + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/tests/org.eclipse.remote.proxy.tests/.settings/org.eclipse.jdt.core.prefs b/tests/org.eclipse.remote.proxy.tests/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 00000000000..f42de363afa --- /dev/null +++ b/tests/org.eclipse.remote.proxy.tests/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,7 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7 +org.eclipse.jdt.core.compiler.compliance=1.7 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.7 diff --git a/tests/org.eclipse.remote.proxy.tests/META-INF/MANIFEST.MF b/tests/org.eclipse.remote.proxy.tests/META-INF/MANIFEST.MF new file mode 100644 index 00000000000..02587dcfd29 --- /dev/null +++ b/tests/org.eclipse.remote.proxy.tests/META-INF/MANIFEST.MF @@ -0,0 +1,19 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: Remote Proxy Tests +Bundle-SymbolicName: org.eclipse.remote.proxy.tests +Bundle-Version: 1.0.0.qualifier +Bundle-Activator: org.eclipse.remote.proxy.tests.Activator +Bundle-Vendor: Eclipse PTP +Require-Bundle: org.eclipse.ui, + org.eclipse.core.runtime, + org.eclipse.core.filesystem, + org.eclipse.remote.core, + org.eclipse.remote.proxy.core, + org.junit, + org.eclipse.remote.proxy.protocol.core +Bundle-RequiredExecutionEnvironment: JavaSE-1.7 +Bundle-ActivationPolicy: lazy +Import-Package: com.jcraft.jsch;version="0.1.53", + org.eclipse.jsch.core, + org.eclipse.jsch.ui diff --git a/tests/org.eclipse.remote.proxy.tests/build.properties b/tests/org.eclipse.remote.proxy.tests/build.properties new file mode 100644 index 00000000000..34d2e4d2dad --- /dev/null +++ b/tests/org.eclipse.remote.proxy.tests/build.properties @@ -0,0 +1,4 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + . diff --git a/tests/org.eclipse.remote.proxy.tests/src/org/eclipse/remote/proxy/tests/Activator.java b/tests/org.eclipse.remote.proxy.tests/src/org/eclipse/remote/proxy/tests/Activator.java new file mode 100644 index 00000000000..f9e96094b4c --- /dev/null +++ b/tests/org.eclipse.remote.proxy.tests/src/org/eclipse/remote/proxy/tests/Activator.java @@ -0,0 +1,55 @@ +package org.eclipse.remote.proxy.tests; + +import org.eclipse.ui.plugin.AbstractUIPlugin; +import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceReference; + +/** + * The activator class controls the plug-in life cycle + */ +public class Activator extends AbstractUIPlugin { + + // The plug-in ID + public static final String PLUGIN_ID = "org.eclipse.remote.proxy.tests"; //$NON-NLS-1$ + + // The shared instance + private static Activator plugin; + + /** + * The constructor + */ + public Activator() { + } + + public void start(BundleContext context) throws Exception { + super.start(context); + plugin = this; + } + + public void stop(BundleContext context) throws Exception { + plugin = null; + super.stop(context); + } + + /** + * Returns the shared instance + * + * @return the shared instance + */ + public static Activator getDefault() { + return plugin; + } + + /** + * Return the OSGi service with the given service interface. + * + * @param service service interface + * @return the specified service or null if it's not registered + */ + public static T getService(Class service) { + BundleContext context = plugin.getBundle().getBundleContext(); + ServiceReference ref = context.getServiceReference(service); + return ref != null ? context.getService(ref) : null; + } + +} diff --git a/tests/org.eclipse.remote.proxy.tests/src/org/eclipse/remote/proxy/tests/ConnectionTests.java b/tests/org.eclipse.remote.proxy.tests/src/org/eclipse/remote/proxy/tests/ConnectionTests.java new file mode 100644 index 00000000000..66c9a459659 --- /dev/null +++ b/tests/org.eclipse.remote.proxy.tests/src/org/eclipse/remote/proxy/tests/ConnectionTests.java @@ -0,0 +1,258 @@ +package org.eclipse.remote.proxy.tests; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.util.Arrays; +import java.util.Base64; + +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.jsch.core.IJSchService; +import org.eclipse.jsch.ui.UserInfoPrompter; +import org.eclipse.remote.core.IRemoteConnectionType; +import org.eclipse.remote.core.exception.RemoteConnectionException; + +import com.jcraft.jsch.ChannelExec; +import com.jcraft.jsch.ChannelShell; +import com.jcraft.jsch.JSchException; +import com.jcraft.jsch.Session; + +import junit.framework.TestCase; + +public class ConnectionTests extends TestCase { + + private IRemoteConnectionType connType; + + class Context { + private String line; + private State state; + private BufferedReader reader; + private BufferedWriter writer; + + public Context(BufferedReader reader, BufferedWriter writer) { + this.reader = reader; + this.writer = writer; + setState(States.INIT); + } + + String getLine() { + return line; + } + + void setLine(String line) { + this.line = line; + } + + State getState() { + return state; + } + + void setState(State state) { + this.state = state; + } + } + + interface State { + /** + * @return true to keep processing, false to read more data. + */ + boolean process(Context context) throws IOException; + } + + enum States implements State { + INIT { + @Override + public boolean process(Context context) throws IOException { + System.out.println("state="+INIT); + String line = context.reader.readLine(); + System.out.println("got "+ line); + if (line.equals("running")) { + context.setState(States.CHECK); + return true; + } + return false; + } + }, + CHECK { + @Override + public boolean process(Context context) throws IOException { + System.out.println("state="+CHECK); + context.writer.write("check\n"); + context.writer.flush(); + String line = context.reader.readLine(); + String[] parts = line.split(":"); + switch (parts[0]) { + case "ok": + context.setState(States.START); + return true; + case "warning": + context.setState(States.DOWNLOAD); + return true; + } + System.out.println("fail:"+parts[1]); + return false; + } + }, + DOWNLOAD { + @Override + public boolean process(Context context) throws IOException { + System.out.println("state="+DOWNLOAD); + File file = new File("proxy.server-linux.gtk.x86_64.tar.gz"); + long count = file.length() / 510; + System.out.println("download " + count); + context.writer.write("download " + count + "\n"); + context.writer.flush(); + if (downloadFile(file, context.writer)) { + String line = context.reader.readLine(); + String[] parts = line.split(":"); + switch (parts[0]) { + case "ok": + context.setState(States.START); + return true; + case "fail": + System.out.println("fail:"+parts[1]); + return false; + } + } + return false; + } + + private boolean downloadFile(File file, BufferedWriter writer) { + try { + Base64.Encoder encoder = Base64.getEncoder(); + FileInputStream in = new FileInputStream(file); + byte[] buf = new byte[510]; // Multiple of 3 + int n; + while ((n = in.read(buf)) >= 0) { + if (n < 510) { + writer.write(encoder.encodeToString(Arrays.copyOf(buf, n)) + "\n"); + } else { + writer.write(encoder.encodeToString(buf)); + } + } + writer.flush(); + in.close(); + return true; + } catch (IOException e) { + return false; + } + } + }, + START { + @Override + public boolean process(Context context) throws IOException { + System.out.println("state="+START); + context.writer.write("start\n"); + context.writer.flush(); + return false; + } + } + } + + public void testProxyConnection() { + try { + IJSchService jService = Activator.getService(IJSchService.class); + Session session = jService.createSession("titan.ccs.ornl.gov", 22, "gw6"); + session.setConfig("PreferredAuthentications", "password,keyboard-interactive,gssapi-with-mic,publickey"); //$NON-NLS-1$ //$NON-NLS-2$ + new UserInfoPrompter(session); + jService.connect(session, 0, new NullProgressMonitor()); + ChannelExec server = (ChannelExec)session.openChannel("exec"); + server.setCommand("/bin/sh"); + server.connect(); + BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(server.getOutputStream())); + BufferedReader reader = new BufferedReader(new InputStreamReader(server.getInputStream())); + FileReader script = new FileReader("bootstrap.sh"); + BufferedReader scriptReader = new BufferedReader(script); + String line; + while ((line = scriptReader.readLine()) != null) { + writer.write(line + "\n"); + } + scriptReader.close(); + writer.flush(); + Context context = new Context(reader, writer); + while (context.getState().process(context)) { + // do state machine + } + } catch (JSchException | IOException e) { + fail(e.getMessage()); + } + +// try { +// final Process proc = Runtime.getRuntime().exec("java" +// + " -cp /Users/gw6/Work/git/org.eclipse.remote/releng/org.eclipse.remote.proxy.server.product/target/products/proxy.server/macosx/cocoa/x86_64/Proxy.app/Contents/Eclipse/plugins/org.eclipse.equinox.launcher_1.3.200.v20160318-1642.jar" +// + " org.eclipse.equinox.launcher.Main" +// + " -application org.eclipse.remote.proxy.server.core.application" +// + " -noExit"); +// assertTrue(proc.isAlive()); +// +// new Thread("stderr") { +// private byte[] buf = new byte[1024]; +// @Override +// public void run() { +// int n; +// BufferedInputStream err = new BufferedInputStream(proc.getErrorStream()); +// try { +// while ((n = err.read(buf)) >= 0) { +// if (n > 0) { +// System.err.println("server: " + new String(buf, 0, n)); +// } +// } +// } catch (IOException e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); +// } +// } +// +// }.start(); +// +// IRemoteConnection conn = connType.newConnection("test"); +// assertNotNull(conn); +// IRemoteProxyService proxy = conn.getService(IRemoteProxyService.class); +// assertNotNull(proxy); +// proxy.setStreams(proc.getInputStream(), proc.getOutputStream()); +// conn.open(new NullProgressMonitor()); +// conn.close(); +// +// proc.destroy(); +// proc.waitFor(); +// assertEquals(false, proc.isAlive()); +// } catch (IOException | RemoteConnectionException | InterruptedException e) { +// fail(e.getMessage()); +// } + } + + private String executeSshCommand(ChannelShell shell, String command) throws RemoteConnectionException { + try { + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + ByteArrayOutputStream err = new ByteArrayOutputStream(); + shell.setOutputStream(stream); + shell.setExtOutputStream(err); + BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(shell.getOutputStream())); + writer.write(command); + writer.flush(); + if (err.size() > 0) { + throw new RemoteConnectionException(err.toString()); + } + return stream.toString(); + } catch (IOException e) { + throw new RemoteConnectionException(e.getMessage()); + } + } + + @Override + protected void setUp() throws Exception { +// IRemoteServicesManager manager = Activator.getService(IRemoteServicesManager.class); +// connType = manager.getConnectionType("org.eclipse.remote.Proxy"); //$NON-NLS-1$ +// assertNotNull(connType); + } + + @Override + protected void tearDown() throws Exception { + } +} diff --git a/tests/org.eclipse.remote.proxy.tests/src/org/eclipse/remote/proxy/tests/FileStoreTests.java b/tests/org.eclipse.remote.proxy.tests/src/org/eclipse/remote/proxy/tests/FileStoreTests.java new file mode 100644 index 00000000000..755f4f5e6e6 --- /dev/null +++ b/tests/org.eclipse.remote.proxy.tests/src/org/eclipse/remote/proxy/tests/FileStoreTests.java @@ -0,0 +1,289 @@ +package org.eclipse.remote.proxy.tests; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.net.URI; +import java.util.UUID; + +import org.eclipse.core.filesystem.EFS; +import org.eclipse.core.filesystem.IFileInfo; +import org.eclipse.core.filesystem.IFileStore; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.core.runtime.Path; +import org.eclipse.remote.core.IRemoteConnection; +import org.eclipse.remote.core.IRemoteConnectionHostService; +import org.eclipse.remote.core.IRemoteConnectionType; +import org.eclipse.remote.core.IRemoteConnectionWorkingCopy; +import org.eclipse.remote.core.IRemoteFileService; +import org.eclipse.remote.core.IRemoteServicesManager; + +import junit.framework.TestCase; + +public class FileStoreTests extends TestCase { + private static final String CONNECTION_NAME = "test_connection"; + private static final String LOCAL_DIR = "/tmp/ptp_" + UUID.randomUUID(); + private static final String REMOTE_DIR = "/tmp/ptp_" + UUID.randomUUID(); + private static final String DIR_NAME = "filestore_tests"; + private static final String LOCAL_FILE = "local_file"; + private static final String REMOTE_FILE = "remote_file"; + private static final String REMOTE_FILE2 = "remote_file2"; + private static final String TEST_CONTENTS = "a string containing fairly *()(*&^$%##\n random text\n with some newlines\n"; + private static final String TEST_CONTENTS2 = "a different string containing \nfairly *()(*&^$%## random text\n with some newlines\n"; + + private IFileStore remoteParent; + private IFileStore localParent; + private IFileStore remoteDir; + private IFileStore localDir; + + private static IRemoteFileService fileService; + private static IRemoteConnection connection; + + private void createFile(IFileStore fileStore, String contents) throws CoreException, IOException { + OutputStream stream = fileStore.openOutputStream(EFS.NONE, new NullProgressMonitor()); + assertNotNull(stream); + BufferedWriter buf = new BufferedWriter(new OutputStreamWriter(stream)); + buf.write(contents); + buf.close(); + } + + public void testStreams() { + IFileStore remoteFileStore = remoteDir.getChild(REMOTE_FILE); + + for (int i = 0; i < 5; i++) { + try { + remoteFileStore.delete(EFS.NONE, null); + } catch (CoreException e) { + fail(e.getMessage()); + } + + assertFalse(remoteFileStore.fetchInfo().exists()); + + try { + createFile(remoteFileStore, TEST_CONTENTS); + } catch (Exception e) { + fail(e.getMessage()); + } + + assertTrue(remoteFileStore.fetchInfo().exists()); + + try { + InputStream stream = remoteFileStore.openInputStream(EFS.NONE, null); + assertNotNull(stream); + BufferedReader buf = new BufferedReader(new InputStreamReader(stream)); + String line = buf.readLine(); + assertEquals(line, TEST_CONTENTS.split("\n")[0]); + + buf.close(); + } catch (Exception e) { + fail(e.getMessage()); + } + } + } + + public void testMultiStreams() { + IFileStore remoteFileStore = remoteDir.getChild(REMOTE_FILE); + IFileStore remoteFileStore2 = remoteDir.getChild(REMOTE_FILE2); + + try { + createFile(remoteFileStore, TEST_CONTENTS); + createFile(remoteFileStore2, TEST_CONTENTS2); + } catch (Exception e) { + fail(e.getMessage()); + } + + assertTrue(remoteFileStore.fetchInfo().exists()); + assertTrue(remoteFileStore2.fetchInfo().exists()); + + /* + * Check how many streams we can open + */ + InputStream streams[] = new InputStream[10]; + int streamCount = 0; + + for (; streamCount < streams.length; streamCount++) { + try { + streams[streamCount] = remoteFileStore.openInputStream(EFS.NONE, null); + } catch (Exception e) { + if (!e.getMessage().endsWith("channel is not opened.")) { + fail(e.getMessage()); + } + break; + } + } + + for (int i = 0; i < streamCount; i++) { + try { + streams[i].close(); + } catch (IOException e) { + // No need to deal with this + } + } + + for (int i = 0; i < streamCount / 2; i++) { + try { + InputStream stream = remoteFileStore.openInputStream(EFS.NONE, null); + assertNotNull(stream); + BufferedReader buf = new BufferedReader(new InputStreamReader(stream)); + String line = buf.readLine(); + assertEquals(line, TEST_CONTENTS.split("\n")[0]); + + InputStream stream2 = remoteFileStore2.openInputStream(EFS.NONE, null); + assertNotNull(stream2); + BufferedReader buf2 = new BufferedReader(new InputStreamReader(stream2)); + String line2 = buf2.readLine(); + assertEquals(line2, TEST_CONTENTS2.split("\n")[0]); + + stream.close(); + stream2.close(); + } catch (Exception e) { + fail(e.getMessage()); + } + } + } + + public void testCopy() { + final IFileStore localFileStore = localDir.getChild(LOCAL_FILE); + final IFileStore remoteFileStore = remoteDir.getChild(REMOTE_FILE); + try { + localFileStore.delete(EFS.NONE, new NullProgressMonitor()); + remoteFileStore.delete(EFS.NONE, new NullProgressMonitor()); + createFile(localFileStore, "foo\n"); + localFileStore.copy(remoteFileStore, EFS.NONE, new NullProgressMonitor()); + } catch (CoreException e) { + fail(e.getMessage()); + } catch (IOException e) { + fail(e.getMessage()); + } + IFileInfo srcInfo = localFileStore.fetchInfo(); + IFileInfo dstInfo = remoteFileStore.fetchInfo(); + assertTrue(dstInfo.exists()); + assertTrue(srcInfo.getLength() == dstInfo.getLength()); + try { + InputStream stream = remoteFileStore.openInputStream(EFS.NONE, new NullProgressMonitor()); + byte[] b = new byte[4]; + stream.read(b); + stream.close(); + assertTrue(b[0] == 'f'); + assertTrue(b[1] == 'o'); + assertTrue(b[2] == 'o'); + assertTrue(b[3] == '\n'); + } catch (CoreException e) { + fail(e.getMessage()); + } catch (IOException e) { + fail(e.getMessage()); + } + } + + public void testExecutable() { + IFileStore fs = remoteDir.getChild(REMOTE_FILE); + try { + fs.delete(EFS.NONE, new NullProgressMonitor()); + createFile(fs, "contents"); + } catch (Exception e) { + fail(e.getMessage()); + } + IFileInfo fi = fs.fetchInfo(); + boolean current = fi.getAttribute(EFS.ATTRIBUTE_EXECUTABLE); + boolean expected = !current; + fi.setAttribute(EFS.ATTRIBUTE_EXECUTABLE, expected); + try { + fs.putInfo(fi, EFS.SET_ATTRIBUTES, new NullProgressMonitor()); + } catch (CoreException e) { + fail(e.getMessage()); + } + fs = remoteDir.getChild(REMOTE_FILE); + fi = fs.fetchInfo(); + assertEquals(expected, fi.getAttribute(EFS.ATTRIBUTE_EXECUTABLE)); + } + + public void xtestLargeFile() { + IFileStore local = EFS.getLocalFileSystem().getStore(new Path("/usr/bin/php")); + IFileStore remote = remoteDir.getChild("php.xxx"); + try { + remote.delete(0, new NullProgressMonitor()); + InputStream inp = local.openInputStream(0, new NullProgressMonitor()); + OutputStream out = remote.openOutputStream(0, new NullProgressMonitor()); + byte[] b = new byte[1024]; + int len; + while ((len = inp.read(b)) > 0) { + out.write(b, 0, len); + } + inp.close(); + out.close(); + IFileInfo linfo = local.fetchInfo(); + IFileInfo rinfo = remote.fetchInfo(); + assertEquals(linfo.getLength(), rinfo.getLength()); + } catch (CoreException | IOException e) { + fail(e.getMessage()); + } + } + + public void testCopyLargeFile() { + IFileStore local = EFS.getLocalFileSystem().getStore(new Path("/usr/bin/php")); + IFileStore remote = remoteDir.getChild("php.xxx"); + try { + local.copy(remote, EFS.OVERWRITE, new NullProgressMonitor()); + IFileInfo linfo = local.fetchInfo(); + IFileInfo rinfo = remote.fetchInfo(); + assertEquals(linfo.getLength(), rinfo.getLength()); + } catch (CoreException e) { + fail(e.getMessage()); + } + } + + /* + * (non-Javadoc) + * + * @see junit.framework.TestCase#setUp() + */ + @Override + protected void setUp() throws Exception { + if (connection == null) { + IRemoteServicesManager manager = Activator.getService(IRemoteServicesManager.class); + IRemoteConnectionType connType = manager.getConnectionType("org.eclipse.remote.Proxy"); //$NON-NLS-1$ + assertNotNull(connType); + IRemoteConnectionWorkingCopy wc = connType.newConnection(CONNECTION_NAME); + IRemoteConnectionHostService host = wc.getService(IRemoteConnectionHostService.class); + host.setHostname("titan-ext1.ccs.ornl.gov"); +// host.setHostname("localhost"); + host.setUsername("gw6"); + connection = wc.save(); + assertNotNull(connection); + connection.open(new NullProgressMonitor()); + assertTrue(connection.isOpen()); + fileService = connection.getService(IRemoteFileService.class); + assertNotNull(fileService); + } + + URI remoteDirUri = fileService.toURI(REMOTE_DIR); + URI localDirUri = fileService.toURI(LOCAL_DIR); + assertNotNull(remoteDirUri); + assertNotNull(localDirUri); + + remoteParent = EFS.getStore(fileService.toURI(REMOTE_DIR)); + remoteDir = remoteParent.getChild(DIR_NAME); + localParent = EFS.getLocalFileSystem().getStore(new Path(LOCAL_DIR)); + localDir = localParent.getChild(DIR_NAME); + + remoteDir.mkdir(EFS.NONE, null); + localDir.mkdir(EFS.NONE, null); + } + + /* + * (non-Javadoc) + * + * @see junit.framework.TestCase#tearDown() + */ + @Override + protected void tearDown() throws Exception { + remoteParent.delete(EFS.NONE, new NullProgressMonitor()); + localParent.delete(EFS.NONE, new NullProgressMonitor()); + } + +} diff --git a/tests/org.eclipse.remote.proxy.tests/src/org/eclipse/remote/proxy/tests/MultiplexServerTests.java b/tests/org.eclipse.remote.proxy.tests/src/org/eclipse/remote/proxy/tests/MultiplexServerTests.java new file mode 100644 index 00000000000..6c3d2c9c1cb --- /dev/null +++ b/tests/org.eclipse.remote.proxy.tests/src/org/eclipse/remote/proxy/tests/MultiplexServerTests.java @@ -0,0 +1,190 @@ +package org.eclipse.remote.proxy.tests; + +import java.io.BufferedInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +import org.eclipse.remote.proxy.protocol.core.StreamChannelManager; +import org.eclipse.remote.proxy.protocol.core.StreamChannel; + +import junit.framework.TestCase; + +public class MultiplexServerTests extends TestCase { + private static final int NUM_CHANS = 5; + + private class ChanReader implements Runnable { + private byte[] buf = new byte[8192]; + private StreamChannel chan; + private StringBuffer[] recvBufs; + private String name; + + public ChanReader(StreamChannel chan, StringBuffer[] recvBufs, String name) { + this.chan = chan; + this.recvBufs = recvBufs; + this.name = name; + } + + public String getName() { + return name; + } + + @Override + public void run() { + try { + synchronized (MultiplexServerTests.this) { + System.out.println(getName() + " started"); + } + int n; + while ((n = chan.getInputStream().read(buf)) >= 0) { + if (n > 0) { + String s = new String(buf, 0, n); + recvBufs[chan.getId()].append(s); + } + } + synchronized (MultiplexServerTests.this) { + System.out.println(getName() + " finished"); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + private class ChanWriter implements Runnable { + private StreamChannel chan; + private StringBuffer[] sentBufs; + private Random r = new Random(); + private String name; + + public ChanWriter(StreamChannel chan, StringBuffer[] sentBufs, String name) { + this.chan = chan; + this.sentBufs = sentBufs; + this.name = name; + } + + public String getName() { + return name; + } + + @Override + public void run() { + try{ + synchronized (MultiplexServerTests.this) { + System.out.println(getName() + " started"); + } + for (int i = 0; i < 100; i++) { + String s = String.format("%05d\n", i); + chan.getOutputStream().write(s.getBytes()); + // chan.getOutputStream().flush(); + sentBufs[chan.getId()].append(s); + try { + Thread.sleep(r.nextInt(100)); + } catch (InterruptedException e) { + fail(e.getMessage()); + } + } + chan.getOutputStream().flush(); + synchronized (MultiplexServerTests.this) { + System.out.println(getName() + " finished"); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + public void testChannels() { + try { + final StringBuffer[] clntSentBufs = new StringBuffer[NUM_CHANS]; + final StringBuffer[] clntRecvBufs = new StringBuffer[NUM_CHANS]; + + final Thread[] clntReaders = new Thread[NUM_CHANS]; + final Thread[] clntWriters = new Thread[NUM_CHANS]; + + for (int i = 0; i < NUM_CHANS; i++) { + clntSentBufs[i] = new StringBuffer(); + clntRecvBufs[i] = new StringBuffer(); + } + + final Process proc = Runtime.getRuntime().exec("java -jar /Users/gw6/Desktop/Server.jar"); + assertTrue(proc.isAlive()); + + new Thread("stderr") { + private byte[] buf = new byte[1024]; + @Override + public void run() { + int n; + BufferedInputStream err = new BufferedInputStream(proc.getErrorStream()); + try { + while ((n = err.read(buf)) >= 0) { + if (n > 0) { + System.err.println("server: " + new String(buf, 0, n)); + } + } + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + }.start(); + + StreamChannelManager mpxClnt = startMpxClient(proc.getInputStream(), proc.getOutputStream()); + + List channels = runChannelTest(mpxClnt, clntReaders, clntWriters, clntSentBufs, clntRecvBufs); + + for (int i = 0; i < NUM_CHANS; i++) { + clntWriters[i].join(); + } + + for (StreamChannel channel : channels) { + channel.close(); + } + + for (int i = 0; i < NUM_CHANS; i++) { + if (clntReaders[i] != null) { + clntReaders[i].join(); + } + } + + proc.destroy(); + proc.waitFor(); + assertEquals(0, proc.exitValue()); + } catch (IOException | InterruptedException e) { + fail(e.getMessage()); + } + } + + private List runChannelTest(StreamChannelManager mpx, Thread[] readers, Thread[] writers, final StringBuffer[] sentBufs, final StringBuffer[] recvBufs) throws IOException { + List channels = new ArrayList(); + for (int i = 0 ; i < NUM_CHANS; i++) { + StreamChannel chan = mpx.openChannel(); // needs to be in same thread as reader +// ChanReader reader = new ChanReader(chan, recvBufs, "clnt reader thread " + chan.getId()); +// readers[chan.getId()] = new Thread(reader, reader.getName()); + ChanWriter writer = new ChanWriter(chan, sentBufs, "clnt writer thread " + chan.getId()); + writers[chan.getId()] = new Thread(writer, writer.getName()); +// readers[chan.getId()].start(); + writers[chan.getId()].start(); + channels.add(chan); + } + return channels; + } + + private StreamChannelManager startMpxClient(InputStream in, OutputStream out) { + final StreamChannelManager mpx = new StreamChannelManager(in, out); + new Thread(mpx, "client multiplexer").start(); + return mpx; + } + + @Override + protected void setUp() throws Exception { + } + + @Override + protected void tearDown() throws Exception { + } +} diff --git a/tests/org.eclipse.remote.proxy.tests/src/org/eclipse/remote/proxy/tests/MultiplexTests.java b/tests/org.eclipse.remote.proxy.tests/src/org/eclipse/remote/proxy/tests/MultiplexTests.java new file mode 100644 index 00000000000..29703f962e6 --- /dev/null +++ b/tests/org.eclipse.remote.proxy.tests/src/org/eclipse/remote/proxy/tests/MultiplexTests.java @@ -0,0 +1,278 @@ +package org.eclipse.remote.proxy.tests; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.EOFException; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.PipedInputStream; +import java.io.PipedOutputStream; +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +import org.eclipse.remote.proxy.protocol.core.StreamChannelManager; +import org.eclipse.remote.proxy.protocol.core.StreamChannelManager.IChannelListener; +import org.eclipse.remote.proxy.protocol.core.StreamChannel; + +import junit.framework.TestCase; + +public class MultiplexTests extends TestCase { + private static final int NUM_CHANS_PER_THREAD = 5; + private static final int NUM_THREADS = 5; + private static final int FINISH = -1; + + private class ChanReader implements Runnable { + private DataInputStream in; + private List recvBufs; + private String name; + + public ChanReader(StreamChannel chan, List recvBufs, String name) { + this.in = new DataInputStream(chan.getInputStream()); + this.recvBufs = recvBufs; + this.name = name; + } + + public String getName() { + return name; + } + + @Override + public void run() { + try { + synchronized (MultiplexTests.this) { + System.out.println(getName() + " started"); + } + try { + while (true) { + int val = in.readInt(); + if (val == FINISH) { + break; + } + recvBufs.add(val); + } + } catch (EOFException e) { + // Finish + } + synchronized (MultiplexTests.this) { + System.out.println(getName() + " finished"); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + private class ChanWriter implements Runnable { + private DataOutputStream out; + private List sentBufs; + private Random r = new Random(); + private String name; + + public ChanWriter(StreamChannel chan, List sentBufs, String name) { + this.out = new DataOutputStream(chan.getOutputStream()); + this.sentBufs = sentBufs; + this.name = name; + } + + public String getName() { + return name; + } + + @Override + public void run() { + try{ + synchronized (MultiplexTests.this) { + System.out.println(getName() + " started"); + } + for (int i = 0; i < 100; i++) { + int val = r.nextInt(1024); + out.writeInt(val); + out.flush(); + sentBufs.add(val); + try { + Thread.sleep(r.nextInt(100)); + } catch (InterruptedException e) { + fail(e.getMessage()); + } + } + out.writeInt(FINISH); + out.flush(); + synchronized (MultiplexTests.this) { + System.out.println(getName() + " finished"); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + private class ChanReaderWriter implements Runnable { + private DataInputStream in; + private DataOutputStream out; + private String name; + + public ChanReaderWriter(StreamChannel chan, String name) { + this.in = new DataInputStream(chan.getInputStream()); + this.out = new DataOutputStream(chan.getOutputStream()); + this.name = name; + } + + public String getName() { + return name; + } + + @Override + public void run() { + try{ + synchronized (MultiplexTests.this) { + System.out.println(getName() + " started"); + } + try { + while (true) { + int val = in.readInt(); + out.writeInt(val); + out.flush(); + } + } catch (EOFException e) { + // Finish + } + synchronized (MultiplexTests.this) { + System.out.println(getName() + " finished"); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + + public void testChannels() { + try { + final PipedInputStream inClnt = new PipedInputStream(); + final PipedInputStream inSvr = new PipedInputStream(); + final PipedOutputStream outClnt = new PipedOutputStream(inSvr); + final PipedOutputStream outSvr = new PipedOutputStream(inClnt); + + final List> clntSentBufs = new ArrayList>(); + final List> clntRecvBufs = new ArrayList>(); + + final Thread[][] clntReaders = new Thread[NUM_THREADS][NUM_CHANS_PER_THREAD]; + final Thread[][] clntWriters = new Thread[NUM_THREADS][NUM_CHANS_PER_THREAD]; + final Thread[] svrRW = new Thread[NUM_THREADS * NUM_CHANS_PER_THREAD]; + final Thread[] testers = new Thread[NUM_THREADS]; + + for (int i = 0; i < NUM_CHANS_PER_THREAD * NUM_THREADS; i++) { + clntSentBufs.add(new ArrayList()); + clntRecvBufs.add(new ArrayList()); + } + + // Must start server first or it will miss the new channel message + StreamChannelManager mpxSvr = startMpxServer(inSvr, outSvr, svrRW); + + StreamChannelManager mpxClnt = startMpxClient(inClnt, outClnt); + + List channels = runChannelTest(mpxClnt, testers, clntReaders, clntWriters, clntSentBufs, clntRecvBufs); + + // Make sure all the testers have finished + for (int i = 0; i < NUM_THREADS; i++) { + testers[i].join(); + } + + // Wait for the readers and writers to complete + for (int i = 0; i < NUM_THREADS; i++) { + for (int j = 0; j < NUM_CHANS_PER_THREAD; j++) { + clntWriters[i][j].join(); + clntReaders[i][j].join(); + } + } + + for (StreamChannel channel : channels) { + channel.close(); + } + + for (int i = 0; i < NUM_THREADS * NUM_CHANS_PER_THREAD; i++) { + svrRW[i].join(); + } + + for (int i = 0; i < NUM_CHANS_PER_THREAD * NUM_THREADS; i++) { + assertEquals(clntSentBufs.get(i), clntRecvBufs.get(i)); + } + } catch (IOException | InterruptedException e) { + fail(e.getMessage()); + } + } + + private List runChannelTest(final StreamChannelManager mpx, final Thread[] testers, final Thread[][] readers, final Thread[][] writers, final List> sentBufs, final List> recvBufs) throws IOException { + final List channels = new ArrayList(); + for (int i = 0 ; i < NUM_THREADS; i++) { + final int thread = i; + testers[i] = new Thread("client test thread " + thread) { + @Override + public void run() { + try { + for (int j = 0 ; j < NUM_CHANS_PER_THREAD; j++) { + StreamChannel chan = mpx.openChannel(); + ChanReader reader = new ChanReader(chan, recvBufs.get(thread * NUM_CHANS_PER_THREAD + j), "clnt reader thread=" + thread + " chan=" + chan.getId()); + readers[thread][j] = new Thread(reader, reader.getName()); + ChanWriter writer = new ChanWriter(chan, sentBufs.get(thread * NUM_CHANS_PER_THREAD + j), "clnt writer thread=" + thread + " chan=" + chan.getId()); + writers[thread][j] = new Thread(writer, writer.getName()); + readers[thread][j].start(); + writers[thread][j].start(); + channels.add(chan); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + }; + testers[i].start(); + } + return channels; + } + + private StreamChannelManager startMpxClient(InputStream in, OutputStream out) { + final StreamChannelManager mpx = new StreamChannelManager(in, out); + new Thread(mpx, "client multiplexer").start(); + return mpx; + } + + private StreamChannelManager startMpxServer(InputStream in, OutputStream out, final Thread[] rws) throws IOException { + final StreamChannelManager mpx = new StreamChannelManager(in, out); + mpx.setServer(true); + mpx.addListener(new IChannelListener() { + private int numThreadChans; + + @Override + public void newChannel(final StreamChannel chan) { + synchronized (MultiplexTests.this) { + System.out.println("newChannel "+chan.getId()); + } + + ChanReaderWriter rw = new ChanReaderWriter(chan, "svr rw thread " + numThreadChans); + rws[numThreadChans] = new Thread(rw, rw.getName()); + rws[numThreadChans++].start(); + } + + @Override + public void closeChannel(StreamChannel chan) { +// readers[idx].interrupt(); +// writers[idx].interrupt(); + synchronized (MultiplexTests.this) { + System.out.println("closeChannel "+ chan.getId()); + } + } + }); + new Thread(mpx, "server multiplexer").start(); + return mpx; + } + + @Override + protected void setUp() throws Exception { + } + + @Override + protected void tearDown() throws Exception { + } +} diff --git a/tests/org.eclipse.remote.proxy.tests/src/org/eclipse/remote/proxy/tests/ProcessTests.java b/tests/org.eclipse.remote.proxy.tests/src/org/eclipse/remote/proxy/tests/ProcessTests.java new file mode 100644 index 00000000000..eddb93a3db3 --- /dev/null +++ b/tests/org.eclipse.remote.proxy.tests/src/org/eclipse/remote/proxy/tests/ProcessTests.java @@ -0,0 +1,269 @@ +package org.eclipse.remote.proxy.tests; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.remote.core.IRemoteConnection; +import org.eclipse.remote.core.IRemoteConnectionHostService; +import org.eclipse.remote.core.IRemoteConnectionType; +import org.eclipse.remote.core.IRemoteConnectionWorkingCopy; +import org.eclipse.remote.core.IRemoteProcess; +import org.eclipse.remote.core.IRemoteProcessBuilder; +import org.eclipse.remote.core.IRemoteProcessService; +import org.eclipse.remote.core.IRemoteServicesManager; +import org.eclipse.remote.core.RemoteProcessAdapter; + +import junit.framework.TestCase; + +public class ProcessTests extends TestCase { + private static final String CONNECTION_NAME = "test_connection"; + private static final int NUM_THREADS = 1; + + private static IRemoteConnection connection; + private static IRemoteProcessService processService; + + private boolean threadFailed = false; + + public void testStreamHalfClose() { + IRemoteProcessBuilder builder = processService.getProcessBuilder("perl", "-v"); //$NON-NLS-1$ + try { + final Set results = new HashSet(); + IRemoteProcess proc = builder.start(); + proc.getOutputStream().close(); // close stdin to make sure half closed channel works + BufferedReader stdout = new BufferedReader(new InputStreamReader(proc.getInputStream())); + String line; + while ((line = stdout.readLine()) != null) { + results.add(line); + results.add("\n"); + } + try { + proc.waitFor(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + assertTrue(results.toString().contains("Larry Wall")); + } catch (IOException e) { + fail(e.getMessage()); + } + + } + + public void testConcurrentProcess() { + Thread[] threads = new Thread[NUM_THREADS]; + + for (int t = 0; t < NUM_THREADS; t++) { + final String threadNum = Integer.toString(t); + Thread thread = new Thread("test thread " + t) { + @Override + public void run() { + final Set results = Collections.synchronizedSet(new HashSet()); + IRemoteProcessBuilder builder = processService.getProcessBuilder("perl", "-v"); //$NON-NLS-1$ + assertNotNull(builder); +// builder.redirectErrorStream(true); + for (int i = 0; i < 1; i++) { + try { + IRemoteProcess proc = builder.start(); + BufferedReader stdout = new BufferedReader(new InputStreamReader(proc.getInputStream())); + String line; + while ((line = stdout.readLine()) != null) { + System.out.println("read "+line); + results.add(line); + results.add("\n"); + } + try { + proc.waitFor(); + } catch (InterruptedException e) { + fail(e.getMessage()); + } + if (!results.toString().contains("Larry Wall")) { + threadFailed = true; + } + assertTrue(results.toString().contains("Larry Wall")); + } catch (IOException e) { + fail(e.getMessage()); + } + } + } + + }; + thread.start(); + threads[t] = thread; + } + for (Thread t : threads) { + try { + t.join(); + } catch (InterruptedException e) { + } + } + assertFalse(threadFailed); + } + + public void testEnv() { + IRemoteProcessBuilder builder = processService.getProcessBuilder("printenv"); //$NON-NLS-1$ + assertNotNull(builder); + builder.redirectErrorStream(true); + String path = builder.environment().get("PATH"); + builder.environment().clear(); + builder.environment().put("PATH", path); + try { + IRemoteProcess proc = builder.start(); + BufferedReader stdout = new BufferedReader(new InputStreamReader(proc.getInputStream())); + String line; + String result = null; + while ((line = stdout.readLine()) != null) { + assertNull(result); + result = line; + break; + } + assertEquals("PATH=" + path, result); + } catch (IOException e) { + e.printStackTrace(); + fail(e.getLocalizedMessage()); + } + } + + public void testEcho() { + IRemoteProcessBuilder builder = processService.getProcessBuilder("cat"); //$NON-NLS-1$ + assertNotNull(builder); + builder.redirectErrorStream(true); + final StringBuffer result = new StringBuffer(); + try { + final IRemoteProcess proc = builder.start(); + Thread readerThread = new Thread("echo reader thread") { + @Override + public void run() { + try { + BufferedReader stdout = new BufferedReader(new InputStreamReader(proc.getInputStream())); + String line = stdout.readLine(); + int count = Integer.parseInt(line); + for (int i = 0 ; i < count; i++) { + line = stdout.readLine(); + if (line == null) { + break; + } + result.append(line); + System.out.println(line); + } + try { + proc.destroy(); + proc.waitFor(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } catch (IOException e) { + e.printStackTrace(); + fail(e.getLocalizedMessage()); + } + } + + }; + Thread writerThread = new Thread("echo writer thread") { + @Override + public void run() { + try { + BufferedWriter stdin = new BufferedWriter(new OutputStreamWriter(proc.getOutputStream())); + int count = 10; + String line = count + "\n"; + stdin.write(line); + stdin.flush(); + for (int i = 0; i < count; i++) { + line = i + "\n"; + stdin.write(line); + stdin.flush(); + } + try { + proc.waitFor(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } catch (IOException e) { + e.printStackTrace(); + fail(e.getLocalizedMessage()); + } + } + + }; + writerThread.start(); + readerThread.start(); + writerThread.join(); + readerThread.join(); + } catch (IOException e) { + e.printStackTrace(); + fail(e.getLocalizedMessage()); + } catch (InterruptedException e) { + e.printStackTrace(); + fail(e.getLocalizedMessage()); + } + + assertEquals("0123456789", result.toString()); + } + + public void testExitValue() { + IRemoteProcessBuilder builder = processService.getProcessBuilder(new String[]{"sleep","50"}); //$NON-NLS-1$ + assertNotNull(builder); + IRemoteProcess rp = null; + try { + rp = builder.start(); + } catch (IOException e) { + e.printStackTrace(); + fail(e.getLocalizedMessage()); + } + assertNotNull(rp); + Process p = new RemoteProcessAdapter(rp); + try { + p.exitValue(); + fail("Process has not exited. Should throws an IllegalThreadStateException exception"); + } catch(IllegalThreadStateException e) { + // Ok + } + try { + p.destroyForcibly(); + p.waitFor(); + } catch (InterruptedException e) { + fail(e.getMessage()); + } + assertFalse(p.isAlive()); + } + + /* + * (non-Javadoc) + * + * @see junit.framework.TestCase#setUp() + */ + @Override + protected void setUp() throws Exception { + if (connection == null) { + IRemoteServicesManager manager = Activator.getService(IRemoteServicesManager.class); + IRemoteConnectionType connType = manager.getConnectionType("org.eclipse.remote.Proxy"); //$NON-NLS-1$ + assertNotNull(connType); + IRemoteConnectionWorkingCopy wc = connType.newConnection(CONNECTION_NAME); + IRemoteConnectionHostService host = wc.getService(IRemoteConnectionHostService.class); + host.setHostname("localhost"); +// host.setHostname("titan-ext1.ccs.ornl.gov"); + host.setUsername("gw6"); + connection = wc.save(); + assertNotNull(connection); + connection.open(new NullProgressMonitor()); + assertTrue(connection.isOpen()); + processService = connection.getService(IRemoteProcessService.class); + assertNotNull(processService); + } + } + + /* + * (non-Javadoc) + * + * @see junit.framework.TestCase#tearDown() + */ + @Override + protected void tearDown() throws Exception { + } + +} diff --git a/tests/org.eclipse.remote.proxy.tests/src/org/eclipse/remote/proxy/tests/RemoteCoreTestSuite.java b/tests/org.eclipse.remote.proxy.tests/src/org/eclipse/remote/proxy/tests/RemoteCoreTestSuite.java new file mode 100644 index 00000000000..2d9151705a4 --- /dev/null +++ b/tests/org.eclipse.remote.proxy.tests/src/org/eclipse/remote/proxy/tests/RemoteCoreTestSuite.java @@ -0,0 +1,13 @@ +package org.eclipse.remote.proxy.tests; + +import junit.framework.Test; +import junit.framework.TestSuite; + +public class RemoteCoreTestSuite { + public static Test suite() { + TestSuite suite = new TestSuite(RemoteCoreTestSuite.class.getName()); + + return suite; + } + +} diff --git a/tests/org.eclipse.remote.ui.tests/.gitignore b/tests/org.eclipse.remote.ui.tests/.gitignore new file mode 100644 index 00000000000..ae3c1726048 --- /dev/null +++ b/tests/org.eclipse.remote.ui.tests/.gitignore @@ -0,0 +1 @@ +/bin/