From 250119f1dbac19febf1b4fb149ab97ad7b632e3c Mon Sep 17 00:00:00 2001 From: Anna Dushistova Date: Thu, 4 Dec 2008 22:20:10 +0000 Subject: [PATCH] [240523][227569] added new generic terminal shell service, generic terminal subsystem and telnet reference implementation. --- .../telnet/TelnetConnectorService.java | 19 +- .../META-INF/MANIFEST.MF | 5 +- .../telnet/ITelnetSessionProvider.java | 14 +- .../EOFDetectingInputStreamWrapper.java | 80 +++++ .../terminal/TelnetTerminalService.java | 98 +++++++ .../telnet/terminal/TelnetTerminalShell.java | 274 ++++++++++++++++++ .../org.eclipse.rse.services/plugin.xml | 20 ++ .../shells/TerminalServiceHostShell.java | 158 ++++++++++ .../TerminalServiceShellOutputReader.java | 150 ++++++++++ .../TerminalServiceShellWriterThread.java | 101 +++++++ .../shells/TerminalShellAdapterFactory.java | 38 +++ .../services/shells/TerminalShellService.java | 96 ++++++ .../telnet/TelnetServiceCommandShell.java | 7 +- .../TelnetShellSubSystemConfiguration.java | 7 +- .../build.properties | 3 +- .../icons/full/obj16/terminalcommands_obj.gif | Bin 0 -> 938 bytes .../full/obj16/terminalcommandslive_obj.gif | Bin 0 -> 938 bytes .../plugin.properties | 3 + .../plugin.xml | 30 ++ .../DelegatingTerminalConnectorService.java | 66 +++++ .../core/DelegatingTerminalService.java | 84 ++++++ .../TerminalSubSystemConfigurationImpl.java | 66 +++++ .../core/TerminalSubSystemHelper.java | 75 +++++ .../core/TerminalServiceSubSystem.java | 183 ++++++------ ...TerminalServiceSubSystemConfiguration.java | 27 +- .../terminals/ui/TerminalServiceHelper.java | 8 +- .../META-INF/MANIFEST.MF | 3 +- rse/tests/org.eclipse.rse.tests/plugin.xml | 7 + .../subsystems/shells/ShellServiceTest.java | 17 +- .../shells/TerminalShellServiceTest.java | 102 +++++++ .../sshTerminalConnection.properties | 28 ++ .../test.data/telnetConnection.properties | 28 ++ 32 files changed, 1671 insertions(+), 126 deletions(-) create mode 100644 rse/plugins/org.eclipse.rse.services.telnet/src/org/eclipse/rse/internal/services/telnet/terminal/EOFDetectingInputStreamWrapper.java create mode 100644 rse/plugins/org.eclipse.rse.services.telnet/src/org/eclipse/rse/internal/services/telnet/terminal/TelnetTerminalService.java create mode 100644 rse/plugins/org.eclipse.rse.services.telnet/src/org/eclipse/rse/internal/services/telnet/terminal/TelnetTerminalShell.java create mode 100644 rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/internal/services/shells/TerminalServiceHostShell.java create mode 100644 rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/internal/services/shells/TerminalServiceShellOutputReader.java create mode 100644 rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/internal/services/shells/TerminalServiceShellWriterThread.java create mode 100644 rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/internal/services/shells/TerminalShellAdapterFactory.java create mode 100644 rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/internal/services/shells/TerminalShellService.java create mode 100644 rse/plugins/org.eclipse.rse.subsystems.terminals.core/icons/full/obj16/terminalcommands_obj.gif create mode 100644 rse/plugins/org.eclipse.rse.subsystems.terminals.core/icons/full/obj16/terminalcommandslive_obj.gif create mode 100644 rse/plugins/org.eclipse.rse.subsystems.terminals.core/plugin.xml create mode 100644 rse/plugins/org.eclipse.rse.subsystems.terminals.core/src/org/eclipse/rse/internal/subsystems/terminals/core/DelegatingTerminalConnectorService.java create mode 100644 rse/plugins/org.eclipse.rse.subsystems.terminals.core/src/org/eclipse/rse/internal/subsystems/terminals/core/DelegatingTerminalService.java create mode 100644 rse/plugins/org.eclipse.rse.subsystems.terminals.core/src/org/eclipse/rse/internal/subsystems/terminals/core/TerminalSubSystemConfigurationImpl.java create mode 100644 rse/plugins/org.eclipse.rse.subsystems.terminals.core/src/org/eclipse/rse/internal/subsystems/terminals/core/TerminalSubSystemHelper.java create mode 100644 rse/tests/org.eclipse.rse.tests/src/org/eclipse/rse/tests/subsystems/shells/TerminalShellServiceTest.java create mode 100644 rse/tests/org.eclipse.rse.tests/test.data/sshTerminalConnection.properties create mode 100644 rse/tests/org.eclipse.rse.tests/test.data/telnetConnection.properties diff --git a/rse/plugins/org.eclipse.rse.connectorservice.telnet/src/org/eclipse/rse/internal/connectorservice/telnet/TelnetConnectorService.java b/rse/plugins/org.eclipse.rse.connectorservice.telnet/src/org/eclipse/rse/internal/connectorservice/telnet/TelnetConnectorService.java index fb4096a572f..ee49e03728e 100644 --- a/rse/plugins/org.eclipse.rse.connectorservice.telnet/src/org/eclipse/rse/internal/connectorservice/telnet/TelnetConnectorService.java +++ b/rse/plugins/org.eclipse.rse.connectorservice.telnet/src/org/eclipse/rse/internal/connectorservice/telnet/TelnetConnectorService.java @@ -7,18 +7,19 @@ * * Contributors: * Martin Oberhuber (Wind River) - initial API and implementation - * David Dykstal (IBM) - 168977: refactoring IConnectorService and ServerLauncher hierarchies - * Sheldon D'souza (Celunite) - adapted from SshConnectorService + * David Dykstal (IBM) - [168977] refactoring IConnectorService and ServerLauncher hierarchies + * Sheldon D'souza (Celunite) - adapted from SshConnectorService * Martin Oberhuber (Wind River) - apply refactorings for StandardConnectorService * Martin Oberhuber (Wind River) - [178606] fix endless loop in readUntil() - * Sheldon D'souza (Celunite) - [186536] login and password should be configurable - * Sheldon D'souza (Celunite) - [186570] handle invalid user id and password more gracefully + * Sheldon D'souza (Celunite) - [186536] login and password should be configurable + * Sheldon D'souza (Celunite) - [186570] handle invalid user id and password more gracefully * Martin Oberhuber (Wind River) - [187218] Fix error reporting for connect() - * Sheldon D'souza (Celunite) - [187301] support multiple telnet shells - * Sheldon D'souza (Celunite) - [194464] fix create multiple telnet shells quickly + * Sheldon D'souza (Celunite) - [187301] support multiple telnet shells + * Sheldon D'souza (Celunite) - [194464] fix create multiple telnet shells quickly * Martin Oberhuber (Wind River) - [186761] make the port setting configurable * David McKnight (IBM) - [216252] [api][nls] Resource Strings specific to subsystems should be moved from rse.ui into files.ui / shells.ui / processes.ui where possible * David McKnight (IBM) - [220547] [api][breaking] SimpleSystemMessage needs to specify a message id and some messages should be shared + * Anna Dushistova (MontaVista) - [240523] [rseterminals] Provide a generic adapter factory that adapts any ITerminalService to an IShellService *******************************************************************************/ package org.eclipse.rse.internal.connectorservice.telnet; @@ -148,8 +149,12 @@ public class TelnetConnectorService extends StandardConnectorService implements return port; } - public TelnetClient makeNewTelnetClient( IProgressMonitor monitor ) throws Exception { + public TelnetClient makeNewTelnetClient(IProgressMonitor monitor ) throws Exception { TelnetClient client = new TelnetClient(); + return makeNewTelnetClient(client, monitor); + } + + public TelnetClient makeNewTelnetClient(TelnetClient client, IProgressMonitor monitor ) throws Exception { String host = getHostName(); String user = getUserId(); String password = ""; //$NON-NLS-1$ diff --git a/rse/plugins/org.eclipse.rse.services.telnet/META-INF/MANIFEST.MF b/rse/plugins/org.eclipse.rse.services.telnet/META-INF/MANIFEST.MF index 89d91d09b6e..62eab588b42 100644 --- a/rse/plugins/org.eclipse.rse.services.telnet/META-INF/MANIFEST.MF +++ b/rse/plugins/org.eclipse.rse.services.telnet/META-INF/MANIFEST.MF @@ -2,14 +2,15 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %pluginName Bundle-SymbolicName: org.eclipse.rse.services.telnet -Bundle-Version: 1.1.100.qualifier +Bundle-Version: 1.2.0.qualifier Bundle-Activator: org.eclipse.rse.internal.services.telnet.Activator Bundle-Localization: plugin Require-Bundle: org.eclipse.core.runtime, org.eclipse.rse.services;bundle-version="[3.0.0,4.0.0)", org.apache.commons.net;bundle-version="[1.4.1,2.0.0)" Export-Package: org.eclipse.rse.internal.services.telnet;x-friends:="org.eclipse.rse.connectorservice.telnet,org.eclipse.rse.subsystems.files.telnet,org.eclipse.rse.subsystems.shells.telnet", - org.eclipse.rse.internal.services.telnet.shell;x-friends:="org.eclipse.rse.connectorservice.telnet,org.eclipse.rse.subsystems.shells.telnet" + org.eclipse.rse.internal.services.telnet.shell;x-friends:="org.eclipse.rse.connectorservice.telnet,org.eclipse.rse.subsystems.shells.telnet", + org.eclipse.rse.internal.services.telnet.terminal;x-friends:="org.eclipse.rse.subsystems.shells.telnet" Bundle-ActivationPolicy: lazy Eclipse-LazyStart: true Bundle-Vendor: %providerName diff --git a/rse/plugins/org.eclipse.rse.services.telnet/src/org/eclipse/rse/internal/services/telnet/ITelnetSessionProvider.java b/rse/plugins/org.eclipse.rse.services.telnet/src/org/eclipse/rse/internal/services/telnet/ITelnetSessionProvider.java index f17909a5780..c22e327d49b 100644 --- a/rse/plugins/org.eclipse.rse.services.telnet/src/org/eclipse/rse/internal/services/telnet/ITelnetSessionProvider.java +++ b/rse/plugins/org.eclipse.rse.services.telnet/src/org/eclipse/rse/internal/services/telnet/ITelnetSessionProvider.java @@ -12,8 +12,9 @@ * Emily Bruner, Mazen Faraj, Adrian Storisteanu, Li Ding, and Kent Hawley. * * Contributors: - * Sheldon D'souza (Celunite) - adapted from ISshSessionProvider - * Sheldon D'souza (Celunite) - [187301] support multiple telnet shells + * Sheldon D'souza (Celunite) - adapted from ISshSessionProvider + * Sheldon D'souza (Celunite) - [187301] support multiple telnet shells + * Anna Dushistova (MontaVista) - [240523] [rseterminals] Provide a generic adapter factory that adapts any ITerminalService to an IShellService *******************************************************************************/ package org.eclipse.rse.internal.services.telnet; @@ -29,5 +30,14 @@ public interface ITelnetSessionProvider { * @throws Exception in case of any error */ public TelnetClient makeNewTelnetClient(IProgressMonitor monitor) throws Exception ; + + /** + * Initialize a new Commons.Net TelnetClient with a given ptyType. + * @param client telnet client already created + * @param monitor progress monitor + * @return authenticated client for the given connection + * @throws Exception in case of any error + */ + public TelnetClient makeNewTelnetClient(TelnetClient client, IProgressMonitor monitor) throws Exception ; } diff --git a/rse/plugins/org.eclipse.rse.services.telnet/src/org/eclipse/rse/internal/services/telnet/terminal/EOFDetectingInputStreamWrapper.java b/rse/plugins/org.eclipse.rse.services.telnet/src/org/eclipse/rse/internal/services/telnet/terminal/EOFDetectingInputStreamWrapper.java new file mode 100644 index 00000000000..7e63d744d11 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services.telnet/src/org/eclipse/rse/internal/services/telnet/terminal/EOFDetectingInputStreamWrapper.java @@ -0,0 +1,80 @@ +/******************************************************************************* + * Copyright (c) 2008 MontaVista Software, Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Anna Dushistova (MontaVista) - initial API and implementation + * Martin Oberhuber (Wind River) - [240523] [rseterminals] Provide a generic adapter factory that adapts any ITerminalService to an IShellService + *******************************************************************************/ + +package org.eclipse.rse.internal.services.telnet.terminal; + +import java.io.FilterInputStream; +import java.io.IOException; +import java.io.InputStream; + +/** + * @since 1.2 + */ +public class EOFDetectingInputStreamWrapper extends FilterInputStream { + + private boolean fEOF = false; + + public EOFDetectingInputStreamWrapper(InputStream origStream) { + super(origStream); + } + + public synchronized boolean isEOF() { + return fEOF; + } + + public synchronized void setEOF(boolean eof) { + fEOF = eof; + } + + public int read() throws IOException { + try { + int result = in.read(); + if (result < 0) { + setEOF(true); + } + return result; + } catch (IOException e) { + setEOF(true); + throw (e); + } + } + + /* + * (non-Javadoc) + * + * @see java.io.InputStream#close() + */ + public void close() throws IOException { + try { + in.close(); + } finally { + setEOF(true); + } + } + + /* + * (non-Javadoc) + * + * @see java.io.InputStream#read(byte[], int, int) + */ + public int read(byte[] b, int off, int len) throws IOException { + try { + int result = in.read(b, off, len); + if (result < 0) + setEOF(true); + return result; + } catch (IOException e) { + setEOF(true); + throw (e); + } + } +} diff --git a/rse/plugins/org.eclipse.rse.services.telnet/src/org/eclipse/rse/internal/services/telnet/terminal/TelnetTerminalService.java b/rse/plugins/org.eclipse.rse.services.telnet/src/org/eclipse/rse/internal/services/telnet/terminal/TelnetTerminalService.java new file mode 100644 index 00000000000..cd80329b0d3 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services.telnet/src/org/eclipse/rse/internal/services/telnet/terminal/TelnetTerminalService.java @@ -0,0 +1,98 @@ +/******************************************************************************* + * Copyright (c) 2008 Wind River Systems, Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Martin Oberhuber (Wind River) - initial API and implementation + * Anna Dushistova (MontaVista) - adapted from SshTerminalService + * Anna Dushistova (MontaVista) - [240523] [rseterminals] Provide a generic adapter factory that adapts any ITerminalService to an IShellService + *******************************************************************************/ + +package org.eclipse.rse.internal.services.telnet.terminal; + +import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.PlatformObject; +import org.eclipse.rse.internal.services.shells.TerminalShellService; +import org.eclipse.rse.internal.services.telnet.ITelnetService; +import org.eclipse.rse.internal.services.telnet.ITelnetSessionProvider; +import org.eclipse.rse.internal.services.telnet.TelnetServiceResources; +import org.eclipse.rse.internal.services.terminals.AbstractTerminalService; +import org.eclipse.rse.internal.services.terminals.ITerminalShell; +import org.eclipse.rse.services.clientserver.messages.SystemMessageException; +import org.eclipse.rse.services.shells.IShellService; + +/** + * A Terminal Service for telnet. + * @since 1.2 + */ +public class TelnetTerminalService extends AbstractTerminalService implements ITelnetService { + + private final ITelnetSessionProvider fSessionProvider; + private IShellService fRelatedShellService; + + public TelnetTerminalService(ITelnetSessionProvider sessionProvider) { + fSessionProvider = sessionProvider; + } + + public ITelnetSessionProvider getSessionProvider() { + return fSessionProvider; + } + + public ITerminalShell launchTerminal(String ptyType, String encoding, String[] environment, String initialWorkingDirectory, String commandToRun, + IProgressMonitor monitor) throws SystemMessageException { + TelnetTerminalShell hostShell = new TelnetTerminalShell(fSessionProvider, ptyType, encoding, environment, initialWorkingDirectory, commandToRun); + return hostShell; + } + + /** + * Return an RSE IShellService related to this Terminal Service. + */ + protected synchronized IShellService getRelatedShellService() { + if (fRelatedShellService == null) { + fRelatedShellService = new TerminalShellService(this); + } + return fRelatedShellService; + } + + /** + * Adapt this terminal service to different (potentially contributed) + * interfaces, in order to provide additional functionality. + * + * Asks the adapter manager first whether it got any contributed adapter; if + * none is found contributed externally, try to adapt to an SshShellService. + * That way, clients can easily convert this ITerminalService into an + * IShellService: + * + *
+	 * IShellService ss = (IShellService) myTerminalService.getAdapter(IShellService.class);
+	 * 
+ * + * @see IAdaptable + * @see PlatformObject#getAdapter(Class) + */ + public Object getAdapter(Class adapter) { + // TODO I'm not sure if this is the right way doing things. First of + // all, we're holding on to the created terminal service forever if + // we're asked for it, thus needing extra memory. + // Second, by asking the adapter manager first, we might get no chance + // returning what we think is right. + Object o = super.getAdapter(adapter); + if (o==null && adapter.isAssignableFrom(IShellService.class)) { + return getRelatedShellService(); + } + return o; + } + + public String getName() { + return TelnetServiceResources.TelnetShellService_Name; + } + + public String getDescription() { + return TelnetServiceResources.TelnetShellService_Description; + } + +} diff --git a/rse/plugins/org.eclipse.rse.services.telnet/src/org/eclipse/rse/internal/services/telnet/terminal/TelnetTerminalShell.java b/rse/plugins/org.eclipse.rse.services.telnet/src/org/eclipse/rse/internal/services/telnet/terminal/TelnetTerminalShell.java new file mode 100644 index 00000000000..59d7a54f22c --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services.telnet/src/org/eclipse/rse/internal/services/telnet/terminal/TelnetTerminalShell.java @@ -0,0 +1,274 @@ +/******************************************************************************* + * Copyright (c) 2008 Wind River Systems, Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Martin Oberhuber (Wind River) - initial API and implementation + * Anna Dushistova (MontaVista) - [170910] Integrate the TM Terminal View with RSE + * Martin Oberhuber (Wind River) - [227320] Fix endless loop in TelnetTerminalShell + * Anna Dushistova (MontaVista) - [240523] [rseterminals] Provide a generic adapter factory that adapts any ITerminalService to an IShellService + *******************************************************************************/ + +package org.eclipse.rse.internal.services.telnet.terminal; + +import java.io.BufferedWriter; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.UnsupportedEncodingException; +import java.io.Writer; + +import org.apache.commons.net.io.ToNetASCIIInputStream; +import org.apache.commons.net.telnet.EchoOptionHandler; +import org.apache.commons.net.telnet.SuppressGAOptionHandler; +import org.apache.commons.net.telnet.TelnetClient; +import org.apache.commons.net.telnet.TelnetOption; +import org.apache.commons.net.telnet.TerminalTypeOptionHandler; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.rse.internal.services.telnet.ITelnetSessionProvider; +import org.eclipse.rse.internal.services.terminals.AbstractTerminalShell; +import org.eclipse.rse.internal.services.terminals.ITerminalService; +import org.eclipse.rse.services.clientserver.PathUtility; +import org.eclipse.rse.services.clientserver.messages.SystemMessageException; +import org.eclipse.rse.services.files.RemoteFileException; + +/** + * A remote shell connection supporting Streams for I/O. + * + * @since 1.2 + */ +public class TelnetTerminalShell extends AbstractTerminalShell { + + private ITelnetSessionProvider fSessionProvider; + private TelnetClient fTelnetClient; + private String fEncoding; + private EOFDetectingInputStreamWrapper fInputStream; + private OutputStream fOutputStream; + private Writer fOutputStreamWriter; + private int fWidth = 0; + private int fHeight = 0; + private static String defaultEncoding = new java.io.InputStreamReader( + new java.io.ByteArrayInputStream(new byte[0])).getEncoding(); + + /** + * Construct a new Terminal connection. + * + * The SSH channel is immediately connected in the Constructor. + * + * @param sessionProvider + * SSH session provider + * @param ptyType + * Terminal type to set, or null if not relevant + * @param encoding + * The default encoding to use for initial command. + * @param environment + * Environment array to set, or null if not + * relevant. + * @param initialWorkingDirectory + * initial directory to open the Terminal in. Use + * null or empty String ("") to start in a default + * directory. Empty String will typically start in the home + * directory. + * @param commandToRun + * initial command to send. + * @throws SystemMessageException + * in case anything goes wrong. Channels and Streams are all + * cleaned up again in this case. + * @see ITerminalService + */ + public TelnetTerminalShell(ITelnetSessionProvider sessionProvider, + String ptyType, String encoding, String[] environment, + String initialWorkingDirectory, String commandToRun) + throws SystemMessageException { + try { + fSessionProvider = sessionProvider; + boolean onUNIX = System.getProperty("os.name").toLowerCase()//$NON-NLS-1$ + .startsWith("unix")//$NON-NLS-1$ + || System.getProperty("os.name").toLowerCase().startsWith( //$NON-NLS-1$ + "linux");//$NON-NLS-1$ + fEncoding = encoding; + fTelnetClient = new TelnetClient(ptyType); + // request remote echo, but accept local if desired + fTelnetClient.addOptionHandler(new EchoOptionHandler(false, true, + true, true)); + fTelnetClient.addOptionHandler(new SuppressGAOptionHandler(true, + true, true, true)); + fTelnetClient.addOptionHandler(new TerminalTypeOptionHandler( + ptyType, true, true, true, true)); + fTelnetClient = fSessionProvider.makeNewTelnetClient(fTelnetClient, + new NullProgressMonitor()); + fOutputStream = fTelnetClient.getOutputStream(); + if (onUNIX) + fInputStream = new EOFDetectingInputStreamWrapper( + new ToNetASCIIInputStream(fTelnetClient + .getInputStream())); + else + fInputStream = new EOFDetectingInputStreamWrapper(fTelnetClient + .getInputStream()); + if (fEncoding != null) { + fOutputStreamWriter = new BufferedWriter( + new OutputStreamWriter(fOutputStream, encoding)); + } else { + // default encoding == System.getProperty("file.encoding") + // TODO should try to determine remote encoding if possible + fOutputStreamWriter = new BufferedWriter( + new OutputStreamWriter(fOutputStream)); + } + + if (initialWorkingDirectory != null + && initialWorkingDirectory.length() > 0 + && !initialWorkingDirectory.equals(".") //$NON-NLS-1$ + && !initialWorkingDirectory.equals("Command Shell") //$NON-NLS-1$ //FIXME workaround for bug 153047 + ) { + writeToShell("cd " + PathUtility.enQuoteUnix(initialWorkingDirectory)); //$NON-NLS-1$ + } + if (commandToRun != null && commandToRun.length() > 0) { + writeToShell(commandToRun); + } + } catch (Exception e) { + throw new RemoteFileException("Error creating Terminal", e); //$NON-NLS-1$ + } finally { + isActive(); + } + } + + public String getDefaultEncoding() { + return fEncoding; + } + + /** + * Encode String with requested user encoding, in case it differs from + * Platform default encoding. + * + * @param s + * String to encode + * @param encoding + * Encoding to use + * @return encoded String + * @throws UnsupportedEncodingException + * in case the requested encoding is not supported + */ + protected String recode(String s, String encoding) + throws UnsupportedEncodingException { + if (encoding == null) { + return s; + } else if (encoding.equals(defaultEncoding)) { + return s; + } + // what we want on the wire: + byte[] bytes = s.getBytes(encoding); + // what we need to tell Jsch to get this on the wire: + return new String(bytes, defaultEncoding); + } + + /* + * (non-Javadoc) + * + * @see ITerminalHostShell#getInputStream(Object) + */ + public InputStream getInputStream() { + return fInputStream; + } + + /* + * (non-Javadoc) + * + * @see ITerminalHostShell#getOutputStream(Object) + */ + public OutputStream getOutputStream() { + return fOutputStream; + } + + /** + * Write a command to the shell, honoring specified Encoding. Can only be + * done before an outputStream is obtained, since these commands would + * interfere with the outputStream. + * + * @param command + * Command String to send, or "#break" to send a Ctrl+C command. + */ + public void writeToShell(String command) throws IOException { + if (isActive()) { + if ("#break".equals(command)) { //$NON-NLS-1$ + command = "\u0003"; // Unicode 3 == Ctrl+C //$NON-NLS-1$ + } else { + command += "\r\n"; //$NON-NLS-1$ + } + fOutputStreamWriter.write(command); + fOutputStreamWriter.flush(); + } + } + + public void exit() { + if (fTelnetClient != null) { + try { + try { + getInputStream().close(); + } catch (IOException ioe) { + /* ignore */ + } + try { + getOutputStream().close(); + } catch (IOException ioe) { + /* ignore */ + ioe.printStackTrace(); + } + try { + // TODO disconnect should better be done via the + // ConnectorService!! + // Because like we do it here, the connector service is not + // notified! + synchronized (fTelnetClient) { + if (fTelnetClient.isConnected()) + fTelnetClient.disconnect(); + } + } catch (IOException e) { + e.printStackTrace(); + } + } finally { + fTelnetClient = null; + isActive(); + } + } + } + + public boolean isActive() { + if (fTelnetClient != null && fTelnetClient.isConnected() + && !isDisconnected()) { + return true; + } + // shell is not active: check for session lost + exit(); + + // //MOB: Telnet sessions are really independent of each other. + // //So if one telnet session disconnects, it must not disconnect + // //the other sessions. + // if (fTelnetClient!=null && !fTelnetClient.isConnected()) { + // fSessionProvider.handleSessionLost(); + // } + return false; + } + + private boolean isDisconnected() { + return fInputStream.isEOF(); + } + + public boolean isLocalEcho() { + return fTelnetClient.getLocalOptionState(TelnetOption.ECHO); + } + + public void setTerminalSize(int newWidth, int newHeight) { + if (fTelnetClient != null + && (newWidth != fWidth || newHeight != fHeight)) { + // avoid excessive communications due to change size requests by + // caching previous size + fWidth = newWidth; + fHeight = newHeight; + } + } + +} diff --git a/rse/plugins/org.eclipse.rse.services/plugin.xml b/rse/plugins/org.eclipse.rse.services/plugin.xml index 52d1ae933c3..4d596ae3c38 100644 --- a/rse/plugins/org.eclipse.rse.services/plugin.xml +++ b/rse/plugins/org.eclipse.rse.services/plugin.xml @@ -1,7 +1,27 @@ + + + + + + + diff --git a/rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/internal/services/shells/TerminalServiceHostShell.java b/rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/internal/services/shells/TerminalServiceHostShell.java new file mode 100644 index 00000000000..5c1c2a1ff15 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/internal/services/shells/TerminalServiceHostShell.java @@ -0,0 +1,158 @@ +/******************************************************************************* + * Copyright (c) 2006, 2008 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Initial Contributors: + * The following IBM employees contributed to the Remote System Explorer + * component that contains this file: David McKnight, Kushal Munir, + * Michael Berger, David Dykstal, Phil Coulthard, Don Yantzi, Eric Simpson, + * Emily Bruner, Mazen Faraj, Adrian Storisteanu, Li Ding, and Kent Hawley. + * + * Contributors: + * Martin Oberhuber (Wind River) - Adapted from LocalHostShell. + * David McKnight (IBM) - [191599] Use the remote encoding specified in the host property page + * David McKnight (IBM) - [196301] Check that the remote encoding isn't null before using it + * Martin Oberhuber (Wind River) - [204744] Honor encoding in SSH command input field + * Martin Oberhuber (Wind River) - [226262] Make IService IAdaptable + * Anna Dushistova (MontaVista) - adapted from SshHostShell + * Anna Dushistova (MontaVista) - [240523] [rseterminals] Provide a generic adapter factory that adapts any ITerminalService to an IShellService + *******************************************************************************/ + +package org.eclipse.rse.internal.services.shells; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; +import java.nio.charset.Charset; +import java.util.regex.Pattern; + +import org.eclipse.rse.internal.services.terminals.ITerminalShell; +import org.eclipse.rse.services.clientserver.PathUtility; +import org.eclipse.rse.services.shells.AbstractHostShell; +import org.eclipse.rse.services.shells.IHostShellOutputReader; + +/** + * @since 3.1 + */ +public class TerminalServiceHostShell extends AbstractHostShell { + + public static final String SHELL_INVOCATION = ">"; //$NON-NLS-1$ + + ITerminalShell fTerminalShell; + + private TerminalServiceShellOutputReader fStdoutHandler; + + private TerminalServiceShellOutputReader fStderrHandler; + + private TerminalServiceShellWriterThread fShellWriter; + + public TerminalServiceHostShell(ITerminalShell terminalShell, + String initialWorkingDirectory, String commandToRun, + String[] environment) { + try { + fTerminalShell = terminalShell; + String encoding = fTerminalShell.getDefaultEncoding(); + if (encoding != null) { + fStdoutHandler = new TerminalServiceShellOutputReader(this, + new BufferedReader(new InputStreamReader(fTerminalShell + .getInputStream(), encoding)), false); + } else { + fStdoutHandler = new TerminalServiceShellOutputReader(this, + new BufferedReader(new InputStreamReader(fTerminalShell + .getInputStream())), false); + } + fStderrHandler = new TerminalServiceShellOutputReader(this, null, + true); + OutputStream outputStream = fTerminalShell.getOutputStream(); + if (encoding != null) { + // use specified encoding + Charset cs = Charset.forName(encoding); + PrintWriter outputWriter = new PrintWriter( + new OutputStreamWriter(outputStream, cs)); + fShellWriter = new TerminalServiceShellWriterThread( + outputWriter); + } else { + PrintWriter outputWriter = new PrintWriter(outputStream); + fShellWriter = new TerminalServiceShellWriterThread( + outputWriter); + } + + if (initialWorkingDirectory != null + && initialWorkingDirectory.length() > 0 + && !initialWorkingDirectory.equals(".") //$NON-NLS-1$ + && !initialWorkingDirectory.equals("Command Shell") //$NON-NLS-1$ //FIXME workaround for bug 153047 + ) { + writeToShell("cd " + PathUtility.enQuoteUnix(initialWorkingDirectory)); //$NON-NLS-1$ + } else if (SHELL_INVOCATION.equals(commandToRun)) { + writeToShell(getPromptCommand()); + } else if (commandToRun != null && commandToRun.length() > 0) { + writeToShell(commandToRun); + } + + } catch (Exception e) { + // TODO [209043] Forward exception to RSE properly + e.printStackTrace(); + if (fShellWriter != null) { + fShellWriter.stopThread(); + fShellWriter = null; + } + if (fStderrHandler != null) { + fStderrHandler.interrupt(); + fStderrHandler = null; + } + if (fStdoutHandler != null) { + fStdoutHandler.interrupt(); + fStdoutHandler = null; + } + } + + } + + public void exit() { + if (fShellWriter != null) { + fShellWriter.stopThread(); + } + fTerminalShell.exit(); + } + + public IHostShellOutputReader getStandardErrorReader() { + return fStderrHandler; + } + + public IHostShellOutputReader getStandardOutputReader() { + return fStdoutHandler; + } + + public boolean isActive() { + return fTerminalShell.isActive(); + } + + private static final Pattern cdCommands = Pattern + .compile("\\A\\s*(cd|chdir|ls)\\b"); //$NON-NLS-1$ + + public void writeToShell(String command) { + if (isActive()) { + if ("#break".equals(command)) { //$NON-NLS-1$ + command = "\u0003"; //Unicode 3 == Ctrl+C //$NON-NLS-1$ + } else if (cdCommands.matcher(command).find()) { + command += "\r\n" + getPromptCommand(); //$NON-NLS-1$ + } + if (!fShellWriter.sendCommand(command)) { + // exception occurred: terminate writer thread, cancel + // connection + exit(); + isActive(); + } + } + } + + public String getPromptCommand() { + return "echo $PWD'>'"; //$NON-NLS-1$ + } + +} diff --git a/rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/internal/services/shells/TerminalServiceShellOutputReader.java b/rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/internal/services/shells/TerminalServiceShellOutputReader.java new file mode 100644 index 00000000000..db8ce647c00 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/internal/services/shells/TerminalServiceShellOutputReader.java @@ -0,0 +1,150 @@ +/******************************************************************************* + * Copyright (c) 2006, 2008 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Initial Contributors: + * The following IBM employees contributed to the Remote System Explorer + * component that contains this file: David McKnight, Kushal Munir, + * Michael Berger, David Dykstal, Phil Coulthard, Don Yantzi, Eric Simpson, + * Emily Bruner, Mazen Faraj, Adrian Storisteanu, Li Ding, and Kent Hawley. + * + * Contributors: + * Martin Oberhuber (Wind River) - Adapted from LocalShellOutputReader. + * Martin Oberhuber (Wind River) - Added vt100 escape sequence ignoring. + * Anna Dushistova (MontaVista) - adapted from SshShellOutputReader + * Anna Dushistova (MontaVista) - [240523] [rseterminals] Provide a generic adapter factory that adapts any ITerminalService to an IShellService + *******************************************************************************/ + +package org.eclipse.rse.internal.services.shells; + +import java.io.BufferedReader; +import java.io.IOException; + +import org.eclipse.rse.internal.services.Activator; +import org.eclipse.rse.services.shells.AbstractHostShellOutputReader; +import org.eclipse.rse.services.shells.IHostOutput; +import org.eclipse.rse.services.shells.IHostShell; +import org.eclipse.rse.services.shells.SimpleHostOutput; + +/** + * @since 3.1 + */ +public class TerminalServiceShellOutputReader extends + AbstractHostShellOutputReader { + protected BufferedReader fReader; + private String fPromptChars = ">$%#]"; //Characters we accept as the end of a prompt //$NON-NLS-1$; + + public TerminalServiceShellOutputReader(IHostShell hostShell, + BufferedReader reader, boolean isErrorReader) { + super(hostShell, isErrorReader); + setName("Terminal Service ShellOutputReader" + getName()); //$NON-NLS-1$ + fReader = reader; + } + + protected IHostOutput internalReadLine() { + if (fReader == null) { + //Our workaround sets the stderr reader to null, so we never give any stderr output. + //TODO Check if ssh supports some method of having separate stdout and stderr streams + return null; + } + StringBuffer theLine = new StringBuffer(); + StringBuffer theDebugLine = null; + theDebugLine = new StringBuffer(); + int ch; + boolean done = false; + while (!done && !isFinished()) { + try { + ch = fReader.read(); + switch (ch) { + case -1: + case 65535: + if (theLine.length() == 0) // End of Reader + return null; + done = true; + break; + case '\b': //backspace + if(theDebugLine!=null) theDebugLine.append((char)ch); + int len = theLine.length()-1; + if (len>=0) theLine.deleteCharAt(len); + break; + case 13: + if(theDebugLine!=null) theDebugLine.append((char)ch); + break; // Carriage Return: dont append to the buffer + case 10: + if(theDebugLine!=null) theDebugLine.append((char)ch); + done = true; // Newline + break; + case 9: + //Tab: we count tabs at column 8 + //TODO Check: SystemViewRemoteOutputAdapter.translateTabs() also translates + //Therefore this special handling here might be unnecessary + if(theDebugLine!=null) theDebugLine.append((char)ch); + int tabIndex = theLine.length() % 8; + while (tabIndex < 8) { + theLine.append(' '); + tabIndex++; + } + break; + default: + char tch = (char) ch; + if(theDebugLine!=null) theDebugLine.append(tch); + if (!Character.isISOControl(tch)) { + theLine.append(tch); // Any other character + } else if (ch == 27) { + // Escape: ignore next char too + int nch = fReader.read(); + if (theDebugLine!=null) theDebugLine.append((char)nch); + if (nch == 91) { + //vt100 escape sequence: read until end-of-command (skip digits and semicolon) + //e.g. \x1b;13;m --> ignore the entire command, including the trailing m + do { + nch = fReader.read(); + if (theDebugLine!=null) theDebugLine.append((char)nch); + } while (Character.isDigit((char)nch) || nch == ';'); + } + } + } + + // Check to see if the BufferedReader is still ready which means + // there are more characters + // in the Buffer...If not, then we assume it is waiting for + // input. + if (!done && !fReader.ready()) { + // wait to make sure -- max. 500 msec to wait for new chars + // if we are not at a CRLF seems to be appropriate for the + // Pipes and Threads in ssh. + long waitIncrement = 500; + // Check if we think we are at a prompt + int len = theLine.length()-1; + while (len>0 && Character.isSpaceChar(theLine.charAt(len))) { + len--; + } + if (len>=0 && fPromptChars.indexOf(theLine.charAt(len))>=0) { + waitIncrement = 5; //wait only 5 msec if we think it's a prompt + } + try { + Thread.sleep(waitIncrement); + } catch (InterruptedException e) { + } + if (!fReader.ready()) { + done = true; + } + } + } catch (IOException e) { + //FIXME it's dangerous to return null here since this will end + //our reader thread completely... the exception could just be + //temporary, and we should keep running! + Activator.getDefault().logException(e); + return null; + } + } + if (theDebugLine!=null) { + String debugLine = theDebugLine.toString(); + debugLine.compareTo(""); //$NON-NLS-1$ + } + return new SimpleHostOutput(theLine.toString()); + } +} diff --git a/rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/internal/services/shells/TerminalServiceShellWriterThread.java b/rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/internal/services/shells/TerminalServiceShellWriterThread.java new file mode 100644 index 00000000000..c1fca4d6d06 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/internal/services/shells/TerminalServiceShellWriterThread.java @@ -0,0 +1,101 @@ +/******************************************************************************* + * Copyright (c) 2006, 2008 Wind River Systems, Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Martin Oberhuber (Wind River) - initial API and implementation + * Anna Dushistova (MontaVista) - adapted from SshShellWriterThread + * Anna Dushistova (MontaVista) - [240523] [rseterminals] Provide a generic adapter factory that adapts any ITerminalService to an IShellService + *******************************************************************************/ +package org.eclipse.rse.internal.services.shells; + +import java.io.PrintWriter; + +/** + * @since 3.1 + */ +public class TerminalServiceShellWriterThread extends Thread { + private PrintWriter fOutputWriter; + private String fNextCommand; + private boolean fIsCancelled; + + /** + * constructor for terminal service shell writer thread + * + * @param outputWriter + * PrintWriter to write to in separate Thread + */ + public TerminalServiceShellWriterThread(PrintWriter outputWriter) { + super(); + fOutputWriter = outputWriter; + setName("Terminal Service ShellWriter" + getName()); //$NON-NLS-1$ + start(); + } + + public synchronized boolean isDone() { + return fIsCancelled; + } + + public synchronized void stopThread() { + fIsCancelled = true; + notifyAll(); + } + + /** + * Write command to remote side. Wait until the thread takes the command (no + * queuing). + * + * @param command + * to send + * @return boolean true if command was sent ok + */ + public synchronized boolean sendCommand(String command) { + try { + // In case multiple commands try to send: + // wait until it's our turn + while (!fIsCancelled && fNextCommand != null) { + wait(); + } + if (!fIsCancelled) { + // Now it's our turn + fNextCommand = command; + notifyAll(); + // Wait until our command is processed + while (!fIsCancelled && fNextCommand != null) { + wait(); + } + } + } catch (InterruptedException e) { + stopThread(); + } + return !fIsCancelled; + } + + public synchronized void run() { + try { + while (!fIsCancelled) { + while (fNextCommand == null && !fIsCancelled) { + wait(); + } + if (!fIsCancelled) { + fOutputWriter.println(fNextCommand); + fNextCommand = null; + notifyAll(); + if (fOutputWriter.checkError()) { // flush AND get error + stopThread(); + } + } + } + } catch (InterruptedException e) { + /* no special handling -> close stream */ + } finally { + stopThread(); + fOutputWriter.close(); + fOutputWriter = null; + } + } + +} diff --git a/rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/internal/services/shells/TerminalShellAdapterFactory.java b/rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/internal/services/shells/TerminalShellAdapterFactory.java new file mode 100644 index 00000000000..00b2a906f20 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/internal/services/shells/TerminalShellAdapterFactory.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * Copyright (c) 2008 MontaVista Software, Inc. + * 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: + * Anna Dushistova (MontaVista)- initial API and implementation + *******************************************************************************/ +package org.eclipse.rse.internal.services.shells; + +import org.eclipse.core.runtime.IAdapterFactory; + +import org.eclipse.rse.internal.services.terminals.ITerminalService; +import org.eclipse.rse.services.shells.IShellService; + +/** + * @since 3.1 + */ +public class TerminalShellAdapterFactory implements IAdapterFactory { + + public Object getAdapter(Object adaptableObject, Class adapterType) { + Object result = null; + if (adaptableObject instanceof ITerminalService) { + if (adapterType == IShellService.class) { + result = new TerminalShellService( + (ITerminalService) adaptableObject); + } + } + return result; + } + + public Class[] getAdapterList() { + return new Class[] { IShellService.class }; + } + +} diff --git a/rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/internal/services/shells/TerminalShellService.java b/rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/internal/services/shells/TerminalShellService.java new file mode 100644 index 00000000000..69912c67025 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.services/src/org/eclipse/rse/internal/services/shells/TerminalShellService.java @@ -0,0 +1,96 @@ +/******************************************************************************* + * Copyright (c) 2006, 2008 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Initial Contributors: + * The following IBM employees contributed to the Remote System Explorer + * component that contains this file: David McKnight, Kushal Munir, + * Michael Berger, David Dykstal, Phil Coulthard, Don Yantzi, Eric Simpson, + * Emily Bruner, Mazen Faraj, Adrian Storisteanu, Li Ding, and Kent Hawley. + * + * Contributors: + * Martin Oberhuber (Wind River) - Adapted from LocalShellService. + * Martin Oberhuber (Wind River) - [186128] Move IProgressMonitor last in all API + * Martin Oberhuber (Wind River) - [226262] Make IService IAdaptable + * Martin Oberhuber (Wind River) - [226301][api] IShellService should throw SystemMessageException on error + * Martin Oberhuber (Wind River) - [170910] Adopt RSE ITerminalService API for SSH + * Anna Dushistova (MontaVista) - adapted from SshShellService + * Anna Dushistova (MontaVista) - [240523] [rseterminals] Provide a generic adapter factory that adapts any ITerminalService to an IShellService + *******************************************************************************/ +package org.eclipse.rse.internal.services.shells; + +import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.PlatformObject; + +import org.eclipse.rse.internal.services.terminals.ITerminalService; +import org.eclipse.rse.internal.services.terminals.ITerminalShell; +import org.eclipse.rse.services.clientserver.messages.SystemMessageException; +import org.eclipse.rse.services.shells.AbstractShellService; +import org.eclipse.rse.services.shells.IHostShell; + +/** + * @since 3.1 + */ +public class TerminalShellService extends AbstractShellService { + + ITerminalService fTerminalService; + + public TerminalShellService(ITerminalService terminalService) { + super(); + fTerminalService = terminalService; + } + + public IHostShell launchShell(String initialWorkingDirectory, + String encoding, String[] environment, IProgressMonitor monitor) + throws SystemMessageException { + ITerminalShell terminalShell = fTerminalService.launchTerminal(null, + encoding, environment, initialWorkingDirectory, null, monitor); + TerminalServiceHostShell hostShell = new TerminalServiceHostShell( + terminalShell, initialWorkingDirectory, + TerminalServiceHostShell.SHELL_INVOCATION, environment); + return hostShell; + } + + public IHostShell runCommand(String initialWorkingDirectory, + String command, String encoding, String[] environment, + IProgressMonitor monitor) throws SystemMessageException { + ITerminalShell terminalShell = fTerminalService.launchTerminal(null, + encoding, environment, initialWorkingDirectory, null, monitor); + TerminalServiceHostShell hostShell = new TerminalServiceHostShell( + terminalShell, initialWorkingDirectory, command, environment); + return hostShell; + } + + /** + * Adapt this shell service to different (potentially contributed) + * interfaces. + * + * Asks the adapter manager first whether it got any contributed adapter; if + * none is found contributed externally, try to adapt to an + * SshTerminalService. That way, clients can easily convert this + * IShellService into an ITerminalService: + * + *
+	 * ITerminalService ts = (ITerminalService) myShellService.getAdapter(ITerminalService.class);
+	 * 
+ * + * @see IAdaptable + * @see PlatformObject#getAdapter(Class) + */ + public Object getAdapter(Class adapter) { + // TODO I'm not sure if this is the right way doing things. First of + // all, we're holding on to the created terminal service forever if + // we're asked for it, thus needing extra memory. + // Second, by asking the adapter manager first, we might get no chance + // returning what we think is right. + Object o = super.getAdapter(adapter); + if (o == null && adapter.isAssignableFrom(ITerminalService.class)) { + return fTerminalService; + } + return o; + } +} diff --git a/rse/plugins/org.eclipse.rse.subsystems.shells.telnet/src/org/eclipse/rse/internal/subsystems/shells/telnet/TelnetServiceCommandShell.java b/rse/plugins/org.eclipse.rse.subsystems.shells.telnet/src/org/eclipse/rse/internal/subsystems/shells/telnet/TelnetServiceCommandShell.java index c6ad7b60b22..6eef87790d1 100644 --- a/rse/plugins/org.eclipse.rse.subsystems.shells.telnet/src/org/eclipse/rse/internal/subsystems/shells/telnet/TelnetServiceCommandShell.java +++ b/rse/plugins/org.eclipse.rse.subsystems.shells.telnet/src/org/eclipse/rse/internal/subsystems/shells/telnet/TelnetServiceCommandShell.java @@ -13,8 +13,9 @@ * * Contributors: * Martin Oberhuber (Wind River) - Adapted from LocalServiceCommandShell - * Sheldon D'souza (Celunite) - Adapted from SshServiceCommandShell + * Sheldon D'souza (Celunite) - Adapted from SshServiceCommandShell * Martin Oberhuber (Wind River) - [225510][api] Fix OutputRefreshJob API leakage + * Anna Dushistova (MontaVista) - [240523] [rseterminals] Provide a generic adapter factory that adapts any ITerminalService to an IShellService *******************************************************************************/ package org.eclipse.rse.internal.subsystems.shells.telnet; @@ -25,6 +26,7 @@ import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.Path; import org.eclipse.rse.core.subsystems.ISubSystem; +import org.eclipse.rse.internal.services.shells.TerminalServiceHostShell; import org.eclipse.rse.internal.services.telnet.shell.TelnetHostShell; import org.eclipse.rse.services.shells.IHostOutput; import org.eclipse.rse.services.shells.IHostShell; @@ -175,6 +177,9 @@ public class TelnetServiceCommandShell extends ServiceCommandShell { protected String getPromptCommand() { IHostShell shell = getHostShell(); //assert shell instanceof TelnetHostShell; + if (shell instanceof TerminalServiceHostShell) { + return ((TerminalServiceHostShell)shell).getPromptCommand(); + } if (shell instanceof TelnetHostShell) { return ((TelnetHostShell)shell).getPromptCommand(); } diff --git a/rse/plugins/org.eclipse.rse.subsystems.shells.telnet/src/org/eclipse/rse/subsystems/shells/telnet/TelnetShellSubSystemConfiguration.java b/rse/plugins/org.eclipse.rse.subsystems.shells.telnet/src/org/eclipse/rse/subsystems/shells/telnet/TelnetShellSubSystemConfiguration.java index c280a2af28c..ecf3515e36e 100644 --- a/rse/plugins/org.eclipse.rse.subsystems.shells.telnet/src/org/eclipse/rse/subsystems/shells/telnet/TelnetShellSubSystemConfiguration.java +++ b/rse/plugins/org.eclipse.rse.subsystems.shells.telnet/src/org/eclipse/rse/subsystems/shells/telnet/TelnetShellSubSystemConfiguration.java @@ -13,7 +13,8 @@ * * Contributors: * Martin Oberhuber (Wind River) - Adapted template for ssh service. - * Sheldon D'souza (Celunite) - Adapted template for telnet service + * Sheldon D'souza (Celunite) - Adapted template for telnet service + * Anna Dushistova (MontaVista) - [240523] [rseterminals] Provide a generic adapter factory that adapts any ITerminalService to an IShellService *******************************************************************************/ package org.eclipse.rse.subsystems.shells.telnet; @@ -23,7 +24,7 @@ import org.eclipse.rse.core.subsystems.ISubSystem; import org.eclipse.rse.internal.connectorservice.telnet.TelnetConnectorService; import org.eclipse.rse.internal.connectorservice.telnet.TelnetConnectorServiceManager; import org.eclipse.rse.internal.services.telnet.ITelnetService; -import org.eclipse.rse.internal.services.telnet.shell.TelnetShellService; +import org.eclipse.rse.internal.services.telnet.terminal.TelnetTerminalService; import org.eclipse.rse.internal.subsystems.shells.telnet.TelnetServiceCommandShell; import org.eclipse.rse.services.shells.IHostShell; import org.eclipse.rse.services.shells.IShellService; @@ -61,7 +62,7 @@ public class TelnetShellSubSystemConfiguration extends public IShellService createShellService(IHost host) { TelnetConnectorService cserv = (TelnetConnectorService)getConnectorService(host); - return new TelnetShellService(cserv); + return (IShellService) (new TelnetTerminalService(cserv)).getAdapter(IShellService.class); } public IConnectorService getConnectorService(IHost host) { diff --git a/rse/plugins/org.eclipse.rse.subsystems.terminals.core/build.properties b/rse/plugins/org.eclipse.rse.subsystems.terminals.core/build.properties index e4cf4a53ba3..f26a677c9d9 100644 --- a/rse/plugins/org.eclipse.rse.subsystems.terminals.core/build.properties +++ b/rse/plugins/org.eclipse.rse.subsystems.terminals.core/build.properties @@ -13,5 +13,6 @@ output.. = bin/ bin.includes = META-INF/,\ .,\ plugin.properties,\ - about.html + about.html,\ + plugin.xml src.includes = about.html diff --git a/rse/plugins/org.eclipse.rse.subsystems.terminals.core/icons/full/obj16/terminalcommands_obj.gif b/rse/plugins/org.eclipse.rse.subsystems.terminals.core/icons/full/obj16/terminalcommands_obj.gif new file mode 100644 index 0000000000000000000000000000000000000000..bbb6a9e153e146f57903aa2b5e0d2bc58cd641c8 GIT binary patch literal 938 zcmZ?wbhEHb6krfw_|Cxa|NsA)GiL(HKmWeGdG{tQEzQ{2n8nEC$+IgA3}@2L{AWn} zZ#?sVS{lO{5MTg;pFe-joXIe2)~xRC?%A_v`}+F+{reXrF$zXQV5o(F;!hSvkehWt z1Sn59aI`Zpa>#gWP&mlIC&%G%V1r^46B`$sK!HM|Yd62LSV6;uMg|TcDTyf>3sO!p zvT!)4L>4xBvq>`gln5|79hzvws<1?00YeLyg({nbSILTlo$QmedMhU+F|q2;J|?;5|=b=70_{LC}2!?U|_HY0P>7m*#H0l literal 0 HcmV?d00001 diff --git a/rse/plugins/org.eclipse.rse.subsystems.terminals.core/icons/full/obj16/terminalcommandslive_obj.gif b/rse/plugins/org.eclipse.rse.subsystems.terminals.core/icons/full/obj16/terminalcommandslive_obj.gif new file mode 100644 index 0000000000000000000000000000000000000000..be88df2b43e5048dd5cce649fb34502be599cfe5 GIT binary patch literal 938 zcmZ?wbhEHb6krfw_|CwvfBt?3h6a24dVBl$_;?^0ykNl+`}qBCerfjg`xzPW#i{s + + + + + + + + + diff --git a/rse/plugins/org.eclipse.rse.subsystems.terminals.core/src/org/eclipse/rse/internal/subsystems/terminals/core/DelegatingTerminalConnectorService.java b/rse/plugins/org.eclipse.rse.subsystems.terminals.core/src/org/eclipse/rse/internal/subsystems/terminals/core/DelegatingTerminalConnectorService.java new file mode 100644 index 00000000000..908248fb377 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.subsystems.terminals.core/src/org/eclipse/rse/internal/subsystems/terminals/core/DelegatingTerminalConnectorService.java @@ -0,0 +1,66 @@ +/******************************************************************************** + * Copyright (c) 2007, 2008 IBM Corporation and others. All rights reserved. + * This program and the accompanying materials are made available under the terms + * of the Eclipse Public License v1.0 which accompanies this distribution, and is + * available at http://www.eclipse.org/legal/epl-v10.html + * + * Initial Contributors: + * The following IBM employees contributed to the Remote System Explorer + * component that contains this file: David McKnight. + * + * Contributors: + * Anna Dushistova (MontaVista) - [239159] The shell process subsystem not working without the shells subsystem present for the systemType + * David McKnight (IBM) - adapted from DelegatingShellProcessConnectorService + ********************************************************************************/ +package org.eclipse.rse.internal.subsystems.terminals.core; + +import org.eclipse.rse.core.model.IHost; +import org.eclipse.rse.core.subsystems.AbstractDelegatingConnectorService; +import org.eclipse.rse.core.subsystems.IConnectorService; +import org.eclipse.rse.core.subsystems.ISubSystem; +import org.eclipse.rse.subsystems.terminals.core.ITerminalServiceSubSystem; + +/** + * This class delegates the connector service requests for the terminal + * subsystem to the connector service of any subsystem that has service which + * can be adopted to ITerminalService. + */ +public class DelegatingTerminalConnectorService extends + AbstractDelegatingConnectorService { + private IConnectorService _realService; + + /** + * @param host + * the linux host that is the target for this connector service. + */ + public DelegatingTerminalConnectorService(IHost host) { + super(host); + } + + /* + * (non-Javadoc) + * + * @seeorg.eclipse.rse.core.subsystems.AbstractDelegatingConnectorService# + * getRealConnectorService() + */ + public IConnectorService getRealConnectorService() { + if (_realService != null) { + return _realService; + } else { + ISubSystem ss = TerminalSubSystemHelper + .getSuitableSubSystem(getHost()); + if (ss != null) { + _realService = ss.getConnectorService(); + + // register the process subsystem + ITerminalServiceSubSystem ts = TerminalSubSystemHelper + .getTerminalServiceSubSystem(getHost()); + _realService.registerSubSystem(ts); + return _realService; + } else { + return null; + } + } + } + +} diff --git a/rse/plugins/org.eclipse.rse.subsystems.terminals.core/src/org/eclipse/rse/internal/subsystems/terminals/core/DelegatingTerminalService.java b/rse/plugins/org.eclipse.rse.subsystems.terminals.core/src/org/eclipse/rse/internal/subsystems/terminals/core/DelegatingTerminalService.java new file mode 100644 index 00000000000..444043f4105 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.subsystems.terminals.core/src/org/eclipse/rse/internal/subsystems/terminals/core/DelegatingTerminalService.java @@ -0,0 +1,84 @@ +/******************************************************************************** + * Copyright (c) 2008 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 + * + * Initial Contributors: + * The following IBM employees contributed to the Remote System Explorer + * component that contains this file: David McKnight. + * + * Contributors: + * {Name} (company) - description of contribution. + ********************************************************************************/ +package org.eclipse.rse.internal.subsystems.terminals.core; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.rse.core.model.IHost; +import org.eclipse.rse.core.subsystems.ISubSystem; +import org.eclipse.rse.internal.services.terminals.ITerminalService; +import org.eclipse.rse.internal.services.terminals.ITerminalShell; +import org.eclipse.rse.services.IService; +import org.eclipse.rse.services.clientserver.messages.SystemMessageException; + +public class DelegatingTerminalService implements ITerminalService { + + private IHost _host; + private ITerminalService _realService; + + public DelegatingTerminalService(IHost host) { + _host = host; + } + + private ITerminalService getRealService() { + if (_host != null && _realService == null) { + ISubSystem[] subSystems = _host.getSubSystems(); + if (subSystems != null) { + for (int i = 0; i < subSystems.length && _realService == null; i++) { + ISubSystem subsys = subSystems[i]; + + IService svc = subsys.getSubSystemConfiguration() + .getService(_host); + if (svc != null) { + ITerminalService tsvc = (ITerminalService) svc + .getAdapter(ITerminalService.class); + if (tsvc != null && tsvc != this) { + _realService = tsvc; + } + } + } + } + } + + return _realService; + } + + public ITerminalShell launchTerminal(String ptyType, String encoding, + String[] environment, String initialWorkingDirectory, + String commandToRun, IProgressMonitor monitor) + throws SystemMessageException { + return getRealService().launchTerminal(ptyType, encoding, environment, + initialWorkingDirectory, commandToRun, monitor); + } + + public String getDescription() { + return "Generic Terminal Service"; + } + + public String getName() { + return "Terminal Service"; + } + + public void initService(IProgressMonitor monitor) { + getRealService().initService(monitor); + } + + public void uninitService(IProgressMonitor monitor) { + getRealService().uninitService(monitor); + } + + public Object getAdapter(Class adapter) { + return getRealService().getAdapter(adapter); + } + +} diff --git a/rse/plugins/org.eclipse.rse.subsystems.terminals.core/src/org/eclipse/rse/internal/subsystems/terminals/core/TerminalSubSystemConfigurationImpl.java b/rse/plugins/org.eclipse.rse.subsystems.terminals.core/src/org/eclipse/rse/internal/subsystems/terminals/core/TerminalSubSystemConfigurationImpl.java new file mode 100644 index 00000000000..ae7563eba17 --- /dev/null +++ b/rse/plugins/org.eclipse.rse.subsystems.terminals.core/src/org/eclipse/rse/internal/subsystems/terminals/core/TerminalSubSystemConfigurationImpl.java @@ -0,0 +1,66 @@ +/******************************************************************************* + * Copyright (c) 2008 MontaVista Software, Inc. + * 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: + * Yu-Fen Kuo (MontaVista) - initial API and implementation + * Anna Dushistova (MontaVista) - adapted from SshTerminalSubsystemConfiguration + *******************************************************************************/ + +package org.eclipse.rse.internal.subsystems.terminals.core; + +import org.eclipse.rse.core.model.IHost; +import org.eclipse.rse.core.subsystems.IConnectorService; +import org.eclipse.rse.core.subsystems.ISubSystem; +import org.eclipse.rse.internal.services.terminals.ITerminalService; +import org.eclipse.rse.subsystems.terminals.core.TerminalServiceSubSystem; +import org.eclipse.rse.subsystems.terminals.core.TerminalServiceSubSystemConfiguration; + +public class TerminalSubSystemConfigurationImpl extends + TerminalServiceSubSystemConfiguration { + + /** + * Instantiate and return an instance of OUR subsystem. Do not populate it + * yet though! + * + * @see org.eclipse.rse.core.subsystems.SubSystemConfiguration#createSubSystemInternal(IHost) + */ + public ISubSystem createSubSystemInternal(IHost host) { + IConnectorService connectorService = getConnectorService(host); + ISubSystem subsys = new TerminalServiceSubSystem(host, + connectorService, getTerminalService(host)); + return subsys; + } + + public ITerminalService createTerminalService(IHost host) { + + ISubSystem ss = TerminalSubSystemHelper.getSuitableSubSystem(host); + if (ss != null) { + return (ITerminalService) (ss.getSubSystemConfiguration() + .getService(host)).getAdapter(ITerminalService.class); + } else { + return new DelegatingTerminalService(host); + } + + } + + public void setConnectorService(IHost host, + IConnectorService connectorService) { + // SshConnectorServiceManager.getInstance().setConnectorService(host, + // ISshService.class, connectorService); + // Nothing to do here since we just re-use the existing suitable + // subsystem + } + + public IConnectorService getConnectorService(IHost host) { + ISubSystem ss = TerminalSubSystemHelper.getSuitableSubSystem(host); + if (ss != null) { + return ss.getConnectorService(); + } else { + return new DelegatingTerminalConnectorService(host); + } + } +} diff --git a/rse/plugins/org.eclipse.rse.subsystems.terminals.core/src/org/eclipse/rse/internal/subsystems/terminals/core/TerminalSubSystemHelper.java b/rse/plugins/org.eclipse.rse.subsystems.terminals.core/src/org/eclipse/rse/internal/subsystems/terminals/core/TerminalSubSystemHelper.java new file mode 100644 index 00000000000..f6f35d1b35f --- /dev/null +++ b/rse/plugins/org.eclipse.rse.subsystems.terminals.core/src/org/eclipse/rse/internal/subsystems/terminals/core/TerminalSubSystemHelper.java @@ -0,0 +1,75 @@ +/******************************************************************************** + * Copyright (c) 2008 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 + * + * Initial Contributors: + * The following IBM employees contributed to the Remote System Explorer + * component that contains this file: David McKnight. + * + * Contributors: + * {Name} (company) - description of contribution. + ********************************************************************************/ +package org.eclipse.rse.internal.subsystems.terminals.core; + +import org.eclipse.rse.core.model.IHost; +import org.eclipse.rse.core.subsystems.ISubSystem; +import org.eclipse.rse.internal.services.terminals.ITerminalService; +import org.eclipse.rse.services.IService; +import org.eclipse.rse.subsystems.terminals.core.ITerminalServiceSubSystem; + +/** + * Helper class that helps to get subsystem with service that can be adapted to + * ITerminalService most of the code + * + */ +public class TerminalSubSystemHelper { + /** + * Find the first ITerminalServiceSubSystem service associated with the + * host. + * + * @param host + * the connection + * @return shell service subsystem, or null if not found. + */ + public static ISubSystem getSuitableSubSystem(IHost host) { + if (host == null) + return null; + ISubSystem[] subSystems = host.getSubSystems(); + ITerminalService ssvc = null; + for (int i = 0; subSystems != null && i < subSystems.length; i++) { + IService svc = subSystems[i].getSubSystemConfiguration() + .getService(host); + if (svc != null) { + ssvc = (ITerminalService) svc + .getAdapter(ITerminalService.class); + if (ssvc != null) { + return subSystems[i]; + } + } + } + return null; + } + + /** + * Returns ITerminalServiceSubSystem associated with the host. + * + * @param host + * the connection + * @return shell service subsystem, or null if not found. + */ + public static ITerminalServiceSubSystem getTerminalServiceSubSystem( + IHost host) { + if (host == null) + return null; + ISubSystem[] subSystems = host.getSubSystems(); + for (int i = 0; subSystems != null && i < subSystems.length; i++) { + if (subSystems[i] instanceof ITerminalServiceSubSystem) { + return (ITerminalServiceSubSystem) subSystems[i]; + } + } + return null; + } + +} diff --git a/rse/plugins/org.eclipse.rse.subsystems.terminals.core/src/org/eclipse/rse/subsystems/terminals/core/TerminalServiceSubSystem.java b/rse/plugins/org.eclipse.rse.subsystems.terminals.core/src/org/eclipse/rse/subsystems/terminals/core/TerminalServiceSubSystem.java index 371824df9d8..5c1199b4426 100644 --- a/rse/plugins/org.eclipse.rse.subsystems.terminals.core/src/org/eclipse/rse/subsystems/terminals/core/TerminalServiceSubSystem.java +++ b/rse/plugins/org.eclipse.rse.subsystems.terminals.core/src/org/eclipse/rse/subsystems/terminals/core/TerminalServiceSubSystem.java @@ -6,10 +6,11 @@ * http://www.eclipse.org/legal/epl-v10.html * * Contributors: - * Yu-Fen Kuo (MontaVista) - initial API and implementation - * Yu-Fen Kuo (MontaVista) - [227572] RSE Terminal doesn't reset the "connected" state when the shell exits - * Anna Dushistova (MontaVista) - [228577] [rseterminal] Clean up RSE Terminal impl + * Yu-Fen Kuo (MontaVista) - initial API and implementation + * Yu-Fen Kuo (MontaVista) - [227572] RSE Terminal doesn't reset the "connected" state when the shell exits + * Anna Dushistova (MontaVista) - [228577] [rseterminal] Clean up RSE Terminal impl * Martin Oberhuber (Wind River) - [228577] [rseterminal] Further cleanup + * Anna Dushistova (MontaVista) - [227569] [rseterminal][api] Provide a "generic" Terminal subsystem ********************************************************************************/ package org.eclipse.rse.subsystems.terminals.core; @@ -26,6 +27,7 @@ import org.eclipse.rse.core.model.ISystemRegistry; import org.eclipse.rse.core.subsystems.CommunicationsEvent; import org.eclipse.rse.core.subsystems.ICommunicationsListener; import org.eclipse.rse.core.subsystems.IConnectorService; +import org.eclipse.rse.core.subsystems.ISubSystemConfiguration; import org.eclipse.rse.core.subsystems.SubSystem; import org.eclipse.rse.internal.services.terminals.ITerminalService; import org.eclipse.rse.subsystems.terminals.core.elements.TerminalElement; @@ -35,39 +37,40 @@ import org.eclipse.swt.widgets.Display; * A Subsystem that has terminal instances as children. */ public class TerminalServiceSubSystem extends SubSystem implements - ITerminalServiceSubSystem, ICommunicationsListener { + ITerminalServiceSubSystem, ICommunicationsListener { - private ITerminalService _hostService = null; + private ITerminalService _hostService = null; - private ArrayList children = new ArrayList(); + private ArrayList children = new ArrayList(); - /** + /** * Constructor. */ - public TerminalServiceSubSystem(IHost host, - IConnectorService connectorService, ITerminalService hostService) { - super(host, connectorService); - _hostService = hostService; - } + public TerminalServiceSubSystem(IHost host, + IConnectorService connectorService, ITerminalService hostService) { + super(host, connectorService); + _hostService = hostService; + } - private void fireAsyncRefresh(final Object target) { + private void fireAsyncRefresh(final Object target) { Display.getDefault().asyncExec(new Runnable() { public void run() { ISystemRegistry registry = RSECorePlugin.getTheSystemRegistry(); - registry.fireEvent(new SystemResourceChangeEvent(target, ISystemResourceChangeEvents.EVENT_REFRESH, target)); + registry.fireEvent(new SystemResourceChangeEvent(target, + ISystemResourceChangeEvents.EVENT_REFRESH, target)); } }); } - /** + /** * Return the Terminal Service associated with this subsystem. */ - public ITerminalService getTerminalService() { - return _hostService; - } + public ITerminalService getTerminalService() { + return _hostService; + } - public Class getServiceType() { + public Class getServiceType() { return ITerminalService.class; } @@ -78,81 +81,81 @@ public class TerminalServiceSubSystem extends SubSystem implements } fireAsyncRefresh(this); } - } + } - public void removeChild(TerminalElement element) { - if(element!=null){ - synchronized (children) { - children.remove(element); - } + public void removeChild(TerminalElement element) { + if (element != null) { + synchronized (children) { + children.remove(element); + } fireAsyncRefresh(this); - } - } + } + } - public void removeChild(String terminalTitle) { - removeChild(getChild(terminalTitle)); - } + public void removeChild(String terminalTitle) { + removeChild(getChild(terminalTitle)); + } - public TerminalElement getChild(String terminalTitle) { - synchronized (children) { + public TerminalElement getChild(String terminalTitle) { + synchronized (children) { for (Iterator it = children.iterator(); it.hasNext();) { TerminalElement element = (TerminalElement) it.next(); if (element.getName().equals(terminalTitle)) return element; } } - return null; - } + return null; + } - public Object[] getChildren() { - synchronized (children) { - return children.toArray(); - } - } + public Object[] getChildren() { + synchronized (children) { + return children.toArray(); + } + } - public boolean hasChildren() { - synchronized (children) { - return !children.isEmpty(); - } - } + public boolean hasChildren() { + synchronized (children) { + return !children.isEmpty(); + } + } - /** + /** * Set the terminal service associated with this subsystem. */ - public void setTerminalService(ITerminalService service) { - _hostService = service; - } + public void setTerminalService(ITerminalService service) { + _hostService = service; + } - public void communicationsStateChange(CommunicationsEvent e) { - switch (e.getState()) { - case CommunicationsEvent.AFTER_DISCONNECT: - // no longer listen - getConnectorService().removeCommunicationsListener(this); - break; + public void communicationsStateChange(CommunicationsEvent e) { + switch (e.getState()) { + case CommunicationsEvent.AFTER_DISCONNECT: + // no longer listen + getConnectorService().removeCommunicationsListener(this); + break; - case CommunicationsEvent.BEFORE_DISCONNECT: - case CommunicationsEvent.CONNECTION_ERROR: - Display.getDefault().asyncExec(new Runnable(){ - public void run() { - cancelAllTerminals(); - } - }); - break; - default: - break; - } + case CommunicationsEvent.BEFORE_DISCONNECT: + case CommunicationsEvent.CONNECTION_ERROR: + Display.getDefault().asyncExec(new Runnable() { + public void run() { + cancelAllTerminals(); + } + }); + break; + default: + break; + } - } + } - public boolean isPassiveCommunicationsListener() { - return true; - } + public boolean isPassiveCommunicationsListener() { + return true; + } - /** + /** * Set the terminal service associated with this subsystem. */ - public void cancelAllTerminals() { - Object[] terminals; + public void cancelAllTerminals() { + Object[] terminals; synchronized (children) { terminals = getChildren(); children.clear(); @@ -163,26 +166,32 @@ public class TerminalServiceSubSystem extends SubSystem implements try { removeTerminalElement(element); } catch (Exception e) { - RSECorePlugin.getDefault().getLogger().logError("Error removing terminal", e); //$NON-NLS-1$ + RSECorePlugin.getDefault().getLogger().logError( + "Error removing terminal", e); //$NON-NLS-1$ } } fireAsyncRefresh(this); } - } + } - private void removeTerminalElement(TerminalElement element) { - element.getTerminalShell().exit(); - ISystemRegistry registry = RSECorePlugin.getTheSystemRegistry(); - registry.fireEvent(new SystemResourceChangeEvent(element, ISystemResourceChangeEvents.EVENT_COMMAND_SHELL_REMOVED, null)); - } + private void removeTerminalElement(TerminalElement element) { + element.getTerminalShell().exit(); + ISystemRegistry registry = RSECorePlugin.getTheSystemRegistry(); + registry.fireEvent(new SystemResourceChangeEvent(element, + ISystemResourceChangeEvents.EVENT_COMMAND_SHELL_REMOVED, null)); + } - public void initializeSubSystem(IProgressMonitor monitor) { - super.initializeSubSystem(monitor); - getConnectorService().addCommunicationsListener(this); - } + public void initializeSubSystem(IProgressMonitor monitor) { + super.initializeSubSystem(monitor); + getConnectorService().addCommunicationsListener(this); + } - public void uninitializeSubSystem(IProgressMonitor monitor) { - getConnectorService().removeCommunicationsListener(this); - super.uninitializeSubSystem(monitor); - } + public void uninitializeSubSystem(IProgressMonitor monitor) { + getConnectorService().removeCommunicationsListener(this); + super.uninitializeSubSystem(monitor); + } + + public boolean canSwitchTo(ISubSystemConfiguration configuration) { + return (configuration instanceof ITerminalServiceSubSystemConfiguration); + } } \ No newline at end of file diff --git a/rse/plugins/org.eclipse.rse.subsystems.terminals.core/src/org/eclipse/rse/subsystems/terminals/core/TerminalServiceSubSystemConfiguration.java b/rse/plugins/org.eclipse.rse.subsystems.terminals.core/src/org/eclipse/rse/subsystems/terminals/core/TerminalServiceSubSystemConfiguration.java index b74083a4179..95b920a0837 100644 --- a/rse/plugins/org.eclipse.rse.subsystems.terminals.core/src/org/eclipse/rse/subsystems/terminals/core/TerminalServiceSubSystemConfiguration.java +++ b/rse/plugins/org.eclipse.rse.subsystems.terminals.core/src/org/eclipse/rse/subsystems/terminals/core/TerminalServiceSubSystemConfiguration.java @@ -5,7 +5,8 @@ * available at http://www.eclipse.org/legal/epl-v10.html * * Contributors: - * Yu-Fen Kuo (MontaVista) - initial API and implementation + * Yu-Fen Kuo (MontaVista) - initial API and implementation + * Anna Dushistova (MontaVista) - [227569] [rseterminal][api] Provide a "generic" Terminal subsystem ********************************************************************************/ package org.eclipse.rse.subsystems.terminals.core; @@ -18,21 +19,20 @@ import org.eclipse.rse.core.subsystems.SubSystemConfiguration; import org.eclipse.rse.internal.services.terminals.ITerminalService; import org.eclipse.rse.services.IService; - public abstract class TerminalServiceSubSystemConfiguration extends - SubSystemConfiguration implements - ITerminalServiceSubSystemConfiguration { + SubSystemConfiguration implements + ITerminalServiceSubSystemConfiguration { private Map _services; - protected TerminalServiceSubSystemConfiguration() { - super(); - _services = new HashMap(); - } + protected TerminalServiceSubSystemConfiguration() { + super(); + _services = new HashMap(); + } - public boolean supportsFilters() { - return false; - } + public boolean supportsFilters() { + return false; + } public final ITerminalService getTerminalService(IHost host) { ITerminalService service = (ITerminalService) _services.get(host); @@ -51,4 +51,9 @@ public abstract class TerminalServiceSubSystemConfiguration extends return ITerminalService.class; } + public boolean isFactoryFor(Class subSystemType) { + boolean isFor = TerminalServiceSubSystem.class.equals(subSystemType); + return isFor; + } + } diff --git a/rse/plugins/org.eclipse.rse.terminals.ui/src/org/eclipse/rse/internal/terminals/ui/TerminalServiceHelper.java b/rse/plugins/org.eclipse.rse.terminals.ui/src/org/eclipse/rse/internal/terminals/ui/TerminalServiceHelper.java index 1dc17fee6a3..a1201c2eee4 100644 --- a/rse/plugins/org.eclipse.rse.terminals.ui/src/org/eclipse/rse/internal/terminals/ui/TerminalServiceHelper.java +++ b/rse/plugins/org.eclipse.rse.terminals.ui/src/org/eclipse/rse/internal/terminals/ui/TerminalServiceHelper.java @@ -5,9 +5,10 @@ * available at http://www.eclipse.org/legal/epl-v10.html * * Contributors: - * Yu-Fen Kuo (MontaVista) - initial API and implementation - * Yu-Fen Kuo (MontaVista) - [227572] RSE Terminal doesn't reset the "connected" state when the shell exits + * Yu-Fen Kuo (MontaVista) - initial API and implementation + * Yu-Fen Kuo (MontaVista) - [227572] RSE Terminal doesn't reset the "connected" state when the shell exits * Anna Dushistova (MontaVista) - [227535] [rseterminal][api] terminals.ui should not depend on files.core + * Anna Dushistova (MontaVista) - [227569] [rseterminal][api] Provide a "generic" Terminal subsystem ********************************************************************************/ package org.eclipse.rse.internal.terminals.ui; @@ -42,8 +43,7 @@ public class TerminalServiceHelper { ISystemRegistry systemRegistry = RSECorePlugin.getTheSystemRegistry(); ISubSystem[] subsystems = systemRegistry.getSubSystems(connection); for (int i = 0; i < subsystems.length; i++) { - if ("ssh.terminals".equals(subsystems[i] - .getSubSystemConfiguration().getId())) { + if (subsystems[i] instanceof ITerminalServiceSubSystem) { ITerminalServiceSubSystem subSystem = (ITerminalServiceSubSystem) subsystems[i]; return subSystem; } diff --git a/rse/tests/org.eclipse.rse.tests/META-INF/MANIFEST.MF b/rse/tests/org.eclipse.rse.tests/META-INF/MANIFEST.MF index 8f53bad5d3b..af2532f56f3 100644 --- a/rse/tests/org.eclipse.rse.tests/META-INF/MANIFEST.MF +++ b/rse/tests/org.eclipse.rse.tests/META-INF/MANIFEST.MF @@ -25,7 +25,8 @@ Require-Bundle: org.junit, org.eclipse.rse.files.ui, org.eclipse.rse.efs, org.eclipse.rse.tests.framework;bundle-version="[2.0.0,3.0.0)", - org.apache.commons.net;bundle-version="[1.4.1,2.0.0)" + org.apache.commons.net;bundle-version="[1.4.1,2.0.0)", + org.eclipse.rse.subsystems.terminals.core;bundle-version="0.1.1" Bundle-ActivationPolicy: lazy Eclipse-LazyStart: true Bundle-RequiredExecutionEnvironment: J2SE-1.4 diff --git a/rse/tests/org.eclipse.rse.tests/plugin.xml b/rse/tests/org.eclipse.rse.tests/plugin.xml index daa60f3b3bf..19056624a25 100644 --- a/rse/tests/org.eclipse.rse.tests/plugin.xml +++ b/rse/tests/org.eclipse.rse.tests/plugin.xml @@ -96,6 +96,13 @@ value="true"> + + diff --git a/rse/tests/org.eclipse.rse.tests/src/org/eclipse/rse/tests/subsystems/shells/ShellServiceTest.java b/rse/tests/org.eclipse.rse.tests/src/org/eclipse/rse/tests/subsystems/shells/ShellServiceTest.java index a8cb6353baa..1b91fd8cf00 100644 --- a/rse/tests/org.eclipse.rse.tests/src/org/eclipse/rse/tests/subsystems/shells/ShellServiceTest.java +++ b/rse/tests/org.eclipse.rse.tests/src/org/eclipse/rse/tests/subsystems/shells/ShellServiceTest.java @@ -21,6 +21,7 @@ import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.rse.core.RSECorePlugin; import org.eclipse.rse.core.model.IHost; import org.eclipse.rse.core.subsystems.ISubSystem; +import org.eclipse.rse.services.clientserver.messages.SystemMessageException; import org.eclipse.rse.services.shells.IHostOutput; import org.eclipse.rse.services.shells.IHostShell; import org.eclipse.rse.services.shells.IShellService; @@ -30,13 +31,13 @@ import org.eclipse.rse.tests.core.connection.RSEBaseConnectionTestCase; public class ShellServiceTest extends RSEBaseConnectionTestCase { - private String fPropertiesFileName; + protected String fPropertiesFileName; // For testing the test: verify methods on Local public static String fDefaultPropertiesFile = "localConnection.properties"; - private IShellServiceSubSystem shellSubSystem; - private IShellService shellService; - private IProgressMonitor mon = new NullProgressMonitor(); + protected IShellServiceSubSystem shellSubSystem; + protected IShellService shellService; + protected IProgressMonitor mon = new NullProgressMonitor(); /** * Constructor with specific test name. @@ -71,9 +72,7 @@ public class ShellServiceTest extends RSEBaseConnectionTestCase { TestSuite suite = new TestSuite(baseName); // // Add a test suite for each connection type - String[] connTypes = { "local", "ssh", "telnet", "linux" }; - // String[] connTypes = { "local" }; - // String[] connTypes = { "ssh" }; + String[] connTypes = { "local", "ssh", "telnet" }; for (int i = 0; i < connTypes.length; i++) { String suiteName = connTypes[i]; @@ -110,6 +109,10 @@ public class ShellServiceTest extends RSEBaseConnectionTestCase { public void setUp() throws Exception { super.setUp(); + initShellService(); + } + + protected void initShellService() throws SystemMessageException { shellSubSystem = getShellServiceSubSystem(); shellService = shellSubSystem.getShellService(); shellSubSystem.checkIsConnected(getDefaultProgressMonitor()); diff --git a/rse/tests/org.eclipse.rse.tests/src/org/eclipse/rse/tests/subsystems/shells/TerminalShellServiceTest.java b/rse/tests/org.eclipse.rse.tests/src/org/eclipse/rse/tests/subsystems/shells/TerminalShellServiceTest.java new file mode 100644 index 00000000000..5a71ebe5eae --- /dev/null +++ b/rse/tests/org.eclipse.rse.tests/src/org/eclipse/rse/tests/subsystems/shells/TerminalShellServiceTest.java @@ -0,0 +1,102 @@ +/******************************************************************************* + * Copyright (c) 2008 MontaVista Software, Inc. + * 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: + * Anna Dushistova (MontaVista)- initial API and implementation + *******************************************************************************/ + +package org.eclipse.rse.tests.subsystems.shells; + +import java.lang.reflect.Method; + +import junit.framework.Test; +import junit.framework.TestSuite; + +import org.eclipse.rse.core.RSECorePlugin; +import org.eclipse.rse.core.model.IHost; +import org.eclipse.rse.core.subsystems.ISubSystem; +import org.eclipse.rse.internal.services.terminals.ITerminalService; +import org.eclipse.rse.services.clientserver.messages.SystemMessageException; +import org.eclipse.rse.services.shells.IShellService; +import org.eclipse.rse.subsystems.terminals.core.TerminalServiceSubSystem; + +public class TerminalShellServiceTest extends ShellServiceTest{ + + protected ITerminalService terminalService; + protected TerminalServiceSubSystem terminalSubSystem; + + /** + * @param name + * @param propertiesFileName + */ + public TerminalShellServiceTest(String name, String propertiesFileName) { + super(name, propertiesFileName); + } + + /** + * @param name + */ + public TerminalShellServiceTest(String name) { + super(name); + } + + public static Test suite() { + String baseName = TerminalShellServiceTest.class.getName(); + TestSuite suite = new TestSuite(baseName); + + // // Add a test suite for each connection type + String[] connTypes = { "sshTerminal" }; + // String[] connTypes = { "local" }; + // String[] connTypes = { "ssh" }; + + for (int i = 0; i < connTypes.length; i++) { + String suiteName = connTypes[i]; + String propFileName = connTypes[i] == null ? null : connTypes[i] + + "Connection.properties"; + TestSuite subSuite = new TestSuite(baseName + "." + suiteName); + Method[] m = TerminalShellServiceTest.class.getMethods(); + for (int j = 0; j < m.length; j++) { + String testName = m[j].getName(); + if (testName.startsWith("test")) { + subSuite.addTest(new TerminalShellServiceTest(testName, + propFileName)); + } + } + suite.addTest(subSuite); + } + return suite; + } + + protected TerminalServiceSubSystem getTerminalServiceSubSystem() { + if (fPropertiesFileName == null) { + return null; + } + IHost host = getHost(fPropertiesFileName); + ISubSystem[] ss = RSECorePlugin.getTheSystemRegistry() + .getServiceSubSystems(host, ITerminalService.class); + for (int i = 0; i < ss.length; i++) { + if (ss[i] instanceof TerminalServiceSubSystem) { + return (TerminalServiceSubSystem) ss[i]; + } + } + return null; + } + + /* (non-Javadoc) + * @see org.eclipse.rse.tests.subsystems.shells.ShellServiceTest#initShellService() + */ + protected void initShellService() throws SystemMessageException { + terminalSubSystem = getTerminalServiceSubSystem(); + terminalService = terminalSubSystem.getTerminalService(); + terminalSubSystem.checkIsConnected(getDefaultProgressMonitor()); + shellService = (IShellService) terminalService.getAdapter(IShellService.class); + } + + public boolean isWindows() { + return terminalSubSystem.getHost().getSystemType().isWindows(); + } +} diff --git a/rse/tests/org.eclipse.rse.tests/test.data/sshTerminalConnection.properties b/rse/tests/org.eclipse.rse.tests/test.data/sshTerminalConnection.properties new file mode 100644 index 00000000000..46774247eec --- /dev/null +++ b/rse/tests/org.eclipse.rse.tests/test.data/sshTerminalConnection.properties @@ -0,0 +1,28 @@ +############################################################################### +# Copyright (c) 2008 IBM Corporation and others. All rights reserved. +# 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 +############################################################################### + +# name/label for this windows connection +name = test_ssh_terminals_only + +# profile name this connection should be created for +profile_name = junit_test_profile + +# SSH system ID +system_type_id = org.eclipse.rse.tests.sshTerminal + +# Address of ssh connection +address = unknown + +# userid to connect to ssh connection +#userid = + +# password to connect to ssh connection +#password = diff --git a/rse/tests/org.eclipse.rse.tests/test.data/telnetConnection.properties b/rse/tests/org.eclipse.rse.tests/test.data/telnetConnection.properties new file mode 100644 index 00000000000..603f669af3c --- /dev/null +++ b/rse/tests/org.eclipse.rse.tests/test.data/telnetConnection.properties @@ -0,0 +1,28 @@ +############################################################################### +# Copyright (c) 2008 IBM Corporation and others. All rights reserved. +# 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 +############################################################################### + +# name/label for this windows connection +name = test_telnet_only + +# profile name this connection should be created for +profile_name = junit_test_profile + +# SSH system ID +system_type_id = org.eclipse.rse.systemtype.telnet + +# Address of ssh connection +address = unknown + +# userid to connect to ssh connection +#userid = + +# password to connect to ssh connection +#password =