Refactor multiple CommandProcessors support.
diff --git a/console/org.eclipse.equinox.console.supportability.tests/src/org/eclipse/equinox/console/ssh/SshCommandTests.java b/console/org.eclipse.equinox.console.supportability.tests/src/org/eclipse/equinox/console/ssh/SshCommandTests.java
index 76212e1..7fab978 100644
--- a/console/org.eclipse.equinox.console.supportability.tests/src/org/eclipse/equinox/console/ssh/SshCommandTests.java
+++ b/console/org.eclipse.equinox.console.supportability.tests/src/org/eclipse/equinox/console/ssh/SshCommandTests.java
@@ -73,7 +73,7 @@
 		CommandSession session = EasyMock.createMock(CommandSession.class);
 		EasyMock.makeThreadSafe(session, true);
 		session.put((String)EasyMock.anyObject(), EasyMock.anyObject());
-		EasyMock.expectLastCall().times(4);
+		EasyMock.expectLastCall().times(5);
 		EasyMock.expect(session.execute(GOGO_SHELL_COMMAND)).andReturn(null);
 		session.close();
 		EasyMock.expectLastCall();
diff --git a/console/org.eclipse.equinox.console.supportability.tests/src/org/eclipse/equinox/console/ssh/SshCommandWithConfigAdminTests.java b/console/org.eclipse.equinox.console.supportability.tests/src/org/eclipse/equinox/console/ssh/SshCommandWithConfigAdminTests.java
index 09a585b..099442d 100644
--- a/console/org.eclipse.equinox.console.supportability.tests/src/org/eclipse/equinox/console/ssh/SshCommandWithConfigAdminTests.java
+++ b/console/org.eclipse.equinox.console.supportability.tests/src/org/eclipse/equinox/console/ssh/SshCommandWithConfigAdminTests.java
@@ -77,7 +77,7 @@
 		CommandSession session = EasyMock.createMock(CommandSession.class);
 		EasyMock.makeThreadSafe(session, true);
 		session.put((String)EasyMock.anyObject(), EasyMock.anyObject());
-		EasyMock.expectLastCall().times(4);
+		EasyMock.expectLastCall().times(5);
 		EasyMock.expect(session.execute(GOGO_SHELL_COMMAND)).andReturn(null);
 		session.close();
 		EasyMock.expectLastCall();
diff --git a/console/org.eclipse.equinox.console.supportability.tests/src/org/eclipse/equinox/console/ssh/SshDisconnectCommand.java b/console/org.eclipse.equinox.console.supportability.tests/src/org/eclipse/equinox/console/ssh/SshDisconnectCommandTests.java
similarity index 95%
rename from console/org.eclipse.equinox.console.supportability.tests/src/org/eclipse/equinox/console/ssh/SshDisconnectCommand.java
rename to console/org.eclipse.equinox.console.supportability.tests/src/org/eclipse/equinox/console/ssh/SshDisconnectCommandTests.java
index 91eb454..8ab10b2 100644
--- a/console/org.eclipse.equinox.console.supportability.tests/src/org/eclipse/equinox/console/ssh/SshDisconnectCommand.java
+++ b/console/org.eclipse.equinox.console.supportability.tests/src/org/eclipse/equinox/console/ssh/SshDisconnectCommandTests.java
@@ -35,7 +35,7 @@
 import org.junit.Test;
 import org.osgi.framework.BundleContext;
 
-public class SshDisconnectCommand {
+public class SshDisconnectCommandTests {
 	private static final int TEST_CONTENT = 100;
 	private static final String USER_STORE_FILE_NAME = "org.eclipse.equinox.console.jaas.file";
 	private static final String JAAS_CONFIG_FILE_NAME = "jaas.config";
@@ -56,7 +56,7 @@
 	private static final String HOST = "localhost";
 	private static final int SSH_PORT = 2222;
 	private static final long WAIT_TIME = 5000;
-	private SshShell sshShell;
+	private SshSession sshSession;
 	private InputStream in;
 
 	@Before
@@ -77,19 +77,21 @@
 		session.put((String)EasyMock.anyObject(), EasyMock.anyObject());
 		EasyMock.expectLastCall();
 		session.put((String)EasyMock.anyObject(), EasyMock.anyObject());
+		EasyMock.expectLastCall();
+		session.put((String)EasyMock.anyObject(), EasyMock.anyObject());
 		EasyMock.expectLastCall().andAnswer(new IAnswer<Object>() {
 
 			@Override
 			public Object answer() throws Throwable {
-				sshShell = (SshShell)EasyMock.getCurrentArguments()[1];
+				sshSession = (SshSession)EasyMock.getCurrentArguments()[1];
 				return null;
 			}
 			
 		});
 		EasyMock.expect(session.execute(GOGO_SHELL_COMMAND)).andReturn(null);
-		EasyMock.expect(session.get("CLOSEABLE")).andReturn(sshShell);
+		EasyMock.expect(session.get("CLOSEABLE")).andReturn(sshSession);
 		session.close();
-		EasyMock.expectLastCall();
+		EasyMock.expectLastCall().atLeastOnce();
 		EasyMock.replay(session);
 
 		CommandProcessor processor = EasyMock.createMock(CommandProcessor.class);
diff --git a/console/org.eclipse.equinox.console.supportability.tests/src/org/eclipse/equinox/console/ssh/SshShellTests.java b/console/org.eclipse.equinox.console.supportability.tests/src/org/eclipse/equinox/console/ssh/SshShellTests.java
index 69a8642..9c041fd 100644
--- a/console/org.eclipse.equinox.console.supportability.tests/src/org/eclipse/equinox/console/ssh/SshShellTests.java
+++ b/console/org.eclipse.equinox.console.supportability.tests/src/org/eclipse/equinox/console/ssh/SshShellTests.java
@@ -17,7 +17,9 @@
 import java.io.PrintStream;
 import java.net.ServerSocket;
 import java.net.Socket;
+import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
 import org.apache.felix.service.command.CommandProcessor;
@@ -93,7 +95,9 @@
             EasyMock.expect(env.getEnv()).andReturn(environment);
             EasyMock.replay(env);
             
-            shell = new SshShell(processor, context);
+            List<CommandProcessor> processors = new ArrayList<CommandProcessor>();
+            processors.add(processor);
+            shell = new SshShell(processors, context);
             shell.setInputStream(socketServer.getInputStream());
             shell.setOutputStream(socketServer.getOutputStream());
             shell.start(env);
diff --git a/console/org.eclipse.equinox.console.supportability.tests/src/org/eclipse/equinox/console/telnet/TelnetServerTests.java b/console/org.eclipse.equinox.console.supportability.tests/src/org/eclipse/equinox/console/telnet/TelnetServerTests.java
index 319912e..21eb4c5 100644
--- a/console/org.eclipse.equinox.console.supportability.tests/src/org/eclipse/equinox/console/telnet/TelnetServerTests.java
+++ b/console/org.eclipse.equinox.console.supportability.tests/src/org/eclipse/equinox/console/telnet/TelnetServerTests.java
@@ -22,6 +22,8 @@
 import java.io.PrintStream;
 import java.net.ConnectException;
 import java.net.Socket;
+import java.util.ArrayList;
+import java.util.List;
 
 import static org.easymock.EasyMock.*;
 
@@ -47,7 +49,9 @@
         EasyMock.expect(processor.createSession((ConsoleInputStream)EasyMock.anyObject(), (PrintStream)EasyMock.anyObject(), (PrintStream)EasyMock.anyObject())).andReturn(session);
         EasyMock.replay(processor);
         
-        TelnetServer telnetServer = new TelnetServer(null, processor, HOST, PORT);
+        List<CommandProcessor> processors = new ArrayList<CommandProcessor>();
+        processors.add(processor);
+        TelnetServer telnetServer = new TelnetServer(null, processors, HOST, PORT);
         telnetServer.start();
         Socket socketClient = null;
 
@@ -88,7 +92,9 @@
         EasyMock.expect(processor.createSession((ConsoleInputStream)EasyMock.anyObject(), (PrintStream)EasyMock.anyObject(), (PrintStream)EasyMock.anyObject())).andReturn(session);
         EasyMock.replay(processor);
         
-        TelnetServer telnetServer = new TelnetServer(null, processor, null, PORT);
+        List<CommandProcessor> processors = new ArrayList<CommandProcessor>();
+        processors.add(processor);
+        TelnetServer telnetServer = new TelnetServer(null, processors, null, PORT);
         telnetServer.start();
         Socket socketClient = null;
 
diff --git a/console/org.eclipse.equinox.console.supportability/src/org/eclipse/equinox/console/command/adapter/Activator.java b/console/org.eclipse.equinox.console.supportability/src/org/eclipse/equinox/console/command/adapter/Activator.java
index 56aac3b..d6a4b4c 100644
--- a/console/org.eclipse.equinox.console.supportability/src/org/eclipse/equinox/console/command/adapter/Activator.java
+++ b/console/org.eclipse.equinox.console.supportability/src/org/eclipse/equinox/console/command/adapter/Activator.java
@@ -55,6 +55,11 @@
 	private ServiceTracker<PermissionAdmin, ?> permissionAdminTracker;
 	private ServiceTracker<PackageAdmin, PackageAdmin> packageAdminTracker;
 	private ServiceTracker<PlatformAdmin, ?> platformAdminTracker;
+	private static boolean isFirstProcessor = true;
+	private static TelnetCommand telnetConnection = null;
+	private static SshCommand sshConnection = null;
+	private static Object telnetLock = new Object();
+	private static Object sshLock = new Object(); 
 	private static List<TelnetCommand> telnetConnections = new ArrayList<TelnetCommand>();
 	private static List<SshCommand> sshConnections = new ArrayList<SshCommand>();
 	
@@ -79,12 +84,16 @@
 			if (processor == null)
 				return null;
 			
-			TelnetCommand telnetCommand = new TelnetCommand(processor, context);
-			telnetCommand.start();
-			telnetConnections.add(telnetCommand);
-			SshCommand sshCommand = new SshCommand(processor, context);
-			sshCommand.start();
-			sshConnections.add(sshCommand);
+			if (isFirstProcessor) {
+				isFirstProcessor = false;
+				telnetConnection = new TelnetCommand(processor, context);
+				telnetConnection.start();
+				sshConnection = new SshCommand(processor, context);
+				sshConnection.start();
+			} else {
+				telnetConnection.addCommandProcessor(processor);
+				sshConnection.addCommandProcessor(processor);
+			}
 			
 			ServiceTracker<ConsoleSession, CommandSession> tracker = new ServiceTracker<ConsoleSession, CommandSession>(context, ConsoleSession.class, new SessionCustomizer(context, processor));
 			tracker.open();
@@ -101,6 +110,9 @@
 			ServiceReference<CommandProcessor> reference,
 			ServiceTracker<ConsoleSession, CommandSession> tracker) {
 			tracker.close();
+			CommandProcessor processor = context.getService(reference);
+			telnetConnection.removeCommandProcessor(processor);
+			sshConnection.removeCommandProcessor(processor);
 		}	
 	}
 
@@ -315,21 +327,18 @@
 		if (equinoxCmdProvider != null) {
 			equinoxCmdProvider.stop();
 		}
-		
-		for (TelnetCommand telnetCommand : telnetConnections) {
-			try {
-				telnetCommand.telnet(new String[]{"stop"});
-			} catch (Exception e) {
-				// expected if the telnet server is not started
-			}
+
+		try {
+			telnetConnection.telnet(new String[]{"stop"});
+		} catch (Exception e) {
+			// expected if the telnet server is not started
 		}
-		
-		for (SshCommand sshCommand : sshConnections) {
-			try {
-				sshCommand.ssh(new String[]{"stop"});
-			} catch (Exception e) {
-				// expected if the ssh server is not started
-			}
+
+		try {
+			sshConnection.ssh(new String[]{"stop"});
+		} catch (Exception e) {
+			// expected if the ssh server is not started
 		}
+
 	}
 }
diff --git a/console/org.eclipse.equinox.console.supportability/src/org/eclipse/equinox/console/ssh/SshCommand.java b/console/org.eclipse.equinox.console.supportability/src/org/eclipse/equinox/console/ssh/SshCommand.java
index 2f4d189..136509a 100644
--- a/console/org.eclipse.equinox.console.supportability/src/org/eclipse/equinox/console/ssh/SshCommand.java
+++ b/console/org.eclipse.equinox.console.supportability/src/org/eclipse/equinox/console/ssh/SshCommand.java
@@ -14,8 +14,10 @@
 import java.io.IOException;
 import java.net.BindException;
 import java.net.ServerSocket;
+import java.util.ArrayList;
 import java.util.Dictionary;
 import java.util.Hashtable;
+import java.util.List;
 
 import org.apache.felix.service.command.CommandProcessor;
 import org.apache.felix.service.command.Descriptor;
@@ -34,7 +36,7 @@
 public class SshCommand {
 	private String defaultHost = null;
 	private int defaultPort;
-    private final CommandProcessor processor;
+    private List<CommandProcessor> processors = new ArrayList<CommandProcessor>();
     private String host = null;
     private int port;
     private SshServ sshServ;
@@ -53,7 +55,7 @@
     private static final String ENABLED = "enabled";
     
     public SshCommand(CommandProcessor processor, BundleContext context) {
-        this.processor = processor;
+        processors.add(processor);
         this.context = context;
         
         if ("true".equals(context.getProperty(USE_CONFIG_ADMIN_PROP))) {
@@ -160,7 +162,7 @@
             checkPortAvailable(port);
             
             try {
-				sshServ = new SshServ(processor, context, host, port);
+				sshServ = new SshServ(processors, context, host, port);
 			} catch (NoClassDefFoundError e) {
 				// ssh server bundles are optional and may not be available
 				System.out.println("SSH bundles not available! If you want to use SSH, please install Apache sshd-core, Apache mina-core, slf4j-api and a slf4j logger implementation bundles");
@@ -200,6 +202,16 @@
         } 
     }
     
+    public synchronized void addCommandProcessor(CommandProcessor processor) {
+    	processors.add(processor);
+    	sshServ.addCommandProcessor(processor);
+    }
+    
+    public synchronized void removeCommandProcessor(CommandProcessor processor) {
+    	processors.remove(processor);
+    	sshServ.removeCommandProcessor(processor);
+    }
+    
     private void checkPortAvailable(int port) throws Exception {
     	ServerSocket socket = null;
     	try {
diff --git a/console/org.eclipse.equinox.console.supportability/src/org/eclipse/equinox/console/ssh/SshServ.java b/console/org.eclipse.equinox.console.supportability/src/org/eclipse/equinox/console/ssh/SshServ.java
index 1f10179..a8cfed6 100644
--- a/console/org.eclipse.equinox.console.supportability/src/org/eclipse/equinox/console/ssh/SshServ.java
+++ b/console/org.eclipse.equinox.console.supportability/src/org/eclipse/equinox/console/ssh/SshServ.java
@@ -12,6 +12,7 @@
 package org.eclipse.equinox.console.ssh;
 
 import java.io.IOException;
+import java.util.List;
 
 import org.apache.felix.service.command.CommandProcessor;
 import org.apache.sshd.SshServer;
@@ -34,10 +35,10 @@
 	private static final String SSH_KEYSTORE_PROP_DEFAULT = "hostkey.ser";
 	private static final String EQUINOX_CONSOLE_DOMAIN = "equinox_console";
 	
-    public SshServ(CommandProcessor processor, BundleContext context, String host, int port) {
+    public SshServ(List<CommandProcessor> processors, BundleContext context, String host, int port) {
     	this.host = host;
     	this.port = port;
-    	shellFactory = new SshShellFactory(processor, context);
+    	shellFactory = new SshShellFactory(processors, context);
     }
     
     public void run() throws RuntimeException {
@@ -69,6 +70,14 @@
 		}
     }
     
+    public synchronized void addCommandProcessor(CommandProcessor processor) {
+    	shellFactory.addCommandProcessor(processor);
+    }
+    
+    public synchronized void removeCommandProcessor(CommandProcessor processor) {
+    	shellFactory.removeCommandProcessor(processor);
+    }
+    
     private PasswordAuthenticator createJaasPasswordAuthenticator() {
             JaasPasswordAuthenticator jaasPasswordAuthenticator = new JaasPasswordAuthenticator();
             jaasPasswordAuthenticator.setDomain(EQUINOX_CONSOLE_DOMAIN);
diff --git a/console/org.eclipse.equinox.console.supportability/src/org/eclipse/equinox/console/ssh/SshSession.java b/console/org.eclipse.equinox.console.supportability/src/org/eclipse/equinox/console/ssh/SshSession.java
new file mode 100755
index 0000000..38a67db
--- /dev/null
+++ b/console/org.eclipse.equinox.console.supportability/src/org/eclipse/equinox/console/ssh/SshSession.java
@@ -0,0 +1,136 @@
+/*******************************************************************************

+ * Copyright (c) 2011 SAP AG

+ * 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:

+ *     Lazar Kirchev, SAP AG - initial API and implementation

+ *******************************************************************************/

+package org.eclipse.equinox.console.ssh;

+

+import java.io.Closeable;

+import java.io.IOException;

+import java.io.InputStream;

+import java.io.OutputStream;

+import java.io.PrintStream;

+import java.util.Map;

+

+import org.apache.felix.service.command.CommandProcessor;

+import org.apache.felix.service.command.CommandSession;

+import org.eclipse.equinox.console.common.ConsoleInputStream;

+import org.eclipse.equinox.console.common.ConsoleOutputStream;

+import org.eclipse.equinox.console.common.KEYS;

+import org.eclipse.equinox.console.common.terminal.TerminalTypeMappings;

+import org.eclipse.equinox.console.storage.SecureUserStore;

+import org.eclipse.equinox.console.supportability.ConsoleInputHandler;

+import org.eclipse.equinox.console.supportability.ConsoleInputScanner;

+import org.osgi.framework.BundleContext;

+

+/**

+ * This class manages a ssh connection. It is responsible for wrapping the original io streams

+ * from the socket, and starting a CommandSession to execute commands from the ssh.

+ *

+ */

+public class SshSession extends Thread implements Closeable {

+	private CommandProcessor processor;

+	private BundleContext context;

+	private SshShell sshShell;

+	private InputStream in;

+	private OutputStream out;

+	private TerminalTypeMappings currentMappings;

+	private Map<String, KEYS> currentEscapesToKey;

+	

+	private static final String PROMPT = "prompt";

+    private static final String OSGI_PROMPT = "osgi> ";

+    private static final String SCOPE = "SCOPE";

+    private static final String EQUINOX_SCOPE = "equinox:*";

+    private static final String INPUT_SCANNER = "INPUT_SCANNER";

+    private static final String SSH_INPUT_SCANNER = "SSH_INPUT_SCANNER";

+    private static final String USER_STORAGE_PROPERTY_NAME = "osgi.console.ssh.useDefaultSecureStorage";

+    private static final String DEFAULT_USER = "equinox";

+    private static final String CLOSEABLE = "CLOSEABLE";

+	private static final int ADD_USER_COUNTER_LIMIT = 2;

+	

+	public SshSession(CommandProcessor processor, BundleContext context, SshShell sshShell, InputStream in, OutputStream out, TerminalTypeMappings currentMappings, Map<String, KEYS> currentExcapesToKey) {

+		this.processor = processor;

+		this.context = context;

+		this.sshShell = sshShell;

+		this.in = in;

+		this.out = out;

+		this.currentMappings = currentMappings;

+		this.currentEscapesToKey = currentExcapesToKey;

+	}

+	

+	public void run() {

+		ConsoleInputStream input = new ConsoleInputStream();

+		ConsoleOutputStream outp = new ConsoleOutputStream(out);

+		SshInputHandler inputHandler = new SshInputHandler(in, input, outp);

+		inputHandler.getScanner().setBackspace(currentMappings.getBackspace());

+		inputHandler.getScanner().setDel(currentMappings.getDel());

+		inputHandler.getScanner().setCurrentEscapesToKey(currentEscapesToKey);

+		inputHandler.getScanner().setEscapes(currentMappings.getEscapes());

+		inputHandler.start();

+

+		ConsoleInputStream inp = new ConsoleInputStream();

+		ConsoleInputHandler consoleInputHandler = new ConsoleInputHandler(input, inp, outp);

+		consoleInputHandler.getScanner().setBackspace(currentMappings.getBackspace());

+		consoleInputHandler.getScanner().setDel(currentMappings.getDel());

+		consoleInputHandler.getScanner().setCurrentEscapesToKey(currentEscapesToKey);

+		consoleInputHandler.getScanner().setEscapes(currentMappings.getEscapes());

+		((ConsoleInputScanner)consoleInputHandler.getScanner()).setContext(context);

+		consoleInputHandler.start();

+

+		final CommandSession session;

+		final PrintStream output = new PrintStream(outp);

+

+		session = processor.createSession(inp, output, output);

+		session.put(SCOPE, EQUINOX_SCOPE);

+		session.put(PROMPT, OSGI_PROMPT);

+		session.put(INPUT_SCANNER, consoleInputHandler.getScanner());

+		session.put(SSH_INPUT_SCANNER, inputHandler.getScanner());

+		// Store this closeable object in the session, so that the disconnect command can close it

+		session.put(CLOSEABLE, this);

+		((ConsoleInputScanner)consoleInputHandler.getScanner()).setSession(session);

+

+		try {

+			if ("true".equals(context.getProperty(USER_STORAGE_PROPERTY_NAME))) {

+				String[] names = SecureUserStore.getUserNames();

+				for (String name : names) {

+					// if the default user is the only user, request creation of a new user and delete the default

+					if (DEFAULT_USER.equals(name)) {

+						if (names.length == 1) {

+							session.getConsole().println("Currently the default user is the only one; since it will be deleted after first login, create a new user:");

+							boolean isUserAdded =false;

+							int count = 0;

+							while (!isUserAdded && count < ADD_USER_COUNTER_LIMIT ){

+								isUserAdded = ((Boolean) session.execute("addUser")).booleanValue();

+								count++;

+							}

+							if (!isUserAdded) {

+								break;

+							}

+						}

+						if (SecureUserStore.existsUser(name)) {

+							SecureUserStore.deleteUser(name);

+						}

+						break;

+					}

+				}

+			}

+			session.execute("gosh --login --noshutdown");

+		} catch (Exception e) {

+			e.printStackTrace();

+		} finally {

+			session.close();

+		}

+

+	}

+	

+	public void close() throws IOException {

+		this.interrupt();

+		sshShell.removeSession(this);

+	}

+

+}

diff --git a/console/org.eclipse.equinox.console.supportability/src/org/eclipse/equinox/console/ssh/SshShell.java b/console/org.eclipse.equinox.console.supportability/src/org/eclipse/equinox/console/ssh/SshShell.java
index 99992a1..f1f4839 100644
--- a/console/org.eclipse.equinox.console.supportability/src/org/eclipse/equinox/console/ssh/SshShell.java
+++ b/console/org.eclipse.equinox.console.supportability/src/org/eclipse/equinox/console/ssh/SshShell.java
@@ -15,18 +15,14 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
-import java.io.PrintStream;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
 import org.apache.felix.service.command.CommandProcessor;
-import org.apache.felix.service.command.CommandSession;
 import org.apache.sshd.server.Command;
 import org.apache.sshd.server.Environment;
 import org.apache.sshd.server.ExitCallback;
-import java.io.Closeable;
-import org.eclipse.equinox.console.common.ConsoleInputStream;
-import org.eclipse.equinox.console.common.ConsoleOutputStream;
 import org.eclipse.equinox.console.common.KEYS;
 import org.eclipse.equinox.console.common.terminal.ANSITerminalTypeMappings;
 import org.eclipse.equinox.console.common.terminal.SCOTerminalTypeMappings;
@@ -34,43 +30,30 @@
 import org.eclipse.equinox.console.common.terminal.VT100TerminalTypeMappings;
 import org.eclipse.equinox.console.common.terminal.VT220TerminalTypeMappings;
 import org.eclipse.equinox.console.common.terminal.VT320TerminalTypeMappings;
-import org.eclipse.equinox.console.storage.SecureUserStore;
-import org.eclipse.equinox.console.supportability.ConsoleInputHandler;
-import org.eclipse.equinox.console.supportability.ConsoleInputScanner;
 import org.osgi.framework.BundleContext;
 
 /**
- * This class manages a ssh connection. It is responsible for wrapping the original io streams
- * from the ssh server, and starting a CommandSession to execute commands from the ssh.
+ * This class manages a ssh connection. It is responsible for starting a sessions to execute commands 
+ * from the ssh. If there are multiple CommandProcessors, a session is started for each of them.
  *
  */
-public class SshShell implements Command, Closeable {
+public class SshShell implements Command {
 	
-	private CommandProcessor processor;
+	private List<CommandProcessor> processors;
 	private BundleContext context;
 	private InputStream in;
 	private OutputStream out;
 	private ExitCallback callback;
-	private Thread thread;
+	private Map<CommandProcessor, SshSession> commandProcessorToConsoleThreadMap = new HashMap<CommandProcessor, SshSession>();
 	
 	private final Map<String, TerminalTypeMappings> supportedEscapeSequences;
 	private static final String DEFAULT_TTYPE = File.separatorChar == '/' ? "XTERM" : "ANSI";
 	private TerminalTypeMappings currentMappings;
 	private Map<String, KEYS> currentEscapesToKey;
-	private static final String PROMPT = "prompt";
-    private static final String OSGI_PROMPT = "osgi> ";
-    private static final String SCOPE = "SCOPE";
-    private static final String EQUINOX_SCOPE = "equinox:*";
-    private static final String INPUT_SCANNER = "INPUT_SCANNER";
-    private static final String SSH_INPUT_SCANNER = "SSH_INPUT_SCANNER";
-    private static final String USER_STORAGE_PROPERTY_NAME = "osgi.console.ssh.useDefaultSecureStorage";
-    private static final String DEFAULT_USER = "equinox";
     private static final String TERMINAL_PROPERTY = "TERM";
-    private static final String CLOSEABLE = "CLOSEABLE";
-	private static final int ADD_USER_COUNTER_LIMIT = 2;
 	
-	public SshShell(CommandProcessor processor, BundleContext context) {
-		this.processor = processor;
+	public SshShell(List<CommandProcessor> processors, BundleContext context) {
+		this.processors = processors;
 		this.context = context;
 		supportedEscapeSequences = new HashMap<String, TerminalTypeMappings> ();
         supportedEscapeSequences.put("ANSI", new ANSITerminalTypeMappings());
@@ -102,7 +85,7 @@
 		this.callback = callback;
 	}
 
-	public void start(Environment env) throws IOException {
+	public synchronized void start(Environment env) throws IOException {
 		String term = env.getEnv().get(TERMINAL_PROPERTY);
 		TerminalTypeMappings mapping = supportedEscapeSequences.get(term.toUpperCase());
 		if(mapping != null) {
@@ -110,73 +93,25 @@
 			currentEscapesToKey = mapping.getEscapesToKey();
 		}
 		
-		ConsoleInputStream input = new ConsoleInputStream();
-		ConsoleOutputStream outp = new ConsoleOutputStream(out);
-		SshInputHandler inputHandler = new SshInputHandler(in, input, outp);
-		inputHandler.getScanner().setBackspace(currentMappings.getBackspace());
-		inputHandler.getScanner().setDel(currentMappings.getDel());
-		inputHandler.getScanner().setCurrentEscapesToKey(currentEscapesToKey);
-		inputHandler.getScanner().setEscapes(currentMappings.getEscapes());
-		inputHandler.start();
-		
-		ConsoleInputStream inp = new ConsoleInputStream();
-        ConsoleInputHandler consoleInputHandler = new ConsoleInputHandler(input, inp, outp);
-        consoleInputHandler.getScanner().setBackspace(currentMappings.getBackspace());
-        consoleInputHandler.getScanner().setDel(currentMappings.getDel());
-        consoleInputHandler.getScanner().setCurrentEscapesToKey(currentEscapesToKey);
-        consoleInputHandler.getScanner().setEscapes(currentMappings.getEscapes());
-        ((ConsoleInputScanner)consoleInputHandler.getScanner()).setContext(context);
-        consoleInputHandler.start();
-        
-        final CommandSession session;
-		final PrintStream output = new PrintStream(outp);
-		
-        session = processor.createSession(inp, output, output);
-        session.put(SCOPE, EQUINOX_SCOPE);
-        session.put(PROMPT, OSGI_PROMPT);
-        session.put(INPUT_SCANNER, consoleInputHandler.getScanner());
-        session.put(SSH_INPUT_SCANNER, inputHandler.getScanner());
-        // Store this closeable object in the session, so that the disconnect command can close it
-        session.put(CLOSEABLE, this);
-        ((ConsoleInputScanner)consoleInputHandler.getScanner()).setSession(session);
-        
-        thread = new Thread() {
-        	public void run() {
-        		try {
-        			if ("true".equals(context.getProperty(USER_STORAGE_PROPERTY_NAME))) {
-        				String[] names = SecureUserStore.getUserNames();
-        				for (String name : names) {
-        					// if the default user is the only user, request creation of a new user and delete the default
-        					if (DEFAULT_USER.equals(name)) {
-        						if (names.length == 1) {
-        							session.getConsole().println("Currently the default user is the only one; since it will be deleted after first login, create a new user:");
-        							boolean isUserAdded =false;
-        							int count = 0;
-        							while (!isUserAdded && count < ADD_USER_COUNTER_LIMIT ){
-        								isUserAdded = ((Boolean) session.execute("addUser")).booleanValue();
-        								count++;
-        							}
-        							if (!isUserAdded) {
-        								break;
-        							}
-        						}
-        						if (SecureUserStore.existsUser(name)) {
-        							SecureUserStore.deleteUser(name);
-        						}
-        						break;
-        					}
-        				}
-        			}
-					session.execute("gosh --login --noshutdown");
-                } catch (Exception e) {
-                    e.printStackTrace();
-                } finally {
-                    session.close();
-                }
-        	}
-        };
-        
-        thread.start();
+		for (CommandProcessor processor : processors) {
+			createNewSession(processor);
+		}
+	}
+	
+	public synchronized void addCommandProcessor(CommandProcessor processor) {
+		createNewSession(processor);
+	}
+	
+	public synchronized void removeCommandProcessor(CommandProcessor processor) {
+		Thread consoleSession = commandProcessorToConsoleThreadMap.get(processor);
+		if (consoleSession != null) {
+			consoleSession.interrupt();
+		}
+	}
+	
+	private void createNewSession(CommandProcessor processor) {
+		SshSession consoleSession = startNewConsoleSession(processor);
+		commandProcessorToConsoleThreadMap.put(processor, consoleSession);
 	}
 
 	public void destroy() {
@@ -184,12 +119,36 @@
 	}
 	
 	public void onExit() {
-		thread.interrupt();
+		if (commandProcessorToConsoleThreadMap.values() != null) {
+			for (Thread consoleSession : commandProcessorToConsoleThreadMap.values()) {
+				consoleSession.interrupt();
+			}
+		}
 		callback.onExit(0);
 	}
-
-	public void close() {
-		onExit();
+	
+	public void removeSession(SshSession session) {
+		CommandProcessor processorToRemove = null;
+		for (CommandProcessor processor : commandProcessorToConsoleThreadMap.keySet()) {
+			if (session.equals(commandProcessorToConsoleThreadMap.get(processor))) {
+				processorToRemove = processor;
+				break;
+			}
+		}
+		
+		if (processorToRemove != null) {
+			commandProcessorToConsoleThreadMap.remove(processorToRemove);
+		}
+		
+		if (commandProcessorToConsoleThreadMap.size() == 0) {
+			onExit();
+		}
+	}
+	
+	private SshSession startNewConsoleSession(CommandProcessor processor) {
+		SshSession consoleSession = new SshSession(processor, context, this, in, out, currentMappings, currentEscapesToKey);
+        consoleSession.start();
+        return consoleSession;
 	}
 
 }
diff --git a/console/org.eclipse.equinox.console.supportability/src/org/eclipse/equinox/console/ssh/SshShellFactory.java b/console/org.eclipse.equinox.console.supportability/src/org/eclipse/equinox/console/ssh/SshShellFactory.java
index 9971193..82b7964 100644
--- a/console/org.eclipse.equinox.console.supportability/src/org/eclipse/equinox/console/ssh/SshShellFactory.java
+++ b/console/org.eclipse.equinox.console.supportability/src/org/eclipse/equinox/console/ssh/SshShellFactory.java
@@ -12,6 +12,7 @@
 package org.eclipse.equinox.console.ssh;
 
 import java.util.HashSet;
+import java.util.List;
 import java.util.Set;
 
 import org.apache.felix.service.command.CommandProcessor;
@@ -25,21 +26,35 @@
  */
 public class SshShellFactory implements Factory<Command> {
 	
-	private CommandProcessor processor;
+	private List<CommandProcessor> processors;
 	private BundleContext context;
 	private Set<SshShell> shells = new HashSet<SshShell>();
 	
-	public SshShellFactory(CommandProcessor processor, BundleContext context) {
-		this.processor = processor;
+	public SshShellFactory(List<CommandProcessor> processors, BundleContext context) {
+		this.processors = processors;
 		this.context = context;
 	}
 	
-	public Command create() {
-		SshShell shell = new SshShell(processor, context);
+	public synchronized Command create() {
+		SshShell shell = new SshShell(processors, context);
 		shells.add(shell);
 		return shell;
 	}
 	
+	public synchronized void addCommandProcessor (CommandProcessor processor) {
+		processors.add(processor);
+		for (SshShell shell : shells) {
+			shell.addCommandProcessor(processor);
+		}
+	}
+	
+	public synchronized void removeCommandProcessor (CommandProcessor processor) {
+		processors.remove(processor);
+		for (SshShell shell : shells) {
+			shell.removeCommandProcessor(processor);
+		}
+	}
+	
 	public void exit() {
 		for(SshShell shell : shells) {
 			shell.onExit();
diff --git a/console/org.eclipse.equinox.console.supportability/src/org/eclipse/equinox/console/telnet/TelnetCommand.java b/console/org.eclipse.equinox.console.supportability/src/org/eclipse/equinox/console/telnet/TelnetCommand.java
index 2d4bc58..5673a30 100644
--- a/console/org.eclipse.equinox.console.supportability/src/org/eclipse/equinox/console/telnet/TelnetCommand.java
+++ b/console/org.eclipse.equinox.console.supportability/src/org/eclipse/equinox/console/telnet/TelnetCommand.java
@@ -12,8 +12,10 @@
 package org.eclipse.equinox.console.telnet;
 
 import java.net.BindException;
+import java.util.ArrayList;
 import java.util.Dictionary;
 import java.util.Hashtable;
+import java.util.List;
 
 import org.apache.felix.service.command.CommandProcessor;
 import org.apache.felix.service.command.Descriptor;
@@ -31,7 +33,7 @@
 	
 	private String defaultHost = null;
     private int defaultPort;
-    private final CommandProcessor processor;
+    private List<CommandProcessor> processors = new ArrayList<CommandProcessor>();
     private final BundleContext context;
     private String host = null;
     private int port;
@@ -49,7 +51,7 @@
 
     public TelnetCommand(CommandProcessor processor, BundleContext context)
     {
-        this.processor = processor;
+        processors.add(processor);
         this.context = context;
         if ("true".equals(context.getProperty(USE_CONFIG_ADMIN_PROP))) {
         	Dictionary<String, String> telnetProperties = new Hashtable<String, String>();
@@ -154,7 +156,7 @@
             }
             
             try {
-				telnetServer = new TelnetServer(context, processor, host, port);
+				telnetServer = new TelnetServer(context, processors, host, port);
 			} catch (BindException e) {
 				throw new Exception("Port " + port + " already in use");
 			}
@@ -171,6 +173,16 @@
         } 
     }
     
+    public synchronized void addCommandProcessor(CommandProcessor processor) {
+    	processors.add(processor);
+    	telnetServer.addCommandProcessor(processor);
+    }
+    
+    public synchronized void removeCommandProcessor(CommandProcessor processor) {
+    	processors.remove(processor);
+    	telnetServer.removeCommandProcessor(processor);
+    }
+    
     private void printHelp() {
     	StringBuffer help = new StringBuffer();
     	help.append("telnet - start simple telnet server");
diff --git a/console/org.eclipse.equinox.console.supportability/src/org/eclipse/equinox/console/telnet/TelnetServer.java b/console/org.eclipse.equinox.console.supportability/src/org/eclipse/equinox/console/telnet/TelnetServer.java
index 019b1cf..3ea6189 100644
--- a/console/org.eclipse.equinox.console.supportability/src/org/eclipse/equinox/console/telnet/TelnetServer.java
+++ b/console/org.eclipse.equinox.console.supportability/src/org/eclipse/equinox/console/telnet/TelnetServer.java
@@ -16,27 +16,31 @@
 import java.net.ServerSocket;
 import java.net.Socket;
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 import org.apache.felix.service.command.CommandProcessor;
 import org.osgi.framework.BundleContext;
 
 /**
  * A telnet server, which listens for telnet connections and starts a telnet connection manager
- * when a connection is accepted.
+ * when a connection is accepted. If there are multiple CommandProcessor, a telnet connection
+ * is created for each of them.
  *
  */
 public class TelnetServer extends Thread {
 	
 	private ServerSocket server;
     private boolean isRunning = true;
-    private CommandProcessor processor;
+    private List<CommandProcessor> processors = null;
     private BundleContext context;
-    private List<TelnetConnection> telnetConnections = new ArrayList<TelnetConnection>();
+    private List<Socket> sockets = new ArrayList<Socket>();
+    private Map<CommandProcessor, List<TelnetConnection>> processorToConnectionsMapping = new HashMap<CommandProcessor, List<TelnetConnection>>();
     
-    public TelnetServer(BundleContext context, CommandProcessor processor, String host, int port) throws IOException {
+    public TelnetServer(BundleContext context, List<CommandProcessor> processors, String host, int port) throws IOException {
     	this.context = context;
-    	this.processor = processor;
+    	this.processors = processors;
     	if(host != null) {
     		server = new ServerSocket(port, 0, InetAddress.getByName(host));
     	} else {
@@ -51,9 +55,17 @@
             while (isRunning)
             {
                 final Socket socket = server.accept();
-                TelnetConnection telnetConnection = new TelnetConnection(socket, processor, context);
-                telnetConnections.add(telnetConnection);
-                telnetConnection.start();
+                sockets.add(socket);
+                for (CommandProcessor processor : processors) {
+                	TelnetConnection telnetConnection = new TelnetConnection(socket, processor, context);
+                	List<TelnetConnection> telnetConnections = processorToConnectionsMapping.get(processor);
+                	if (telnetConnections == null) {
+                		telnetConnections = new ArrayList<TelnetConnection>();
+                		processorToConnectionsMapping.put(processor, telnetConnections);
+                	}
+                	telnetConnections.add(telnetConnection);
+                	telnetConnection.start();
+                }
             }
         } catch (IOException e) {
             if (isRunning == true) {
@@ -71,6 +83,25 @@
         }
     }
 	
+	public synchronized void addCommandProcessor(CommandProcessor processor) {
+		List<TelnetConnection> telnetConnections = new ArrayList<TelnetConnection>();
+		for (Socket socket : sockets) {
+			TelnetConnection telnetConnection = new TelnetConnection(socket, processor, context);
+			telnetConnections.add(telnetConnection);
+        	telnetConnection.start();
+		}
+		processorToConnectionsMapping.put(processor, telnetConnections);
+	}
+	
+	public synchronized void removeCommandProcessor(CommandProcessor processor) {
+		List<TelnetConnection> telnetConnections = processorToConnectionsMapping.remove(processor);
+		if (telnetConnections != null) {
+			for (TelnetConnection telnetConnection : telnetConnections) {
+				telnetConnection.close();
+			}
+		}
+	}
+	
 	public synchronized void stopTelnetServer() {
 		isRunning = false;
 		try {
@@ -81,8 +112,10 @@
         	// do nothing
         }
         
-        for(TelnetConnection telnetConnection : telnetConnections) {
-        	telnetConnection.close();
+        for(List<TelnetConnection> telnetConnections : processorToConnectionsMapping.values()) {
+        	for (TelnetConnection telnetConnection : telnetConnections) {
+        		telnetConnection.close();
+        	}
         }
         
 		this.interrupt();