blob: acf0e25cc557a931d44abe4ef8f2ceb78bae073d [file] [log] [blame]
/******************************************************************************
* Copyright (c) 2006, 2010 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:
* IBM Corporation - Initial Implementation
* Roland Schulz, University of Tennessee
*
*****************************************************************************/
package org.eclipse.ptp.remotetools.internal.ssh;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Set;
import java.util.concurrent.ArrayBlockingQueue;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.SubMonitor;
import org.eclipse.jsch.core.IJSchService;
import org.eclipse.osgi.util.NLS;
import org.eclipse.ptp.remotetools.RemotetoolsPlugin;
import org.eclipse.ptp.remotetools.core.AuthToken;
import org.eclipse.ptp.remotetools.core.IRemoteConnection;
import org.eclipse.ptp.remotetools.core.IRemoteExecutionManager;
import org.eclipse.ptp.remotetools.core.IRemoteOperation;
import org.eclipse.ptp.remotetools.core.KeyAuthToken;
import org.eclipse.ptp.remotetools.core.PasswdAuthToken;
import org.eclipse.ptp.remotetools.core.messages.Messages;
import org.eclipse.ptp.remotetools.exception.LocalPortBoundException;
import org.eclipse.ptp.remotetools.exception.RemoteConnectionException;
import org.eclipse.ptp.remotetools.internal.common.RemoteTunnel;
import org.eclipse.ptp.remotetools.internal.core.ConnectionProperties;
import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelExec;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Proxy;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.SocketFactory;
import com.jcraft.jsch.UIKeyboardInteractive;
import com.jcraft.jsch.UserInfo;
/**
* The connection to a remote host. Manages a pool of connection used to open
* execution channels, since some SSH server showed to impose a limit of
* execution channels per connection.
*
* @author Richard Maciel and Daniel Felix Ferber.
*/
public class Connection implements IRemoteConnection {
private class ConnectionSlot {
Session session = null;
int numberUsedChannels = 0;
ConnectionSlot(Session session) {
this.session = session;
}
ConnectionSlot(Session session, int initialLoad) {
this.session = session;
this.numberUsedChannels = initialLoad;
}
}
/**
* This class is required by the JSch library.
*
* JSch will call {@link #promptKeyboardInteractive} until the password is
* correct or it times out. We only allow it to try once, then return null
* in order to speed up the timeout.
*
* TODO: this should prompt the user for a password if {@link
* @promptKeyboardInteractive} is called twice, since their password is
* wrong for some reason.
*
* @author Richard Maciel
*
*/
private class SSHUserInfo implements UserInfo, UIKeyboardInteractive {
private String password;
private String passphrase;
private boolean isPasswdBased;
private boolean firstTry = true;
private SSHUserInfo() {
}
public String getPassphrase() {
return passphrase;
}
public String getPassword() {
if (firstTry) {
firstTry = false;
return password;
}
return null;
}
public String[] promptKeyboardInteractive(final String destination, final String name, final String instruction,
final String[] prompt, final boolean[] echo) {
if (prompt.length != 1 || echo[0] != false || password == null) {
return null;
}
String[] response = new String[1];
response[0] = password;
if (firstTry) {
firstTry = false;
return response;
}
return null;
}
public boolean promptPassphrase(String message) {
return !isPasswdBased;
}
public boolean promptPassword(String message) {
return isPasswdBased;
}
public boolean promptYesNo(String str) {
// Always accept host identity
return true;
}
public void reset() {
firstTry = true;
}
public void setPassphrase(String passphrase) {
this.passphrase = passphrase;
}
public void setPassword(String password) {
this.password = password;
}
public void setUsePassword(boolean usePassword) {
this.isPasswdBased = usePassword;
}
public void showMessage(String message) {
}
}
/**
* By default the Jsch connect method ignores the timeout argument which
* prevents any way of interrupting the connection (e.g. with a progress
* monitor). We use a proxy so that we can connect to a remote host with a
* timeout.
*/
private class SSHProxy implements Proxy {
private final Socket fSocket = new Socket();
/*
* (non-Javadoc)
*
* @see com.jcraft.jsch.Proxy#connect(com.jcraft.jsch.SocketFactory,
* java.lang.String, int, int)
*/
public void connect(SocketFactory socket_factory, String host, int port, int timeout) throws Exception {
InetSocketAddress addr = new InetSocketAddress(host, port);
fSocket.connect(addr, timeout);
}
/*
* (non-Javadoc)
*
* @see com.jcraft.jsch.Proxy#getInputStream()
*/
public InputStream getInputStream() {
try {
return fSocket.getInputStream();
} catch (IOException e) {
return null;
}
}
/*
* (non-Javadoc)
*
* @see com.jcraft.jsch.Proxy#getOutputStream()
*/
public OutputStream getOutputStream() {
try {
return fSocket.getOutputStream();
} catch (IOException e) {
return null;
}
}
/*
* (non-Javadoc)
*
* @see com.jcraft.jsch.Proxy#getSocket()
*/
public Socket getSocket() {
return fSocket;
}
/*
* (non-Javadoc)
*
* @see com.jcraft.jsch.Proxy#close()
*/
public void close() {
try {
fSocket.close();
} catch (IOException e) {
// do nothing
}
}
}
/**
* Data structure to access the ssh library.
*/
private final IJSchService jsch = RemotetoolsPlugin.getDefault().getJSchService();
/**
* A connection to the remote host. The default connections is always
* created, but more connections may be added to the pool on demand.
*/
private Session defaultSession;
private String fUsername;
private String fHostname;
private int fPort;
private int fTimeout;
private String fCipherType;
private final SSHUserInfo sshuserinfo = new SSHUserInfo();
/**
* The execution managers created for this connection.
*/
private IRemoteExecutionManager executionManager = null;
/**
* Tunnels to remote host.
*/
private final Set<RemoteTunnel> tunnels = new HashSet<RemoteTunnel>();
/**
* sftp channel pool shared by all executions managers and file tools.
*/
private static final int SFTP_POOLSIZE = 3;
private final ArrayBlockingQueue<ChannelSftp> sftpChannelPool = new ArrayBlockingQueue<ChannelSftp>(SFTP_POOLSIZE);
/**
* Hashtable that keeps all remote executions that can be killed. The table
* is indexed by Internal PID.
*/
private final Hashtable<Integer, KillableExecution> activeProcessTable = new Hashtable<Integer, KillableExecution>();
/**
* The internal identification number for the next remote execution.
*/
private int nextInternalPID;
/**
* The control connection.
*/
private ControlChannel controlChannel;
/**
* A job that watches for finished executions.
*/
private ExecutionObserver executionObserver;
/**
* Array of all connections and how many pty channels were used.
*/
private final ArrayList<ConnectionSlot> connectionPool = new ArrayList<ConnectionSlot>();
/**
* Maps a channel to the connection where it was created.
*/
private final HashMap<Channel, ConnectionSlot> channelToConnectioPool = new HashMap<Channel, ConnectionSlot>();
/**
* Locks used on synchronized operations.
*/
protected ConnectionLocks connectionLocks;
private RemotePortForwardingPool forwardingPool;
/*
* (non-Javadoc)
*
* @see
* org.eclipse.ptp.remotetools.core.IRemoteConnection#connect(org.eclipse
* .ptp.remotetools.core.AuthToken, java.lang.String, int, java.lang.String,
* int, org.eclipse.core.runtime.IProgressMonitor)
*/
public synchronized void connect(AuthToken authToken, String hostname, int port, String cipherType, int timeout,
IProgressMonitor monitor) throws RemoteConnectionException {
SubMonitor progress = SubMonitor.convert(monitor, 100);
try {
this.nextInternalPID = 0;
fUsername = authToken.getUsername();
// Convert information for the UserInfo class used by JSch
if (authToken instanceof PasswdAuthToken) {
sshuserinfo.setUsePassword(true);
sshuserinfo.setPassword(((PasswdAuthToken) authToken).getPassword());
} else if (authToken instanceof KeyAuthToken) {
KeyAuthToken token = (KeyAuthToken) authToken;
sshuserinfo.setUsePassword(false);
sshuserinfo.setPassphrase(token.getPassphrase());
try {
jsch.getJSch().addIdentity(token.getKeyPath().getAbsolutePath());
} catch (JSchException e) {
throw new RemoteConnectionException(e.getMessage());
}
} else {
throw new RuntimeException(Messages.Connection_AuthenticationTypeNotSupported);
}
fHostname = hostname;
fPort = port;
if (fPort == 0) {
fPort = ConnectionProperties.defaultPort;
}
fCipherType = cipherType;
if (fCipherType == null) {
fCipherType = CipherTypes.CIPHER_DEFAULT;
}
fTimeout = timeout;
if (fTimeout == 0) {
fTimeout = ConnectionProperties.defaultTimeout;
}
/*
* Create session.
*/
try {
defaultSession = jsch.createSession(fHostname, fPort, fUsername);
sshuserinfo.reset();
defaultSession.setUserInfo(sshuserinfo);
defaultSession.setServerAliveInterval(300000);
defaultSession.setServerAliveCountMax(6);
defaultSession.setProxy(new SSHProxy());
} catch (JSchException e) {
disconnect();
throw new RemoteConnectionException(e.getMessage());
}
setSessionCipherType(defaultSession);
/*
* Connect to remote host. Try connecting at 1 sec intervals to
* allow the connection to be cancelled. Note that a timeout of 0
* implies infinite (or until cancelled).
*/
int connTimeout = fTimeout;
int tryTimeout = connTimeout > 0 ? 1000 : connTimeout;
while (!defaultSession.isConnected() && !progress.isCanceled() && connTimeout >= 0) {
try {
defaultSession.connect(1000);
} catch (JSchException e) {
connTimeout -= tryTimeout;
} catch (Exception e) {
disconnect();
throw new RemoteConnectionException(e.getMessage());
}
}
if (connTimeout < 0) {
disconnect();
throw new RemoteConnectionException(NLS.bind(Messages.Connection_Connect_FailedConnect, fHostname));
}
if (progress.isCanceled()) {
disconnect();
throw new RemoteConnectionException(Messages.Connection_Operation_cancelled_by_user);
}
/*
* Create control execution channel.
*/
if (controlChannel == null) {
controlChannel = new ControlChannel(this);
}
try {
controlChannel.open(progress.newChild(10));
} catch (RemoteConnectionException e) {
disconnect();
throw new RemoteConnectionException(e.getMessage());
}
/*
* Create sft pool.
*/
try {
for (int i = 0; i < SFTP_POOLSIZE; i++) {
ChannelSftp sftp = (ChannelSftp) defaultSession.openChannel("sftp"); //$NON-NLS-1$
sftp.connect();
boolean bInterrupted = Thread.interrupted();
while (sftp != null) {
try {
sftpChannelPool.put(sftp);
sftp = null;
} catch (InterruptedException e) {
// System.out.println("Connection.connect: InterruptedException ignored");
bInterrupted = true;
}
}
if (bInterrupted)
Thread.currentThread().interrupt(); // set interrupt
// state
}
} catch (JSchException e) {
throw new RemoteConnectionException(e.getMessage());
}
/*
* The default session cannot be fully used for connection pool,
* since some channels are already using pty.
*/
ConnectionSlot slot = new ConnectionSlot(defaultSession, ConnectionProperties.initialDefaultSessionLoad);
connectionPool.add(slot);
if (forwardingPool == null) {
forwardingPool = new RemotePortForwardingPool(this);
}
/*
* Reset cancel flag
*/
if (executionManager != null) {
executionManager.resetCancel();
}
/*
* Create observer thread and start it
*/
executionObserver = new ExecutionObserver(this);
executionObserver.start();
} finally {
if (monitor != null) {
monitor.done();
}
}
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.ptp.remotetools.IRemoteConnection#getRemoteExecutionManager()
*/
public synchronized IRemoteExecutionManager createRemoteExecutionManager() throws RemoteConnectionException {
if (executionManager == null) {
executionManager = new ExecutionManager(this);
}
return executionManager;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.ptp.remotetools.IRemoteConnection#disconnect()
*/
public synchronized void disconnect() {
/*
* First, cancel all ongoing executions and tunnels created by managers,
* by closing the execution manager.
*/
if (executionManager != null) {
executionManager.close();
}
if (executionObserver != null) {
executionObserver.cancel();
}
/*
* Then, close channels created by the connection.
*/
if (controlChannel != null) {
controlChannel.close();
}
boolean bInterrupted = Thread.interrupted();
while (!sftpChannelPool.isEmpty()) {
try {
sftpChannelPool.take().disconnect();
} catch (InterruptedException e) {
bInterrupted = true;
}
}
sftpChannelPool.clear();
if (bInterrupted) {
Thread.currentThread().interrupt(); // set interrupt state
}
/*
* Close all connections from the pool.
*/
for (ConnectionSlot slot : connectionPool) {
slot.session.disconnect();
}
connectionPool.clear();
/*
* Reset internal state variables.
*/
defaultSession = null;
if (forwardingPool != null) {
forwardingPool.disconnect();
}
}
public String getHostname() {
return fHostname;
}
public int getPort() {
return fPort;
}
public Session getSession() {
return defaultSession;
}
/*
* public String getPassword() { return password; }
*/
/**
* Gets the SFTP channel that may be used by the internal implementation to
* do file system operations on the remote host. Gets a new channel if the
* default has been closed for some reason.
*
* @return default channel
* @throws RemoteConnectionException
*/
public ChannelSftp getSFTPChannel() throws RemoteConnectionException {
// System.out.println("channelPool.size() -> " +
// sftpChannelPool.size());
// System.out.println("thread: "+Thread.currentThread().getName());
try {
// if (sftpChannelPool.size() == 0)
// System.err.println("SFTPChannelPool currently empty. Thread will have to wait till other thread releases a channel.");
ChannelSftp channel = null;
boolean bInterrupted = Thread.interrupted();
while (channel == null) {
try {
channel = sftpChannelPool.take();
} catch (InterruptedException e) {
// System.out.println("getSFTPChannel: InterruptedException ignored");
bInterrupted = true;
}
}
if (bInterrupted) {
Thread.currentThread().interrupt(); // set interrupt state
}
// System.out.println("channel: "+channel.isConnected()+","+channel.isEOF());
if (!channel.isConnected()) {
channel = (ChannelSftp) defaultSession.openChannel("sftp"); //$NON-NLS-1$
channel.connect();
}
return channel;
} catch (JSchException e) {
throw new RemoteConnectionException(Messages.Connection_Connect_FailedCreateSFTPConnection, e);
}
}
public int getTimeout() {
return fTimeout;
}
public String getUsername() {
return fUsername;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.ptp.remotetools.IRemoteConnection#isConnected()
*/
public synchronized boolean isConnected() {
if (defaultSession == null) {
return false;
}
try {
test();
} catch (RemoteConnectionException e) {
return false;
}
return defaultSession.isConnected();
}
/**
* Releases the SFTP channel
*
* @param channel
* channel to release
*/
public void releaseSFTPChannel(ChannelSftp channel) {
// System.out.println("release, channelPool.size() -> " +
// sftpChannelPool.size());
// System.out.println("thread: "+Thread.currentThread().getName());
boolean bInterrupted = Thread.interrupted();
while (channel != null) {
try {
sftpChannelPool.put(channel);
channel = null; // Successful returned
} catch (InterruptedException e) {
// System.out.println("releaseSFTPChannel: InterruptedException ignored");
bInterrupted = true;
}
}
if (bInterrupted) {
Thread.currentThread().interrupt(); // set interrupt state
}
}
/**
* Open a new connection to the remote host and add this connection to the
* pool.
*
* @return A pool entry.
* @throws RemoteConnectionException
*/
private ConnectionSlot createConnectionSlot() throws RemoteConnectionException {
/*
* Create a Jsch session, with the same authentication values as the
* default session.
*/
Session newSession = null;
try {
newSession = jsch.createSession(fHostname, fPort, fUsername);
sshuserinfo.reset();
newSession.setUserInfo(sshuserinfo);
newSession.setServerAliveInterval(300000);
newSession.setServerAliveCountMax(6);
setSessionCipherType(newSession);
} catch (JSchException e) {
throw new RemoteConnectionException(Messages.Connection_CreateConnectionSlot_FailedCreateNewSession, e);
}
/*
* Connect to remote host.
*/
try {
newSession.connect(fTimeout);
} catch (JSchException e) {
throw new RemoteConnectionException(Messages.Connection_CreateConnectionSlot_FailedConnectNewSession, e);
}
/*
* Create slot and add to the pool.
*/
ConnectionSlot slot = new ConnectionSlot(newSession);
connectionPool.add(slot);
return slot;
}
/**
* Select a cipher for the session based on the cipherType attribute
*
* @param session
* Session that will have its cipher altered.
*/
private void setSessionCipherType(Session session) {
/*
* If the user selected a cipher other than the default, setup the
* cipher
*/
// TODO: Let the user select a list of ciphers, instead of only one
if (!fCipherType.equals(CipherTypes.CIPHER_DEFAULT)) {
// Verify if the cipher is supported. Throw an exception if it isnt.
if (!CipherTypes.getCipherTypesMap().containsKey(fCipherType)) {
// TODO: Throw a real exception, not a runtime one
throw new RuntimeException(Messages.Connection_SetCipherType_CipherNotSupported);
}
// Set the session's cipher
Hashtable<String, String> config = new Hashtable<String, String>();
config.put("cipher.s2c", fCipherType); //$NON-NLS-1$
config.put("cipher.c2s", fCipherType); //$NON-NLS-1$
session.setConfig(config);
}
}
/**
* Creates a new execution channel. The channel may or may not be managed by
* the connection pool. All execution channels that require PTY must be
* managed by the pool, except really special cases, like the control
* channel and default SFTP channel. Channels without PTY may be managed, by
* it is recommended no to be. This will allocate them into the default
* session, since an unlimited number of not PTY channels can be allocated
* into the default session.
*
* @param isInConnectionPool
* As described.
* @return The requested execution channel.
* @throws RemoteConnectionException
* If the allocation of new channel failed of if it was not
* possible to create a new ssh session for the new channel.
*/
protected ChannelExec createExecChannel(boolean isInConnectionPool) throws RemoteConnectionException {
if (isInConnectionPool) {
/*
* Search for the first available connection slot or create a new
* one if all are full.
*/
ConnectionSlot suggestedSlot = null;
for (ConnectionSlot slot : connectionPool) {
if (slot.numberUsedChannels < ConnectionProperties.maxChannelsPerConnection) {
suggestedSlot = slot;
break;
}
}
if (suggestedSlot == null) {
suggestedSlot = createConnectionSlot();
}
/*
* Create the channel and update the pool.
*/
ChannelExec channel;
try {
channel = (ChannelExec) suggestedSlot.session.openChannel("exec"); //$NON-NLS-1$
} catch (JSchException e) {
throw new RemoteConnectionException(Messages.Connection_CreateExecChannel_FailedCreateNewExecChannel, e);
}
suggestedSlot.numberUsedChannels++;
channelToConnectioPool.put(channel, suggestedSlot);
return channel;
} else {
/*
* Create a channel on the default channel.
*/
try {
return (ChannelExec) defaultSession.openChannel("exec"); //$NON-NLS-1$
} catch (JSchException e) {
throw new RemoteConnectionException(Messages.Connection_CreateExecChannel_FailedCreateNewExecChannel, e);
}
}
}
protected synchronized int createNextPIID() {
return ++nextInternalPID % Integer.MAX_VALUE;
}
/**
* Create a forwarding from a remote port to a local port.
*
* @param localPort
* @param addressOnRemoteHost
* @param portOnRemoteHost
* @return
* @throws RemoteConnectionException
*/
protected RemoteTunnel createTunnel(int localPort, String addressOnRemoteHost, int portOnRemoteHost)
throws RemoteConnectionException, LocalPortBoundException {
RemoteTunnel tunnel = new RemoteTunnel(localPort, portOnRemoteHost, addressOnRemoteHost);
if (tunnels.contains(tunnel)) {
throw new LocalPortBoundException(Messages.Connection_CreateTunnel_TunnelPortAlreadyAlloced);
}
try {
defaultSession.setPortForwardingL(tunnel.getLocalPort(), tunnel.getAddressOnRemoteHost(), tunnel.getPortOnRemoteHost());
} catch (JSchException e) {
if (e.getMessage().matches("PortForwardingL: local port .* is already registered.")) { //$NON-NLS-1$
// Selected local port is already bound.
throw new LocalPortBoundException(Messages.Connection_CreateTunnel_TunnelPortAlreadyAlloced);
}
throw new RemoteConnectionException(Messages.Connection_CreateTunnel_FailedCreateTunnel, e);
}
tunnels.add(tunnel);
return tunnel;
}
protected Hashtable<Integer, KillableExecution> getActiveProcessTable() {
return activeProcessTable;
}
protected RemotePortForwardingPool getForwardingPool() {
return forwardingPool;
}
protected String getKillablePrefix(KillableExecution execution) {
return controlChannel.getKillablePrefix(execution.getInternaID());
}
/**
* Sends a KILL signal to the remote killable execution.
*
* @param execution
*/
protected void killExecution(KillableExecution execution) {
controlChannel.killRemoteProcess(execution.getPID());
}
protected void registerObservedExecution(IRemoteOperation operation) {
if (operation instanceof KillableExecution) {
KillableExecution killableExecution = (KillableExecution) operation;
synchronized (getActiveProcessTable()) {
getActiveProcessTable().put(new Integer(killableExecution.getInternaID()), killableExecution);
}
}
}
/**
* Remove a channel from the pool, leaving the slot available for another
* channel.
*
* @param channel
*/
protected void releaseChannel(Channel channel) {
/*
* The channel may or may not be in the connection pool, depending how
* it was created. Ant any case, always disconnect the channel.
*/
channel.disconnect();
ConnectionSlot slot = channelToConnectioPool.remove(channel);
if (slot != null) {
slot.numberUsedChannels--;
}
}
/**
* Release the forwarding of the remote port.
*
* @param tunnel
* @throws RemoteConnectionException
*/
protected void releaseTunnel(RemoteTunnel tunnel) throws RemoteConnectionException {
if (!tunnels.contains(tunnel)) {
throw new RemoteConnectionException(Messages.Connection_ReleaseTunnel_PortNotAllocedForTunnel);
}
try {
RemoteTunnel remoteTunnel = tunnel;
defaultSession.delPortForwardingL(remoteTunnel.getLocalPort());
} catch (JSchException e) {
throw new RemoteConnectionException(Messages.Connection_ReleaseTunnel_FailedRemoveTunnel, e);
}
tunnels.remove(tunnel);
}
protected void setPID(int piid, int pid) {
// Look for the object which key is PIID.
synchronized (getActiveProcessTable()) {
KillableExecution exec = getActiveProcessTable().get(new Integer(piid));
if (exec != null) {
// Process could be already finished and removed fro mthe table.
exec.setPID(pid);
}
}
}
/**
* Performs a sanity test to make sure that the connection is alive and has
* a valid state.
* <p>
* The connection may get dropped due some external interference, like
* loosing physical access to the remote machine. Or the connection may drop
* some channel, as it may be caused by a misbehavior of the remote SSH
* server or by a bug in the local SSH implementation.
* <p>
* If some problem is detected, then an {@link RemoteConnectionException} is
* thrown. Else, the method returns.
*
* @throws RemoteConnectionException
* The connection was entirely dropped or some channel got lost.
*/
protected synchronized void test() throws RemoteConnectionException {
/*
* Check all SSH sessions
*/
for (ConnectionSlot slot : connectionPool) {
if (!slot.session.isConnected()) {
throw new RemoteConnectionException(Messages.Connection_0);
}
}
/*
* Check control channel.
*/
if (controlChannel == null || !controlChannel.isConnected()) {
throw new RemoteConnectionException(Messages.Connection_1);
}
}
protected void unregisterObservedExecution(IRemoteOperation operation) {
if (operation instanceof KillableExecution) {
KillableExecution killableExecution = (KillableExecution) operation;
synchronized (getActiveProcessTable()) {
getActiveProcessTable().remove(new Integer(killableExecution.getInternaID()));
}
}
}
}