1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-07-21 16:05:25 +02:00

[240523][227569] added new generic terminal shell service, generic terminal subsystem and telnet reference implementation.

This commit is contained in:
Anna Dushistova 2008-12-04 22:20:10 +00:00
parent 24908d60f5
commit 250119f1db
32 changed files with 1671 additions and 126 deletions

View file

@ -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$

View file

@ -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

View file

@ -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 ;
}

View file

@ -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);
}
}
}

View file

@ -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:
*
* <pre>
* IShellService ss = (IShellService) myTerminalService.getAdapter(IShellService.class);
* </pre>
*
* @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;
}
}

View file

@ -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 <code>null</code> if not relevant
* @param encoding
* The default encoding to use for initial command.
* @param environment
* Environment array to set, or <code>null</code> if not
* relevant.
* @param initialWorkingDirectory
* initial directory to open the Terminal in. Use
* <code>null</code> 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;
}
}
}

View file

@ -1,7 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
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
Contributors:
Anna Dushistova (MontaVista)- initial API and implementation
-->
<?eclipse version="3.2"?>
<plugin>
<extension-point id="archivehandlers" name="%extPoint.archivehandlers" schema="schema/archivehandlers.exsd"/>
<extension-point id="codePageConverters" name="%extPoint.codePageConverters" schema="schema/codePageConverters.exsd"/>
<extension
point="org.eclipse.core.runtime.adapters">
<factory
adaptableType="org.eclipse.rse.internal.services.terminals.ITerminalService"
class="org.eclipse.rse.internal.services.shells.TerminalShellAdapterFactory">
<adapter
type="org.eclipse.rse.services.shells.IShellService">
</adapter>
</factory>
</extension>
</plugin>

View file

@ -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$
}
}

View file

@ -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());
}
}

View file

@ -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;
}
}
}

View file

@ -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 };
}
}

View file

@ -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:
*
* <pre>
* ITerminalService ts = (ITerminalService) myShellService.getAdapter(ITerminalService.class);
* </pre>
*
* @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;
}
}

View file

@ -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();
}

View file

@ -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) {

View file

@ -13,5 +13,6 @@ output.. = bin/
bin.includes = META-INF/,\
.,\
plugin.properties,\
about.html
about.html,\
plugin.xml
src.includes = about.html

Binary file not shown.

After

Width:  |  Height:  |  Size: 938 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 938 B

View file

@ -14,3 +14,6 @@
pluginName = RSE Terminals Core (Incubation)
providerName = Eclipse.org
TerminalSubsystemName = Terminals
TerminalSubsystemDescription = Work with terminals and commands on remote systems.

View file

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
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
-->
<?eclipse version="3.1"?>
<plugin>
<extension
point="org.eclipse.rse.core.subsystemConfigurations">
<configuration
category="terminals"
class="org.eclipse.rse.internal.subsystems.terminals.core.TerminalSubSystemConfigurationImpl"
description="%TerminalSubsystemDescription"
icon="icons/full/obj16/terminalcommands_obj.gif"
iconlive="icons/full/obj16/terminalcommandslive_obj.gif"
id="terminals"
name="%TerminalSubsystemName"
priority="300"
systemTypeIds="org.eclipse.rse.systemtype.telnet"
vendor="%providerName">
</configuration>
</extension>
</plugin>

View file

@ -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;
}
}
}
}

View file

@ -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);
}
}

View file

@ -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);
}
}
}

View file

@ -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 <code>null</code> 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 <code>null</code> 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;
}
}

View file

@ -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);
}
}

View file

@ -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;
}
}

View file

@ -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;
}

View file

@ -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

View file

@ -96,6 +96,13 @@
value="true">
</property>
</systemType>
<systemType
description="Linux without shells subsystem"
id="org.eclipse.rse.tests.sshTerminal"
label="Ssh without shells"
name="Ssh without shells"
subsystemConfigurationIds="ssh.terminals;ssh.files;processes.shell.linux">
</systemType>
</extension>
<extension point="org.eclipse.rse.core.modelInitializers">

View file

@ -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());

View file

@ -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();
}
}

View file

@ -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 =

View file

@ -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 =