You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@taverna.apache.org by st...@apache.org on 2016/06/30 13:53:30 UTC

[06/50] [abbrv] incubator-taverna-common-activities git commit: TAVERNA-963 package taverna.externaltool.*

http://git-wip-us.apache.org/repos/asf/incubator-taverna-common-activities/blob/98468d30/taverna-external-tool-activity/src/main/java/org/apache/taverna/activities/externaltool/local/LocalUseCaseInvocation.java
----------------------------------------------------------------------
diff --git a/taverna-external-tool-activity/src/main/java/org/apache/taverna/activities/externaltool/local/LocalUseCaseInvocation.java b/taverna-external-tool-activity/src/main/java/org/apache/taverna/activities/externaltool/local/LocalUseCaseInvocation.java
new file mode 100755
index 0000000..b57be14
--- /dev/null
+++ b/taverna-external-tool-activity/src/main/java/org/apache/taverna/activities/externaltool/local/LocalUseCaseInvocation.java
@@ -0,0 +1,560 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.taverna.activities.externaltool.local;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Reader;
+import java.io.UnsupportedEncodingException;
+import java.io.Writer;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Matcher;
+
+import org.apache.taverna.activities.externaltool.desc.ScriptInput;
+import org.apache.taverna.activities.externaltool.desc.ScriptOutput;
+import org.apache.taverna.activities.externaltool.desc.UseCaseDescription;
+import org.apache.taverna.activities.externaltool.invocation.InvocationException;
+import org.apache.taverna.activities.externaltool.invocation.UseCaseInvocation;
+import org.apache.taverna.activities.externaltool.ssh.SshNode;
+import org.apache.taverna.activities.externaltool.ssh.SshNodeFactory;
+import org.apache.taverna.activities.externaltool.ssh.SshUrl;
+import org.apache.taverna.reference.AbstractExternalReference;
+import org.apache.taverna.reference.ErrorDocument;
+import org.apache.taverna.reference.ExternalReferenceSPI;
+import org.apache.taverna.reference.Identified;
+import org.apache.taverna.reference.ReferenceService;
+import org.apache.taverna.reference.ReferenceSet;
+import org.apache.taverna.reference.ReferencedDataNature;
+import org.apache.taverna.reference.T2Reference;
+import org.apache.taverna.reference.impl.external.file.FileReference;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.IOUtils;
+import org.apache.log4j.Logger;
+
+/**
+ * The job is executed locally, i.e. not via the grid.
+ * @author Hajo Krabbenhoeft
+ */
+public class LocalUseCaseInvocation extends UseCaseInvocation {
+
+	private static Logger logger = Logger.getLogger(LocalUseCaseInvocation.class);
+
+	private final File tempDir;
+	
+	public static String LOCAL_USE_CASE_INVOCATION_TYPE = "789663B8-DA91-428A-9F7D-B3F3DA185FD4";
+	
+	private Process running;
+
+	private final String shellPrefix;
+
+	private final String linkCommand;
+
+	private Reader stdInReader = null;
+	
+	private static Map<String, Set<String>> runIdToTempDir = Collections.synchronizedMap(new HashMap<String, Set<String>> ());
+	
+	private static String LOCAL_INVOCATION_FILE = "localInvocations";
+
+	public LocalUseCaseInvocation(UseCaseDescription desc, boolean retrieveData, String mainTempDirectory, String shellPrefix, String linkCommand) throws IOException {
+
+		usecase = desc;
+		setRetrieveData(retrieveData);
+		this.shellPrefix = shellPrefix;
+		this.linkCommand = linkCommand;
+		
+		if (mainTempDirectory != null) {
+		
+			File mainTempDir = new File(mainTempDirectory);
+
+			tempDir = File.createTempFile("usecase", "dir", mainTempDir);
+		} else {
+			tempDir = File.createTempFile("usecase", "dir");
+		}
+		tempDir.delete();
+		tempDir.mkdir();
+		logger.info("mainTempDirectory is " + mainTempDirectory);
+		logger.info("Using tempDir " + tempDir.getAbsolutePath());
+
+	}
+
+	void recDel(File c) {
+		File[] files = c.listFiles();
+		if (files != null) {
+			for (File cc : files)
+				recDel(cc);
+		}
+		c.delete();
+	}
+	
+	private String setOneBinaryInput(ReferenceService referenceService,
+			T2Reference t2Reference, ScriptInput input, String targetSuffix)
+			throws InvocationException {
+
+		if (input.isFile() || input.isTempFile()) {
+			// Try to get it as a file
+			String target = tempDir.getAbsolutePath() + "/" + targetSuffix;
+			FileReference fileRef = getAsFileReference(referenceService,
+					t2Reference);
+			if (fileRef != null) {
+
+				if (!input.isForceCopy()) {
+					if (linkCommand != null) {
+						String source = fileRef.getFile().getAbsolutePath();
+						String actualLinkCommand = getActualOsCommand(
+								linkCommand, source, targetSuffix, target);
+						logger.info("Link command is " + actualLinkCommand);
+						String[] splitCmds = actualLinkCommand.split(" ");
+						ProcessBuilder builder = new ProcessBuilder(splitCmds);
+						builder.directory(tempDir);
+						try {
+							int code = builder.start().waitFor();
+							if (code == 0) {
+								return target;
+							} else {
+								logger.error("Link command gave errorcode: "
+										+ code);
+							}
+
+						} catch (InterruptedException e) {
+							// go through
+						} catch (IOException e) {
+							// go through
+						}
+
+					}
+				}
+			}
+
+			InputStream is = null;
+			OutputStream os = null;
+			is = getAsStream(referenceService, t2Reference);
+
+			try {
+				os = new FileOutputStream(target);
+			} catch (FileNotFoundException e) {
+				throw new InvocationException(e);
+			}
+
+			try {
+				IOUtils.copyLarge(is, os);
+			} catch (IOException e) {
+				throw new InvocationException(e);
+			}
+			try {
+				is.close();
+				os.close();
+			} catch (IOException e) {
+				throw new InvocationException(e);
+			}
+			return target;
+		} else {
+			String value = (String) referenceService.renderIdentifier(
+					t2Reference, String.class, this.getContext());
+			return value;
+		}
+	}
+	
+	@Override
+	public String setOneInput(ReferenceService referenceService,
+			T2Reference t2Reference, ScriptInput input)
+			throws InvocationException {
+
+		if (input.getCharsetName() == null) {
+			input.setCharsetName(Charset.defaultCharset().name());
+		}
+		String target = null;
+		String targetSuffix = null;
+		if (input.isFile()) {
+			targetSuffix = input.getTag();
+		} else if (input.isTempFile()) {
+			targetSuffix = "tempfile." + (nTempFiles++) + ".tmp";
+		}
+
+		if (input.isBinary()) {
+			return setOneBinaryInput(referenceService, t2Reference, input,
+					targetSuffix);
+		}
+
+		logger.info("Target is " + target);
+		if (input.isFile() || input.isTempFile()) {
+			target = tempDir.getAbsolutePath() + "/" + targetSuffix;
+			// Try to get it as a file
+			Reader r;
+			Writer w;
+			FileReference fileRef = getAsFileReference(referenceService,
+					t2Reference);
+			if (fileRef != null) {
+
+				if (!input.isForceCopy()) {
+					if (linkCommand != null) {
+						String source = fileRef.getFile().getAbsolutePath();
+						String actualLinkCommand = getActualOsCommand(
+								linkCommand, source, targetSuffix, target);
+						logger.info("Link command is " + actualLinkCommand);
+						String[] splitCmds = actualLinkCommand.split(" ");
+						ProcessBuilder builder = new ProcessBuilder(splitCmds);
+						builder.directory(tempDir);
+						try {
+							int code = builder.start().waitFor();
+							if (code == 0) {
+								return target;
+							} else {
+								logger.error("Link command gave errorcode: "
+										+ code);
+							}
+
+						} catch (InterruptedException e) {
+							// go through
+						} catch (IOException e) {
+							// go through
+						}
+
+					}
+				}
+
+				if (fileRef.getDataNature().equals(ReferencedDataNature.TEXT)) {
+					r = new InputStreamReader(fileRef.openStream(this
+							.getContext()), Charset.forName(fileRef
+							.getCharset()));
+				} else {
+					try {
+						r = new FileReader(fileRef.getFile());
+					} catch (FileNotFoundException e) {
+						throw new InvocationException(e);
+					}
+				}
+			} else {
+				r = new InputStreamReader(getAsStream(referenceService,
+						t2Reference));
+			}
+			try {
+				w = new OutputStreamWriter(new FileOutputStream(target), input
+						.getCharsetName());
+			} catch (UnsupportedEncodingException e) {
+				throw new InvocationException(e);
+			} catch (FileNotFoundException e) {
+				throw new InvocationException(e);
+			}
+			try {
+				IOUtils.copyLarge(r, w);
+			} catch (IOException e) {
+				throw new InvocationException(e);
+			}
+			try {
+				r.close();
+				w.close();
+			} catch (IOException e) {
+				throw new InvocationException(e);
+			}
+			return target;
+		} else {
+			String value = (String) referenceService.renderIdentifier(
+					t2Reference, String.class, this.getContext());
+			return value;
+		}
+	}
+	
+	private void forgetRun() {
+		Set<String> directories = runIdToTempDir.get(getRunId());
+		try {
+			directories.remove(tempDir.getCanonicalPath());
+		} catch (IOException e) {
+			logger.error(e);
+		}
+	}
+
+	private static void deleteDirectory(String location) {
+		try {
+			FileUtils.deleteDirectory(new File(location));
+		} catch (IOException e) {
+			logger.error("Problem deleting " + location, e);
+		}
+	}
+	
+	public static void cleanup(String runId) {
+		Set<String> tempDirectories = runIdToTempDir.get(runId);
+		if (tempDirectories != null) {
+			for (String tempDir : tempDirectories) {
+				deleteDirectory(tempDir);
+			}
+			runIdToTempDir.remove(runId);
+		}
+	}
+	
+	@Override
+	protected void submit_generate_job_inner() throws InvocationException {
+		tags.put("uniqueID", "" + getSubmissionID());
+		String command = usecase.getCommand();
+		for (String cur : tags.keySet()) {
+		    command = command.replaceAll("\\Q%%" + cur + "%%\\E", Matcher.quoteReplacement(tags.get(cur)));
+		}
+
+		List<String> cmds = new ArrayList<String>();
+		if ((shellPrefix != null) && !shellPrefix.isEmpty()) {
+			String[] prefixCmds = shellPrefix.split(" ");
+			for (int i = 0; i < prefixCmds.length; i++) {
+				cmds.add(prefixCmds[i]);
+			}
+			cmds.add(command);
+		} else {
+			String[] splitCmds = command.split(" ");
+			for (int i = 0; i < splitCmds.length; i++) {
+				cmds.add(splitCmds[i]);
+			}
+		}
+	
+		ProcessBuilder builder = new ProcessBuilder(cmds);
+		builder.directory(tempDir);
+
+		for (int i = 0; i < cmds.size(); i++) {
+			logger.info("cmds[" + i + "] = " + cmds.get(i));
+		}
+		logger.info("Command is " + command + " in directory " + tempDir);
+		try {
+			running = builder.start();
+			if (stdInReader != null) {
+				BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(running.getOutputStream()));
+				IOUtils.copyLarge(stdInReader, writer);
+				writer.close();
+			}
+		} catch (IOException e) {
+			throw new InvocationException(e);
+		}
+	}
+
+	private void copy_stream(InputStream read, OutputStream write) throws IOException {
+		int a = read.available();
+		if (a > 0) {
+			byte[] buf = new byte[a];
+			read.read(buf);
+			write.write(buf);
+		}
+	}
+
+	@Override
+	public HashMap<String, Object> submit_wait_fetch_results(ReferenceService referenceService) throws InvocationException {
+		ByteArrayOutputStream stdout_buf = new ByteArrayOutputStream();
+		ByteArrayOutputStream stderr_buf = new ByteArrayOutputStream();
+		while (true) {
+			try {
+				copy_stream(running.getInputStream(), stdout_buf);
+				copy_stream(running.getErrorStream(), stderr_buf);
+			} catch (IOException e1) {
+				throw new InvocationException(e1);
+			}
+			try {
+				int exitcode = running.exitValue();
+				if (!usecase.getValidReturnCodes().contains(exitcode)) {
+					try {
+						throw new InvocationException("Invalid exit code " + exitcode + ":" + stderr_buf.toString("US-ASCII"));
+					} catch (UnsupportedEncodingException e) {
+						throw new InvocationException("Invalid exit code " + exitcode + ":" + stderr_buf.toString());
+					}
+				}
+				else
+					break;
+			} catch (IllegalThreadStateException e) {
+
+				try {
+					Thread.sleep(100);
+				} catch (InterruptedException e1) {
+					throw new InvocationException(e);
+				}
+
+			}
+		}
+
+		HashMap<String, Object> results = new HashMap<String, Object>();
+			results.put("STDOUT", stdout_buf.toByteArray());
+			results.put("STDERR", stderr_buf.toByteArray());
+
+		for (Map.Entry<String, ScriptOutput> cur : usecase.getOutputs().entrySet()) {
+			ScriptOutput scriptOutput = cur.getValue();
+			File result = new File(tempDir.getAbsoluteFile() + "/" + cur.getValue().getPath());
+			if (result.exists()) {
+				AbstractExternalReference ref;
+				if (isRetrieveData()) {
+					FileInputStream is;
+					try {
+						is = new FileInputStream(result);
+					} catch (FileNotFoundException e) {
+						throw new InvocationException(e);
+					}
+					if (scriptOutput.isBinary()) {
+						ref = inlineByteArrayReferenceBuilder.createReference(is, null);
+					} else {
+						ref = inlineStringReferenceBuilder.createReference(is, null);
+					}
+					try {
+						is.close();
+					} catch (IOException e) {
+						throw new InvocationException(e);
+					}
+				}
+				else {
+					ref = new FileReference(result);
+					if (scriptOutput.isBinary()) {
+						((FileReference) ref)
+								.setDataNature(ReferencedDataNature.BINARY);
+					} else {
+						((FileReference) ref)
+								.setDataNature(ReferencedDataNature.TEXT);
+						((FileReference) ref).setCharset("UTF-8");
+					}
+				}
+				results.put(cur.getKey(), ref);
+			} else {
+				ErrorDocument ed = referenceService.getErrorDocumentService().registerError("No result for " + cur.getKey(), 0, getContext());
+				results.put(cur.getKey(), ed);
+			}
+		}
+		
+		if (isRetrieveData()) {
+			forgetRun();
+			try {
+				deleteDirectory(tempDir.getCanonicalPath());
+			} catch (IOException e) {
+				throw new InvocationException(e);
+			}
+		}
+
+		return results;
+	}
+
+	private FileReference getAsFileReference(ReferenceService referenceService, T2Reference t2Reference) {
+		Identified identified = referenceService.resolveIdentifier(t2Reference, null, null);
+		if (identified instanceof ReferenceSet) {
+			for (ExternalReferenceSPI ref : ((ReferenceSet) identified).getExternalReferences()) {
+				if (ref instanceof FileReference) {
+					return (FileReference) ref;
+				}
+			}
+		}
+		return null;
+	}
+
+	@Override
+	public void setStdIn(ReferenceService referenceService,
+			T2Reference t2Reference) {
+		stdInReader = new BufferedReader(new InputStreamReader(getAsStream(referenceService, t2Reference)));
+	}
+
+	@Override
+	public void rememberRun(String runId) {
+		this.setRunId(runId);
+		Set<String> directories = runIdToTempDir.get(runId);
+		if (directories == null) {
+			directories = Collections.synchronizedSet(new HashSet<String> ());
+			runIdToTempDir.put(runId, directories);
+		}
+		try {
+			directories.add(tempDir.getCanonicalPath());
+		} catch (IOException e) {
+			logger.error("Unable to record temporary directory: " + tempDir, e);
+		}
+	}
+
+	public static void load(File directory) {
+		File invocationsFile = new File(directory, LOCAL_INVOCATION_FILE);
+		if (!invocationsFile.exists()) {
+			return;
+		}
+		BufferedReader reader = null;
+		try {
+			reader = new BufferedReader(new FileReader(invocationsFile));
+			String line = reader.readLine();
+			while (line != null) {
+				String[] parts = line.split(" ");
+				if (parts.length != 2) {
+					break;
+				}
+				String runId = parts[0];
+				String tempDirString = parts[1];
+				Set<String> tempDirs = runIdToTempDir.get(runId);
+				if (tempDirs == null) {
+					tempDirs = new HashSet<String>();
+					runIdToTempDir.put(runId, tempDirs);
+				}
+				tempDirs.add(tempDirString);
+				line = reader.readLine();
+			}
+		} catch (FileNotFoundException e) {
+			logger.error(e);
+		} catch (IOException e) {
+			logger.error(e);
+		} finally {
+			if (reader != null) {
+				try {
+					reader.close();
+				} catch (IOException e) {
+					logger.error(e);
+				}
+			}
+		}
+	}
+
+	public static void persist(File directory) {
+		File invocationsFile = new File(directory, LOCAL_INVOCATION_FILE);
+		BufferedWriter writer = null;
+		try {
+			writer = new BufferedWriter(new FileWriter(invocationsFile));
+			for (String runId : runIdToTempDir.keySet()) {
+				for (String tempDir : runIdToTempDir.get(runId)) {
+					writer.write(runId);
+					writer.write(" ");
+					writer.write(tempDir);
+					writer.newLine();
+				}
+			}
+		} catch (IOException e) {
+			logger.error(e);
+		} finally {
+			if (writer != null) {
+				try {
+					writer.close();
+				} catch (IOException e) {
+					logger.error(e);
+				}
+			}
+		}
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-common-activities/blob/98468d30/taverna-external-tool-activity/src/main/java/org/apache/taverna/activities/externaltool/ssh/ExternalToolSshInvocationMechanism.java
----------------------------------------------------------------------
diff --git a/taverna-external-tool-activity/src/main/java/org/apache/taverna/activities/externaltool/ssh/ExternalToolSshInvocationMechanism.java b/taverna-external-tool-activity/src/main/java/org/apache/taverna/activities/externaltool/ssh/ExternalToolSshInvocationMechanism.java
index c373879..94cc466 100644
--- a/taverna-external-tool-activity/src/main/java/org/apache/taverna/activities/externaltool/ssh/ExternalToolSshInvocationMechanism.java
+++ b/taverna-external-tool-activity/src/main/java/org/apache/taverna/activities/externaltool/ssh/ExternalToolSshInvocationMechanism.java
@@ -24,13 +24,8 @@ import java.util.List;
 
 import org.jdom.Element;
 import org.jdom.Text;
-
-import de.uni_luebeck.inb.knowarc.usecases.invocation.ssh.SshNodeFactory;
-import de.uni_luebeck.inb.knowarc.usecases.invocation.ssh.SshUseCaseInvocation;
 import org.apache.taverna.activities.externaltool.manager.InvocationMechanism;
 
-import de.uni_luebeck.inb.knowarc.usecases.invocation.ssh.SshNode;
-
 /**
  * @author alanrw
  *

http://git-wip-us.apache.org/repos/asf/incubator-taverna-common-activities/blob/98468d30/taverna-external-tool-activity/src/main/java/org/apache/taverna/activities/externaltool/ssh/SshAutoLoginTrustEveryone.java
----------------------------------------------------------------------
diff --git a/taverna-external-tool-activity/src/main/java/org/apache/taverna/activities/externaltool/ssh/SshAutoLoginTrustEveryone.java b/taverna-external-tool-activity/src/main/java/org/apache/taverna/activities/externaltool/ssh/SshAutoLoginTrustEveryone.java
new file mode 100644
index 0000000..dfee8bb
--- /dev/null
+++ b/taverna-external-tool-activity/src/main/java/org/apache/taverna/activities/externaltool/ssh/SshAutoLoginTrustEveryone.java
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.taverna.activities.externaltool.ssh;
+
+import org.apache.log4j.Logger;
+import org.apache.taverna.activities.externaltool.invocation.AskUserForPw;
+
+import com.jcraft.jsch.UIKeyboardInteractive;
+import com.jcraft.jsch.UserInfo;
+
+final class SshAutoLoginTrustEveryone implements UserInfo, UIKeyboardInteractive {
+	
+	private static Logger logger = Logger.getLogger(SshAutoLoginTrustEveryone.class);
+
+	private final AskUserForPw askUserForPw;
+
+	public SshAutoLoginTrustEveryone(AskUserForPw askUserForPw) {
+		super();
+		this.askUserForPw = askUserForPw;
+	}
+
+	public void showMessage(String arg0) {
+		logger.info(arg0);
+	}
+
+	public boolean promptYesNo(String arg0) {
+		if (arg0.startsWith("The authenticity of host"))
+			return true;
+		return false;
+	}
+
+	public boolean promptPassword(String arg0) {
+		return true;
+	}
+
+	public boolean promptPassphrase(String arg0) {
+		return true;
+	}
+
+	public String getPassword() {
+		return askUserForPw.getPassword();
+	}
+
+	public String getPassphrase() {
+		return askUserForPw.getPassphrase();
+	}
+
+	public String[] promptKeyboardInteractive(String destination, String name, String instruction, String[] prompt, boolean[] echo) {
+		if (prompt.length >= 1 && prompt[0].toLowerCase().startsWith("password"))
+			return new String[] { askUserForPw.getPassword() };
+		return null;
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-common-activities/blob/98468d30/taverna-external-tool-activity/src/main/java/org/apache/taverna/activities/externaltool/ssh/SshInvocationCreator.java
----------------------------------------------------------------------
diff --git a/taverna-external-tool-activity/src/main/java/org/apache/taverna/activities/externaltool/ssh/SshInvocationCreator.java b/taverna-external-tool-activity/src/main/java/org/apache/taverna/activities/externaltool/ssh/SshInvocationCreator.java
index 88f6ceb..b876ec8 100644
--- a/taverna-external-tool-activity/src/main/java/org/apache/taverna/activities/externaltool/ssh/SshInvocationCreator.java
+++ b/taverna-external-tool-activity/src/main/java/org/apache/taverna/activities/externaltool/ssh/SshInvocationCreator.java
@@ -25,20 +25,13 @@ import java.util.Map;
 
 import org.apache.taverna.activities.externaltool.InvocationCreator;
 import org.apache.taverna.activities.externaltool.RetrieveLoginFromTaverna;
-
+import org.apache.taverna.activities.externaltool.desc.UseCaseDescription;
+import org.apache.taverna.activities.externaltool.invocation.UseCaseInvocation;
 import org.apache.log4j.Logger;
 
 import com.jcraft.jsch.JSchException;
 import com.jcraft.jsch.SftpException;
 
-import de.uni_luebeck.inb.knowarc.usecases.UseCaseDescription;
-import de.uni_luebeck.inb.knowarc.usecases.invocation.UseCaseInvocation;
-import de.uni_luebeck.inb.knowarc.usecases.invocation.ssh.SshNode;
-import de.uni_luebeck.inb.knowarc.usecases.invocation.ssh.SshNodeFactory;
-import de.uni_luebeck.inb.knowarc.usecases.invocation.ssh.SshReference;
-import de.uni_luebeck.inb.knowarc.usecases.invocation.ssh.SshUrl;
-import de.uni_luebeck.inb.knowarc.usecases.invocation.ssh.SshUseCaseInvocation;
-
 import org.apache.taverna.activities.externaltool.manager.InvocationMechanism;
 import org.apache.taverna.reference.ExternalReferenceSPI;
 import org.apache.taverna.reference.Identified;

http://git-wip-us.apache.org/repos/asf/incubator-taverna-common-activities/blob/98468d30/taverna-external-tool-activity/src/main/java/org/apache/taverna/activities/externaltool/ssh/SshInvocationPersister.java
----------------------------------------------------------------------
diff --git a/taverna-external-tool-activity/src/main/java/org/apache/taverna/activities/externaltool/ssh/SshInvocationPersister.java b/taverna-external-tool-activity/src/main/java/org/apache/taverna/activities/externaltool/ssh/SshInvocationPersister.java
index 1884cbe..bad5c2e 100644
--- a/taverna-external-tool-activity/src/main/java/org/apache/taverna/activities/externaltool/ssh/SshInvocationPersister.java
+++ b/taverna-external-tool-activity/src/main/java/org/apache/taverna/activities/externaltool/ssh/SshInvocationPersister.java
@@ -21,6 +21,7 @@ package org.apache.taverna.activities.externaltool.ssh;
 
 import java.io.File;
 
+import org.apache.taverna.activities.externaltool.invocation.InvocationException;
 import org.apache.taverna.activities.externaltool.manager.InvocationPersister;
 /*
 * Licensed to the Apache Software Foundation (ASF) under one
@@ -45,9 +46,6 @@ import org.apache.taverna.security.credentialmanager.CredentialManager;
 
 import org.apache.log4j.Logger;
 
-import de.uni_luebeck.inb.knowarc.usecases.invocation.InvocationException;
-import de.uni_luebeck.inb.knowarc.usecases.invocation.ssh.SshUseCaseInvocation;
-
 /**
  * @author alanrw
  *

http://git-wip-us.apache.org/repos/asf/incubator-taverna-common-activities/blob/98468d30/taverna-external-tool-activity/src/main/java/org/apache/taverna/activities/externaltool/ssh/SshMechanismCreator.java
----------------------------------------------------------------------
diff --git a/taverna-external-tool-activity/src/main/java/org/apache/taverna/activities/externaltool/ssh/SshMechanismCreator.java b/taverna-external-tool-activity/src/main/java/org/apache/taverna/activities/externaltool/ssh/SshMechanismCreator.java
index 2a15d38..097f8db 100644
--- a/taverna-external-tool-activity/src/main/java/org/apache/taverna/activities/externaltool/ssh/SshMechanismCreator.java
+++ b/taverna-external-tool-activity/src/main/java/org/apache/taverna/activities/externaltool/ssh/SshMechanismCreator.java
@@ -27,10 +27,6 @@ import org.apache.taverna.activities.externaltool.manager.MechanismCreator;
 import org.apache.log4j.Logger;
 import org.jdom.Element;
 
-import de.uni_luebeck.inb.knowarc.usecases.invocation.ssh.SshNode;
-import de.uni_luebeck.inb.knowarc.usecases.invocation.ssh.SshNodeFactory;
-import de.uni_luebeck.inb.knowarc.usecases.invocation.ssh.SshUseCaseInvocation;
-
 /**
  * @author alanrw
  *

http://git-wip-us.apache.org/repos/asf/incubator-taverna-common-activities/blob/98468d30/taverna-external-tool-activity/src/main/java/org/apache/taverna/activities/externaltool/ssh/SshNode.java
----------------------------------------------------------------------
diff --git a/taverna-external-tool-activity/src/main/java/org/apache/taverna/activities/externaltool/ssh/SshNode.java b/taverna-external-tool-activity/src/main/java/org/apache/taverna/activities/externaltool/ssh/SshNode.java
new file mode 100644
index 0000000..378696f
--- /dev/null
+++ b/taverna-external-tool-activity/src/main/java/org/apache/taverna/activities/externaltool/ssh/SshNode.java
@@ -0,0 +1,157 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.taverna.activities.externaltool.ssh;
+
+import org.apache.taverna.activities.externaltool.manager.InvocationMechanism;
+
+public class SshNode {
+	
+    public static String DEFAULT_HOST = "127.0.0.1";
+    public static int DEFAULT_PORT = 22;
+    public static String DEFAULT_DIRECTORY = "/tmp/";
+
+    private String host = DEFAULT_HOST;
+    private int port = DEFAULT_PORT;
+    private String directory = DEFAULT_DIRECTORY;
+	
+	private SshUrl url;
+	
+	private String linkCommand = null;
+	private String copyCommand = null;
+	private boolean retrieveData = false;
+
+	/**
+	 * 
+	 */
+	SshNode() {
+		super();
+		linkCommand = InvocationMechanism.UNIX_LINK;
+		copyCommand = InvocationMechanism.UNIX_COPY;
+		
+	}
+	/**
+	 * @param directory the directory to set
+	 */
+	public void setDirectory(String directory) {
+		if ((directory != null) && !directory.isEmpty()) {
+			if (!directory.endsWith("/")) {
+				directory = directory + "/";
+			}
+			this.directory = directory;
+		}
+	}
+
+	/**
+	 * @return the directory
+	 */
+	public String getDirectory() {
+		return directory;
+	}
+
+	/**
+	 * @param host the host to set
+	 */
+	public void setHost(String host) {
+		this.host = host;
+	}
+
+	/**
+	 * @return the host
+	 */
+	public String getHost() {
+		return host;
+	}
+
+	/**
+	 * @param port the port to set
+	 */
+	public void setPort(int port) {
+		this.port = port;
+	}
+
+	/**
+	 * @return the port
+	 */
+	public int getPort() {
+		return port;
+	}
+	
+	SshUrl getUrl() {
+		if (url == null) {
+			url = new SshUrl(this);
+		}
+		return url;
+	}
+	
+	public int hashCode() {
+		return getUrl().hashCode();	
+	}
+
+	public boolean equals(Object obj) {
+		if ((obj == null) || !(obj instanceof SshNode)) {
+			return false;
+		}
+		return (this.hashCode() == obj.hashCode());
+	}
+	/**
+	 * @return the linkCommand
+	 */
+	public String getLinkCommand() {
+		return linkCommand;
+	}
+	/**
+	 * @param linkCommand the linkCommand to set
+	 */
+	public void setLinkCommand(String linkCommand) {
+		if ((linkCommand != null) && linkCommand.isEmpty()) {
+			this.linkCommand = null;
+		} else {
+			this.linkCommand = linkCommand;
+		}	}
+	/**
+	 * @return the copyCommand
+	 */
+	public String getCopyCommand() {
+		return copyCommand;
+	}
+	/**
+	 * @param copyCommand the copyCommand to set
+	 */
+	public void setCopyCommand(String copyCommand) {
+		if ((copyCommand != null) && copyCommand.isEmpty()) {
+			this.copyCommand = null;
+		} else {
+			this.copyCommand = copyCommand;
+		}
+	}
+	
+	/**
+	 * @return the retrieveData
+	 */
+	public boolean isRetrieveData() {
+		return retrieveData;
+	}
+	/**
+	 * @param retrieveData the retrieveData to set
+	 */
+	public void setRetrieveData(boolean retrieveData) {
+		this.retrieveData = retrieveData;
+	}
+	
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-common-activities/blob/98468d30/taverna-external-tool-activity/src/main/java/org/apache/taverna/activities/externaltool/ssh/SshNodeFactory.java
----------------------------------------------------------------------
diff --git a/taverna-external-tool-activity/src/main/java/org/apache/taverna/activities/externaltool/ssh/SshNodeFactory.java b/taverna-external-tool-activity/src/main/java/org/apache/taverna/activities/externaltool/ssh/SshNodeFactory.java
new file mode 100644
index 0000000..a697bd7
--- /dev/null
+++ b/taverna-external-tool-activity/src/main/java/org/apache/taverna/activities/externaltool/ssh/SshNodeFactory.java
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.taverna.activities.externaltool.ssh;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+public class SshNodeFactory {
+	
+	private Map<String, SshNode> nodeMap = Collections.synchronizedMap(new HashMap<String, SshNode> ());
+	
+	private static SshNodeFactory INSTANCE = new SshNodeFactory();
+	
+	private SshNode defaultNode;
+	
+	private SshNodeFactory() {
+		defaultNode = getSshNode(SshNode.DEFAULT_HOST, SshNode.DEFAULT_PORT, SshNode.DEFAULT_DIRECTORY);
+	}
+
+	public SshNode getDefaultNode() {
+		return defaultNode;
+	}
+
+	public static SshNodeFactory getInstance() {
+		return INSTANCE;
+	}
+	
+	public SshNode getSshNode(String host, int port, String directory) {
+		String url = makeUrl(host, port, directory);
+		if (nodeMap.containsKey(url)) {
+			return nodeMap.get(url);
+		}
+		else {
+			SshNode newNode = new SshNode();
+			newNode.setHost(host);
+			newNode.setPort(port);
+			newNode.setDirectory(directory);
+			nodeMap.put(url, newNode);
+			return newNode;
+		}
+	}
+	
+	public boolean containsSshNode(String host, int port, String directory) {
+		return nodeMap.containsKey(makeUrl(host, port, directory));
+	}
+	
+	public static String makeUrl(String host, int port, String directory) {
+		return ("ssh://" + host + ":" + port + directory);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-common-activities/blob/98468d30/taverna-external-tool-activity/src/main/java/org/apache/taverna/activities/externaltool/ssh/SshPool.java
----------------------------------------------------------------------
diff --git a/taverna-external-tool-activity/src/main/java/org/apache/taverna/activities/externaltool/ssh/SshPool.java b/taverna-external-tool-activity/src/main/java/org/apache/taverna/activities/externaltool/ssh/SshPool.java
new file mode 100755
index 0000000..e7f9787
--- /dev/null
+++ b/taverna-external-tool-activity/src/main/java/org/apache/taverna/activities/externaltool/ssh/SshPool.java
@@ -0,0 +1,157 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.taverna.activities.externaltool.ssh;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.log4j.Logger;
+import org.apache.taverna.activities.externaltool.desc.RuntimeEnvironmentConstraint;
+import org.apache.taverna.activities.externaltool.invocation.AskUserForPw;
+
+import com.jcraft.jsch.ChannelExec;
+import com.jcraft.jsch.ChannelSftp;
+import com.jcraft.jsch.JSch;
+import com.jcraft.jsch.JSchException;
+import com.jcraft.jsch.Session;
+
+public class SshPool {
+	
+	private static Logger logger = Logger.getLogger(SshPool.class);
+
+	
+	private static JSch jsch = new JSch();
+	
+    private static int CONNECT_TIMEOUT = 10000; // milliseconds
+
+	private static Map<SshNode, Session> sessionMap = Collections.synchronizedMap(new HashMap<SshNode, Session> ());
+	private static Map<Session, ChannelSftp> sftpGetMap = Collections.synchronizedMap(new HashMap<Session, ChannelSftp> ());
+	private static Map<Session, ChannelSftp> sftpPutMap = Collections.synchronizedMap(new HashMap<Session, ChannelSftp> ());
+	
+	public static Session getSshSession(final SshUrl sshUrl, final AskUserForPw askUserForPw) throws JSchException {
+		return getSshSession(sshUrl.getSshNode(), askUserForPw);
+	}
+	
+	public static synchronized Session getSshSession(final SshNode sshNode, final AskUserForPw askUserForPw) throws JSchException {
+
+		Session s = sessionMap.get(sshNode);
+		if ((s != null) && s.isConnected()) {
+			logger.info("Reusing session");
+			return s;
+		}
+		if (s != null) {
+			logger.info("Session was not connected");
+		}
+		if (s == null) {
+			logger.info("No session found for " + sshNode.toString());
+		}
+
+		if (askUserForPw.getKeyfile().length() > 0) {
+			jsch.addIdentity(askUserForPw.getKeyfile());
+		}
+		logger.info("Using host is " + sshNode.getHost() + " and port " + sshNode.getPort());
+		Session sshSession = jsch.getSession(askUserForPw.getUsername(), sshNode.getHost(), sshNode.getPort());
+		sshSession.setUserInfo(new SshAutoLoginTrustEveryone(askUserForPw));
+		sshSession.connect(CONNECT_TIMEOUT);
+		
+		askUserForPw.authenticationSucceeded();
+		sessionMap.put(sshNode, sshSession);
+		if (sshSession == null) {
+			logger.error("Returning a null session");
+		}
+		return sshSession;
+	}
+	
+	public static ChannelSftp getSftpGetChannel(SshNode sshNode, final AskUserForPw askUserForPw) throws JSchException {
+		return getSftpGetChannel(getSshSession(sshNode, askUserForPw));
+	}
+
+	private static synchronized ChannelSftp getSftpGetChannel(Session session) throws JSchException {
+		ChannelSftp result = sftpGetMap.get(session);
+		if (!session.isConnected()) {
+			logger.warn("Session is not connected");
+		}
+		if (result == null) {
+			logger.info("Creating new sftp channel");
+			result = (ChannelSftp) session.openChannel("sftp");
+			sftpGetMap.put(session, result);
+		}
+		else {
+			logger.info("Reusing sftp channel");			
+		}
+		if (!result.isConnected()) {
+			logger.info("Connecting");
+			result.connect();
+		} else {
+			logger.info("Already connected");
+		}
+		return result;
+	}
+	
+	public static ChannelSftp getSftpPutChannel(SshNode sshNode, final AskUserForPw askUserForPw) throws JSchException {
+		return getSftpPutChannel(getSshSession(sshNode, askUserForPw));
+	}
+
+	private static synchronized ChannelSftp getSftpPutChannel(Session session) throws JSchException {
+	    ChannelSftp result = null;
+	    synchronized(sftpPutMap) {
+		result = sftpPutMap.get(session);
+		if (!session.isConnected()) {
+			logger.info("Session is not connected");
+		}
+		if (result == null) {
+			logger.info("Creating new sftp channel");
+			result = (ChannelSftp) session.openChannel("sftp");
+			sftpPutMap.put(session, result);
+		}
+		else {
+			logger.info("Reusing sftp channel");			
+		}
+	    }
+	    if (!result.isConnected()) {
+		logger.info("Connecting");
+		result.connect(CONNECT_TIMEOUT);
+	    } else {
+		logger.info("Already connected");
+	    }
+	    return result;
+	}
+	
+	public static synchronized ChannelExec openExecChannel(SshNode sshNode, final AskUserForPw askUserForPw) throws JSchException {
+		return (ChannelExec) getSshSession(sshNode, askUserForPw).openChannel("exec");
+	}
+
+	private static synchronized ChannelExec openExecChannel(Session session) throws JSchException {
+		return (ChannelExec) session.openChannel("exec");
+	}
+
+}
+
+
+
+
+
+
+
+
+
+
+
+
+

http://git-wip-us.apache.org/repos/asf/incubator-taverna-common-activities/blob/98468d30/taverna-external-tool-activity/src/main/java/org/apache/taverna/activities/externaltool/ssh/SshReference.java
----------------------------------------------------------------------
diff --git a/taverna-external-tool-activity/src/main/java/org/apache/taverna/activities/externaltool/ssh/SshReference.java b/taverna-external-tool-activity/src/main/java/org/apache/taverna/activities/externaltool/ssh/SshReference.java
new file mode 100644
index 0000000..091bd0c
--- /dev/null
+++ b/taverna-external-tool-activity/src/main/java/org/apache/taverna/activities/externaltool/ssh/SshReference.java
@@ -0,0 +1,222 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.taverna.activities.externaltool.ssh;
+
+import java.io.InputStream;
+
+import org.apache.taverna.activities.externaltool.RetrieveLoginFromTaverna;
+import org.apache.taverna.reference.AbstractExternalReference;
+import org.apache.taverna.reference.DereferenceException;
+import org.apache.taverna.reference.ExternalReferenceSPI;
+import org.apache.taverna.reference.ReferenceContext;
+import org.apache.taverna.security.credentialmanager.CredentialManager;
+import org.apache.taverna.reference.ReferencedDataNature;
+
+import org.apache.log4j.Logger;
+
+import com.jcraft.jsch.ChannelSftp;
+import com.jcraft.jsch.JSchException;
+import com.jcraft.jsch.SftpException;
+
+/**
+ * @author alanrw
+ *
+ */
+public class SshReference extends AbstractExternalReference implements
+	ExternalReferenceSPI {
+
+	private static Logger logger = Logger.getLogger(SshReference.class);
+
+
+	private String host = "127.0.0.1";
+	private int port = 22;
+	private String directory = "/tmp/";
+	private String subDirectory;
+	private String fileName;
+
+	private CredentialManager credentialManager;
+
+	private int dataNatureInteger = ReferencedDataNature.UNKNOWN.ordinal();
+	private String charset = "UTF-8";
+	
+	public SshReference() {
+		super();
+	}
+
+	public SshReference(SshUrl url) {
+		super();
+		this.host = url.getSshNode().getHost();
+		this.port = url.getSshNode().getPort();
+		this.directory = url.getSshNode().getDirectory();
+		this.subDirectory = url.getSubDirectory();
+		this.fileName = url.getFileName();
+		this.setDataNature(url.getDataNature());
+		this.setCharset(url.getCharset());
+	}
+
+	/* (non-Javadoc)
+	 * @see net.sf.taverna.t2.reference.ExternalReferenceSPI#getApproximateSizeInBytes()
+	 */
+	@Override
+	public Long getApproximateSizeInBytes() {
+		return 10000L;
+	}
+
+	/* (non-Javadoc)
+	 * @see net.sf.taverna.t2.reference.ExternalReferenceSPI#openStream(net.sf.taverna.t2.reference.ReferenceContext)
+	 */
+	@Override
+	public InputStream openStream(ReferenceContext context)
+			throws DereferenceException {
+		try {
+			SshNode node = SshNodeFactory.getInstance().getSshNode(this.getHost(), this.getPort(), this.getDirectory());
+			String fullPath = getDirectory() +  getSubDirectory() + "/" + getFileName();
+			ChannelSftp channel = SshPool.getSftpGetChannel(node, new RetrieveLoginFromTaverna(new SshUrl(node).toString(), credentialManager));
+			logger.info("Opening stream on " + fullPath);
+			return (channel.get(fullPath));
+		} catch (JSchException e) {
+			//TODO
+			logger.error(e);
+		} catch (SftpException e) {
+			// TODO Auto-generated catch block
+			logger.error(e);
+		}
+		return null;
+	}
+
+	/**
+	 * @return the host
+	 */
+	public String getHost() {
+		return host;
+	}
+
+	/**
+	 * @param host the host to set
+	 */
+	public void setHost(String host) {
+		this.host = host;
+	}
+
+	/**
+	 * @return the port
+	 */
+	public int getPort() {
+		return port;
+	}
+
+	/**
+	 * @param port the port to set
+	 */
+	public void setPort(int port) {
+		this.port = port;
+	}
+
+	/**
+	 * @return the directory
+	 */
+	public String getDirectory() {
+		return directory;
+	}
+
+	/**
+	 * @param directory the directory to set
+	 */
+	public void setDirectory(String directory) {
+		this.directory = directory;
+	}
+
+	/**
+	 * @return the subDirectory
+	 */
+	public String getSubDirectory() {
+		return subDirectory;
+	}
+
+	/**
+	 * @param subDirectory the subDirectory to set
+	 */
+	public void setSubDirectory(String subDirectory) {
+		this.subDirectory = subDirectory;
+	}
+
+	/**
+	 * @return the fileName
+	 */
+	public String getFileName() {
+		return fileName;
+	}
+
+	/**
+	 * @param fileName the fileName to set
+	 */
+	public void setFileName(String fileName) {
+		this.fileName = fileName;
+	}
+
+	public String getFullPath() {
+		return getDirectory() + "/" + getSubDirectory() + "/" + getFileName();
+	}
+	
+	public ReferencedDataNature getDataNature() {
+		return ReferencedDataNature.values()[dataNatureInteger];
+	}
+
+	public void setDataNature(ReferencedDataNature dataNature) {
+		this.dataNatureInteger = dataNature.ordinal();
+	}
+
+	public String getCharset() {
+		return charset;
+	}
+
+	public void setCredentialManager(CredentialManager credentialManager) {
+		this.credentialManager = credentialManager;
+	}
+
+	public void setCharset(String charset) {
+		this.charset = charset;
+	}
+
+	/**
+	 * @return the dataNatureInteger
+	 */
+	public int getDataNatureInteger() {
+		return dataNatureInteger;
+	}
+
+	/**
+	 * @param dataNatureInteger the dataNatureInteger to set
+	 */
+	public void setDataNatureInteger(int dataNatureInteger) {
+		this.dataNatureInteger = dataNatureInteger;
+	}
+	
+	public SshReference clone() {
+		SshReference result = new SshReference();
+		result.setHost(this.getHost());
+		result.setPort(this.getPort());
+		result.setDirectory(this.getDirectory());
+		result.setSubDirectory(this.getSubDirectory());
+		result.setFileName(this.getFileName());
+		result.setDataNature(this.getDataNature());
+		result.setCharset(this.getCharset());
+		return result;
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-common-activities/blob/98468d30/taverna-external-tool-activity/src/main/java/org/apache/taverna/activities/externaltool/ssh/SshUrl.java
----------------------------------------------------------------------
diff --git a/taverna-external-tool-activity/src/main/java/org/apache/taverna/activities/externaltool/ssh/SshUrl.java b/taverna-external-tool-activity/src/main/java/org/apache/taverna/activities/externaltool/ssh/SshUrl.java
new file mode 100644
index 0000000..4c39d66
--- /dev/null
+++ b/taverna-external-tool-activity/src/main/java/org/apache/taverna/activities/externaltool/ssh/SshUrl.java
@@ -0,0 +1,163 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.taverna.activities.externaltool.ssh;
+
+import org.apache.taverna.reference.ReferencedDataNature;
+
+public class SshUrl {
+	
+	private SshNode sshNode;
+	private String subDirectory;
+	private String fileName;
+
+	private ReferencedDataNature dataNature = ReferencedDataNature.UNKNOWN;
+	private String charset = "UTF-8";
+	
+
+	public SshUrl(SshNode sshNode) {
+		this.setSshNode(sshNode);
+	}
+	
+
+	/**
+	 * @return the host
+	 */
+	public String getHost() {
+		return getSshNode().getHost();
+	}
+	/**
+	 * @param host the host to set
+	 */
+	public void setHost(String host) {
+		getSshNode().setHost(host);
+	}
+	/**
+	 * @return the port
+	 */
+	public int getPort() {
+		return getSshNode().getPort();
+	}
+	/**
+	 * @param port the port to set
+	 */
+	public void setPort(int port) {
+		getSshNode().setPort(port);
+	}
+	/**
+	 * @return the directory
+	 */
+	public String getDirectory() {
+		return getSshNode().getDirectory();
+	}
+	/**
+	 * @param directory the directory to set
+	 */
+	public void setDirectory(String directory) {
+		getSshNode().setDirectory(directory);
+	}
+	/**
+	 * @return the subDirectory
+	 */
+	public String getSubDirectory() {
+		return subDirectory;
+	}
+	/**
+	 * @param subDirectory the subDirectory to set
+	 */
+	public void setSubDirectory(String subDirectory) {
+		this.subDirectory = subDirectory;
+	}
+	/**
+	 * @return the fileName
+	 */
+	public String getFileName() {
+		return fileName;
+	}
+	/**
+	 * @param fileName the fileName to set
+	 */
+	public void setFileName(String fileName) {
+		this.fileName = fileName;
+	}
+	
+	public String toString() {
+		String result = SshNodeFactory.makeUrl(getHost(), getPort(), getDirectory());
+		if (getSubDirectory() != null) {
+			result += getSubDirectory();
+		}
+		if (getFileName() != null) {
+			result += "/" + getFileName();
+		}
+		return result;
+	}
+	
+	public int hashCode() {
+		return toString().hashCode();
+		
+	}
+	
+	public boolean equals(Object obj) {
+		if ((obj == null) || !(obj instanceof SshUrl)) {
+			return false;
+		}
+		return (this.hashCode() == obj.hashCode());
+	}
+	
+	public SshUrl getBaseUrl() {
+		SshUrl result = new SshUrl(this.getSshNode());
+		return result;
+	}
+
+
+	/**
+	 * @return the sshNode
+	 */
+	public SshNode getSshNode() {
+		return sshNode;
+	}
+
+
+	/**
+	 * @param sshNode the sshNode to set
+	 */
+	public void setSshNode(SshNode sshNode) {
+		this.sshNode = sshNode;
+	}
+	
+	public ReferencedDataNature getDataNature() {
+		return dataNature;
+	}
+
+
+	public void setDataNature(ReferencedDataNature dataNature) {
+		this.dataNature = dataNature;
+	}
+
+
+	public String getCharset() {
+		return charset;
+	}
+
+
+	public void setCharset(String charset) {
+		this.charset = charset;
+	}
+
+
+	
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-common-activities/blob/98468d30/taverna-external-tool-activity/src/main/java/org/apache/taverna/activities/externaltool/ssh/SshUrlToSshReference.java
----------------------------------------------------------------------
diff --git a/taverna-external-tool-activity/src/main/java/org/apache/taverna/activities/externaltool/ssh/SshUrlToSshReference.java b/taverna-external-tool-activity/src/main/java/org/apache/taverna/activities/externaltool/ssh/SshUrlToSshReference.java
new file mode 100644
index 0000000..74b01e1
--- /dev/null
+++ b/taverna-external-tool-activity/src/main/java/org/apache/taverna/activities/externaltool/ssh/SshUrlToSshReference.java
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.taverna.activities.externaltool.ssh;
+
+import org.apache.taverna.reference.ExternalReferenceSPI;
+import org.apache.taverna.reference.ReferenceContext;
+import org.apache.taverna.reference.ValueToReferenceConversionException;
+import org.apache.taverna.reference.ValueToReferenceConverterSPI;
+import org.apache.taverna.security.credentialmanager.CredentialManager;
+
+public class SshUrlToSshReference implements ValueToReferenceConverterSPI {
+
+	private CredentialManager credentialManager;
+
+	/* (non-Javadoc)
+	 * @see net.sf.taverna.t2.reference.ValueToReferenceConverterSPI#canConvert(java.lang.Object, net.sf.taverna.t2.reference.ReferenceContext)
+	 */
+	@Override
+	public boolean canConvert(Object o, ReferenceContext context) {
+		return (o instanceof SshUrl);
+	}
+
+	/* (non-Javadoc)
+	 * @see net.sf.taverna.t2.reference.ValueToReferenceConverterSPI#convert(java.lang.Object, net.sf.taverna.t2.reference.ReferenceContext)
+	 */
+	@Override
+	public ExternalReferenceSPI convert(Object o, ReferenceContext context)
+			throws ValueToReferenceConversionException {
+		SshReference result = new SshReference((SshUrl) o);
+		result.setCredentialManager(credentialManager);
+		return result;
+	}
+
+	public void setCredentialManager(CredentialManager credentialManager) {
+		this.credentialManager = credentialManager;
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-common-activities/blob/98468d30/taverna-external-tool-activity/src/main/java/org/apache/taverna/activities/externaltool/ssh/SshUseCaseInvocation.java
----------------------------------------------------------------------
diff --git a/taverna-external-tool-activity/src/main/java/org/apache/taverna/activities/externaltool/ssh/SshUseCaseInvocation.java b/taverna-external-tool-activity/src/main/java/org/apache/taverna/activities/externaltool/ssh/SshUseCaseInvocation.java
new file mode 100755
index 0000000..fcbc33f
--- /dev/null
+++ b/taverna-external-tool-activity/src/main/java/org/apache/taverna/activities/externaltool/ssh/SshUseCaseInvocation.java
@@ -0,0 +1,560 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.taverna.activities.externaltool.ssh;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+import java.util.Set;
+import java.util.Vector;
+import java.util.regex.Matcher;
+
+import org.apache.taverna.activities.externaltool.RetrieveLoginFromTaverna;
+import org.apache.taverna.activities.externaltool.desc.ScriptInput;
+import org.apache.taverna.activities.externaltool.desc.ScriptOutput;
+import org.apache.taverna.activities.externaltool.desc.UseCaseDescription;
+import org.apache.taverna.activities.externaltool.invocation.AskUserForPw;
+import org.apache.taverna.activities.externaltool.invocation.InvocationException;
+import org.apache.taverna.activities.externaltool.invocation.UseCaseInvocation;
+import org.apache.taverna.reference.AbstractExternalReference;
+import org.apache.taverna.reference.ErrorDocument;
+import org.apache.taverna.reference.ErrorDocumentServiceException;
+import org.apache.taverna.reference.ExternalReferenceSPI;
+import org.apache.taverna.reference.Identified;
+import org.apache.taverna.reference.ReferenceService;
+import org.apache.taverna.reference.ReferenceSet;
+import org.apache.taverna.reference.ReferencedDataNature;
+import org.apache.taverna.reference.T2Reference;
+import org.apache.taverna.security.credentialmanager.CredentialManager;
+
+import org.apache.log4j.Logger;
+
+import com.jcraft.jsch.ChannelExec;
+import com.jcraft.jsch.ChannelSftp;
+import com.jcraft.jsch.JSchException;
+import com.jcraft.jsch.Session;
+import com.jcraft.jsch.SftpException;
+import com.jcraft.jsch.ChannelSftp.LsEntry;
+
+/**
+ * The job is executed by connecting to a worker pc using ssh, i.e. not via the
+ * grid.
+ * 
+ * @author Hajo Krabbenhoeft
+ */
+public class SshUseCaseInvocation extends UseCaseInvocation {
+
+	private static Logger logger = Logger.getLogger(SshUseCaseInvocation.class);
+
+	private SshUrl location = null;
+
+	private InputStream stdInputStream = null;
+
+	public static final String SSH_USE_CASE_INVOCATION_TYPE = "D0A4CDEB-DD10-4A8E-A49C-8871003083D8";
+	private String tmpname;
+	private final SshNode workerNode;
+	private final AskUserForPw askUserForPw;
+
+	private ChannelExec running;
+
+	private List<String> precedingCommands = new ArrayList<String>();
+
+	private final ByteArrayOutputStream stdout_buf = new ByteArrayOutputStream();
+	private final ByteArrayOutputStream stderr_buf = new ByteArrayOutputStream();
+
+	private static Map<String, Object> nodeLock = Collections
+			.synchronizedMap(new HashMap<String, Object>());
+
+	private static Map<String, Set<SshUrl>> runIdToTempDir = Collections
+			.synchronizedMap(new HashMap<String, Set<SshUrl>>());
+
+	private static String SSH_INVOCATION_FILE = "sshInvocations";
+
+	private final CredentialManager credentialManager;
+
+	public static String test(final SshNode workerNode,
+			final AskUserForPw askUserForPw) {
+		try {
+			Session sshSession = SshPool
+					.getSshSession(workerNode, askUserForPw);
+
+			ChannelSftp sftpTest = (ChannelSftp) sshSession.openChannel("sftp");
+			sftpTest.connect();
+			sftpTest.cd(workerNode.getDirectory());
+			sftpTest.disconnect();
+			sshSession.disconnect();
+		} catch (JSchException e) {
+			return e.toString();
+		} catch (SftpException e) {
+			return e.toString();
+		}
+		return null;
+	}
+
+	public SshUseCaseInvocation(UseCaseDescription desc, SshNode workerNodeA,
+			AskUserForPw askUserForPwA, CredentialManager credentialManager)
+			throws JSchException, SftpException {
+		this.workerNode = workerNodeA;
+		this.credentialManager = credentialManager;
+
+		setRetrieveData(workerNodeA.isRetrieveData());
+		this.askUserForPw = askUserForPwA;
+		usecase = desc;
+
+		ChannelSftp sftp = SshPool.getSftpPutChannel(workerNode, askUserForPw);
+		synchronized (getNodeLock(workerNode)) {
+
+			logger.info("Changing remote directory to "
+					+ workerNode.getDirectory());
+			sftp.cd(workerNode.getDirectory());
+			Random rnd = new Random();
+			while (true) {
+				tmpname = "usecase" + rnd.nextLong();
+				try {
+					sftp.lstat(workerNode.getDirectory() + tmpname);
+					continue;
+				} catch (Exception e) {
+					// file seems to not exist :)
+				}
+				sftp.mkdir(workerNode.getDirectory() + tmpname);
+				sftp.cd(workerNode.getDirectory() + tmpname);
+				break;
+			}
+		}
+	}
+
+	private static void recursiveDelete(ChannelSftp sftp, String path)
+			throws SftpException, JSchException {
+		Vector<?> entries = sftp.ls(path);
+		for (Object object : entries) {
+			LsEntry entry = (LsEntry) object;
+			if (entry.getFilename().equals(".")
+					|| entry.getFilename().equals("..")) {
+				continue;
+			}
+			if (entry.getAttrs().isDir()) {
+				recursiveDelete(sftp, path + entry.getFilename() + "/");
+			} else {
+				sftp.rm(path + entry.getFilename());
+			}
+		}
+		sftp.rmdir(path);
+	}
+
+	private static void deleteDirectory(SshUrl directory,
+			CredentialManager credentialManager) throws InvocationException {
+		URI uri;
+		try {
+			uri = new URI(directory.toString());
+
+			ChannelSftp sftp;
+			SshNode workerNode;
+			String fullPath = uri.getPath();
+			String path = fullPath.substring(0, fullPath.lastIndexOf("/"));
+			String tempDir = fullPath.substring(fullPath.lastIndexOf("/"));
+			try {
+				workerNode = SshNodeFactory.getInstance().getSshNode(
+						uri.getHost(), uri.getPort(), path);
+
+				sftp = SshPool.getSftpPutChannel(workerNode,
+						new RetrieveLoginFromTaverna(workerNode.getUrl()
+								.toString(), credentialManager));
+			} catch (JSchException e) {
+				throw new InvocationException(e);
+			}
+			synchronized (getNodeLock(workerNode)) {
+				try {
+					sftp.cd(path);
+					recursiveDelete(sftp, path + "/" + tempDir + "/");
+				} catch (SftpException e) {
+					throw new InvocationException(e);
+				} catch (JSchException e) {
+					throw new InvocationException(e);
+				}
+			}
+		} catch (URISyntaxException e1) {
+			throw new InvocationException(e1);
+		}
+	}
+
+	public static void cleanup(String runId, CredentialManager credentialManager)
+			throws InvocationException {
+		Set<SshUrl> tempDirectories = runIdToTempDir.get(runId);
+		if (tempDirectories != null) {
+			for (SshUrl tempUrl : tempDirectories) {
+				deleteDirectory(tempUrl, credentialManager);
+			}
+			runIdToTempDir.remove(runId);
+		}
+	}
+
+	@Override
+	protected void submit_generate_job_inner() throws InvocationException {
+		tags.put("uniqueID", "" + getSubmissionID());
+		String command = usecase.getCommand();
+		for (String cur : tags.keySet()) {
+			command = command.replaceAll("\\Q%%" + cur + "%%\\E",
+					Matcher.quoteReplacement(tags.get(cur)));
+		}
+		String fullCommand = "cd " + workerNode.getDirectory() + tmpname;
+		for (String preceding : precedingCommands) {
+			fullCommand += " && " + preceding;
+		}
+		fullCommand += " && " + command;
+
+		logger.info("Full command is " + fullCommand);
+
+		try {
+			running = SshPool.openExecChannel(workerNode, askUserForPw);
+			running.setCommand(fullCommand);
+			running.setOutputStream(stdout_buf);
+			running.setErrStream(stderr_buf);
+			if (stdInputStream != null) {
+				running.setInputStream(stdInputStream);
+			}
+			running.connect();
+		} catch (JSchException e) {
+			throw new InvocationException(e);
+		}
+
+	}
+
+	@Override
+	public HashMap<String, Object> submit_wait_fetch_results(
+			ReferenceService referenceService) throws InvocationException {
+		while (!running.isClosed()) {
+			try {
+				Thread.sleep(1000);
+			} catch (InterruptedException e) {
+				throw new InvocationException("Invocation interrupted:"
+						+ e.getMessage());
+			}
+		}
+
+		int exitcode = running.getExitStatus();
+		if (!usecase.getValidReturnCodes().contains(exitcode)) {
+			try {
+				throw new InvocationException("Invalid exit code " + exitcode
+						+ ":" + stderr_buf.toString("US-ASCII"));
+			} catch (UnsupportedEncodingException e) {
+				throw new InvocationException("Invalid exit code " + exitcode
+						+ ":" + stderr_buf.toString());
+			}
+		}
+
+		HashMap<String, Object> results = new HashMap<String, Object>();
+
+		results.put("STDOUT", stdout_buf.toByteArray());
+		results.put("STDERR", stderr_buf.toByteArray());
+		try {
+			stdout_buf.close();
+			stderr_buf.close();
+		} catch (IOException e2) {
+			throw new InvocationException(e2);
+		}
+
+		try {
+			ChannelSftp sftp = SshPool.getSftpPutChannel(workerNode,
+					askUserForPw);
+			synchronized (getNodeLock(workerNode)) {
+				for (Map.Entry<String, ScriptOutput> cur : usecase.getOutputs()
+						.entrySet()) {
+					ScriptOutput scriptOutput = cur.getValue();
+					String fullPath = workerNode.getDirectory() + tmpname + "/"
+							+ scriptOutput.getPath();
+					try {
+						if (sftp.stat(fullPath) != null) {
+							SshUrl url = new SshUrl(workerNode);
+							url.setSubDirectory(tmpname);
+							url.setFileName(scriptOutput.getPath());
+							if (scriptOutput.isBinary()) {
+								url.setDataNature(ReferencedDataNature.BINARY);
+							} else {
+								url.setDataNature(ReferencedDataNature.TEXT);
+								url.setCharset("UTF-8");
+							}
+							if (isRetrieveData()) {
+								SshReference urlRef = new SshReference(url);
+								InputStream is = urlRef.openStream(null);
+								AbstractExternalReference ref;
+								if (scriptOutput.isBinary()) {
+									ref = inlineByteArrayReferenceBuilder
+											.createReference(is, null);
+								} else {
+									ref = inlineStringReferenceBuilder
+											.createReference(is, null);
+								}
+								try {
+									is.close();
+								} catch (IOException e) {
+									throw new InvocationException(e);
+								}
+								results.put(cur.getKey(), ref);
+							} else {
+								results.put(cur.getKey(), url);
+							}
+						} else {
+							ErrorDocument ed = referenceService
+									.getErrorDocumentService().registerError(
+											"No result for " + cur.getKey(), 0,
+											getContext());
+							results.put(cur.getKey(), ed);
+						}
+					} catch (SftpException e) {
+						ErrorDocument ed = referenceService
+								.getErrorDocumentService().registerError(
+										"No result for " + cur.getKey(), 0,
+										getContext());
+						results.put(cur.getKey(), ed);
+
+					}
+				}
+			}
+		} catch (JSchException e1) {
+			throw new InvocationException(e1);
+		} catch (ErrorDocumentServiceException e) {
+			throw new InvocationException(e);
+		}
+
+		if (running != null) {
+			running.disconnect();
+		}
+		if (stdInputStream != null) {
+			try {
+				stdInputStream.close();
+			} catch (IOException e) {
+				throw new InvocationException(e);
+			}
+		}
+
+		if (isRetrieveData()) {
+			forgetRun();
+			deleteDirectory(location, credentialManager);
+
+		}
+		return results;
+	}
+
+	@Override
+	public String setOneInput(ReferenceService referenceService,
+			T2Reference t2Reference, ScriptInput input)
+			throws InvocationException {
+		String target = null;
+		String remoteName = null;
+		if (input.isFile()) {
+			remoteName = input.getTag();
+		} else if (input.isTempFile()) {
+			remoteName = "tempfile." + (nTempFiles++) + ".tmp";
+
+		}
+		if (input.isFile() || input.isTempFile()) {
+			SshReference sshRef = getAsSshReference(referenceService,
+					t2Reference, workerNode);
+			target = workerNode.getDirectory() + tmpname + "/" + remoteName;
+			logger.info("Target is " + target);
+			if (sshRef != null) {
+				if (!input.isForceCopy()) {
+					String linkCommand = workerNode.getLinkCommand();
+					if (linkCommand != null) {
+						String actualLinkCommand = getActualOsCommand(
+								linkCommand, sshRef.getFullPath(), remoteName,
+								target);
+						precedingCommands.add(actualLinkCommand);
+						return target;
+
+					}
+				}
+				String copyCommand = workerNode.getCopyCommand();
+				if (copyCommand != null) {
+					String actualCopyCommand = getActualOsCommand(copyCommand,
+							sshRef.getFullPath(), remoteName, target);
+					precedingCommands.add(actualCopyCommand);
+					return target;
+				}
+			}
+			try {
+				ChannelSftp sftp = SshPool.getSftpPutChannel(workerNode,
+						askUserForPw);
+				synchronized (getNodeLock(workerNode)) {
+					InputStream r = getAsStream(referenceService, t2Reference);
+					sftp.put(r, target);
+					r.close();
+				}
+			} catch (SftpException e) {
+				throw new InvocationException(e);
+			} catch (JSchException e) {
+				throw new InvocationException(e);
+			} catch (IOException e) {
+				throw new InvocationException(e);
+			}
+			return target;
+		} else {
+			String value = (String) referenceService.renderIdentifier(
+					t2Reference, String.class, this.getContext());
+			return value;
+
+		}
+	}
+
+	public SshReference getAsSshReference(ReferenceService referenceService,
+			T2Reference t2Reference, SshNode workerNode) {
+		Identified identified = referenceService.resolveIdentifier(t2Reference,
+				null, null);
+		if (identified instanceof ReferenceSet) {
+			for (ExternalReferenceSPI ref : ((ReferenceSet) identified)
+					.getExternalReferences()) {
+				if (ref instanceof SshReference) {
+					SshReference sshRef = (SshReference) ref;
+					if (sshRef.getHost().equals(workerNode.getHost())) {
+						return sshRef;
+					}
+				}
+			}
+		}
+		return null;
+	}
+
+	private static Object getNodeLock(final SshNode node) {
+		return getNodeLock(node.getHost());
+	}
+
+	private static synchronized Object getNodeLock(String hostName) {
+		if (!nodeLock.containsKey(hostName)) {
+			nodeLock.put(hostName, new Object());
+		}
+		return nodeLock.get(hostName);
+	}
+
+	@Override
+	public void setStdIn(ReferenceService referenceService,
+			T2Reference t2Reference) {
+		stdInputStream = new BufferedInputStream(getAsStream(referenceService,
+				t2Reference));
+	}
+
+	@Override
+	public void rememberRun(String runId) {
+		this.setRunId(runId);
+		Set<SshUrl> directories = runIdToTempDir.get(runId);
+		if (directories == null) {
+			directories = Collections.synchronizedSet(new HashSet<SshUrl>());
+			runIdToTempDir.put(runId, directories);
+		}
+		location = new SshUrl(workerNode);
+		location.setSubDirectory(tmpname);
+		directories.add(location);
+	}
+
+	private void forgetRun() {
+		Set<SshUrl> directories = runIdToTempDir.get(getRunId());
+		directories.remove(location);
+	}
+
+	public static void load(File directory) {
+		File invocationsFile = new File(directory, SSH_INVOCATION_FILE);
+		if (!invocationsFile.exists()) {
+			return;
+		}
+		BufferedReader reader = null;
+		try {
+			reader = new BufferedReader(new FileReader(invocationsFile));
+			String line = reader.readLine();
+			while (line != null) {
+				String[] parts = line.split(" ");
+				if (parts.length != 2) {
+					break;
+				}
+				String runId = parts[0];
+				String urlString = parts[1];
+				Set<SshUrl> urls = runIdToTempDir.get(runId);
+				if (urls == null) {
+					urls = new HashSet<SshUrl>();
+					runIdToTempDir.put(runId, urls);
+				}
+				URI uri = new URI(urlString);
+				String fullPath = uri.getPath();
+				String path = fullPath.substring(0, fullPath.lastIndexOf("/"));
+				String tempDir = fullPath.substring(fullPath.lastIndexOf("/"));
+				SshNode node = SshNodeFactory.getInstance().getSshNode(
+						uri.getHost(), uri.getPort(), path);
+				SshUrl newUrl = new SshUrl(node);
+				newUrl.setSubDirectory(tempDir);
+				urls.add(newUrl);
+				line = reader.readLine();
+			}
+		} catch (FileNotFoundException e) {
+			logger.error(e);
+		} catch (URISyntaxException e) {
+			logger.error(e);
+		} catch (IOException e) {
+			logger.error(e);
+		} finally {
+			if (reader != null) {
+				try {
+					reader.close();
+				} catch (IOException e) {
+					logger.error(e);
+				}
+			}
+		}
+	}
+
+	public static void persist(File directory) {
+		File invocationsFile = new File(directory, SSH_INVOCATION_FILE);
+		BufferedWriter writer = null;
+		try {
+			writer = new BufferedWriter(new FileWriter(invocationsFile));
+			for (String runId : runIdToTempDir.keySet()) {
+				for (SshUrl url : runIdToTempDir.get(runId)) {
+					writer.write(runId);
+					writer.write(" ");
+					writer.write(url.toString());
+					writer.newLine();
+				}
+			}
+		} catch (IOException e) {
+			logger.error(e);
+		} finally {
+			if (writer != null) {
+				try {
+					writer.close();
+				} catch (IOException e) {
+					logger.error(e);
+				}
+			}
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-common-activities/blob/98468d30/taverna-external-tool-activity/src/main/resources/META-INF/services/org.apache.taverna.reference.ExternalReferenceSPI
----------------------------------------------------------------------
diff --git a/taverna-external-tool-activity/src/main/resources/META-INF/services/org.apache.taverna.reference.ExternalReferenceSPI b/taverna-external-tool-activity/src/main/resources/META-INF/services/org.apache.taverna.reference.ExternalReferenceSPI
index 6a18935..d63d896 100644
--- a/taverna-external-tool-activity/src/main/resources/META-INF/services/org.apache.taverna.reference.ExternalReferenceSPI
+++ b/taverna-external-tool-activity/src/main/resources/META-INF/services/org.apache.taverna.reference.ExternalReferenceSPI
@@ -1,2 +1,2 @@
 # Implementation classes of ExternalReferenceSPI go here, one per line
-de.uni_luebeck.inb.knowarc.usecases.invocation.ssh.SshReference
+org.apache.taverna.activities.externaltool.invocation.ssh.SshReference

http://git-wip-us.apache.org/repos/asf/incubator-taverna-common-activities/blob/98468d30/taverna-external-tool-activity/src/main/resources/META-INF/services/org.apache.taverna.reference.ValueToReferenceConverterSPI
----------------------------------------------------------------------
diff --git a/taverna-external-tool-activity/src/main/resources/META-INF/services/org.apache.taverna.reference.ValueToReferenceConverterSPI b/taverna-external-tool-activity/src/main/resources/META-INF/services/org.apache.taverna.reference.ValueToReferenceConverterSPI
index 53ca06c..50c5a16 100644
--- a/taverna-external-tool-activity/src/main/resources/META-INF/services/org.apache.taverna.reference.ValueToReferenceConverterSPI
+++ b/taverna-external-tool-activity/src/main/resources/META-INF/services/org.apache.taverna.reference.ValueToReferenceConverterSPI
@@ -1,3 +1,3 @@
 # Implementation classes of ValueToReferenceConverterSPI go here, one per line
-de.uni_luebeck.inb.knowarc.usecases.invocation.ssh.SshUrlToSshReference
+org.apache.taverna.activities.externaltool.invocation.ssh.SshUrlToSshReference
 

http://git-wip-us.apache.org/repos/asf/incubator-taverna-common-activities/blob/98468d30/taverna-external-tool-activity/src/main/resources/META-INF/spring/external-tool-activity-context.xml
----------------------------------------------------------------------
diff --git a/taverna-external-tool-activity/src/main/resources/META-INF/spring/external-tool-activity-context.xml b/taverna-external-tool-activity/src/main/resources/META-INF/spring/external-tool-activity-context.xml
index d933de9..297fc8d 100644
--- a/taverna-external-tool-activity/src/main/resources/META-INF/spring/external-tool-activity-context.xml
+++ b/taverna-external-tool-activity/src/main/resources/META-INF/spring/external-tool-activity-context.xml
@@ -21,7 +21,7 @@
 	xsi:schemaLocation="http://www.springframework.org/schema/beans
                       http://www.springframework.org/schema/beans/spring-beans.xsd">
 
-	<bean id="SshReference" class="de.uni_luebeck.inb.knowarc.usecases.invocation.ssh.SshReference">
+	<bean id="SshReference" class="org.apache.taverna.activities.externaltool.invocation.ssh.SshReference">
 		<property name="credentialManager" ref="credentialManager" />
 	</bean>
 
@@ -37,7 +37,7 @@
 		<property name="invocationGroupManager" ref="invocationGroupManager" />
 	</bean>
 
-	<bean id="SshUrlToSshReference" class="de.uni_luebeck.inb.knowarc.usecases.invocation.ssh.SshUrlToSshReference">
+	<bean id="SshUrlToSshReference" class="org.apache.taverna.activities.externaltool.invocation.ssh.SshUrlToSshReference">
 		<property name="credentialManager" ref="credentialManager" />
 	</bean>
 

http://git-wip-us.apache.org/repos/asf/incubator-taverna-common-activities/blob/98468d30/taverna-external-tool-activity/src/main/resources/de/uni_luebeck/inb/knowarc/usecases/invocation/ssh/SshReference.hbm.xml
----------------------------------------------------------------------
diff --git a/taverna-external-tool-activity/src/main/resources/de/uni_luebeck/inb/knowarc/usecases/invocation/ssh/SshReference.hbm.xml b/taverna-external-tool-activity/src/main/resources/de/uni_luebeck/inb/knowarc/usecases/invocation/ssh/SshReference.hbm.xml
index 4f0a737..b67f6be 100644
--- a/taverna-external-tool-activity/src/main/resources/de/uni_luebeck/inb/knowarc/usecases/invocation/ssh/SshReference.hbm.xml
+++ b/taverna-external-tool-activity/src/main/resources/de/uni_luebeck/inb/knowarc/usecases/invocation/ssh/SshReference.hbm.xml
@@ -23,7 +23,7 @@
 <!-- Hibernate mapping for ssh reference bean -->
 <hibernate-mapping>
 	<joined-subclass
-		name="de.uni_luebeck.inb.knowarc.usecases.invocation.ssh.SshReference"
+		name="org.apache.taverna.activities.externaltool.invocation.ssh.SshReference"
 		extends="org.apache.taverna.reference.AbstractExternalReference">
 		<!-- Link to primary key from abstract superclass -->
 		<key column="bean_id" />