From d2d6658cb853f560a03d9b9b45ea49d6f7a9178d Mon Sep 17 00:00:00 2001 From: Martin Oberhuber < martin.oberhuber@windriver.com> Date: Wed, 27 Jun 2007 08:24:08 +0000 Subject: [PATCH] [187301] support multiple telnet shells --- releng/org.eclipse.rse.build/maps/rse.map | 4 +- .../telnet/TelnetConnectorService.java | 101 +++++++++++------- .../telnet/ITelnetSessionProvider.java | 12 ++- .../telnet/shell/TelnetHostShell.java | 29 ++--- 4 files changed, 89 insertions(+), 57 deletions(-) diff --git a/releng/org.eclipse.rse.build/maps/rse.map b/releng/org.eclipse.rse.build/maps/rse.map index b93f5ed5788..81b806f5c25 100644 --- a/releng/org.eclipse.rse.build/maps/rse.map +++ b/releng/org.eclipse.rse.build/maps/rse.map @@ -16,7 +16,7 @@ plugin@org.eclipse.rse=v20070605,:pserver:anonymous:none@dev.eclipse.org:/cvsroo plugin@org.eclipse.rse.connectorservice.dstore=v20070606,:pserver:anonymous:none@dev.eclipse.org:/cvsroot/dsdp,,org.eclipse.tm.rse/plugins/org.eclipse.rse.connectorservice.dstore plugin@org.eclipse.rse.connectorservice.local=v20070606,:pserver:anonymous:none@dev.eclipse.org:/cvsroot/dsdp,,org.eclipse.tm.rse/plugins/org.eclipse.rse.connectorservice.local plugin@org.eclipse.rse.connectorservice.ssh=v20070606,:pserver:anonymous:none@dev.eclipse.org:/cvsroot/dsdp,,org.eclipse.tm.rse/plugins/org.eclipse.rse.connectorservice.ssh -plugin@org.eclipse.rse.connectorservice.telnet=v20070606,:pserver:anonymous:none@dev.eclipse.org:/cvsroot/dsdp,,org.eclipse.tm.rse/plugins/org.eclipse.rse.connectorservice.telnet +plugin@org.eclipse.rse.connectorservice.telnet=v20070627,:pserver:anonymous:none@dev.eclipse.org:/cvsroot/dsdp,,org.eclipse.tm.rse/plugins/org.eclipse.rse.connectorservice.telnet plugin@org.eclipse.rse.core=v20070620,:pserver:anonymous:none@dev.eclipse.org:/cvsroot/dsdp,,org.eclipse.tm.rse/plugins/org.eclipse.rse.core plugin@org.eclipse.rse.doc.isv=v20070620,:pserver:anonymous:none@dev.eclipse.org:/cvsroot/dsdp,,org.eclipse.tm.rse/doc/org.eclipse.rse.doc.isv plugin@org.eclipse.rse.doc.user=v20070620a,:pserver:anonymous:none@dev.eclipse.org:/cvsroot/dsdp,,org.eclipse.tm.rse/doc/org.eclipse.rse.doc.user @@ -34,7 +34,7 @@ plugin@org.eclipse.rse.services.dstore=v20070614,:pserver:anonymous:none@dev.ecl plugin@org.eclipse.rse.services.files.ftp=v20070606,:pserver:anonymous:none@dev.eclipse.org:/cvsroot/dsdp,,org.eclipse.tm.rse/plugins/org.eclipse.rse.services.files.ftp plugin@org.eclipse.rse.services.local=v20070606,:pserver:anonymous:none@dev.eclipse.org:/cvsroot/dsdp,,org.eclipse.tm.rse/plugins/org.eclipse.rse.services.local plugin@org.eclipse.rse.services.ssh=v20070606,:pserver:anonymous:none@dev.eclipse.org:/cvsroot/dsdp,,org.eclipse.tm.rse/plugins/org.eclipse.rse.services.ssh -plugin@org.eclipse.rse.services.telnet=v20070606,:pserver:anonymous:none@dev.eclipse.org:/cvsroot/dsdp,,org.eclipse.tm.rse/plugins/org.eclipse.rse.services.telnet +plugin@org.eclipse.rse.services.telnet=v20070627,:pserver:anonymous:none@dev.eclipse.org:/cvsroot/dsdp,,org.eclipse.tm.rse/plugins/org.eclipse.rse.services.telnet plugin@org.eclipse.rse.services=v20070605,:pserver:anonymous:none@dev.eclipse.org:/cvsroot/dsdp,,org.eclipse.tm.rse/plugins/org.eclipse.rse.services plugin@org.eclipse.rse.shells.ui=v20070606,:pserver:anonymous:none@dev.eclipse.org:/cvsroot/dsdp,,org.eclipse.tm.rse/plugins/org.eclipse.rse.shells.ui plugin@org.eclipse.rse.subsystems.files.core=v20070609,:pserver:anonymous:none@dev.eclipse.org:/cvsroot/dsdp,,org.eclipse.tm.rse/plugins/org.eclipse.rse.subsystems.files.core 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 10142260888..c48902445bf 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 @@ -14,12 +14,17 @@ * 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 *******************************************************************************/ package org.eclipse.rse.internal.connectorservice.telnet; +import java.io.IOException; import java.io.InputStream; import java.io.PrintStream; import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; import org.apache.commons.net.telnet.TelnetClient; import org.eclipse.core.runtime.IProgressMonitor; @@ -60,7 +65,7 @@ public class TelnetConnectorService extends StandardConnectorService implements private static final int TELNET_DEFAULT_PORT = 23; // TODO Make configurable private static final int TELNET_CONNECT_TIMEOUT = 60; //seconds - TODO: Make configurable - private TelnetClient fTelnetClient = new TelnetClient(); + private List fTelnetClients = new ArrayList(); private SessionLostHandler fSessionLostHandler; private InputStream in; private PrintStream out; @@ -109,6 +114,27 @@ public class TelnetConnectorService extends StandardConnectorService implements } protected void internalConnect(IProgressMonitor monitor) throws Exception { + try { + TelnetClient client = makeNewTelnetClient(monitor); + if( client != null ) { + synchronized(this) { + fTelnetClients.add(client); + if (fSessionLostHandler==null) { + fSessionLostHandler = new SessionLostHandler(this); + } + } + notifyConnection(); + } + }catch( Exception e) { + if( e instanceof SystemMessageException ) { + internalDisconnect( null ); + throw e; + } + } + } + + public TelnetClient makeNewTelnetClient( IProgressMonitor monitor ) throws Exception { + TelnetClient client = new TelnetClient(); String host = getHostName(); String user = getUserId(); String password = ""; //$NON-NLS-1$ @@ -116,14 +142,14 @@ public class TelnetConnectorService extends StandardConnectorService implements Exception nestedException = null; try { Activator.trace("Telnet Service: Connecting....."); //$NON-NLS-1$ - fTelnetClient.connect(host, TELNET_DEFAULT_PORT); + client.connect(host, TELNET_DEFAULT_PORT); SystemSignonInformation ssi = getSignonInformation(); if (ssi != null) { password = ssi.getPassword(); } - in = fTelnetClient.getInputStream(); - out = new PrintStream(fTelnetClient.getOutputStream()); + in = client.getInputStream(); + out = new PrintStream(client.getOutputStream()); long millisToEnd = System.currentTimeMillis() + TELNET_CONNECT_TIMEOUT*1000; LoginThread checkLogin = new LoginThread(user, password); @@ -156,10 +182,13 @@ public class TelnetConnectorService extends StandardConnectorService implements } finally { if (status == CONNECT_CANCELED) { Activator.trace("Telnet Service: Canceled"); //$NON-NLS-1$ - sessionDisconnect(); //will eventually destroy the LoginThread + try { + client.disconnect(); //will eventually destroy the LoginThread + } catch(Exception e) { + /*ignore on forced disconnect*/ + } + client = null; } else if (status == SUCCESS_CODE) { - fSessionLostHandler = new SessionLostHandler(this); - notifyConnection(); Activator.trace("Telnet Service: Connected"); //$NON-NLS-1$ } else { Activator.trace("Telnet Service: Connect failed"); //$NON-NLS-1$ @@ -173,10 +202,10 @@ public class TelnetConnectorService extends StandardConnectorService implements msg = RSEUIPlugin.getPluginMessage(ISystemMessages.MSG_COMM_AUTH_FAILED); msg.makeSubstitution(getHost().getAliasName()); } - internalDisconnect(null); throw new SystemMessageException(msg); } } + return client; } /** @@ -185,18 +214,20 @@ public class TelnetConnectorService extends StandardConnectorService implements */ private synchronized void sessionDisconnect() { Activator.trace("TelnetConnectorService.sessionDisconnect"); //$NON-NLS-1$ - try { - if (fTelnetClient != null) { - synchronized (fTelnetClient) { - if (fTelnetClient.isConnected()) - fTelnetClient.disconnect(); + Iterator it = fTelnetClients.iterator(); + while (it.hasNext()) { + TelnetClient client = (TelnetClient)it.next(); + if (client.isConnected()) { + try { + client.disconnect(); + } catch(IOException e) { + // Avoid NPE on disconnect shown in UI + // This is a non-critical exception so print only in debug mode + if (Activator.isTracingOn()) + e.printStackTrace(); } } - } catch (Exception e) { - // Avoid NPE on disconnect shown in UI - // This is a non-critical exception so print only in debug mode - if (Activator.isTracingOn()) - e.printStackTrace(); + it.remove(); } } @@ -267,10 +298,6 @@ public class TelnetConnectorService extends StandardConnectorService implements notifyDisconnection(); } - public TelnetClient getTelnetClient() { - return fTelnetClient; - } - /** * Handle session-lost events. This is generic for any sort of connector * service. Most of this is extracted from dstore's @@ -514,18 +541,6 @@ public class TelnetConnectorService extends StandardConnectorService implements } } - /* - * Notification from sub-services that our session was lost. Notify all - * subsystems properly. - * TODO allow user to try and reconnect? - */ - public void handleSessionLost() { - Activator.trace("TelnetConnectorService: handleSessionLost"); //$NON-NLS-1$ - if (fSessionLostHandler != null) { - fSessionLostHandler.sessionLost(); - } - } - protected static Display getStandardDisplay() { Display display = Display.getCurrent(); if (display == null) { @@ -535,17 +550,23 @@ public class TelnetConnectorService extends StandardConnectorService implements } public boolean isConnected() { - boolean connected = false; - if (fTelnetClient != null) { - synchronized (fTelnetClient) { - connected = fTelnetClient.isConnected(); + boolean anyConnected = false; + synchronized(this) { + Iterator it = fTelnetClients.iterator(); + while (it.hasNext()) { + TelnetClient client = (TelnetClient)it.next(); + if (client.isConnected()) { + anyConnected = true; + } else { + it.remove(); + } } } - if (!connected && fSessionLostHandler != null) { + if (!anyConnected && fSessionLostHandler != null) { Activator.trace("TelnetConnectorService.isConnected: false -> sessionLost"); //$NON-NLS-1$ fSessionLostHandler.sessionLost(); } - return connected; + return anyConnected; } /** 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 f3c858ab7e9..f17909a5780 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 @@ -13,15 +13,21 @@ * * Contributors: * Sheldon D'souza (Celunite) - adapted from ISshSessionProvider + * Sheldon D'souza (Celunite) - [187301] support multiple telnet shells *******************************************************************************/ package org.eclipse.rse.internal.services.telnet; import org.apache.commons.net.telnet.TelnetClient; +import org.eclipse.core.runtime.IProgressMonitor; public interface ITelnetSessionProvider { - public TelnetClient getTelnetClient(); + /** + * Create a new Commons.Net TelnetClient. + * @param monitor progress monitor + * @return a new Commons.Net TelnetClient for the given connection, already authenticated + * @throws Exception in case of any error + */ + public TelnetClient makeNewTelnetClient(IProgressMonitor monitor) throws Exception ; - /* Inform the connectorService that a session has been lost. */ - public void handleSessionLost(); } diff --git a/rse/plugins/org.eclipse.rse.services.telnet/src/org/eclipse/rse/internal/services/telnet/shell/TelnetHostShell.java b/rse/plugins/org.eclipse.rse.services.telnet/src/org/eclipse/rse/internal/services/telnet/shell/TelnetHostShell.java index 20683e4a289..b178c5e9407 100644 --- a/rse/plugins/org.eclipse.rse.services.telnet/src/org/eclipse/rse/internal/services/telnet/shell/TelnetHostShell.java +++ b/rse/plugins/org.eclipse.rse.services.telnet/src/org/eclipse/rse/internal/services/telnet/shell/TelnetHostShell.java @@ -14,6 +14,7 @@ * Contributors: * Martin Oberhuber (Wind River) - Adapted from LocalHostShell. * Sheldon D'souza (Celunite) - Adapted from SshHostShell + * Sheldon D'souza (Celunite) - [187301] support multiple telnet shells *******************************************************************************/ package org.eclipse.rse.internal.services.telnet.shell; @@ -25,6 +26,7 @@ import java.io.PrintWriter; import java.util.regex.Pattern; import org.apache.commons.net.telnet.TelnetClient; +import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.rse.internal.services.telnet.ITelnetSessionProvider; import org.eclipse.rse.services.clientserver.PathUtility; import org.eclipse.rse.services.shells.AbstractHostShell; @@ -39,15 +41,17 @@ public class TelnetHostShell extends AbstractHostShell implements IHostShell { private TelnetShellOutputReader fStdoutHandler; private TelnetShellOutputReader fStderrHandler; private TelnetShellWriterThread fShellWriter; + private TelnetClient fTelnetClient; public TelnetHostShell(ITelnetSessionProvider sessionProvider, String initialWorkingDirectory, String commandToRun, String encoding, String[] environment) { try { fSessionProvider = sessionProvider; + fTelnetClient = fSessionProvider.makeNewTelnetClient(new NullProgressMonitor()); - fStdoutHandler = new TelnetShellOutputReader(this, new BufferedReader(new InputStreamReader(sessionProvider.getTelnetClient().getInputStream())), false); + fStdoutHandler = new TelnetShellOutputReader(this, new BufferedReader(new InputStreamReader(fTelnetClient.getInputStream())), false); fStderrHandler = new TelnetShellOutputReader(this, null,true); - OutputStream outputStream = sessionProvider.getTelnetClient().getOutputStream(); + OutputStream outputStream = fTelnetClient.getOutputStream(); //TODO check if encoding or command to execute needs to be considered //If a command is given, it might be possible to do without a Thread //Charset cs = Charset.forName(encoding); @@ -85,11 +89,10 @@ public class TelnetHostShell extends AbstractHostShell implements IHostShell { try { //TODO disconnect should better be done via the ConnectorService!! //Because like we do it here, the connector service is not notified! - TelnetClient client = fSessionProvider.getTelnetClient(); - if (client!=null) { - synchronized(client) { - if (client.isConnected()) - client.disconnect(); + if (fTelnetClient!=null) { + synchronized(fTelnetClient) { + if (fTelnetClient.isConnected()) + fTelnetClient.disconnect(); } } } catch (IOException e) { @@ -106,16 +109,18 @@ public class TelnetHostShell extends AbstractHostShell implements IHostShell { } public boolean isActive() { - TelnetClient client = fSessionProvider.getTelnetClient(); - if (client!=null ) { + if (fTelnetClient!=null && fTelnetClient.isConnected()) { return true; } // shell is not active: check for session lost exit(); - if (client!=null && !client.isConnected()) { - fSessionProvider.handleSessionLost(); - } + ////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; }