Revert "Temporarily empty repository"

This reverts commit b4725724cecebe7fff940832c4cbaa4ed62dd621.
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..0c60cf1
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,42 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+	<parent>
+		<groupId>org.apache.taverna</groupId>
+		<artifactId>taverna-parent</artifactId>
+		<version>1-incubating-SNAPSHOT</version>
+	</parent>
+	<groupId>org.apache.taverna.workbench.commonactivities</groupId>
+	<artifactId>taverna-workbench-commonactivities</artifactId>
+	<version>3.1.0-incubating-SNAPSHOT</version>
+	<packaging>pom</packaging>
+	<name>Apache Taverna Workbench Common Activities</name>
+  <description>User interface and Workbench integration for common activities</description>
+  <properties>
+    <taverna.language.version>0.15.0-incubating-SNAPSHOT</taverna.language.version>
+    <taverna.osgi.version>0.2.0-incubating-SNAPSHOT</taverna.osgi.version>
+    <taverna.engine.version>3.1.0-incubating-SNAPSHOT</taverna.engine.version>
+    <taverna.commonactivities.version>2.1.0-incubating-SNAPSHOT</taverna.commonactivities.version>
+    <taverna.workbench.version>3.1.0-incubating-SNAPSHOT</taverna.workbench.version>
+  </properties>
+	<modules>
+    <module>taverna-beanshell-activity-ui</module>
+    <module>taverna-external-tool-activity-ui</module>
+    <module>taverna-localworker-activity-ui</module>
+    <module>taverna-rest-activity-ui</module>
+    <module>taverna-spreadsheet-import-activity-ui</module>
+    <module>taverna-wsdl-activity-ui</module>
+    <module>taverna-xpath-activity-ui</module>
+  </modules>
+  <repositories>
+    <repository>
+      <id>taverna-incubating</id>
+      <name>Apache Taverna incubating Repository</name>
+        <url>http://repository.mygrid.org.uk/artifactory/incubator-snapshot-local/</url>
+      <releases>
+        <enabled>false</enabled>
+      </releases>
+      <snapshots />
+    </repository>
+  </repositories>
+</project>
diff --git a/taverna-beanshell-activity-ui/pom.xml b/taverna-beanshell-activity-ui/pom.xml
new file mode 100644
index 0000000..0afe9ef
--- /dev/null
+++ b/taverna-beanshell-activity-ui/pom.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+	<parent>
+		<groupId>net.sf.taverna</groupId>
+                <artifactId>taverna-parent</artifactId>
+                <version>3.0.1-SNAPSHOT</version>
+	</parent>
+	<groupId>net.sf.taverna.t2.ui-activities</groupId>
+	<artifactId>beanshell-activity-ui</artifactId>
+        <version>2.0-SNAPSHOT</version>
+	<packaging>bundle</packaging>
+	<name>Taverna 2 Beanshell Activity UI</name>
+	<dependencies>
+		<dependency>
+			<groupId>net.sf.taverna.t2.ui-api</groupId>
+			<artifactId>activity-icons-api</artifactId>
+			<version>${t2.ui.api.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>net.sf.taverna.t2.ui-api</groupId>
+			<artifactId>activity-palette-api</artifactId>
+			<version>${t2.ui.api.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>net.sf.taverna.t2.ui-api</groupId>
+			<artifactId>activity-tools</artifactId>
+			<version>${t2.ui.api.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>net.sf.taverna.t2.ui-api</groupId>
+			<artifactId>edits-api</artifactId>
+			<version>${t2.ui.api.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>net.sf.taverna.t2.ui-api</groupId>
+			<artifactId>file-api</artifactId>
+			<version>${t2.ui.api.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>net.sf.taverna.t2.ui-api</groupId>
+			<artifactId>menu-api</artifactId>
+			<version>${t2.ui.api.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>net.sf.taverna.t2.ui-components</groupId>
+			<artifactId>workflow-view</artifactId>
+			<version>${t2.ui.components.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>net.sf.taverna.t2.lang</groupId>
+			<artifactId>ui</artifactId>
+			<version>${t2.lang.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>uk.org.taverna.configuration</groupId>
+			<artifactId>taverna-app-configuration-api</artifactId>
+			<version>${taverna.configuration.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>uk.org.taverna.commons</groupId>
+			<artifactId>taverna-services-api</artifactId>
+			<version>0.1.0-SNAPSHOT</version>
+		</dependency>
+		<dependency>
+			<groupId>uk.org.taverna.scufl2</groupId>
+			<artifactId>scufl2-api</artifactId>
+			<version>${scufl2.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>junit</groupId>
+			<artifactId>junit</artifactId>
+                        <version>${junit.version}</version>
+			<scope>test</scope>
+		</dependency>
+	</dependencies>
+	<repositories>
+		<repository>
+			<releases />
+			<snapshots>
+				<enabled>false</enabled>
+			</snapshots>
+			<id>mygrid-repository</id>
+			<name>myGrid Repository</name>
+			<url>http://www.mygrid.org.uk/maven/repository
+			</url>
+		</repository>
+		<repository>
+			<releases>
+				<enabled>false</enabled>
+			</releases>
+			<snapshots />
+			<id>mygrid-snapshot-repository</id>
+			<name>myGrid Snapshot Repository</name>
+			<url>http://www.mygrid.org.uk/maven/snapshot-repository</url>
+		</repository>
+	</repositories>
+</project>
+
diff --git a/taverna-beanshell-activity-ui/src/main/java/net/sf/taverna/t2/activities/beanshell/actions/BeanshellActivityConfigurationAction.java b/taverna-beanshell-activity-ui/src/main/java/net/sf/taverna/t2/activities/beanshell/actions/BeanshellActivityConfigurationAction.java
new file mode 100644
index 0000000..fe6159c
--- /dev/null
+++ b/taverna-beanshell-activity-ui/src/main/java/net/sf/taverna/t2/activities/beanshell/actions/BeanshellActivityConfigurationAction.java
@@ -0,0 +1,71 @@
+/*******************************************************************************
+ * Copyright (C) 2007 The University of Manchester
+ *
+ *  Modifications to the initial code base are copyright of their
+ *  respective authors, or their employers as appropriate.
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1 of
+ *  the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+package net.sf.taverna.t2.activities.beanshell.actions;
+
+import java.awt.Frame;
+import java.awt.event.ActionEvent;
+
+import net.sf.taverna.t2.activities.beanshell.views.BeanshellConfigurationPanel;
+import net.sf.taverna.t2.servicedescriptions.ServiceDescriptionRegistry;
+import net.sf.taverna.t2.workbench.activityicons.ActivityIconManager;
+import net.sf.taverna.t2.workbench.edits.EditManager;
+import net.sf.taverna.t2.workbench.file.FileManager;
+import net.sf.taverna.t2.workbench.ui.actions.activity.ActivityConfigurationAction;
+import net.sf.taverna.t2.workbench.ui.views.contextualviews.activity.ActivityConfigurationDialog;
+import uk.org.taverna.configuration.app.ApplicationConfiguration;
+import uk.org.taverna.scufl2.api.activity.Activity;
+
+@SuppressWarnings("serial")
+public class BeanshellActivityConfigurationAction extends ActivityConfigurationAction {
+
+	public static final String EDIT_BEANSHELL_SCRIPT = "Edit beanshell script";
+	private final EditManager editManager;
+	private final FileManager fileManager;
+	private final ApplicationConfiguration applicationConfiguration;
+
+	public BeanshellActivityConfigurationAction(Activity activity, Frame owner,
+			EditManager editManager, FileManager fileManager,
+			ActivityIconManager activityIconManager,
+			ServiceDescriptionRegistry serviceDescriptionRegistry,
+			ApplicationConfiguration applicationConfiguration) {
+		super(activity, activityIconManager, serviceDescriptionRegistry);
+		this.editManager = editManager;
+		this.fileManager = fileManager;
+		this.applicationConfiguration = applicationConfiguration;
+		putValue(NAME, EDIT_BEANSHELL_SCRIPT);
+	}
+
+	public void actionPerformed(ActionEvent e) {
+		ActivityConfigurationDialog currentDialog = ActivityConfigurationAction.getDialog(getActivity());
+		if (currentDialog != null) {
+			currentDialog.toFront();
+			return;
+		}
+		final BeanshellConfigurationPanel beanshellConfigView = new BeanshellConfigurationPanel(
+				getActivity(), applicationConfiguration);
+		final ActivityConfigurationDialog dialog = new ActivityConfigurationDialog(getActivity(),
+				beanshellConfigView, editManager);
+
+		ActivityConfigurationAction.setDialog(getActivity(), dialog, fileManager);
+
+	}
+
+}
diff --git a/taverna-beanshell-activity-ui/src/main/java/net/sf/taverna/t2/activities/beanshell/menu/AddBeanshellTemplateAction.java b/taverna-beanshell-activity-ui/src/main/java/net/sf/taverna/t2/activities/beanshell/menu/AddBeanshellTemplateAction.java
new file mode 100644
index 0000000..97eab18
--- /dev/null
+++ b/taverna-beanshell-activity-ui/src/main/java/net/sf/taverna/t2/activities/beanshell/menu/AddBeanshellTemplateAction.java
@@ -0,0 +1,113 @@
+/*******************************************************************************
+ * Copyright (C) 2007-2009 The University of Manchester
+ *
+ *  Modifications to the initial code base are copyright of their
+ *  respective authors, or their employers as appropriate.
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1 of
+ *  the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+package net.sf.taverna.t2.activities.beanshell.menu;
+
+import java.awt.event.ActionEvent;
+import java.net.URI;
+
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+
+import net.sf.taverna.t2.activities.beanshell.servicedescriptions.BeanshellTemplateService;
+import net.sf.taverna.t2.servicedescriptions.ServiceDescriptionRegistry;
+import net.sf.taverna.t2.ui.menu.AbstractContextualMenuAction;
+import net.sf.taverna.t2.ui.menu.MenuManager;
+import net.sf.taverna.t2.workbench.activityicons.ActivityIconManager;
+import net.sf.taverna.t2.workbench.edits.EditManager;
+import net.sf.taverna.t2.workbench.selection.SelectionManager;
+import net.sf.taverna.t2.workbench.ui.workflowview.WorkflowView;
+import uk.org.taverna.commons.services.ServiceRegistry;
+import uk.org.taverna.scufl2.api.core.Workflow;
+
+/**
+ * An action to add a beanshell activity + a wrapping processor to the workflow.
+ *
+ * @author Alex Nenadic
+ * @author David Withers
+ */
+@SuppressWarnings("serial")
+public class AddBeanshellTemplateAction extends AbstractContextualMenuAction {
+
+	private static final String ADD_BEANSHELL = "Beanshell";
+
+	private static final URI insertSection = URI
+			.create("http://taverna.sf.net/2009/contextMenu/insert");
+
+	private EditManager editManager;
+	private MenuManager menuManager;
+	private SelectionManager selectionManager;
+	private ActivityIconManager activityIconManager;
+	private ServiceDescriptionRegistry serviceDescriptionRegistry;
+	private ServiceRegistry serviceRegistry;
+
+	public AddBeanshellTemplateAction() {
+		super(insertSection, 300);
+	}
+
+	@Override
+	public boolean isEnabled() {
+		return super.isEnabled() && getContextualSelection().getSelection() instanceof Workflow;
+	}
+
+	@Override
+	protected Action createAction() {
+
+		return new AddBeanshellAction();
+	}
+
+	protected class AddBeanshellAction extends AbstractAction {
+		AddBeanshellAction() {
+			super(ADD_BEANSHELL, activityIconManager
+					.iconForActivity(BeanshellTemplateService.ACTIVITY_TYPE));
+		}
+
+		public void actionPerformed(ActionEvent e) {
+			WorkflowView.importServiceDescription(serviceDescriptionRegistry
+					.getServiceDescription(BeanshellTemplateService.ACTIVITY_TYPE), false,
+					editManager, menuManager, selectionManager, serviceRegistry);
+		}
+	}
+
+	public void setEditManager(EditManager editManager) {
+		this.editManager = editManager;
+	}
+
+	public void setMenuManager(MenuManager menuManager) {
+		this.menuManager = menuManager;
+	}
+
+	public void setSelectionManager(SelectionManager selectionManager) {
+		this.selectionManager = selectionManager;
+	}
+
+	public void setActivityIconManager(ActivityIconManager activityIconManager) {
+		this.activityIconManager = activityIconManager;
+	}
+
+	public void setServiceDescriptionRegistry(ServiceDescriptionRegistry serviceDescriptionRegistry) {
+		this.serviceDescriptionRegistry = serviceDescriptionRegistry;
+	}
+
+	public void setServiceRegistry(ServiceRegistry serviceRegistry) {
+		this.serviceRegistry = serviceRegistry;
+	}
+
+}
diff --git a/taverna-beanshell-activity-ui/src/main/java/net/sf/taverna/t2/activities/beanshell/menu/AddBeanshellTemplateMenuAction.java b/taverna-beanshell-activity-ui/src/main/java/net/sf/taverna/t2/activities/beanshell/menu/AddBeanshellTemplateMenuAction.java
new file mode 100644
index 0000000..7933000
--- /dev/null
+++ b/taverna-beanshell-activity-ui/src/main/java/net/sf/taverna/t2/activities/beanshell/menu/AddBeanshellTemplateMenuAction.java
@@ -0,0 +1,121 @@
+/*******************************************************************************
+ * Copyright (C) 2007-2009 The University of Manchester
+ *
+ *  Modifications to the initial code base are copyright of their
+ *  respective authors, or their employers as appropriate.
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1 of
+ *  the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+package net.sf.taverna.t2.activities.beanshell.menu;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.InputEvent;
+import java.awt.event.KeyEvent;
+import java.net.URI;
+
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+import javax.swing.KeyStroke;
+
+import net.sf.taverna.t2.activities.beanshell.servicedescriptions.BeanshellTemplateService;
+import net.sf.taverna.t2.servicedescriptions.ServiceDescriptionRegistry;
+import net.sf.taverna.t2.ui.menu.AbstractMenuAction;
+import net.sf.taverna.t2.ui.menu.DesignOnlyAction;
+import net.sf.taverna.t2.ui.menu.MenuManager;
+import net.sf.taverna.t2.workbench.activityicons.ActivityIconManager;
+import net.sf.taverna.t2.workbench.edits.EditManager;
+import net.sf.taverna.t2.workbench.selection.SelectionManager;
+import net.sf.taverna.t2.workbench.ui.workflowview.WorkflowView;
+import uk.org.taverna.commons.services.ServiceRegistry;
+
+/**
+ * An action to add a beanshell activity + a wrapping processor to the workflow.
+ *
+ * @author Alex Nenadic
+ * @author alanrw
+ * @author David Withers
+ */
+@SuppressWarnings("serial")
+public class AddBeanshellTemplateMenuAction extends AbstractMenuAction {
+
+	private static final String ADD_BEANSHELL = "Beanshell";
+
+	private static final URI INSERT = URI
+			.create("http://taverna.sf.net/2008/t2workbench/menu#insert");
+
+	private static final URI ADD_BEANSHELL_URI = URI
+			.create("http://taverna.sf.net/2008/t2workbench/menu#graphMenuAddBeanshell");
+
+	private EditManager editManager;
+	private MenuManager menuManager;
+	private SelectionManager selectionManager;
+	private ActivityIconManager activityIconManager;
+	private ServiceDescriptionRegistry serviceDescriptionRegistry;
+	private ServiceRegistry serviceRegistry;
+
+	public AddBeanshellTemplateMenuAction() {
+		super(INSERT, 300, ADD_BEANSHELL_URI);
+	}
+
+	@Override
+	protected Action createAction() {
+		return new AddBeanshellMenuAction();
+	}
+
+	protected class AddBeanshellMenuAction extends AbstractAction implements DesignOnlyAction {
+		AddBeanshellMenuAction() {
+			super();
+			putValue(SMALL_ICON,
+					activityIconManager.iconForActivity(BeanshellTemplateService.ACTIVITY_TYPE));
+			putValue(NAME, ADD_BEANSHELL);
+			putValue(SHORT_DESCRIPTION, "Beanshell service");
+			putValue(
+					Action.ACCELERATOR_KEY,
+					KeyStroke.getKeyStroke(KeyEvent.VK_B, InputEvent.SHIFT_DOWN_MASK
+							| InputEvent.ALT_DOWN_MASK));
+		}
+
+		public void actionPerformed(ActionEvent e) {
+			WorkflowView.importServiceDescription(serviceDescriptionRegistry
+					.getServiceDescription(BeanshellTemplateService.ACTIVITY_TYPE), false,
+					editManager, menuManager, selectionManager, serviceRegistry);
+		}
+	}
+
+	public void setEditManager(EditManager editManager) {
+		this.editManager = editManager;
+	}
+
+	public void setMenuManager(MenuManager menuManager) {
+		this.menuManager = menuManager;
+	}
+
+	public void setSelectionManager(SelectionManager selectionManager) {
+		this.selectionManager = selectionManager;
+	}
+
+	public void setActivityIconManager(ActivityIconManager activityIconManager) {
+		this.activityIconManager = activityIconManager;
+	}
+
+	public void setServiceDescriptionRegistry(ServiceDescriptionRegistry serviceDescriptionRegistry) {
+		this.serviceDescriptionRegistry = serviceDescriptionRegistry;
+	}
+
+	public void setServiceRegistry(ServiceRegistry serviceRegistry) {
+		this.serviceRegistry = serviceRegistry;
+	}
+
+}
diff --git a/taverna-beanshell-activity-ui/src/main/java/net/sf/taverna/t2/activities/beanshell/menu/ConfigureBeanshellMenuAction.java b/taverna-beanshell-activity-ui/src/main/java/net/sf/taverna/t2/activities/beanshell/menu/ConfigureBeanshellMenuAction.java
new file mode 100644
index 0000000..64ef0c8
--- /dev/null
+++ b/taverna-beanshell-activity-ui/src/main/java/net/sf/taverna/t2/activities/beanshell/menu/ConfigureBeanshellMenuAction.java
@@ -0,0 +1,67 @@
+package net.sf.taverna.t2.activities.beanshell.menu;
+
+import java.net.URI;
+
+import net.sf.taverna.t2.activities.beanshell.actions.BeanshellActivityConfigurationAction;
+import net.sf.taverna.t2.activities.beanshell.servicedescriptions.BeanshellTemplateService;
+import net.sf.taverna.t2.servicedescriptions.ServiceDescriptionRegistry;
+import net.sf.taverna.t2.workbench.activityicons.ActivityIconManager;
+import net.sf.taverna.t2.workbench.activitytools.AbstractConfigureActivityMenuAction;
+import net.sf.taverna.t2.workbench.edits.EditManager;
+import net.sf.taverna.t2.workbench.file.FileManager;
+
+import javax.swing.Action;
+
+import uk.org.taverna.configuration.app.ApplicationConfiguration;
+import uk.org.taverna.scufl2.api.activity.Activity;
+
+public class ConfigureBeanshellMenuAction extends AbstractConfigureActivityMenuAction {
+
+	public static final URI LOCALWORKER_ACTIVITY = URI
+			.create("http://ns.taverna.org.uk/2010/activity/localworker");
+
+	private EditManager editManager;
+	private FileManager fileManager;
+	private ActivityIconManager activityIconManager;
+	private ServiceDescriptionRegistry serviceDescriptionRegistry;
+	private ApplicationConfiguration applicationConfiguration;
+
+	public ConfigureBeanshellMenuAction() {
+		super(BeanshellTemplateService.ACTIVITY_TYPE);
+	}
+
+	@Override
+	protected Action createAction() {
+		Activity a = findActivity();
+		Action result = null;
+		if (!(a.getType().equals(LOCALWORKER_ACTIVITY))) {
+			result = new BeanshellActivityConfigurationAction(findActivity(), getParentFrame(),
+					editManager, fileManager, activityIconManager, serviceDescriptionRegistry,
+					applicationConfiguration);
+			result.putValue(Action.NAME, BeanshellActivityConfigurationAction.EDIT_BEANSHELL_SCRIPT);
+			addMenuDots(result);
+		}
+		return result;
+	}
+
+	public void setEditManager(EditManager editManager) {
+		this.editManager = editManager;
+	}
+
+	public void setFileManager(FileManager fileManager) {
+		this.fileManager = fileManager;
+	}
+
+	public void setActivityIconManager(ActivityIconManager activityIconManager) {
+		this.activityIconManager = activityIconManager;
+	}
+
+	public void setServiceDescriptionRegistry(ServiceDescriptionRegistry serviceDescriptionRegistry) {
+		this.serviceDescriptionRegistry = serviceDescriptionRegistry;
+	}
+
+	public void setApplicationConfiguration(ApplicationConfiguration applicationConfiguration) {
+		this.applicationConfiguration = applicationConfiguration;
+	}
+
+}
diff --git a/taverna-beanshell-activity-ui/src/main/java/net/sf/taverna/t2/activities/beanshell/servicedescriptions/BeanshellActivityIcon.java b/taverna-beanshell-activity-ui/src/main/java/net/sf/taverna/t2/activities/beanshell/servicedescriptions/BeanshellActivityIcon.java
new file mode 100644
index 0000000..055aa81
--- /dev/null
+++ b/taverna-beanshell-activity-ui/src/main/java/net/sf/taverna/t2/activities/beanshell/servicedescriptions/BeanshellActivityIcon.java
@@ -0,0 +1,58 @@
+/*******************************************************************************
+ * Copyright (C) 2007 The University of Manchester
+ *
+ *  Modifications to the initial code base are copyright of their
+ *  respective authors, or their employers as appropriate.
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1 of
+ *  the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+package net.sf.taverna.t2.activities.beanshell.servicedescriptions;
+
+import java.net.URI;
+
+import javax.swing.Icon;
+import javax.swing.ImageIcon;
+
+import net.sf.taverna.t2.workbench.activityicons.ActivityIconSPI;
+
+/**
+ *
+ * @author Alex Nenadic
+ * @author David Withers
+ */
+public class BeanshellActivityIcon implements ActivityIconSPI {
+
+	private static Icon icon = null;
+
+	@Override
+	public int canProvideIconScore(URI activityType) {
+		if (BeanshellTemplateService.ACTIVITY_TYPE.equals(activityType))
+			return DEFAULT_ICON + 1;
+		else
+			return NO_ICON;
+	}
+
+	@Override
+	public Icon getIcon(URI activityType) {
+		return getBeanshellIcon();
+	}
+
+	public static Icon getBeanshellIcon() {
+		if (icon == null) {
+			icon = new ImageIcon(BeanshellActivityIcon.class.getResource("/beanshell.png"));
+		}
+		return icon;
+	}
+}
diff --git a/taverna-beanshell-activity-ui/src/main/java/net/sf/taverna/t2/activities/beanshell/servicedescriptions/BeanshellTemplateService.java b/taverna-beanshell-activity-ui/src/main/java/net/sf/taverna/t2/activities/beanshell/servicedescriptions/BeanshellTemplateService.java
new file mode 100644
index 0000000..c2cb38f
--- /dev/null
+++ b/taverna-beanshell-activity-ui/src/main/java/net/sf/taverna/t2/activities/beanshell/servicedescriptions/BeanshellTemplateService.java
@@ -0,0 +1,57 @@
+package net.sf.taverna.t2.activities.beanshell.servicedescriptions;
+
+import java.net.URI;
+
+import javax.swing.Icon;
+
+import net.sf.taverna.t2.servicedescriptions.AbstractTemplateService;
+import net.sf.taverna.t2.servicedescriptions.ServiceDescription;
+import uk.org.taverna.scufl2.api.configurations.Configuration;
+
+public class BeanshellTemplateService extends AbstractTemplateService {
+
+	public static final URI ACTIVITY_TYPE = URI.create("http://ns.taverna.org.uk/2010/activity/beanshell");
+
+	private static final String BEANSHELL = "Beanshell";
+
+	private static final URI providerId = URI
+	.create("http://taverna.sf.net/2010/service-provider/beanshell");
+
+	public String getName() {
+		return BEANSHELL;
+	}
+
+	@Override
+	public URI getActivityType() {
+		return ACTIVITY_TYPE;
+	}
+
+	@Override
+	public Configuration getActivityConfiguration() {
+		Configuration configuration = new Configuration();
+		configuration.setType(ACTIVITY_TYPE.resolve("#Config"));
+		configuration.getJsonAsObjectNode().put("script", "");
+		configuration.getJsonAsObjectNode().put("classLoaderSharing", "workflow");
+		return configuration;
+	}
+
+	@Override
+	public Icon getIcon() {
+		return BeanshellActivityIcon.getBeanshellIcon();
+	}
+
+	@Override
+	public String getDescription() {
+		return "A service that allows Beanshell scripts, with dependencies on libraries";
+	}
+
+	public static ServiceDescription getServiceDescription() {
+		BeanshellTemplateService bts = new BeanshellTemplateService();
+		return bts.templateService;
+	}
+
+	public String getId() {
+		return providerId.toString();
+	}
+
+}
diff --git a/taverna-beanshell-activity-ui/src/main/java/net/sf/taverna/t2/activities/beanshell/views/BeanshellActivityViewFactory.java b/taverna-beanshell-activity-ui/src/main/java/net/sf/taverna/t2/activities/beanshell/views/BeanshellActivityViewFactory.java
new file mode 100644
index 0000000..5c83730
--- /dev/null
+++ b/taverna-beanshell-activity-ui/src/main/java/net/sf/taverna/t2/activities/beanshell/views/BeanshellActivityViewFactory.java
@@ -0,0 +1,84 @@
+/*******************************************************************************
+ * Copyright (C) 2007 The University of Manchester
+ *
+ *  Modifications to the initial code base are copyright of their
+ *  respective authors, or their employers as appropriate.
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1 of
+ *  the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+package net.sf.taverna.t2.activities.beanshell.views;
+
+import java.net.URI;
+import java.util.Arrays;
+import java.util.List;
+
+import net.sf.taverna.t2.servicedescriptions.ServiceDescriptionRegistry;
+import net.sf.taverna.t2.workbench.activityicons.ActivityIconManager;
+import net.sf.taverna.t2.workbench.configuration.colour.ColourManager;
+import net.sf.taverna.t2.workbench.edits.EditManager;
+import net.sf.taverna.t2.workbench.file.FileManager;
+import net.sf.taverna.t2.workbench.ui.views.contextualviews.ContextualView;
+import net.sf.taverna.t2.workbench.ui.views.contextualviews.activity.ContextualViewFactory;
+import uk.org.taverna.configuration.app.ApplicationConfiguration;
+import uk.org.taverna.scufl2.api.activity.Activity;
+
+public class BeanshellActivityViewFactory implements ContextualViewFactory<Activity> {
+
+	private static final URI ACTIVITY_TYPE = URI
+			.create("http://ns.taverna.org.uk/2010/activity/beanshell");
+
+	private EditManager editManager;
+	private FileManager fileManager;
+	private ActivityIconManager activityIconManager;
+	private ColourManager colourManager;
+	private ServiceDescriptionRegistry serviceDescriptionRegistry;
+
+	private ApplicationConfiguration applicationConfiguration;
+
+	public boolean canHandle(Object object) {
+		return object instanceof Activity && ((Activity) object).getType().equals(ACTIVITY_TYPE);
+	}
+
+	public List<ContextualView> getViews(Activity activity) {
+		return Arrays.asList(new ContextualView[] { new BeanshellContextualView(activity,
+				editManager, fileManager, activityIconManager, colourManager,
+				serviceDescriptionRegistry, applicationConfiguration) });
+	}
+
+	public void setEditManager(EditManager editManager) {
+		this.editManager = editManager;
+	}
+
+	public void setFileManager(FileManager fileManager) {
+		this.fileManager = fileManager;
+	}
+
+	public void setActivityIconManager(ActivityIconManager activityIconManager) {
+		this.activityIconManager = activityIconManager;
+	}
+
+	public void setColourManager(ColourManager colourManager) {
+		this.colourManager = colourManager;
+	}
+
+	public void setServiceDescriptionRegistry(ServiceDescriptionRegistry serviceDescriptionRegistry) {
+		this.serviceDescriptionRegistry = serviceDescriptionRegistry;
+	}
+
+	public void setApplicationConfiguration(ApplicationConfiguration applicationConfiguration) {
+		this.applicationConfiguration = applicationConfiguration;
+	}
+
+}
diff --git a/taverna-beanshell-activity-ui/src/main/java/net/sf/taverna/t2/activities/beanshell/views/BeanshellConfigurationPanel.java b/taverna-beanshell-activity-ui/src/main/java/net/sf/taverna/t2/activities/beanshell/views/BeanshellConfigurationPanel.java
new file mode 100644
index 0000000..8489d7a
--- /dev/null
+++ b/taverna-beanshell-activity-ui/src/main/java/net/sf/taverna/t2/activities/beanshell/views/BeanshellConfigurationPanel.java
@@ -0,0 +1,231 @@
+/*******************************************************************************
+ * Copyright (C) 2012 The University of Manchester
+ *
+ *  Modifications to the initial code base are copyright of their
+ *  respective authors, or their employers as appropriate.
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1 of
+ *  the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+package net.sf.taverna.t2.activities.beanshell.views;
+
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.io.File;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JSpinner;
+import javax.swing.SpinnerNumberModel;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
+
+import net.sf.taverna.t2.lang.ui.EditorKeySetUtil;
+import net.sf.taverna.t2.workbench.ui.views.contextualviews.activity.ActivityPortConfiguration;
+import net.sf.taverna.t2.workbench.ui.views.contextualviews.activity.DependencyConfigurationPanel;
+import net.sf.taverna.t2.workbench.ui.views.contextualviews.activity.ListConfigurationComponent;
+import net.sf.taverna.t2.workbench.ui.views.contextualviews.activity.MultiPageActivityConfigurationPanel;
+import net.sf.taverna.t2.workbench.ui.views.contextualviews.activity.ScriptConfigurationComponent;
+import net.sf.taverna.t2.workbench.ui.views.contextualviews.activity.ValidatingTextField;
+import net.sf.taverna.t2.workbench.ui.views.contextualviews.activity.ValidatingTextGroup;
+import uk.org.taverna.configuration.app.ApplicationConfiguration;
+import uk.org.taverna.scufl2.api.activity.Activity;
+import uk.org.taverna.scufl2.api.port.InputActivityPort;
+import uk.org.taverna.scufl2.api.port.OutputActivityPort;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+
+/**
+ * Component for configuring a Beanshell activity.
+ *
+ * @author David Withers
+ */
+@SuppressWarnings("serial")
+public class BeanshellConfigurationPanel extends MultiPageActivityConfigurationPanel {
+
+	private ScriptConfigurationComponent scriptConfigurationComponent;
+	private ValidatingTextGroup inputTextGroup, outputTextGroup;
+	private DependencyConfigurationPanel dependencyConfigurationPanel;
+	private File libDir;
+
+	public BeanshellConfigurationPanel(Activity activity,
+			ApplicationConfiguration applicationConfiguration) {
+		super(activity);
+		libDir = new File(applicationConfiguration.getApplicationHomeDir(), "lib");
+		if (!libDir.exists()) {
+			libDir.mkdir();
+		}
+		initialise();
+	}
+
+	@Override
+	protected void initialise() {
+		super.initialise();
+		removeAllPages();
+		addPage("Script", createScriptEditPanel());
+		addPage("Input ports", createInputPanel());
+		addPage("Output ports", createOutputPanel());
+		addPage("Dependencies", createDependenciesPanel());
+		setPreferredSize(new Dimension(600, 500));
+	}
+
+	@Override
+	public void noteConfiguration() {
+		setProperty("script", scriptConfigurationComponent.getScript());
+		setProperty("classLoaderSharing", dependencyConfigurationPanel.getClassLoaderSharing());
+		List<String> localDependencies = dependencyConfigurationPanel.getLocalDependencies();
+		if (localDependencies == null || localDependencies.isEmpty()) {
+			getJson().remove("localDependency");
+		} else {
+			ArrayNode localDependenciesArray = getJson().arrayNode();
+			for (String localDependency : localDependencies) {
+				localDependenciesArray.add(localDependency);
+			}
+			getJson().put("localDependency", localDependenciesArray);
+		}
+	}
+
+	@Override
+	public boolean checkValues() {
+		return true;
+	}
+
+	private Component createScriptEditPanel() {
+		Set<String> keywords = EditorKeySetUtil.loadKeySet(getClass().getResourceAsStream(
+				"keys.txt"));
+		Set<String> ports = new HashSet<>();
+		for (InputActivityPort ip : getActivity().getInputPorts()) {
+			ports.add(ip.getName());
+		}
+		for (OutputActivityPort op : getActivity().getOutputPorts()) {
+			ports.add(op.getName());
+		}
+		scriptConfigurationComponent = new ScriptConfigurationComponent(getProperty("script"),
+				keywords, ports, "Beanshell", ".bsh");
+		return scriptConfigurationComponent;
+	}
+
+	private Component createInputPanel() {
+		inputTextGroup = new ValidatingTextGroup();
+		ListConfigurationComponent<ActivityPortConfiguration> inputPanel = new ListConfigurationComponent<ActivityPortConfiguration>(
+				"Input Port", getInputPorts()) {
+			@Override
+			protected Component createItemComponent(ActivityPortConfiguration port) {
+				return new PortComponent(port, inputTextGroup);
+			}
+
+			@Override
+			protected ActivityPortConfiguration createDefaultItem() {
+				return new ActivityPortConfiguration("in", 0);
+			}
+		};
+		return inputPanel;
+	}
+
+	private Component createOutputPanel() {
+		outputTextGroup = new ValidatingTextGroup();
+		ListConfigurationComponent<ActivityPortConfiguration> inputPanel = new ListConfigurationComponent<ActivityPortConfiguration>(
+				"Output Port", getOutputPorts()) {
+			@Override
+			protected Component createItemComponent(ActivityPortConfiguration port) {
+				return new PortComponent(port, outputTextGroup);
+			}
+
+			@Override
+			protected ActivityPortConfiguration createDefaultItem() {
+				return new ActivityPortConfiguration("out", 0);
+			}
+		};
+		return inputPanel;
+	}
+
+	private Component createDependenciesPanel() {
+		String classLoaderSharing = getProperty("classLoaderSharing");
+		List<String> localDependencies = new ArrayList<>();
+		if (getJson().has("localDependency")) {
+			for (JsonNode localDependency : getJson().get("localDependency")) {
+				localDependencies.add(localDependency.textValue());
+			}
+		}
+		dependencyConfigurationPanel = new DependencyConfigurationPanel(classLoaderSharing,
+				localDependencies, libDir);
+		return dependencyConfigurationPanel;
+	}
+
+	class PortComponent extends JPanel {
+
+		private ValidatingTextField nameField;
+		private SpinnerNumberModel depthModel;
+		private final ValidatingTextGroup validatingTextGroup;
+
+		public PortComponent(final ActivityPortConfiguration portConfiguration,
+				ValidatingTextGroup validatingTextGroup) {
+			this.validatingTextGroup = validatingTextGroup;
+
+			nameField = new ValidatingTextField(portConfiguration.getName());
+			nameField.getDocument().addDocumentListener(new DocumentListener() {
+				@Override
+				public void removeUpdate(DocumentEvent e) {
+					portConfiguration.setName(nameField.getText());
+				}
+
+				@Override
+				public void insertUpdate(DocumentEvent e) {
+					portConfiguration.setName(nameField.getText());
+				}
+
+				@Override
+				public void changedUpdate(DocumentEvent e) {
+					portConfiguration.setName(nameField.getText());
+				}
+			});
+			validatingTextGroup.addValidTextComponent(nameField);
+			depthModel = new SpinnerNumberModel(portConfiguration.getDepth(), 0, 100, 1);
+			depthModel.addChangeListener(new ChangeListener() {
+				@Override
+				public void stateChanged(ChangeEvent e) {
+					portConfiguration.setDepth(depthModel.getNumber().intValue());
+				}
+			});
+
+			setLayout(new GridBagLayout());
+			GridBagConstraints c = new GridBagConstraints();
+			c.anchor = GridBagConstraints.WEST;
+			add(new JLabel("Name"), c);
+			c.fill = GridBagConstraints.HORIZONTAL;
+			c.weightx = 1;
+			add(nameField, c);
+			c.fill = GridBagConstraints.NONE;
+			c.weightx = 0;
+			add(new JLabel("Depth"), c);
+			add(new JSpinner(depthModel), c);
+
+		}
+
+		public void removeNotify() {
+			validatingTextGroup.removeTextComponent(nameField);
+		}
+
+	}
+
+}
diff --git a/taverna-beanshell-activity-ui/src/main/java/net/sf/taverna/t2/activities/beanshell/views/BeanshellContextualView.java b/taverna-beanshell-activity-ui/src/main/java/net/sf/taverna/t2/activities/beanshell/views/BeanshellContextualView.java
new file mode 100644
index 0000000..e738e38
--- /dev/null
+++ b/taverna-beanshell-activity-ui/src/main/java/net/sf/taverna/t2/activities/beanshell/views/BeanshellContextualView.java
@@ -0,0 +1,104 @@
+/*******************************************************************************
+ * Copyright (C) 2007 The University of Manchester
+ *
+ *  Modifications to the initial code base are copyright of their
+ *  respective authors, or their employers as appropriate.
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1 of
+ *  the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+package net.sf.taverna.t2.activities.beanshell.views;
+
+import java.awt.Frame;
+
+import javax.swing.Action;
+
+import net.sf.taverna.t2.activities.beanshell.actions.BeanshellActivityConfigurationAction;
+import net.sf.taverna.t2.servicedescriptions.ServiceDescriptionRegistry;
+import net.sf.taverna.t2.workbench.activityicons.ActivityIconManager;
+import net.sf.taverna.t2.workbench.configuration.colour.ColourManager;
+import net.sf.taverna.t2.workbench.edits.EditManager;
+import net.sf.taverna.t2.workbench.file.FileManager;
+import net.sf.taverna.t2.workbench.ui.actions.activity.HTMLBasedActivityContextualView;
+import uk.org.taverna.configuration.app.ApplicationConfiguration;
+import uk.org.taverna.scufl2.api.activity.Activity;
+import uk.org.taverna.scufl2.api.port.InputActivityPort;
+import uk.org.taverna.scufl2.api.port.OutputActivityPort;
+
+/**
+ * A simple non editable HTML table view over a {@link BeanshellActivity}.
+ * Clicking on the configure button shows the editable {@link BeanshellConfigView}
+ *
+ * @author Ian Dunlop
+ * @author Stuart Owen
+ * @author David Withers
+ */
+@SuppressWarnings("serial")
+public class BeanshellContextualView extends HTMLBasedActivityContextualView {
+
+	private EditManager editManager;
+	private FileManager fileManager;
+	private final ActivityIconManager activityIconManager;
+	private final ServiceDescriptionRegistry serviceDescriptionRegistry;
+	private final ApplicationConfiguration applicationConfiguration;
+
+	public BeanshellContextualView(Activity activity, EditManager editManager,
+			FileManager fileManager, ActivityIconManager activityIconManager,
+			ColourManager colourManager, ServiceDescriptionRegistry serviceDescriptionRegistry,
+			ApplicationConfiguration applicationConfiguration) {
+		super(activity, colourManager);
+		this.editManager = editManager;
+		this.fileManager = fileManager;
+		this.activityIconManager = activityIconManager;
+		this.serviceDescriptionRegistry = serviceDescriptionRegistry;
+		this.applicationConfiguration = applicationConfiguration;
+		init();
+	}
+
+	private void init() {
+	}
+
+	@Override
+	protected String getRawTableRowsHtml() {
+		StringBuilder html = new StringBuilder();
+		html.append("<tr><th>Input Port Name</th><th>Depth</th></tr>");
+		for (InputActivityPort inputActivityPort : getActivity().getInputPorts()) {
+			html.append("<tr><td>" + inputActivityPort.getName() + "</td><td>");
+			html.append(inputActivityPort.getDepth() + "</td></tr>");
+		}
+		html.append("<tr><th>Output Port Name</th><th>Depth</th></tr>");
+		for (OutputActivityPort outputActivityPort : getActivity().getOutputPorts()) {
+			html.append("<tr><td>" + outputActivityPort.getName() + "</td><td>");
+			html.append(outputActivityPort.getDepth() + "</td></tr>");
+		}
+		return html.toString();
+	}
+
+	@Override
+	public String getViewTitle() {
+		return "Beanshell service";
+	}
+
+	@Override
+	public Action getConfigureAction(Frame owner) {
+		return new BeanshellActivityConfigurationAction(getActivity(), owner, editManager,
+				fileManager, activityIconManager, serviceDescriptionRegistry, applicationConfiguration);
+	}
+
+	@Override
+	public int getPreferredPosition() {
+		return 100;
+	}
+
+}
diff --git a/taverna-beanshell-activity-ui/src/main/resources/META-INF/services/net.sf.taverna.t2.servicedescriptions.ServiceDescriptionProvider b/taverna-beanshell-activity-ui/src/main/resources/META-INF/services/net.sf.taverna.t2.servicedescriptions.ServiceDescriptionProvider
new file mode 100644
index 0000000..a77db8d
--- /dev/null
+++ b/taverna-beanshell-activity-ui/src/main/resources/META-INF/services/net.sf.taverna.t2.servicedescriptions.ServiceDescriptionProvider
@@ -0,0 +1 @@
+net.sf.taverna.t2.activities.beanshell.servicedescriptions.BeanshellTemplateService
diff --git a/taverna-beanshell-activity-ui/src/main/resources/META-INF/services/net.sf.taverna.t2.ui.menu.MenuComponent b/taverna-beanshell-activity-ui/src/main/resources/META-INF/services/net.sf.taverna.t2.ui.menu.MenuComponent
new file mode 100644
index 0000000..a3c71cd
--- /dev/null
+++ b/taverna-beanshell-activity-ui/src/main/resources/META-INF/services/net.sf.taverna.t2.ui.menu.MenuComponent
@@ -0,0 +1,3 @@
+net.sf.taverna.t2.activities.beanshell.menu.AddBeanshellTemplateAction
+net.sf.taverna.t2.activities.beanshell.menu.AddBeanshellTemplateMenuAction
+net.sf.taverna.t2.activities.beanshell.menu.ConfigureBeanshellMenuAction
diff --git a/taverna-beanshell-activity-ui/src/main/resources/META-INF/services/net.sf.taverna.t2.workbench.activityicons.ActivityIconSPI b/taverna-beanshell-activity-ui/src/main/resources/META-INF/services/net.sf.taverna.t2.workbench.activityicons.ActivityIconSPI
new file mode 100644
index 0000000..a268bf1
--- /dev/null
+++ b/taverna-beanshell-activity-ui/src/main/resources/META-INF/services/net.sf.taverna.t2.workbench.activityicons.ActivityIconSPI
@@ -0,0 +1 @@
+net.sf.taverna.t2.activities.beanshell.servicedescriptions.BeanshellActivityIcon
\ No newline at end of file
diff --git a/taverna-beanshell-activity-ui/src/main/resources/META-INF/services/net.sf.taverna.t2.workbench.ui.views.contextualviews.activity.ContextualViewFactory b/taverna-beanshell-activity-ui/src/main/resources/META-INF/services/net.sf.taverna.t2.workbench.ui.views.contextualviews.activity.ContextualViewFactory
new file mode 100644
index 0000000..dcdf598
--- /dev/null
+++ b/taverna-beanshell-activity-ui/src/main/resources/META-INF/services/net.sf.taverna.t2.workbench.ui.views.contextualviews.activity.ContextualViewFactory
@@ -0,0 +1 @@
+net.sf.taverna.t2.activities.beanshell.views.BeanshellActivityViewFactory
\ No newline at end of file
diff --git a/taverna-beanshell-activity-ui/src/main/resources/META-INF/spring/beanshell-activity-ui-context-osgi.xml b/taverna-beanshell-activity-ui/src/main/resources/META-INF/spring/beanshell-activity-ui-context-osgi.xml
new file mode 100644
index 0000000..58a3e18
--- /dev/null
+++ b/taverna-beanshell-activity-ui/src/main/resources/META-INF/spring/beanshell-activity-ui-context-osgi.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans:beans xmlns="http://www.springframework.org/schema/osgi" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xmlns:beans="http://www.springframework.org/schema/beans"
+	xsi:schemaLocation="http://www.springframework.org/schema/beans
+                      http://www.springframework.org/schema/beans/spring-beans.xsd
+                      http://www.springframework.org/schema/osgi
+                      http://www.springframework.org/schema/osgi/spring-osgi.xsd">
+
+	<service ref="BeanshellActivityIcon" interface="net.sf.taverna.t2.workbench.activityicons.ActivityIconSPI" />
+
+	<service ref="BeanshellTemplateService" interface="net.sf.taverna.t2.servicedescriptions.ServiceDescriptionProvider" />
+
+	<service ref="AddBeanshellTemplateAction" auto-export="interfaces" />
+	<service ref="AddBeanshellTemplateMenuAction" auto-export="interfaces" />
+	<service ref="ConfigureBeanshellMenuAction" auto-export="interfaces" />
+
+	<service ref="BeanshellActivityViewFactory" interface="net.sf.taverna.t2.workbench.ui.views.contextualviews.activity.ContextualViewFactory" />
+
+	<reference id="editManager" interface="net.sf.taverna.t2.workbench.edits.EditManager" />
+	<reference id="fileManager" interface="net.sf.taverna.t2.workbench.file.FileManager" />
+	<reference id="menuManager" interface="net.sf.taverna.t2.ui.menu.MenuManager" />
+	<reference id="selectionManager" interface="net.sf.taverna.t2.workbench.selection.SelectionManager" />
+	<reference id="activityIconManager" interface="net.sf.taverna.t2.workbench.activityicons.ActivityIconManager" />
+	<reference id="colourManager" interface="net.sf.taverna.t2.workbench.configuration.colour.ColourManager" />
+	<reference id="serviceDescriptionRegistry" interface="net.sf.taverna.t2.servicedescriptions.ServiceDescriptionRegistry" />
+	<reference id="serviceRegistry" interface="uk.org.taverna.commons.services.ServiceRegistry" />
+	<reference id="applicationConfiguration" interface="uk.org.taverna.configuration.app.ApplicationConfiguration" />
+
+</beans:beans>
diff --git a/taverna-beanshell-activity-ui/src/main/resources/META-INF/spring/beanshell-activity-ui-context.xml b/taverna-beanshell-activity-ui/src/main/resources/META-INF/spring/beanshell-activity-ui-context.xml
new file mode 100644
index 0000000..fc6d5d4
--- /dev/null
+++ b/taverna-beanshell-activity-ui/src/main/resources/META-INF/spring/beanshell-activity-ui-context.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://www.springframework.org/schema/beans
+                      http://www.springframework.org/schema/beans/spring-beans.xsd">
+
+	<bean id="BeanshellActivityIcon" class="net.sf.taverna.t2.activities.beanshell.servicedescriptions.BeanshellActivityIcon" />
+
+	<bean id="BeanshellTemplateService" class="net.sf.taverna.t2.activities.beanshell.servicedescriptions.BeanshellTemplateService" />
+
+	<bean id="AddBeanshellTemplateAction" class="net.sf.taverna.t2.activities.beanshell.menu.AddBeanshellTemplateAction">
+			<property name="editManager" ref="editManager" />
+			<property name="menuManager" ref="menuManager" />
+			<property name="selectionManager" ref="selectionManager" />
+			<property name="activityIconManager" ref="activityIconManager" />
+			<property name="serviceDescriptionRegistry" ref="serviceDescriptionRegistry" />
+			<property name="serviceRegistry" ref="serviceRegistry" />
+	</bean>
+	<bean id="AddBeanshellTemplateMenuAction" class="net.sf.taverna.t2.activities.beanshell.menu.AddBeanshellTemplateMenuAction">
+			<property name="editManager" ref="editManager" />
+			<property name="menuManager" ref="menuManager" />
+			<property name="selectionManager" ref="selectionManager" />
+			<property name="activityIconManager" ref="activityIconManager" />
+			<property name="serviceDescriptionRegistry" ref="serviceDescriptionRegistry" />
+			<property name="serviceRegistry" ref="serviceRegistry" />
+	</bean>
+	<bean id="ConfigureBeanshellMenuAction" class="net.sf.taverna.t2.activities.beanshell.menu.ConfigureBeanshellMenuAction">
+			<property name="editManager" ref="editManager" />
+			<property name="fileManager" ref="fileManager" />
+			<property name="activityIconManager" ref="activityIconManager" />
+			<property name="serviceDescriptionRegistry" ref="serviceDescriptionRegistry" />
+			<property name="applicationConfiguration" ref="applicationConfiguration" />
+	</bean>
+
+	<bean id="BeanshellActivityViewFactory" class="net.sf.taverna.t2.activities.beanshell.views.BeanshellActivityViewFactory">
+			<property name="editManager" ref="editManager" />
+			<property name="fileManager" ref="fileManager" />
+			<property name="activityIconManager" ref="activityIconManager" />
+			<property name="colourManager" ref="colourManager" />
+			<property name="serviceDescriptionRegistry" ref="serviceDescriptionRegistry" />
+			<property name="applicationConfiguration" ref="applicationConfiguration" />
+	</bean>
+
+</beans>
diff --git a/taverna-beanshell-activity-ui/src/main/resources/beanshell.png b/taverna-beanshell-activity-ui/src/main/resources/beanshell.png
new file mode 100644
index 0000000..8f6edfb
--- /dev/null
+++ b/taverna-beanshell-activity-ui/src/main/resources/beanshell.png
Binary files differ
diff --git a/taverna-beanshell-activity-ui/src/main/resources/net/sf/taverna/t2/activities/beanshell/views/keys.txt b/taverna-beanshell-activity-ui/src/main/resources/net/sf/taverna/t2/activities/beanshell/views/keys.txt
new file mode 100644
index 0000000..15cb51b
--- /dev/null
+++ b/taverna-beanshell-activity-ui/src/main/resources/net/sf/taverna/t2/activities/beanshell/views/keys.txt
@@ -0,0 +1,90 @@
+++
+--
++
+-
+~
+!
+*
+/
+%
+<<
+>>
+>>>
+<
+>
+<=
+>=
+==
+!=
+&
+^
+|
+&&
+||
+:
+=
++=
+-=
+*=
+/=
+%=
+&=
+^=
+|=
+<<=
+>>=
+>>>=
+=
+abstract
+assert
+boolean
+break
+byte
+case
+catch
+char
+class
+const
+continue
+default
+do
+double
+else
+enum
+extends
+false
+final
+finally
+float
+for
+goto
+if
+implements
+import
+instanceof
+int
+interface
+long
+native
+new
+null
+package
+private
+protected
+public
+return
+short
+static
+strictfp
+super
+switch
+synchronized
+this
+throw
+throws
+transient
+true
+try
+void
+volatile
+while 
\ No newline at end of file
diff --git a/taverna-external-tool-activity-ui/pom.xml b/taverna-external-tool-activity-ui/pom.xml
new file mode 100644
index 0000000..376cd5c
--- /dev/null
+++ b/taverna-external-tool-activity-ui/pom.xml
@@ -0,0 +1,108 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>net.sf.taverna</groupId>
+    <artifactId>taverna-parent</artifactId>
+    <version>3.0.1-SNAPSHOT</version>
+  </parent>
+	<groupId>net.sf.taverna.t2.ui-activities</groupId>
+	<artifactId>external-tool-activity-ui</artifactId>
+	<name>Taverna 2 ExternalTool Activity UI</name>
+	<dependencies>
+		<dependency>
+			<groupId>net.sf.taverna.t2.ui-api</groupId>
+			<artifactId>menu-api</artifactId>
+			<version>${t2.ui.api.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>net.sf.taverna.t2.ui-components</groupId>
+			<artifactId>graph-view</artifactId>
+			<version>${t2.ui.components.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>net.sf.taverna.t2.ui-api</groupId>
+			<artifactId>activity-icons-api</artifactId>
+			<version>${t2.ui.api.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>net.sf.taverna.t2.ui-api</groupId>
+			<artifactId>activity-palette-api</artifactId>
+			<version>${t2.ui.api.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>net.sf.taverna.t2.activities</groupId>
+			<artifactId>wsdl-activity</artifactId>
+			<version>${t2.activities.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>net.sf.taverna.t2.ui-impl</groupId>
+			<artifactId>contextual-views-impl</artifactId>
+			<version>${t2.ui.impl.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>net.sf.taverna.t2.ui-api</groupId>
+			<artifactId>contextual-views-api</artifactId>
+			<version>${t2.ui.api.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>net.sf.taverna.t2.ui-components</groupId>
+			<artifactId>workflow-view</artifactId>
+			<version>${t2.ui.components.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>net.sf.taverna.t2.ui-api</groupId>
+			<artifactId>activity-tools</artifactId>
+			<version>${t2.ui.api.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>net.sf.taverna.t2.ui-impl</groupId>
+			<artifactId>renderers-impl</artifactId>
+			<version>${t2.ui.impl.version}</version>
+		</dependency>
+
+		<!--  testing dependencies -->
+		<dependency>
+			<groupId>junit</groupId>
+			<artifactId>junit</artifactId>
+                        <version>${junit.version}</version>
+			<scope>test</scope>
+		</dependency>
+		<dependency>
+			<groupId>net.sf.taverna.t2.ui-impl</groupId>
+			<artifactId>activity-palette-impl</artifactId>
+			<version>${t2.ui.impl.version}</version>
+			<scope>test</scope>
+		</dependency>
+
+		<!-- function dependencies for invocation -->
+		<dependency>
+			<groupId>net.sf.taverna.t2.activities</groupId>
+			<artifactId>external-tool-activity</artifactId>
+			<version>${t2.activities.version}</version>
+		</dependency>
+
+	</dependencies>
+        <repositories>
+                <repository>
+                        <releases />
+                        <snapshots>
+                                <enabled>false</enabled>
+                        </snapshots>
+                        <id>mygrid-repository</id>
+                        <name>myGrid Repository</name>
+                        <url>http://www.mygrid.org.uk/maven/repository</url>
+                </repository>
+                <repository>
+                        <releases>
+                                <enabled>false</enabled>
+                        </releases>
+                        <snapshots />
+                        <id>mygrid-snapshot-repository</id>
+                        <name>myGrid Snapshot Repository</name>
+                        <url>http://www.mygrid.org.uk/maven/snapshot-repository</url>
+                </repository>
+        </repositories>
+</project>
+
diff --git a/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/actions/ExternalToolActivityConfigureAction.java b/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/actions/ExternalToolActivityConfigureAction.java
new file mode 100644
index 0000000..398ee7c
--- /dev/null
+++ b/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/actions/ExternalToolActivityConfigureAction.java
@@ -0,0 +1,83 @@
+/*******************************************************************************
+ * Copyright (C) 2009 Hajo Nils Krabbenhoeft, INB, University of Luebeck
+ * modified 2010 Hajo Nils Krabbenhoeft, spratpix GmbH & Co. KG
+ *
+ *  Modifications to the initial code base are copyright of their
+ *  respective authors, or their employers as appropriate.
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1 of
+ *  the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+
+package net.sf.taverna.t2.activities.externaltool.actions;
+
+import java.awt.Frame;
+import java.awt.event.ActionEvent;
+
+import javax.swing.Action;
+
+import net.sf.taverna.t2.activities.externaltool.ExternalToolActivity;
+import net.sf.taverna.t2.activities.externaltool.ExternalToolActivityConfigurationBean;
+import net.sf.taverna.t2.activities.externaltool.views.ExternalToolConfigView;
+import net.sf.taverna.t2.workbench.activityicons.ActivityIconManager;
+import net.sf.taverna.t2.workbench.edits.EditManager;
+import net.sf.taverna.t2.workbench.file.FileManager;
+import net.sf.taverna.t2.workbench.ui.actions.activity.ActivityConfigurationAction;
+import net.sf.taverna.t2.workbench.ui.views.contextualviews.activity.ActivityConfigurationDialog;
+
+/**
+ * This class implements an ActivityConfigurationAction to configure the ExternalToolActivity
+ * plugin. The configuration action is called "Configure UseCase invocation" and is implemented in
+ * the KnowARCConfigurationDialog inside the knowarc-usecases maven artifact.
+ *
+ * @author Hajo Nils Krabbenhoeft
+ */
+@SuppressWarnings("serial")
+public class ExternalToolActivityConfigureAction extends
+		ActivityConfigurationAction<ExternalToolActivity, ExternalToolActivityConfigurationBean> {
+
+	private final Frame owner;
+	private final EditManager editManager;
+	private final FileManager fileManager;
+
+	public ExternalToolActivityConfigureAction(ExternalToolActivity activity, Frame owner,
+			EditManager editManager, FileManager fileManager, ActivityIconManager activityIconManager) {
+		super(activity, activityIconManager);
+		this.editManager = editManager;
+		this.fileManager = fileManager;
+		putValue(Action.NAME, "Configure tool invocation");
+		this.owner = owner;
+	}
+
+	public void actionPerformed(ActionEvent e) {
+		/*
+		 * if (getActivity().getConfiguration() instanceof
+		 * RegisteredExternalToolActivityConfigurationBean) { new KnowARCConfigurationDialog(owner,
+		 * false, KnowARCConfigurationFactory.getConfiguration()).setVisible(true); } else
+		 */{
+			ActivityConfigurationDialog currentDialog = ActivityConfigurationAction
+					.getDialog(getActivity());
+			if (currentDialog != null) {
+				currentDialog.toFront();
+				return;
+			}
+			final ExternalToolConfigView externalToolConfigView = new ExternalToolConfigView(
+					(ExternalToolActivity) getActivity());
+			final ActivityConfigurationDialog<ExternalToolActivity, ExternalToolActivityConfigurationBean> dialog = new ActivityConfigurationDialog<ExternalToolActivity, ExternalToolActivityConfigurationBean>(
+					getActivity(), externalToolConfigView, editManager, fileManager);
+
+			ActivityConfigurationAction.setDialog(getActivity(), dialog, fileManager);
+		}
+	}
+}
diff --git a/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/configuration/ToolInvocationConfiguration.java b/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/configuration/ToolInvocationConfiguration.java
new file mode 100644
index 0000000..0877045
--- /dev/null
+++ b/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/configuration/ToolInvocationConfiguration.java
@@ -0,0 +1,57 @@
+/**
+ *
+ */
+package net.sf.taverna.t2.activities.externaltool.configuration;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import uk.org.taverna.configuration.AbstractConfigurable;
+
+
+/**
+ * @author alanrw
+ *
+ */
+public class ToolInvocationConfiguration extends AbstractConfigurable {
+
+	private static ToolInvocationConfiguration instance;
+
+	private Map<String, String> defaultPropertyMap;
+
+	public static ToolInvocationConfiguration getInstance() {
+		if (instance == null) {
+			instance = new ToolInvocationConfiguration();
+		}
+		return instance;
+	}
+
+	@Override
+	public String getCategory() {
+		return "general";
+	}
+
+	@Override
+	public Map<String, String> getDefaultPropertyMap() {
+		if (defaultPropertyMap == null) {
+			defaultPropertyMap = new HashMap<String, String>();
+		}
+		return defaultPropertyMap;
+	}
+
+	@Override
+	public String getDisplayName() {
+		return "Tool invocation";
+	}
+
+	@Override
+	public String getFilePrefix() {
+		return "ToolInvocation";
+	}
+
+	@Override
+	public String getUUID() {
+		return "B611F5C2-EB49-479E-B01A-7F3F56E6918A";
+	}
+
+}
diff --git a/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/manager/GroupPanel.java b/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/manager/GroupPanel.java
new file mode 100644
index 0000000..8f62787
--- /dev/null
+++ b/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/manager/GroupPanel.java
@@ -0,0 +1,113 @@
+/*******************************************************************************
+ * Copyright (C) 2007 The University of Manchester
+ *
+ *  Modifications to the initial code base are copyright of their
+ *  respective authors, or their employers as appropriate.
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1 of
+ *  the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+package net.sf.taverna.t2.activities.externaltool.manager;
+
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+
+import javax.swing.JComboBox;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JTextField;
+import javax.swing.border.EmptyBorder;
+
+import net.sf.taverna.t2.activities.externaltool.manager.impl.InvocationGroupManagerImpl;
+
+/**
+ * UI for creating/editing dataflow input ports.
+ *
+ * @author David Withers
+ */
+public class GroupPanel extends JPanel {
+
+	private static final long serialVersionUID = 1L;
+
+	private JTextField groupNameField;
+
+	private JComboBox mechanismComboBox;
+
+	private static InvocationGroupManager manager = InvocationGroupManagerImpl.getInstance();
+
+	public GroupPanel(Object[] mechanisms) {
+		super(new GridBagLayout());
+
+		groupNameField = new JTextField();
+
+
+		setBorder(new EmptyBorder(10, 10, 10, 10));
+
+		GridBagConstraints constraints = new GridBagConstraints();
+
+		constraints.anchor = GridBagConstraints.WEST;
+		constraints.gridx = 0;
+		constraints.gridy = 0;
+		constraints.ipadx = 10;
+		add(new JLabel("Name:"), constraints);
+
+		constraints.gridx = 1;
+		constraints.gridwidth = 2;
+		constraints.ipadx = 0;
+		constraints.weightx = 1d;
+		constraints.fill = GridBagConstraints.HORIZONTAL;
+		add(groupNameField, constraints);
+
+		constraints.gridx = 0;
+		constraints.gridy = 1;
+		constraints.gridwidth = 1;
+		constraints.weightx = 0d;
+		constraints.fill = GridBagConstraints.NONE;
+		constraints.ipadx = 10;
+		constraints.insets = new Insets(10, 0, 0, 0);
+		add(new JLabel("Explicit location:"), constraints);
+
+		mechanismComboBox = new JComboBox(mechanisms);
+		mechanismComboBox.setSelectedItem(manager.getDefaultMechanism());
+
+		constraints.gridx = 1;
+		constraints.gridwidth = 2;
+		constraints.ipadx = 0;
+		add(mechanismComboBox, constraints);
+	}
+
+	/**
+	 * Returns the portNameField.
+	 *
+	 * @return the portNameField
+	 */
+	public JTextField getGroupNameField() {
+		return groupNameField;
+	}
+
+	/**
+	 * Returns the group name.
+	 *
+	 * @return the group name
+	 */
+	public String getGroupName() {
+		return groupNameField.getText();
+	}
+
+	public InvocationMechanism getSelectedMechanism() {
+		return (InvocationMechanism) mechanismComboBox.getSelectedItem();
+	}
+
+}
diff --git a/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/manager/InvocationGroupManagerShutdownHook.java b/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/manager/InvocationGroupManagerShutdownHook.java
new file mode 100644
index 0000000..3d54b26
--- /dev/null
+++ b/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/manager/InvocationGroupManagerShutdownHook.java
@@ -0,0 +1,34 @@
+/**
+ * 
+ */
+package net.sf.taverna.t2.activities.externaltool.manager;
+
+import net.sf.taverna.t2.activities.externaltool.manager.impl.InvocationGroupManagerImpl;
+import net.sf.taverna.t2.workbench.ShutdownSPI;
+
+/**
+ * @author alanrw
+ *
+ */
+public class InvocationGroupManagerShutdownHook implements ShutdownSPI {
+
+	/* (non-Javadoc)
+	 * @see net.sf.taverna.t2.workbench.ShutdownSPI#positionHint()
+	 */
+	@Override
+	public int positionHint() {
+		return 710;
+	}
+
+	/* (non-Javadoc)
+	 * @see net.sf.taverna.t2.workbench.ShutdownSPI#shutdown()
+	 */
+	@Override
+	public boolean shutdown() {
+		InvocationGroupManager manager = InvocationGroupManagerImpl.getInstance();
+		manager.saveConfiguration();
+		manager.persistInvocations();
+		return true;
+	}
+
+}
diff --git a/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/manager/InvocationGroupManagerStartupHook.java b/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/manager/InvocationGroupManagerStartupHook.java
new file mode 100644
index 0000000..43cf4df
--- /dev/null
+++ b/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/manager/InvocationGroupManagerStartupHook.java
@@ -0,0 +1,47 @@
+/*******************************************************************************

+ * Copyright (C) 2010 The University of Manchester   

+ * 

+ *  Modifications to the initial code base are copyright of their

+ *  respective authors, or their employers as appropriate.

+ * 

+ *  This program is free software; you can redistribute it and/or

+ *  modify it under the terms of the GNU Lesser General Public License

+ *  as published by the Free Software Foundation; either version 2.1 of

+ *  the License, or (at your option) any later version.

+ *    

+ *  This program is distributed in the hope that it will be useful, but

+ *  WITHOUT ANY WARRANTY; without even the implied warranty of

+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU

+ *  Lesser General Public License for more details.

+ *    

+ *  You should have received a copy of the GNU Lesser General Public

+ *  License along with this program; if not, write to the Free Software

+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307

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

+package net.sf.taverna.t2.activities.externaltool.manager;

+

+import net.sf.taverna.t2.activities.externaltool.manager.impl.InvocationGroupManagerImpl;

+import net.sf.taverna.t2.workbench.StartupSPI;

+

+/**

+ * Load previously saved workflow ids that were scheduled to be deleted before

+ * previous Taverna shutdown, and initiate deletion of them now.

+ * 

+ * @see StoreRunIdsToDeleteLaterShutdownHook

+ * @see DatabaseCleanup

+ * 

+ * @author Stian Soiland-Reyes

+ * 

+ */

+public class InvocationGroupManagerStartupHook implements StartupSPI {

+

+	public int positionHint() {

+		return 900;

+	}

+

+	public boolean startup() {

+		InvocationGroupManagerImpl.getInstance().loadInvocations();

+		return true;

+	}

+

+}

diff --git a/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/manager/InvocationMechanismEditor.java b/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/manager/InvocationMechanismEditor.java
new file mode 100644
index 0000000..495d22b
--- /dev/null
+++ b/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/manager/InvocationMechanismEditor.java
@@ -0,0 +1,28 @@
+/**
+ *
+ */
+package net.sf.taverna.t2.activities.externaltool.manager;
+
+import javax.swing.JPanel;
+
+/**
+ * @author alanrw
+ *
+ */
+public abstract class InvocationMechanismEditor<T extends InvocationMechanism> extends JPanel {
+
+	public abstract String getName();
+
+	public abstract boolean canShow(Class<?> c);
+
+	public abstract void show(T invocationMechanism);
+
+	public abstract T updateInvocationMechanism();
+
+	public abstract InvocationMechanism createMechanism(String mechanismName);
+
+	public boolean isSingleton() {
+		return false;
+	}
+
+}
diff --git a/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/manager/MechanismPanel.java b/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/manager/MechanismPanel.java
new file mode 100644
index 0000000..c068d56
--- /dev/null
+++ b/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/manager/MechanismPanel.java
@@ -0,0 +1,121 @@
+/*******************************************************************************
+ * Copyright (C) 2007 The University of Manchester
+ *
+ *  Modifications to the initial code base are copyright of their
+ *  respective authors, or their employers as appropriate.
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1 of
+ *  the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+package net.sf.taverna.t2.activities.externaltool.manager;
+
+import java.awt.Component;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+import java.util.List;
+
+import javax.swing.JComboBox;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JTextField;
+import javax.swing.border.EmptyBorder;
+
+/**
+ * UI for creating/editing dataflow input ports.
+ *
+ * @author David Withers
+ */
+public class MechanismPanel extends JPanel {
+
+	private static final long serialVersionUID = 1L;
+
+	private JTextField mechanismNameField;
+
+	private JComboBox mechanismTypeSelector;
+
+	public MechanismPanel(List<InvocationMechanismEditor<?>> invocationMechanismEditors) {
+		super(new GridBagLayout());
+
+		mechanismNameField = new JTextField();
+
+
+		setBorder(new EmptyBorder(10, 10, 10, 10));
+
+		GridBagConstraints constraints = new GridBagConstraints();
+
+		constraints.anchor = GridBagConstraints.WEST;
+		constraints.gridx = 0;
+		constraints.gridy = 0;
+		constraints.ipadx = 10;
+		add(new JLabel("Name:"), constraints);
+
+		constraints.gridx = 1;
+		constraints.gridwidth = 2;
+		constraints.ipadx = 0;
+		constraints.weightx = 1d;
+		constraints.fill = GridBagConstraints.HORIZONTAL;
+		add(mechanismNameField, constraints);
+
+		constraints.gridx = 0;
+		constraints.gridy = 1;
+		constraints.gridwidth = 1;
+		constraints.weightx = 0d;
+		constraints.fill = GridBagConstraints.NONE;
+		constraints.ipadx = 10;
+		constraints.insets = new Insets(10, 0, 0, 0);
+		add(new JLabel("Type:"), constraints);
+
+		mechanismTypeSelector = new JComboBox();
+		for (InvocationMechanismEditor<?> ime : invocationMechanismEditors) {
+			if (!ime.isSingleton()) {
+				mechanismTypeSelector.addItem(ime.getName());
+			}
+		}
+		constraints.gridx = 1;
+		constraints.gridwidth = 2;
+		constraints.ipadx = 0;
+		add(mechanismTypeSelector, constraints);
+
+
+	}
+
+	/**
+	 * Returns the portNameField.
+	 *
+	 * @return the portNameField
+	 */
+	public JTextField getMechanismNameField() {
+		return mechanismNameField;
+	}
+
+	/**
+	 * Returns the port name.
+	 *
+	 * @return the port name
+	 */
+	public String getMechanismName() {
+		return mechanismNameField.getText();
+	}
+
+	public String getMechanismTypeName() {
+		return (String) mechanismTypeSelector.getSelectedItem();
+	}
+
+	public Component getMechanismTypeSelector() {
+		return mechanismTypeSelector;
+	}
+
+
+}
diff --git a/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/manager/ToolInvocationConfigurationPanel.java b/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/manager/ToolInvocationConfigurationPanel.java
new file mode 100644
index 0000000..22500cd
--- /dev/null
+++ b/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/manager/ToolInvocationConfigurationPanel.java
@@ -0,0 +1,379 @@
+/**
+ *
+ */
+package net.sf.taverna.t2.activities.externaltool.manager;
+
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.FlowLayout;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import javax.swing.AbstractAction;
+import javax.swing.DefaultListCellRenderer;
+import javax.swing.DefaultListModel;
+import javax.swing.JButton;
+import javax.swing.JComboBox;
+import javax.swing.JLabel;
+import javax.swing.JList;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTextArea;
+import javax.swing.ListSelectionModel;
+import javax.swing.SwingUtilities;
+import javax.swing.border.EmptyBorder;
+
+import net.sf.taverna.t2.activities.externaltool.manager.impl.InvocationGroupManagerImpl;
+import net.sf.taverna.t2.lang.observer.Observable;
+import net.sf.taverna.t2.lang.observer.Observer;
+import net.sf.taverna.t2.lang.ui.DeselectingButton;
+import net.sf.taverna.t2.lang.ui.ValidatingUserInputDialog;
+import net.sf.taverna.t2.workbench.helper.Helper;
+
+/**
+ * @author alanrw
+ *
+ */
+public class ToolInvocationConfigurationPanel extends JPanel implements
+		Observer<InvocationManagerEvent> {
+
+	public static final String HEADER_TEXT = "A tool can be set to run at an explicit location (e.g. on a specificic machine or one of a set of machines). Alternatively, it can be set to run at a symbolic location, which means the tool will then be run at the explicit location pointed to by the symbolic location.";
+
+	private static InvocationGroupManagerImpl manager = InvocationGroupManagerImpl.getInstance();
+
+	private final List<InvocationMechanismEditor<?>> invocationMechanismEditors;
+
+	private JTextArea headerText;
+
+	private static String EXPLICIT_LOCATIONS = "explicit locations";
+	private static String SYMBOLIC_LOCATIONS = "symbolic locations";
+
+	private List<MechanismCreator> mechanismCreators;
+
+	JList locationList = new JList();
+
+	DefaultListModel groupListModel = new DefaultListModel();
+	DefaultListModel mechanismListModel = new DefaultListModel();
+	JComboBox locationTypeCombo = new JComboBox(new String[] { EXPLICIT_LOCATIONS,
+			SYMBOLIC_LOCATIONS });
+
+	public ToolInvocationConfigurationPanel(List<MechanismCreator> mechanismCreators,
+			List<InvocationMechanismEditor<?>> invocationMechanismEditors) {
+		super();
+		this.mechanismCreators = mechanismCreators;
+		this.invocationMechanismEditors = invocationMechanismEditors;
+		manager.addObserver(this);
+
+		this.setLayout(new GridBagLayout());
+		GridBagConstraints gbc = new GridBagConstraints();
+
+		headerText = new JTextArea(HEADER_TEXT);
+		headerText.setLineWrap(true);
+		headerText.setWrapStyleWord(true);
+		headerText.setEditable(false);
+		headerText.setFocusable(false);
+		headerText.setBorder(new EmptyBorder(10, 10, 10, 10));
+
+		gbc.anchor = GridBagConstraints.WEST;
+		gbc.insets = new Insets(0, 0, 10, 0);
+		gbc.gridx = 0;
+		gbc.gridy = 0;
+		gbc.gridwidth = 1;
+		gbc.weightx = 1.0;
+		gbc.weighty = 0.0;
+		gbc.fill = GridBagConstraints.HORIZONTAL;
+		add(headerText, gbc);
+
+		JPanel locationPanel = new JPanel(new BorderLayout());
+		JPanel subPanel = new JPanel(new FlowLayout());
+		JLabel modify = new JLabel("Modify:");
+
+		locationTypeCombo.setSelectedItem(EXPLICIT_LOCATIONS);
+		locationTypeCombo.addActionListener(new ActionListener() {
+
+			@Override
+			public void actionPerformed(ActionEvent e) {
+				switchList();
+			}
+		});
+		subPanel.add(modify);
+		subPanel.add(locationTypeCombo);
+
+		populateLists();
+		switchList();
+		locationList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+		locationList.setCellRenderer(new DefaultListCellRenderer() {
+			public Component getListCellRendererComponent(JList list, Object value, int index,
+					boolean isSelected, boolean cellHasFocus) {
+				Object toShow = value;
+				if (value instanceof InvocationGroup) {
+					InvocationGroup invocationGroup = (InvocationGroup) value;
+					toShow = invocationGroup.getName() + "  -->  "
+							+ invocationGroup.getMechanismName();
+				}
+				return super.getListCellRendererComponent(list, toShow, index, isSelected,
+						cellHasFocus);
+			}
+		});
+		locationPanel.add(new JScrollPane(locationList), BorderLayout.CENTER);
+		locationPanel.add(subPanel, BorderLayout.NORTH);
+
+		JPanel buttonPanel = new JPanel(new FlowLayout());
+		JButton helpButton = new DeselectingButton("Help", new AbstractAction() {
+
+			public void actionPerformed(ActionEvent e) {
+				Helper.showHelp(ToolInvocationConfigurationPanel.this);
+			}
+		});
+
+		buttonPanel.add(helpButton);
+
+		buttonPanel.add(addLocationButton());
+		buttonPanel.add(removeLocationButton());
+		buttonPanel.add(editLocationButton());
+		locationPanel.add(buttonPanel, BorderLayout.SOUTH);
+
+		gbc.gridy++;
+		gbc.weighty = 1;
+
+		gbc.fill = GridBagConstraints.BOTH;
+		gbc.anchor = GridBagConstraints.SOUTH;
+		gbc.insets = new Insets(10, 0, 0, 0);
+		this.add(locationPanel, gbc);
+	}
+
+	private void switchList() {
+		if (isShowingGroups()) {
+			locationList.setModel(groupListModel);
+		} else {
+			locationList.setModel(mechanismListModel);
+		}
+	}
+
+	private void populateLists() {
+		poopulateGroupList();
+		populateMechanismList();
+	}
+
+	private void populateMechanismList() {
+		Object currentSelection = locationList.getSelectedValue();
+		ArrayList<InvocationMechanism> mechanisms = new ArrayList<InvocationMechanism>();
+		mechanisms.addAll(manager.getMechanisms());
+		Collections.sort(mechanisms, new Comparator<InvocationMechanism>() {
+
+			@Override
+			public int compare(InvocationMechanism o1, InvocationMechanism o2) {
+				return o1.getName().compareTo(o2.getName());
+			}
+		});
+		mechanismListModel.clear();
+		for (InvocationMechanism m : mechanisms) {
+			mechanismListModel.addElement(m);
+		}
+		if ((currentSelection != null) && !isShowingGroups()) {
+			locationList.setSelectedValue(currentSelection, true);
+		}
+	}
+
+	private void poopulateGroupList() {
+		Object currentSelection = locationList.getSelectedValue();
+		ArrayList<InvocationGroup> groups = new ArrayList<InvocationGroup>();
+		groups.addAll(manager.getInvocationGroups());
+		Collections.sort(groups, new Comparator<InvocationGroup>() {
+
+			@Override
+			public int compare(InvocationGroup o1, InvocationGroup o2) {
+				return o1.getName().compareTo(o2.getName());
+			}
+		});
+		groupListModel.clear();
+		for (InvocationGroup g : groups) {
+			groupListModel.addElement(g);
+		}
+		if ((currentSelection != null) && isShowingGroups()) {
+			locationList.setSelectedValue(currentSelection, true);
+		}
+	}
+
+	private boolean isShowingGroups() {
+		return (locationTypeCombo.getSelectedItem().equals(SYMBOLIC_LOCATIONS));
+	}
+
+	private JButton addLocationButton() {
+		final JButton result = new DeselectingButton("Add", new AbstractAction() {
+
+			@Override
+			public void actionPerformed(ActionEvent e) {
+				if (isShowingGroups()) {
+					Set<String> usedGroupNames = new HashSet<String>();
+					for (InvocationGroup g : manager.getInvocationGroups()) {
+						usedGroupNames.add(g.getName());
+					}
+
+					GroupPanel inputPanel = new GroupPanel(mechanismListModel.toArray());
+
+					ValidatingUserInputDialog vuid = new ValidatingUserInputDialog(
+							"Add symbolic location", inputPanel);
+					vuid.addTextComponentValidation(inputPanel.getGroupNameField(),
+							"Set the symbolic location name.", usedGroupNames,
+							"Duplicate symbolic location name.", "[\\p{L}\\p{Digit}_.]+",
+							"Invalid symbolic location name.");
+					vuid.setSize(new Dimension(400, 250));
+
+					if (vuid.show(ToolInvocationConfigurationPanel.this)) {
+						String groupName = inputPanel.getGroupName();
+						InvocationGroup newGroup = new InvocationGroup(mechanismCreators);
+						newGroup.setName(groupName);
+						newGroup.setMechanism(inputPanel.getSelectedMechanism());
+						manager.addInvocationGroup(newGroup);
+						locationList.setSelectedValue(newGroup, true);
+					}
+				} else {
+					Set<String> usedNames = new HashSet<String>();
+					for (InvocationMechanism m : manager.getMechanisms()) {
+						usedNames.add(m.getName());
+					}
+
+					MechanismPanel inputPanel = new MechanismPanel(invocationMechanismEditors);
+
+					ValidatingUserInputDialog vuid = new ValidatingUserInputDialog(
+							"Add explicit location", inputPanel);
+					vuid.addTextComponentValidation(inputPanel.getMechanismNameField(),
+							"Set the explicit location name.", usedNames,
+							"Duplicate explicit location name.", "[\\p{L}\\p{Digit}_.]+",
+							"Invalid explicit location name.");
+					vuid.addMessageComponent(inputPanel.getMechanismTypeSelector(),
+							"Set the location name and type.");
+					vuid.setSize(new Dimension(400, 250));
+
+					if (vuid.show(ToolInvocationConfigurationPanel.this)) {
+						String mechanismName = inputPanel.getMechanismName();
+						String mechanismTypeName = inputPanel.getMechanismTypeName();
+						InvocationMechanismEditor ime = findEditor(mechanismTypeName);
+						InvocationMechanism newMechanism = ime.createMechanism(mechanismName);
+						manager.addMechanism(newMechanism);
+						ime.show(newMechanism);
+						ime.setPreferredSize(new Dimension(550, 500));
+						int answer = JOptionPane.showConfirmDialog(
+								ToolInvocationConfigurationPanel.this, ime,
+								"New explicit location", JOptionPane.OK_CANCEL_OPTION,
+								JOptionPane.PLAIN_MESSAGE, null);
+						if (answer == JOptionPane.OK_OPTION) {
+							ime.updateInvocationMechanism();
+							InvocationGroupManagerImpl.getInstance().mechanismChanged(newMechanism);
+						}
+						locationList.setSelectedValue(newMechanism, true);
+					}
+				}
+			}
+		});
+		return result;
+	}
+
+	private JButton removeLocationButton() {
+		JButton result = new DeselectingButton("Remove", new AbstractAction() {
+
+			@Override
+			public void actionPerformed(ActionEvent e) {
+				if (isShowingGroups()) {
+					InvocationGroup toRemove = (InvocationGroup) locationList.getSelectedValue();
+					if ((toRemove != null) && !toRemove.equals(manager.getDefaultGroup())) {
+						manager.removeInvocationGroup(toRemove);
+					}
+					locationList.setSelectedValue(manager.getDefaultGroup(), true);
+				} else {
+					InvocationMechanism toRemove = (InvocationMechanism) locationList
+							.getSelectedValue();
+					if ((toRemove != null) && !toRemove.equals(manager.getDefaultMechanism())) {
+						manager.removeMechanism(toRemove);
+						locationList.setSelectedValue(manager.getDefaultMechanism(), true);
+					}
+				}
+			}
+		});
+		return result;
+	}
+
+	private JButton editLocationButton() {
+		final JButton result = new DeselectingButton("Edit", new AbstractAction() {
+
+			@Override
+			public void actionPerformed(ActionEvent e) {
+				if (isShowingGroups()) {
+					InvocationGroup toEdit = (InvocationGroup) locationList.getSelectedValue();
+					if (toEdit != null) {
+						InvocationMechanism chosenMechanism = (InvocationMechanism) JOptionPane
+								.showInputDialog(ToolInvocationConfigurationPanel.this,
+										"Select an explicit location", "Edit symbolic location",
+										JOptionPane.PLAIN_MESSAGE, null,
+										mechanismListModel.toArray(), toEdit.getMechanism());
+						if (chosenMechanism != null) {
+							toEdit.setMechanism(chosenMechanism);
+							manager.groupChanged(toEdit);
+						}
+					}
+				} else {
+					InvocationMechanism toEdit = (InvocationMechanism) locationList
+							.getSelectedValue();
+					if (toEdit != null) {
+						InvocationMechanismEditor ime = findEditor(toEdit.getClass());
+						ime.show(toEdit);
+						ime.setPreferredSize(new Dimension(550, 500));
+						int answer = JOptionPane.showConfirmDialog(
+								ToolInvocationConfigurationPanel.this, ime,
+								"Edit explicit location", JOptionPane.OK_CANCEL_OPTION,
+								JOptionPane.PLAIN_MESSAGE, null);
+						if (answer == JOptionPane.OK_OPTION) {
+							ime.updateInvocationMechanism();
+							InvocationGroupManagerImpl.getInstance().mechanismChanged(toEdit);
+						}
+					}
+				}
+			}
+		});
+		return result;
+	}
+
+	protected InvocationMechanismEditor findEditor(String name) {
+		for (InvocationMechanismEditor ime : invocationMechanismEditors) {
+			if (ime.getName().equalsIgnoreCase(name)) {
+				return ime;
+			}
+		}
+		return null;
+	}
+
+	protected InvocationMechanismEditor findEditor(Class c) {
+		for (InvocationMechanismEditor ime : invocationMechanismEditors) {
+			if (ime.canShow(c)) {
+				return ime;
+			}
+		}
+		return null;
+	}
+
+	@Override
+	public void notify(Observable<InvocationManagerEvent> arg0, InvocationManagerEvent arg1)
+			throws Exception {
+		if (SwingUtilities.isEventDispatchThread()) {
+			populateLists();
+		} else {
+			SwingUtilities.invokeLater(new Runnable() {
+				public void run() {
+					populateLists();
+				}
+			});
+		}
+	}
+}
diff --git a/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/manager/ToolInvocationConfigurationUIFactory.java b/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/manager/ToolInvocationConfigurationUIFactory.java
new file mode 100644
index 0000000..82dd443
--- /dev/null
+++ b/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/manager/ToolInvocationConfigurationUIFactory.java
@@ -0,0 +1,54 @@
+/**
+ *
+ */
+package net.sf.taverna.t2.activities.externaltool.manager;
+
+import java.util.List;
+
+import javax.swing.JPanel;
+
+import uk.org.taverna.configuration.Configurable;
+import uk.org.taverna.configuration.ConfigurationUIFactory;
+
+import net.sf.taverna.t2.activities.externaltool.configuration.ToolInvocationConfiguration;
+
+/**
+ * @author alanrw
+ *
+ */
+public class ToolInvocationConfigurationUIFactory implements ConfigurationUIFactory {
+
+	private List<MechanismCreator> mechanismCreators;
+	private List<InvocationMechanismEditor<?>> invocationMechanismEditors;
+
+	private ToolInvocationConfigurationPanel configPanel;
+
+	@Override
+	public boolean canHandle(String uuid) {
+		return uuid.equals(getConfigurable().getUUID());
+	}
+
+	@Override
+	public Configurable getConfigurable() {
+		return ToolInvocationConfiguration.getInstance();
+	}
+
+	@Override
+	public JPanel getConfigurationPanel() {
+		if (configPanel == null) {
+			configPanel = new ToolInvocationConfigurationPanel(mechanismCreators,
+					invocationMechanismEditors);
+		}
+		return configPanel;
+	}
+
+	public void setMechanismCreators(List<MechanismCreator> mechanismCreators) {
+		this.mechanismCreators = mechanismCreators;
+	}
+
+	public void setInvocationMechanismEditors(
+			List<InvocationMechanismEditor<?>> invocationMechanismEditors) {
+		this.invocationMechanismEditors = invocationMechanismEditors;
+	}
+
+}
diff --git a/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/manager/local/LocalInvocationMechanismEditor.java b/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/manager/local/LocalInvocationMechanismEditor.java
new file mode 100644
index 0000000..64fcc36
--- /dev/null
+++ b/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/manager/local/LocalInvocationMechanismEditor.java
@@ -0,0 +1,122 @@
+/**
+ * 
+ */
+package net.sf.taverna.t2.activities.externaltool.manager.local;
+
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+
+import javax.swing.JCheckBox;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JTextField;
+
+import net.sf.taverna.t2.activities.externaltool.local.ExternalToolLocalInvocationMechanism;
+import net.sf.taverna.t2.activities.externaltool.manager.InvocationMechanism;
+import net.sf.taverna.t2.activities.externaltool.manager.InvocationMechanismEditor;
+
+/**
+ * @author alanrw
+ *
+ */
+public final class LocalInvocationMechanismEditor extends
+		InvocationMechanismEditor<ExternalToolLocalInvocationMechanism> {
+
+	private ExternalToolLocalInvocationMechanism invocationMechanism;
+	
+	private JTextField directoryField = new JTextField(30);
+	
+	private JTextField shellPrefixField = new JTextField(30);
+	
+	private JTextField linkCommandField = new JTextField(30);
+	
+	private JCheckBox retrieveDataField = new JCheckBox();
+	
+
+	@Override
+	public boolean canShow(Class<?> c) {
+		return ExternalToolLocalInvocationMechanism.class.isAssignableFrom(c);
+	}
+
+	@Override
+	public String getName() {
+		return ("Local");
+	}
+
+	@Override
+	public void show(ExternalToolLocalInvocationMechanism invocationMechanism) {
+		this.invocationMechanism = invocationMechanism;
+		this.removeAll();
+		final JPanel innerPanel = new JPanel(new GridBagLayout());
+		final GridBagConstraints inputConstraint = new GridBagConstraints();
+//		inputConstraint.insets = new Insets(5,5,5,5);
+		inputConstraint.anchor = GridBagConstraints.FIRST_LINE_START;
+		inputConstraint.gridx = 0;
+		inputConstraint.gridy = 0;
+		inputConstraint.weightx = 0.1;
+		inputConstraint.fill = GridBagConstraints.BOTH;
+		innerPanel.add(new JLabel("Working directory: "), inputConstraint);
+		inputConstraint.gridx++;
+		directoryField.setText(invocationMechanism.getDirectory());
+		innerPanel.add(directoryField, inputConstraint);
+		inputConstraint.gridx = 0;
+		inputConstraint.gridy++;
+		innerPanel.add(new JLabel("Shell: "), inputConstraint);
+		inputConstraint.gridx++;
+		shellPrefixField.setText(invocationMechanism.getShellPrefix());
+		innerPanel.add(shellPrefixField, inputConstraint);
+		
+		inputConstraint.gridx = 0;
+		inputConstraint.gridy++;
+		innerPanel.add(new JLabel("Link command: "), inputConstraint);
+		inputConstraint.gridx++;
+		linkCommandField.setText(invocationMechanism.getLinkCommand());
+		innerPanel.add(linkCommandField, inputConstraint);
+		
+		inputConstraint.gridx = 0;
+		inputConstraint.gridy++;
+		innerPanel.add(new JLabel("Fetch data: "), inputConstraint);
+		inputConstraint.gridx++;
+		retrieveDataField.setSelected(invocationMechanism.isRetrieveData());
+		innerPanel.add(retrieveDataField, inputConstraint);
+		
+		this.add(innerPanel);
+	}
+
+	@Override
+	public ExternalToolLocalInvocationMechanism updateInvocationMechanism() {
+		if ((directoryField.getText() == null) || (directoryField.getText().length() == 0)) {
+			invocationMechanism.setDirectory(null);
+		} else {
+			invocationMechanism.setDirectory(directoryField.getText());
+		}
+		if ((shellPrefixField.getText() == null) || (shellPrefixField.getText().length() == 0)) {
+			invocationMechanism.setShellPrefix(null);
+		} else {
+			invocationMechanism.setShellPrefix(shellPrefixField.getText());
+		}
+		if ((shellPrefixField.getText() == null) || (shellPrefixField.getText().length() == 0)) {
+			invocationMechanism.setShellPrefix(null);
+		} else {
+			invocationMechanism.setShellPrefix(shellPrefixField.getText());
+		}
+		if ((linkCommandField.getText() == null) || (linkCommandField.getText().length() == 0)) {
+			invocationMechanism.setLinkCommand(null);
+		} else {
+			invocationMechanism.setLinkCommand(linkCommandField.getText());
+		}
+		invocationMechanism.setRetrieveData(retrieveDataField.isSelected());
+		return invocationMechanism;
+	}
+
+	@Override
+	public InvocationMechanism createMechanism(String mechanismName) {
+		ExternalToolLocalInvocationMechanism result = new ExternalToolLocalInvocationMechanism();
+		result.setName(mechanismName);
+		return(result);
+	}
+
+	public boolean isSingleton() {
+		return true;
+	}
+}
diff --git a/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/manager/ssh/ExternalToolSshNodeViewer.java b/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/manager/ssh/ExternalToolSshNodeViewer.java
new file mode 100644
index 0000000..fb837c5
--- /dev/null
+++ b/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/manager/ssh/ExternalToolSshNodeViewer.java
@@ -0,0 +1,110 @@
+/**
+ * 
+ */
+package net.sf.taverna.t2.activities.externaltool.manager.ssh;
+
+import javax.swing.JCheckBox;
+import javax.swing.JTextField;
+
+import net.sf.taverna.t2.activities.externaltool.manager.InvocationMechanism;
+
+import de.uni_luebeck.inb.knowarc.usecases.invocation.ssh.SshNode;
+
+
+
+/**
+ * @author alanrw
+ *
+ */
+public class ExternalToolSshNodeViewer {
+	
+	private JTextField hostnameField;
+	private JTextField portField;
+	private JTextField directoryField;
+	private JTextField linkCommandField;
+	private JTextField copyCommandField;
+	private JCheckBox retrieveDataField;
+
+	public ExternalToolSshNodeViewer(SshNode node) {
+		this();
+		hostnameField.setText(node.getHost());
+		portField.setText(Integer.toString(node.getPort()));
+		if (node.getDirectory() != null) {
+			directoryField.setText(node.getDirectory());
+		} else {
+			directoryField.setText("");
+		}
+		if (node.getLinkCommand() != null) {
+			linkCommandField.setText(node.getLinkCommand());
+		} else {
+			linkCommandField.setText("");
+		}
+		if (node.getCopyCommand() != null) {
+			copyCommandField.setText(node.getCopyCommand());
+		} else {
+			copyCommandField.setText("");
+		}
+		retrieveDataField.setSelected(node.isRetrieveData());
+	}
+
+	public ExternalToolSshNodeViewer() {
+		hostnameField = new JTextField(30);
+		hostnameField.setText(SshNode.DEFAULT_HOST);
+		portField = new JTextField(3);
+		portField.setText("" + SshNode.DEFAULT_PORT);
+		directoryField = new JTextField(30);
+		directoryField.setText(SshNode.DEFAULT_DIRECTORY);
+		linkCommandField = new JTextField(30);
+		linkCommandField.setText(InvocationMechanism.UNIX_LINK);
+		copyCommandField = new JTextField(30);
+		copyCommandField.setText(InvocationMechanism.UNIX_COPY);
+		retrieveDataField = new JCheckBox();
+	}
+
+	public JTextField getHostnameField() {
+		return hostnameField;
+	}
+
+	public JTextField getPortField() {
+		return portField;
+	}
+	
+	public JTextField getDirectoryField() {
+		return directoryField;
+	}
+
+	public JTextField getLinkCommandField() {
+		return linkCommandField;
+	}
+
+	public JTextField getCopyCommandField() {
+		return copyCommandField;
+	}
+
+	public String getHostname() {
+		return hostnameField.getText();
+	}
+
+	public int getPort() {
+		return Integer.parseInt(portField.getText());
+	}
+	
+	public String getDirectory() {
+		return directoryField.getText();
+	}
+	
+	public String getLinkCommand() {
+		return linkCommandField.getText();
+	}
+	
+	public String getCopyCommand() {
+		return copyCommandField.getText();
+	}
+
+	/**
+	 * @return the retrieveDataField
+	 */
+	public JCheckBox getRetrieveDataField() {
+		return retrieveDataField;
+	}
+}
diff --git a/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/manager/ssh/SshInvocationMechanismEditor.java b/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/manager/ssh/SshInvocationMechanismEditor.java
new file mode 100644
index 0000000..e8291ed
--- /dev/null
+++ b/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/manager/ssh/SshInvocationMechanismEditor.java
@@ -0,0 +1,234 @@
+/**
+ * 
+ */
+package net.sf.taverna.t2.activities.externaltool.manager.ssh;
+
+import java.awt.Color;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+import java.awt.event.ActionEvent;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.swing.AbstractAction;
+import javax.swing.BorderFactory;
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTextField;
+import javax.swing.border.CompoundBorder;
+
+import net.sf.taverna.t2.activities.externaltool.manager.InvocationMechanism;
+import net.sf.taverna.t2.activities.externaltool.manager.InvocationMechanismEditor;
+import net.sf.taverna.t2.activities.externaltool.ssh.ExternalToolSshInvocationMechanism;
+import net.sf.taverna.t2.lang.ui.DeselectingButton;
+import de.uni_luebeck.inb.knowarc.usecases.invocation.ssh.SshNode;
+import de.uni_luebeck.inb.knowarc.usecases.invocation.ssh.SshNodeFactory;
+
+/**
+ * @author alanrw
+ *
+ */
+public final class SshInvocationMechanismEditor extends
+		InvocationMechanismEditor<ExternalToolSshInvocationMechanism> {
+	
+	private ArrayList<ExternalToolSshNodeViewer> nodeViewers = new ArrayList<ExternalToolSshNodeViewer>();
+	private int inputGridy = 0;
+	
+	private ExternalToolSshInvocationMechanism mechanism = null;
+	
+	private static Insets insets = new Insets(1,5,1,5);
+	
+	private static CompoundBorder border = BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(5,5,5,5), BorderFactory.createLineBorder(Color.BLACK, 1));
+
+	@Override
+	public boolean canShow(Class<?> c) {
+		return ExternalToolSshInvocationMechanism.class.isAssignableFrom(c);
+	}
+
+	@Override
+	public void show(ExternalToolSshInvocationMechanism invocationMechanism) {
+		mechanism = invocationMechanism;
+		this.removeAll();
+		inputGridy = 1;
+		final JPanel innerPanel = new JPanel(new GridBagLayout());
+
+		final GridBagConstraints inputConstraint = new GridBagConstraints();
+		inputConstraint.anchor = GridBagConstraints.FIRST_LINE_START;
+		inputConstraint.gridx = 0;
+		inputConstraint.gridy = 0;
+		inputConstraint.weightx = 0.1;
+		inputConstraint.fill = GridBagConstraints.BOTH;
+
+		inputConstraint.gridx = 0;
+			nodeViewers.clear();
+			for (SshNode node : invocationMechanism.getNodes()) {
+				ExternalToolSshNodeViewer nodeViewer = new ExternalToolSshNodeViewer(node);
+				addNodeViewer(this, innerPanel, nodeViewer);
+			}
+
+		this.setLayout(new GridBagLayout());
+		GridBagConstraints outerPanelConstraint = new GridBagConstraints();
+		outerPanelConstraint.gridx = 0;
+		outerPanelConstraint.gridy = 0;
+		outerPanelConstraint.weightx = 0.1;
+		outerPanelConstraint.weighty = 0.1;
+		outerPanelConstraint.fill = GridBagConstraints.BOTH;
+		this.add(new JScrollPane(innerPanel),
+				outerPanelConstraint);
+		outerPanelConstraint.weighty = 0;
+		final JButton addHostButton = new DeselectingButton("Add host",
+				new AbstractAction() {
+			public void actionPerformed(ActionEvent e) {
+
+				ExternalToolSshNodeViewer newViewer = new ExternalToolSshNodeViewer();
+
+					addNodeViewer(SshInvocationMechanismEditor.this, innerPanel, newViewer);
+					innerPanel.revalidate();
+					innerPanel.repaint();
+			}
+
+		});
+		JPanel buttonPanel = new JPanel();
+		buttonPanel.setLayout(new GridBagLayout());
+
+		JPanel filler = new JPanel();
+		outerPanelConstraint.weightx = 0.1;
+		outerPanelConstraint.weighty = 0;
+		outerPanelConstraint.gridx = 0;
+		outerPanelConstraint.gridy = 0;
+
+		buttonPanel.add(filler, outerPanelConstraint);
+
+		outerPanelConstraint.weightx = 0;
+		outerPanelConstraint.weighty = 0;
+		outerPanelConstraint.gridx = 1;
+		outerPanelConstraint.gridy = 0;
+
+		buttonPanel.add(addHostButton, outerPanelConstraint);
+
+		outerPanelConstraint.weightx = 0;
+		outerPanelConstraint.weighty = 0;
+		outerPanelConstraint.gridx = 0;
+		outerPanelConstraint.gridy = 1;
+		outerPanelConstraint.fill = GridBagConstraints.BOTH;
+		this.add(buttonPanel, outerPanelConstraint);
+	}
+
+	protected void addNodeViewer(final JPanel result, final JPanel innerPanel,
+			ExternalToolSshNodeViewer viewer) {
+		final JPanel subPanel = new JPanel();
+		subPanel.setLayout(new GridBagLayout());
+		subPanel.setBorder(border);
+		final GridBagConstraints inputConstraint = new GridBagConstraints();
+		inputConstraint.insets = insets;
+		inputConstraint.anchor = GridBagConstraints.FIRST_LINE_START;
+		inputConstraint.weightx = 0.1;
+		inputConstraint.fill = GridBagConstraints.BOTH;
+
+		inputConstraint.gridy = 0 ;
+		inputConstraint.gridx = 0;
+		
+		subPanel.add(new JLabel("Host: "), inputConstraint);
+		final JTextField hostnameField = viewer.getHostnameField();
+		inputConstraint.gridx++;
+		subPanel.add(hostnameField, inputConstraint);
+
+		inputConstraint.gridy++ ;
+		inputConstraint.gridx = 0;
+		subPanel.add(new JLabel("Port: "), inputConstraint);
+		final JTextField portField = viewer.getPortField();
+		inputConstraint.gridx++;
+		subPanel.add(portField ,inputConstraint);
+		
+		inputConstraint.gridy++ ;
+		inputConstraint.gridx = 0;
+		subPanel.add(new JLabel("Working directory: "), inputConstraint);
+		final JTextField directoryField = viewer.getDirectoryField();
+		inputConstraint.gridx++;
+		subPanel.add(directoryField ,inputConstraint);
+		
+		inputConstraint.gridy++ ;
+		inputConstraint.gridx = 0;
+		subPanel.add(new JLabel("Link command: "), inputConstraint);
+		final JTextField linkCommandField = viewer.getLinkCommandField();
+		inputConstraint.gridx++;
+		subPanel.add(linkCommandField ,inputConstraint);
+
+		inputConstraint.gridy++ ;
+		inputConstraint.gridx = 0;
+		subPanel.add(new JLabel("Copy command: "), inputConstraint);
+		final JTextField copyCommandField = viewer.getCopyCommandField();
+		inputConstraint.gridx++;
+		subPanel.add(copyCommandField ,inputConstraint);
+
+		inputConstraint.gridy++ ;
+		inputConstraint.gridx = 0;
+		subPanel.add(new JLabel("Fetch data: "), inputConstraint);
+		inputConstraint.gridx++;
+		final JCheckBox retrieveDataField = viewer.getRetrieveDataField();
+		subPanel.add(retrieveDataField ,inputConstraint);
+
+		inputConstraint.gridy++ ;
+		inputConstraint.gridx = 1;
+		inputConstraint.fill = GridBagConstraints.NONE;
+		inputConstraint.anchor = GridBagConstraints.EAST;
+		final ExternalToolSshNodeViewer v = viewer;
+		final JButton removeButton = new DeselectingButton("Remove",
+				new AbstractAction() {
+
+			public void actionPerformed(ActionEvent e) {
+				synchronized(nodeViewers) {
+					nodeViewers.remove(v);
+				}
+				innerPanel.remove(subPanel);
+				innerPanel.revalidate();
+				innerPanel.repaint();
+				result.revalidate();
+				result.repaint();
+			}
+
+		});
+		subPanel.add(removeButton, inputConstraint);
+		
+		inputConstraint.gridy = ++inputGridy;
+		innerPanel.add(subPanel, inputConstraint);
+
+		nodeViewers.add(viewer);
+		inputGridy++;		
+	}
+
+	private List<SshNode> getNodeList() {
+		List<SshNode> result = new ArrayList<SshNode>();
+		for (ExternalToolSshNodeViewer viewer : nodeViewers) {
+			SshNode node = SshNodeFactory.getInstance().getSshNode(viewer.getHostname(), viewer.getPort(), viewer.getDirectory());
+			node.setLinkCommand(viewer.getLinkCommand());
+			node.setCopyCommand(viewer.getCopyCommand());
+			node.setRetrieveData(viewer.getRetrieveDataField().isSelected());
+			result.add(node);
+		}
+		return result;
+	}
+
+	@Override
+	public ExternalToolSshInvocationMechanism updateInvocationMechanism() {
+		mechanism.setNodes(getNodeList());
+		return mechanism;
+	}
+
+	@Override
+	public InvocationMechanism createMechanism(String mechanismName) {
+		ExternalToolSshInvocationMechanism result = new ExternalToolSshInvocationMechanism();
+		result.setName(mechanismName);
+		return result;
+	}
+
+	@Override
+	public String getName() {
+		return ("SSH");
+	}
+
+}
diff --git a/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/menu/AddExternalToolContextualMenuAction.java b/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/menu/AddExternalToolContextualMenuAction.java
new file mode 100644
index 0000000..505546d
--- /dev/null
+++ b/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/menu/AddExternalToolContextualMenuAction.java
@@ -0,0 +1,111 @@
+/*******************************************************************************

+ * Copyright (C) 2007-2009 The University of Manchester

+ *

+ *  Modifications to the initial code base are copyright of their

+ *  respective authors, or their employers as appropriate.

+ *

+ *  This program is free software; you can redistribute it and/or

+ *  modify it under the terms of the GNU Lesser General Public License

+ *  as published by the Free Software Foundation; either version 2.1 of

+ *  the License, or (at your option) any later version.

+ *

+ *  This program is distributed in the hope that it will be useful, but

+ *  WITHOUT ANY WARRANTY; without even the implied warranty of

+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU

+ *  Lesser General Public License for more details.

+ *

+ *  You should have received a copy of the GNU Lesser General Public

+ *  License along with this program; if not, write to the Free Software

+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307

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

+package net.sf.taverna.t2.activities.externaltool.menu;

+

+import java.awt.event.ActionEvent;

+import java.net.URI;

+

+import javax.swing.AbstractAction;

+import javax.swing.Action;

+

+import net.sf.taverna.t2.activities.externaltool.ExternalToolActivity;

+import net.sf.taverna.t2.activities.externaltool.servicedescriptions.ExternalToolTemplateServiceDescription;

+import net.sf.taverna.t2.ui.menu.AbstractContextualMenuAction;

+import net.sf.taverna.t2.ui.menu.MenuManager;

+import net.sf.taverna.t2.workbench.activityicons.ActivityIconManager;

+import net.sf.taverna.t2.workbench.edits.EditManager;

+import net.sf.taverna.t2.workbench.file.FileManager;

+import net.sf.taverna.t2.workbench.selection.SelectionManager;

+import net.sf.taverna.t2.workbench.ui.workflowview.WorkflowView;

+import net.sf.taverna.t2.workflowmodel.Dataflow;

+

+import org.apache.log4j.Logger;

+

+/**

+ * An action to add an external tool + a wrapping processor to the workflow.

+ *

+ * @author Alex Nenadic

+ * @author Alan Williamns

+ *

+ */

+@SuppressWarnings("serial")

+public class AddExternalToolContextualMenuAction extends AbstractContextualMenuAction {

+

+	private static final String ADD_EXTERNAL_TOOL = "Tool";

+

+	private static final URI insertSection = URI

+			.create("http://taverna.sf.net/2009/contextMenu/insert");

+

+	private static Logger logger = Logger.getLogger(AddExternalToolMenuAction.class);

+

+	private EditManager editManager;

+

+	private MenuManager menuManager;

+

+	private SelectionManager selectionManager;

+

+	private ActivityIconManager activityIconManager;

+

+	public AddExternalToolContextualMenuAction() {

+		super(insertSection, 900);

+	}

+

+	@Override

+	public boolean isEnabled() {

+		return super.isEnabled() && getContextualSelection().getSelection() instanceof Dataflow;

+	}

+

+	@Override

+	protected Action createAction() {

+

+		return new AddExternalToolAction();

+	}

+

+	protected class AddExternalToolAction extends AbstractAction {

+		AddExternalToolAction() {

+			super(ADD_EXTERNAL_TOOL, activityIconManager.iconForActivity(

+					new ExternalToolActivity()));

+		}

+

+		public void actionPerformed(ActionEvent e) {

+			WorkflowView.importServiceDescription(

+					ExternalToolTemplateServiceDescription.getServiceDescription(), false,

+					editManager, menuManager, selectionManager);

+		}

+	}

+

+	public void setEditManager(EditManager editManager) {

+		this.editManager = editManager;

+	}

+

+	public void setMenuManager(MenuManager menuManager) {

+		this.menuManager = menuManager;

+	}

+

+	public void setSelectionManager(SelectionManager selectionManager) {

+		this.selectionManager = selectionManager;

+	}

+

+	public void setActivityIconManager(ActivityIconManager activityIconManager) {

+		this.activityIconManager = activityIconManager;

+	}

+

+}

diff --git a/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/menu/AddExternalToolMenuAction.java b/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/menu/AddExternalToolMenuAction.java
new file mode 100644
index 0000000..ff1f11e
--- /dev/null
+++ b/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/menu/AddExternalToolMenuAction.java
@@ -0,0 +1,111 @@
+/*******************************************************************************

+ * Copyright (C) 2007-2009 The University of Manchester

+ *

+ *  Modifications to the initial code base are copyright of their

+ *  respective authors, or their employers as appropriate.

+ *

+ *  This program is free software; you can redistribute it and/or

+ *  modify it under the terms of the GNU Lesser General Public License

+ *  as published by the Free Software Foundation; either version 2.1 of

+ *  the License, or (at your option) any later version.

+ *

+ *  This program is distributed in the hope that it will be useful, but

+ *  WITHOUT ANY WARRANTY; without even the implied warranty of

+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU

+ *  Lesser General Public License for more details.

+ *

+ *  You should have received a copy of the GNU Lesser General Public

+ *  License along with this program; if not, write to the Free Software

+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307

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

+package net.sf.taverna.t2.activities.externaltool.menu;

+

+import java.awt.event.ActionEvent;

+import java.awt.event.InputEvent;

+import java.awt.event.KeyEvent;

+import java.net.URI;

+

+import javax.swing.Action;

+import javax.swing.KeyStroke;

+

+import net.sf.taverna.t2.activities.externaltool.ExternalToolActivity;

+import net.sf.taverna.t2.activities.externaltool.servicedescriptions.ExternalToolTemplateServiceDescription;

+import net.sf.taverna.t2.ui.menu.AbstractMenuAction;

+import net.sf.taverna.t2.ui.menu.DesignOnlyAction;

+import net.sf.taverna.t2.ui.menu.MenuManager;

+import net.sf.taverna.t2.workbench.activityicons.ActivityIconManager;

+import net.sf.taverna.t2.workbench.edits.EditManager;

+import net.sf.taverna.t2.workbench.selection.SelectionManager;

+import net.sf.taverna.t2.workbench.ui.workflowview.WorkflowView;

+import net.sf.taverna.t2.workbench.views.graph.menu.InsertMenu;

+

+import org.apache.log4j.Logger;

+

+/**

+ * An action to add a externaltool activity + a wrapping processor to the workflow.

+ *

+ * @author Alex Nenadic

+ * @author alanrw

+ *

+ */

+@SuppressWarnings("serial")

+public class AddExternalToolMenuAction extends AbstractMenuAction {

+

+	private static final String ADD_EXTERNAL_TOOL = "Tool";

+

+	private static final URI ADD_EXTERNAL_TOOL_URI = URI

+	.create("http://taverna.sf.net/2008/t2workbench/menu#graphMenuAddExternalTool");

+

+	private static Logger logger = Logger

+			.getLogger(AddExternalToolMenuAction.class);

+

+	private EditManager editManager;

+	private MenuManager menuManager;

+	private SelectionManager selectionManager;

+

+	private ActivityIconManager activityIconManager;

+

+	public AddExternalToolMenuAction() {

+		super(InsertMenu.INSERT, 900, ADD_EXTERNAL_TOOL_URI);

+	}

+

+	@Override

+	protected Action createAction() {

+

+		return new AddExternalToolAction();

+	}

+

+	protected class AddExternalToolAction extends DesignOnlyAction {

+		AddExternalToolAction () {

+			super ();

+			putValue(SMALL_ICON, activityIconManager.iconForActivity(

+					new ExternalToolActivity()));

+			putValue(NAME, ADD_EXTERNAL_TOOL);

+			putValue(SHORT_DESCRIPTION, "Tool");

+			putValue(Action.ACCELERATOR_KEY,

+					KeyStroke.getKeyStroke(KeyEvent.VK_T, InputEvent.SHIFT_DOWN_MASK | InputEvent.ALT_DOWN_MASK));

+		}

+

+		public void actionPerformed(ActionEvent e) {

+			WorkflowView.importServiceDescription(ExternalToolTemplateServiceDescription.getServiceDescription(),

+			false, editManager, menuManager, selectionManager);

+		}

+	}

+

+	public void setEditManager(EditManager editManager) {

+		this.editManager = editManager;

+	}

+

+	public void setMenuManager(MenuManager menuManager) {

+		this.menuManager = menuManager;

+	}

+

+	public void setSelectionManager(SelectionManager selectionManager) {

+		this.selectionManager = selectionManager;

+	}

+

+	public void setActivityIconManager(ActivityIconManager activityIconManager) {

+		this.activityIconManager = activityIconManager;

+	}

+

+}

diff --git a/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/menu/ConfigureExternalToolMenuAction.java b/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/menu/ConfigureExternalToolMenuAction.java
new file mode 100644
index 0000000..f57b25c
--- /dev/null
+++ b/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/menu/ConfigureExternalToolMenuAction.java
@@ -0,0 +1,69 @@
+/*******************************************************************************
+ * Copyright (C) 2010 Hajo Nils Krabbenhoeft, spratpix GmbH & Co. KG
+ *
+ *  Modifications to the initial code base are copyright of their
+ *  respective authors, or their employers as appropriate.
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1 of
+ *  the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+
+package net.sf.taverna.t2.activities.externaltool.menu;
+
+import javax.swing.Action;
+
+import net.sf.taverna.t2.activities.externaltool.ExternalToolActivity;
+import net.sf.taverna.t2.activities.externaltool.actions.ExternalToolActivityConfigureAction;
+import net.sf.taverna.t2.workbench.activityicons.ActivityIconManager;
+import net.sf.taverna.t2.workbench.activitytools.AbstractConfigureActivityMenuAction;
+import net.sf.taverna.t2.workbench.edits.EditManager;
+import net.sf.taverna.t2.workbench.file.FileManager;
+
+/**
+ * This class adds the plugin configuration action to the context menu of every use case activity.
+ *
+ * @author Hajo Nils Krabbenhoeft
+ */
+public class ConfigureExternalToolMenuAction extends
+		AbstractConfigureActivityMenuAction<ExternalToolActivity> {
+
+	private EditManager editManager;
+	private FileManager fileManager;
+	private ActivityIconManager activityIconManager;
+
+	public ConfigureExternalToolMenuAction() {
+		super(ExternalToolActivity.class);
+	}
+
+	@Override
+	protected Action createAction() {
+		ExternalToolActivityConfigureAction configAction = new ExternalToolActivityConfigureAction(
+				findActivity(), getParentFrame(), editManager, fileManager, activityIconManager);
+		addMenuDots(configAction);
+		return configAction;
+	}
+
+	public void setEditManager(EditManager editManager) {
+		this.editManager = editManager;
+	}
+
+	public void setFileManager(FileManager fileManager) {
+		this.fileManager = fileManager;
+	}
+
+	public void setActivityIconManager(ActivityIconManager activityIconManager) {
+		this.activityIconManager = activityIconManager;
+	}
+
+}
diff --git a/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/menu/FeedbackMenuAction.java b/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/menu/FeedbackMenuAction.java
new file mode 100644
index 0000000..8c7a284
--- /dev/null
+++ b/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/menu/FeedbackMenuAction.java
@@ -0,0 +1,82 @@
+/*******************************************************************************
+ * Copyright (C) 2010 Hajo Nils Krabbenhoeft, spratpix GmbH & Co. KG
+ *
+ *  Modifications to the initial code base are copyright of their
+ *  respective authors, or their employers as appropriate.
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1 of
+ *  the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+
+package net.sf.taverna.t2.activities.externaltool.menu;
+
+import java.awt.Desktop;
+import java.awt.event.ActionEvent;
+import java.io.IOException;
+import java.net.URI;
+
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+import javax.swing.Icon;
+import javax.swing.JOptionPane;
+
+import net.sf.taverna.t2.ui.menu.AbstractMenuAction;
+
+import org.apache.log4j.Logger;
+
+/**
+ * This class adds the feedback item to the context menu of every use case
+ * activity.
+ *
+ * @author Hajo Nils Krabbenhoeft
+ */
+public class FeedbackMenuAction extends AbstractMenuAction {
+
+	private static Logger logger = Logger.getLogger(FeedbackMenuAction.class);
+
+
+	private static final URI feedbackSection = URI.create("http://taverna.sf.net/2009/contextMenu/configure");
+
+	public FeedbackMenuAction() {
+		super(feedbackSection, 51);
+	}
+
+	protected Action createAction() {
+	    // final ImageIcon icon = KnowARCConfigurationFactory.getConfiguration().getIcon();
+		return new SendFeedbackAction("Send Feedback...", null);
+	}
+
+	private final class SendFeedbackAction extends AbstractAction {
+		private static final long serialVersionUID = 1L;
+
+		private static final String errTitle = "Could not open web browser for feedback:";
+		private static final String feedbackUrl = "http://www.taverna.org.uk/about/contact-us/feedback?product=ExternalToolService";
+
+		private SendFeedbackAction(String name, Icon icon) {
+			super(name, icon);
+		}
+
+		public void actionPerformed(ActionEvent e) {
+			if (Desktop.isDesktopSupported()) {
+				try {
+					Desktop.getDesktop().browse(URI.create(feedbackUrl));
+				} catch (IOException e1) {
+					JOptionPane.showMessageDialog(null, feedbackUrl + "\n" + e1.getLocalizedMessage(), errTitle, JOptionPane.ERROR_MESSAGE);
+				}
+			} else {
+				JOptionPane.showMessageDialog(null, "Go to " + feedbackUrl, errTitle, JOptionPane.ERROR_MESSAGE);
+			}
+		}
+	}
+}
diff --git a/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/servicedescriptions/AddExternalToolServiceDialog.java b/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/servicedescriptions/AddExternalToolServiceDialog.java
new file mode 100644
index 0000000..86b0882
--- /dev/null
+++ b/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/servicedescriptions/AddExternalToolServiceDialog.java
@@ -0,0 +1,189 @@
+/*******************************************************************************
+ * Copyright (C) 2007 The University of Manchester   
+ * 
+ *  Modifications to the initial code base are copyright of their
+ *  respective authors, or their employers as appropriate.
+ * 
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1 of
+ *  the License, or (at your option) any later version.
+ *    
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *    
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+package net.sf.taverna.t2.activities.externaltool.servicedescriptions;
+
+import java.awt.BorderLayout;
+import java.awt.FlowLayout;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.KeyEvent;
+import java.io.IOException;
+import java.net.URL;
+import java.net.URLConnection;
+
+import javax.swing.JButton;
+import javax.swing.JDialog;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JTextField;
+import javax.swing.border.EmptyBorder;
+
+import net.sf.taverna.t2.workbench.MainWindow;
+import net.sf.taverna.t2.workbench.helper.HelpEnabledDialog;
+
+import org.apache.log4j.Logger;
+
+/**
+ * Dialog that lets user specify a URL of a Tool service they want 
+ * to add to the Service Panel. In the case the Tool URL is behind
+ * HTTPS or service's endpoints require HTTPS it will ask user to confirm
+ * if they want to trust it. 
+ * 
+ * @author Alex Nenadic
+ *
+ */
+@SuppressWarnings("serial")
+public abstract class AddExternalToolServiceDialog extends HelpEnabledDialog {
+
+	private JTextField toolLocationField;
+	private Logger logger = Logger.getLogger(AddExternalToolServiceDialog.class);
+
+	public AddExternalToolServiceDialog()  {
+		super(MainWindow.getMainWindow(), "Add tool service", true, null); // create a non-modal dialog
+		initComponents();
+		setLocationRelativeTo(getParent());
+	}
+
+	private void initComponents() {
+		JPanel mainPanel = new JPanel(new GridBagLayout());
+		mainPanel.setBorder(new EmptyBorder(10,10,10,10));
+		
+		JLabel toolLocatitionLabel = new JLabel("Tool registry location",ExternalToolActivityIcon.getExternalToolIcon(), JLabel.LEFT);		
+		GridBagConstraints gbc = new GridBagConstraints();
+		gbc.weighty = 0.0;
+		
+		gbc.weightx = 0.0;
+		gbc.gridx = 0;
+		gbc.gridy = 0;
+		gbc.fill = GridBagConstraints.NONE;
+		gbc.anchor = GridBagConstraints.WEST;
+		gbc.insets = new Insets(5, 10, 0, 0);
+		mainPanel.add(toolLocatitionLabel, gbc);
+        
+		toolLocationField = new JTextField("http://taverna.nordugrid.org/sharedRepository/xml.php");
+		gbc.weightx = 1.0;
+		gbc.gridx = 1;
+		gbc.gridy = 0;
+		gbc.fill = GridBagConstraints.HORIZONTAL;
+		gbc.anchor = GridBagConstraints.WEST;
+		gbc.insets = new Insets(5, 10, 0, 5);		
+		mainPanel.add(toolLocationField, gbc);
+		
+	    final JButton addServiceButton = new JButton("Add");
+	    addServiceButton.addActionListener(new ActionListener()
+	        {
+	            public void actionPerformed(ActionEvent evt)
+	            {
+	                addPressed();
+	            }
+	        });
+	    
+	    // When user presses "Return" key fire the action on the "Add" button
+	    addServiceButton.addKeyListener(new java.awt.event.KeyAdapter() {
+			public void keyPressed(java.awt.event.KeyEvent evt) {
+				if (evt.getKeyCode() == KeyEvent.VK_ENTER) {
+					addPressed();
+				}
+			}
+		});
+		getRootPane().setDefaultButton(addServiceButton);
+	    
+        JPanel buttonsPanel = new JPanel(new FlowLayout(FlowLayout.CENTER));
+        buttonsPanel.add(addServiceButton);
+        
+        getContentPane().setLayout(new BorderLayout());
+        getContentPane().add(mainPanel, BorderLayout.CENTER);
+        getContentPane().add(buttonsPanel, BorderLayout.SOUTH);
+        
+		setSize(getPreferredSize());
+        pack();
+	}
+	
+    /**
+     * 'Add service' button pressed or otherwise activated.
+     */
+    private void addPressed()
+    {
+		final String toolURLString = toolLocationField.getText().trim();
+		new Thread("Adding tool " + toolURLString) {
+			public void run() {
+				// Only add the service provider for this service if service URL
+				// starts with 'http'
+				// or if it starts with 'https' and user explicitly said they
+				// wanted to trust this service.
+				/*
+				 * if (shouldTrust(toolURLString)){ addRegistry(toolURLString);
+				 * }
+				 */
+				try {
+					URL url = new URL(toolURLString);
+					URLConnection connection = url.openConnection();
+					try {
+						// If the url starts with 'https' - security hook for
+						// https connection's trust manager
+						// will be engaged and user will be asked automatically
+						// if they want
+						// to trust the connection (if it is not already
+						// trusted). If the urls starts with 'http' -
+						// this will not have any effect apart from checking if
+						// we can open a connection.
+						connection.connect(); // if this does not fail - add the
+						// tool
+						// service provider for this service to
+						// the registry
+					} finally {
+						try {
+							connection.getInputStream().close();
+						} catch (IOException ex) {
+						}
+					}
+					addRegistry(toolURLString);
+				} catch (Exception ex) { // anything failed
+					JOptionPane.showMessageDialog(null,
+							"Could not read the tool descriptions from "
+									+ toolURLString + ":\n" + ex,
+							"Could not add tool service",
+							JOptionPane.ERROR_MESSAGE);
+
+					logger.error(
+							"Failed to add tool description provider for service: "
+									+ toolURLString, ex);
+
+				}
+			};
+		}.start();
+		closeDialog();
+    }
+
+	protected abstract void addRegistry(String tool);	
+	
+	/**
+	 * Closes the dialog.
+	 */
+	private void closeDialog() {
+		setVisible(false);
+		dispose();
+	}
+}
diff --git a/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/servicedescriptions/ExternalToolActivityIcon.java b/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/servicedescriptions/ExternalToolActivityIcon.java
new file mode 100644
index 0000000..f91755f
--- /dev/null
+++ b/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/servicedescriptions/ExternalToolActivityIcon.java
@@ -0,0 +1,73 @@
+/*******************************************************************************
+ * Copyright (C) 2009 Hajo Nils Krabbenhoeft, INB, University of Luebeck
+ *
+ *  Modifications to the initial code base are copyright of their
+ *  respective authors, or their employers as appropriate.
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1 of
+ *  the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+
+package net.sf.taverna.t2.activities.externaltool.servicedescriptions;
+
+import java.awt.Color;
+
+import javax.swing.Icon;
+import javax.swing.ImageIcon;
+
+import net.sf.taverna.t2.activities.externaltool.ExternalToolActivity;
+import net.sf.taverna.t2.workbench.activityicons.ActivityIconSPI;
+import net.sf.taverna.t2.workbench.configuration.colour.ColourManager;
+import net.sf.taverna.t2.workflowmodel.processor.activity.Activity;
+
+/**
+ * This class provides an icon for the use case activity.
+ *
+ * @author Hajo Nils Krabbenhoeft
+ */
+public class ExternalToolActivityIcon implements ActivityIconSPI {
+
+	private static final String PROCESSOR_COLOUR_STRING = "#F28C55";
+
+	private static Icon icon;
+
+	public int canProvideIconScore(Activity<?> activity) {
+		if (activity.getClass().getName().equals(ExternalToolActivity.class.getName()))
+			return DEFAULT_ICON + 1;
+		else
+			return NO_ICON;
+	}
+
+	public Icon getIcon(Activity<?> activity) {
+		return getExternalToolIcon();
+	}
+
+	public static Icon getExternalToolIcon() {
+		if (icon == null) {
+			icon = new ImageIcon(ExternalToolActivityIcon.class.getResource("/externaltool.png"));
+		}
+		return icon;
+	}
+
+	public static String getColourString() {
+		return PROCESSOR_COLOUR_STRING;
+	}
+
+	public void setColourManager(ColourManager colourManager) {
+		// set colour for XPath processors in the workflow diagram
+		colourManager.setPreferredColour(ExternalToolActivity.class.getCanonicalName(),
+				Color.decode(PROCESSOR_COLOUR_STRING));
+	}
+
+}
diff --git a/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/servicedescriptions/ExternalToolServiceDescription.java b/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/servicedescriptions/ExternalToolServiceDescription.java
new file mode 100644
index 0000000..02c2bf6
--- /dev/null
+++ b/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/servicedescriptions/ExternalToolServiceDescription.java
@@ -0,0 +1,149 @@
+/*******************************************************************************
+ * Copyright (C) 2009 Hajo Nils Krabbenhoeft, INB, University of Luebeck   
+ * 
+ *  Modifications to the initial code base are copyright of their
+ *  respective authors, or their employers as appropriate.
+ * 
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1 of
+ *  the License, or (at your option) any later version.
+ *    
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *    
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+
+package net.sf.taverna.t2.activities.externaltool.servicedescriptions;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import javax.swing.Icon;
+import javax.swing.ImageIcon;
+
+import org.apache.log4j.Logger;
+
+import net.sf.taverna.t2.activities.externaltool.ExternalToolActivity;
+import net.sf.taverna.t2.activities.externaltool.ExternalToolActivityConfigurationBean;
+import net.sf.taverna.t2.activities.externaltool.manager.InvocationGroupManager;
+import net.sf.taverna.t2.activities.externaltool.manager.impl.InvocationGroupManagerImpl;
+import net.sf.taverna.t2.activities.externaltool.views.ExternalToolConfigView;
+import net.sf.taverna.t2.servicedescriptions.ServiceDescription;
+import net.sf.taverna.t2.workflowmodel.processor.activity.Activity;
+import de.uni_luebeck.inb.knowarc.usecases.UseCaseDescription;
+
+/**
+ * ExternalToolServiceDescription stores the repository URL and the use case id so
+ * that it can create an ExternalToolActivityConfigurationBean
+ * 
+ * @author Hajo Nils Krabbenhoeft
+ */
+public class ExternalToolServiceDescription extends ServiceDescription<ExternalToolActivityConfigurationBean> {
+	
+	private static Logger logger = Logger
+	.getLogger(ExternalToolServiceDescription.class);
+
+	
+	private static InvocationGroupManager manager = InvocationGroupManagerImpl.getInstance();
+
+	private String repositoryUrl;
+	private String externaltoolid;
+	private UseCaseDescription useCaseDescription;
+
+	public String getRepositoryUrl() {
+		return repositoryUrl;
+	}
+
+	public void setRepositoryUrl(String repositoryUrl) {
+		this.repositoryUrl = repositoryUrl;
+	}
+
+	public String getExternaltoolid() {
+		return externaltoolid;
+	}
+
+	public void setExternaltoolid(String externaltoolid) {
+		this.externaltoolid = externaltoolid;
+	}
+
+	public Icon getIcon() {
+		if (useCaseDescription != null) {
+			String icon_url = useCaseDescription.getIcon_url();
+			if ((icon_url != null) && !icon_url.isEmpty() && !icon_url.endsWith(".ico"))
+				try {
+					ImageIcon result = new ImageIcon(new URL(icon_url));
+					if ((result != null) && (result.getIconHeight() != 0) && (result.getIconWidth() != 0)){
+						return result;
+					}
+				} catch (MalformedURLException e) {
+					logger.error("Problematic URL" + icon_url, e);
+				}
+		}
+		return ExternalToolActivityIcon.getExternalToolIcon();
+	}
+
+	public Class<? extends Activity<ExternalToolActivityConfigurationBean>> getActivityClass() {
+		return ExternalToolActivity.class;
+	}
+
+	public ExternalToolActivityConfigurationBean getActivityConfiguration() {
+		ExternalToolActivityConfigurationBean bean = new ExternalToolActivityConfigurationBean();
+		bean.setRepositoryUrl(repositoryUrl);
+		bean.setExternaltoolid(externaltoolid);
+		bean.setUseCaseDescription(useCaseDescription);
+		bean.setMechanism(manager.getDefaultMechanism());
+
+		return bean;
+	}
+
+	public String getName() {
+		return externaltoolid;
+	}
+
+	@SuppressWarnings("unchecked")
+	public List<? extends Comparable> getPath() {
+		List<String> result = new ArrayList<String>();
+		result.add("Tools decribed @ " + repositoryUrl);
+		String group = useCaseDescription.getGroup();
+		if ((group != null) && !group.isEmpty()) {
+			String[] groups = group.split(":");
+			for (String g : groups) {
+				result.add(g);
+			}
+		}
+		return result;
+	}
+
+	protected List<Object> getIdentifyingData() {
+		// we require use cases inside one XML file to have unique IDs, which
+		// means every externaltool is uniquely identified by its repository URL and
+		// its use case ID.
+		return Arrays.<Object> asList(repositoryUrl, externaltoolid);
+	}
+	
+	public String getDescription() {
+		if (useCaseDescription != null) {
+			String description = useCaseDescription.getDescription();
+			if (description == null) {
+				return "";
+			}
+			return description;
+		}
+		return "";
+	}
+
+	public void setUseCaseDescription(UseCaseDescription usecase) {
+		this.useCaseDescription = usecase;
+	}
+
+}
diff --git a/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/servicedescriptions/ExternalToolServiceProvider.java b/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/servicedescriptions/ExternalToolServiceProvider.java
new file mode 100644
index 0000000..4f3cbf2
--- /dev/null
+++ b/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/servicedescriptions/ExternalToolServiceProvider.java
@@ -0,0 +1,132 @@
+/*******************************************************************************
+ * Copyright (C) 2009 Hajo Nils Krabbenhoeft, INB, University of Luebeck   
+ * 
+ *  Modifications to the initial code base are copyright of their
+ *  respective authors, or their employers as appropriate.
+ * 
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1 of
+ *  the License, or (at your option) any later version.
+ *    
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *    
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+
+package net.sf.taverna.t2.activities.externaltool.servicedescriptions;
+
+import java.io.IOException;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import javax.swing.Icon;
+
+import net.sf.taverna.t2.servicedescriptions.AbstractConfigurableServiceProvider;
+import net.sf.taverna.t2.servicedescriptions.CustomizedConfigurePanelProvider;
+import net.sf.taverna.t2.servicedescriptions.ServiceDescriptionRegistry;
+import de.uni_luebeck.inb.knowarc.usecases.UseCaseDescription;
+import de.uni_luebeck.inb.knowarc.usecases.UseCaseEnumeration;
+
+/**
+ * ExternalToolServiceProvider searches an use case repository XML for use case
+ * descriptions.
+ * 
+ * @author Hajo Nils Krabbenhoeft
+ */
+public class ExternalToolServiceProvider extends AbstractConfigurableServiceProvider<ExternalToolServiceProviderConfig>  implements
+CustomizedConfigurePanelProvider<ExternalToolServiceProviderConfig>{
+
+	private static final URI providerId = URI
+	.create("http://taverna.sf.net/2010/service-provider/externaltool");
+	
+	public ExternalToolServiceProvider() {
+		super(new ExternalToolServiceProviderConfig("http://taverna.nordugrid.org/sharedRepository/xml.php"));
+	}
+
+	public String getName() {
+		return "Tool service";
+	}
+
+	public List<ExternalToolServiceProviderConfig> getDefaultConfigurations() {
+		List<ExternalToolServiceProviderConfig> defaults = new ArrayList<ExternalToolServiceProviderConfig>();
+		// Disabled until sensible set
+//		defaults.add(new ExternalToolServiceProviderConfig("http://taverna.nordugrid.org/sharedRepository/xml.php"));
+		return defaults;
+	}
+
+	public void findServiceDescriptionsAsync(FindServiceDescriptionsCallBack callBack) {
+		String repositoryUrl = serviceProviderConfig.getRepositoryUrl();
+		callBack.status("Parsing use case repository:" + repositoryUrl);
+			// prepare a list of all use case descriptions which are stored in
+			// the given repository URL
+			List<UseCaseDescription> usecases = new ArrayList<UseCaseDescription> ();
+			try {
+				usecases = UseCaseEnumeration.readDescriptionsFromUrl(
+						repositoryUrl);
+			} catch (IOException e) {
+				callBack.fail("Unable to read tool descriptions", e);
+			}
+			callBack.status("Found " + usecases.size() + " use cases:" + repositoryUrl);
+			// convert all the UseCaseDescriptions in the XML file into
+			// ExternalToolServiceDescription items
+			List<ExternalToolServiceDescription> items = new ArrayList<ExternalToolServiceDescription>();
+			for (UseCaseDescription usecase : usecases) {
+				ExternalToolServiceDescription item = new ExternalToolServiceDescription();
+				item.setRepositoryUrl(repositoryUrl);
+				item.setExternaltoolid(usecase.getUsecaseid());
+				item.setUseCaseDescription(usecase);
+				items.add(item);
+			}
+			// we dont have streaming data loading or partial results, so return
+			// results and finish
+			callBack.partialResults(items);
+			callBack.finished();
+	}
+
+	@Override
+	public String toString() {
+		return getName() + " " + getConfiguration().getRepositoryUrl();
+	}
+
+	public Icon getIcon() {
+	    return ExternalToolActivityIcon.getExternalToolIcon();
+	}
+
+	@Override
+	protected List<? extends Object> getIdentifyingData() {
+		List<String> result;
+		// one can fully identify an use case repository by its URL
+		result = Arrays.asList(getConfiguration().getRepositoryUrl());
+		return result;
+	}
+
+	public void setServiceDescriptionRegistry(ServiceDescriptionRegistry registry) {
+	}
+	
+	@SuppressWarnings("serial")
+	public void createCustomizedConfigurePanel(final CustomizedConfigureCallBack<ExternalToolServiceProviderConfig> callBack) {
+			
+		AddExternalToolServiceDialog addWSDLServiceDialog = new AddExternalToolServiceDialog() {
+				@Override
+				protected void addRegistry(String externalToolURL) {
+					
+					ExternalToolServiceProviderConfig providerConfig = new ExternalToolServiceProviderConfig(externalToolURL);					
+					callBack.newProviderConfiguration(providerConfig);
+				}
+			};
+			addWSDLServiceDialog.setVisible(true);		
+	}
+
+
+	public String getId() {
+		return providerId.toString();
+	}
+}
diff --git a/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/servicedescriptions/ExternalToolServiceProviderConfig.java b/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/servicedescriptions/ExternalToolServiceProviderConfig.java
new file mode 100644
index 0000000..0967a6e
--- /dev/null
+++ b/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/servicedescriptions/ExternalToolServiceProviderConfig.java
@@ -0,0 +1,56 @@
+/*******************************************************************************
+ * Copyright (C) 2009 Hajo Nils Krabbenhoeft, INB, University of Luebeck   
+ * 
+ *  Modifications to the initial code base are copyright of their
+ *  respective authors, or their employers as appropriate.
+ * 
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1 of
+ *  the License, or (at your option) any later version.
+ *    
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *    
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+
+package net.sf.taverna.t2.activities.externaltool.servicedescriptions;
+
+import net.sf.taverna.t2.lang.beans.PropertyAnnotated;
+import net.sf.taverna.t2.lang.beans.PropertyAnnotation;
+
+/**
+ * ExternalToolServiceProviderConfig stores the URL of the use case repository XML file
+ * 
+ * @author Hajo Nils Krabbenhoeft
+ */
+public class ExternalToolServiceProviderConfig extends PropertyAnnotated {
+	private String repositoryUrl;
+
+	public ExternalToolServiceProviderConfig() {
+	}
+
+	public ExternalToolServiceProviderConfig(String repositoryUrl) {
+		this.repositoryUrl = repositoryUrl;
+	}
+
+	@PropertyAnnotation(displayName = "Tool registry location", preferred = true)
+	public String getRepositoryUrl() {
+		return repositoryUrl;
+	}
+
+	public void setRepositoryUrl(String repositoryUrl) {
+		this.repositoryUrl = repositoryUrl;
+	}
+
+	@Override
+	public String toString() {
+		return repositoryUrl;
+	}
+
+}
diff --git a/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/servicedescriptions/ExternalToolTemplateServiceDescription.java b/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/servicedescriptions/ExternalToolTemplateServiceDescription.java
new file mode 100644
index 0000000..30ae3eb
--- /dev/null
+++ b/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/servicedescriptions/ExternalToolTemplateServiceDescription.java
@@ -0,0 +1,77 @@
+/**
+ * 
+ */
+package net.sf.taverna.t2.activities.externaltool.servicedescriptions;
+
+import java.net.URI;
+import java.util.UUID;
+
+import javax.swing.Icon;
+
+import de.uni_luebeck.inb.knowarc.usecases.UseCaseDescription;
+
+import net.sf.taverna.t2.activities.externaltool.ExternalToolActivity;
+import net.sf.taverna.t2.activities.externaltool.ExternalToolActivityConfigurationBean;
+import net.sf.taverna.t2.activities.externaltool.manager.InvocationGroupManager;
+import net.sf.taverna.t2.activities.externaltool.manager.impl.InvocationGroupManagerImpl;
+import net.sf.taverna.t2.servicedescriptions.AbstractTemplateService;
+import net.sf.taverna.t2.servicedescriptions.ServiceDescription;
+import net.sf.taverna.t2.workflowmodel.processor.activity.Activity;
+
+/**
+ * @author alanrw
+ *
+ */
+public class ExternalToolTemplateServiceDescription extends
+		AbstractTemplateService<ExternalToolActivityConfigurationBean> {
+	
+	private static final URI providerId = URI
+	.create("http://taverna.sf.net/2010/service-provider/external-tool");
+	
+	private static final String EXTERNAL_TOOL = "Tool";
+	
+	private static InvocationGroupManager manager = InvocationGroupManagerImpl.getInstance();
+
+	@Override
+	public Class<? extends Activity<ExternalToolActivityConfigurationBean>> getActivityClass() {
+		return ExternalToolActivity.class;
+	}
+
+	@Override
+	public ExternalToolActivityConfigurationBean getActivityConfiguration() {
+		ExternalToolActivityConfigurationBean result = new ExternalToolActivityConfigurationBean();
+		result.setExternaltoolid(UUID.randomUUID().toString());
+		result.setUseCaseDescription(new UseCaseDescription(""));
+		result.setMechanism(manager.getDefaultMechanism());
+		return result;
+	}
+
+	@Override
+	public Icon getIcon() {
+		return ExternalToolActivityIcon.getExternalToolIcon();
+	}
+	
+	@Override
+	public String getDescription() {
+		return "A service that allows tools to be used as services";	
+	}
+	
+	@SuppressWarnings("unchecked")
+	public static ServiceDescription getServiceDescription() {
+		ExternalToolTemplateServiceDescription bts = new ExternalToolTemplateServiceDescription();
+		return bts.templateService;
+	}
+
+
+
+	@Override
+	public String getId() {
+		return providerId.toString();
+	}
+
+	@Override
+	public String getName() {
+		return EXTERNAL_TOOL;
+	}
+
+}
diff --git a/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/utils/Tools.java b/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/utils/Tools.java
new file mode 100644
index 0000000..55cda5c
--- /dev/null
+++ b/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/utils/Tools.java
@@ -0,0 +1,129 @@
+/**
+ * 
+ */
+package net.sf.taverna.t2.activities.externaltool.utils;
+
+import java.awt.Color;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+import java.awt.event.ActionEvent;
+import java.util.List;
+import java.util.Map;
+
+import javax.swing.AbstractAction;
+import javax.swing.BorderFactory;
+import javax.swing.JButton;
+import javax.swing.JComponent;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.border.CompoundBorder;
+
+import de.uni_luebeck.inb.knowarc.usecases.ScriptInput;
+import de.uni_luebeck.inb.knowarc.usecases.ScriptInputUser;
+
+import net.sf.taverna.t2.lang.ui.DeselectingButton;
+
+/**
+ * @author alanrw
+ *
+ */
+public class Tools {
+	
+	private static CompoundBorder border = BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(5,5,5,5), BorderFactory.createLineBorder(Color.BLACK, 1));
+	
+	private static Insets insets = new Insets(5,5,5,5);
+	
+	public static void addViewer(final JPanel innerPanel, String[] labels, JComponent[] elements,
+			final List viewerList, final Object viewer, final JPanel outerPanel) {
+		final JPanel subPanel = new JPanel();
+		subPanel.setLayout(new GridBagLayout());
+		subPanel.setBorder(border);
+		
+		final GridBagConstraints labelConstraint = new GridBagConstraints();
+		labelConstraint.insets = insets;
+		labelConstraint.anchor = GridBagConstraints.FIRST_LINE_START;
+		labelConstraint.fill = GridBagConstraints.BOTH;
+		labelConstraint.gridy = 0;
+		labelConstraint.gridx = 0;
+		labelConstraint.weightx = 0;
+
+		final GridBagConstraints elementConstraint = new GridBagConstraints();
+		elementConstraint.insets = insets;
+		elementConstraint.anchor = GridBagConstraints.FIRST_LINE_START;
+		elementConstraint.fill = GridBagConstraints.BOTH;
+		elementConstraint.gridy = 0;
+		elementConstraint.gridx = 1;
+		elementConstraint.weightx = 1.0;
+		
+		final GridBagConstraints removeConstraint = new GridBagConstraints();
+		removeConstraint.insets = insets;
+		removeConstraint.anchor = GridBagConstraints.FIRST_LINE_START;
+		removeConstraint.fill = GridBagConstraints.BOTH;
+		removeConstraint.gridx = 1;
+		removeConstraint.weightx = 0;
+		removeConstraint.fill = GridBagConstraints.NONE;
+		removeConstraint.anchor = GridBagConstraints.EAST;
+		
+		final GridBagConstraints subPanelConstraint = new GridBagConstraints();
+		subPanelConstraint.insets = insets;
+		subPanelConstraint.anchor = GridBagConstraints.FIRST_LINE_START;
+		subPanelConstraint.fill = GridBagConstraints.BOTH;
+		subPanelConstraint.gridx = 1;
+//		subPanelConstraint.gridy = ++stringReplacementGridy;
+		subPanelConstraint.weightx = 1.00;
+		subPanelConstraint.fill = GridBagConstraints.HORIZONTAL;
+		subPanelConstraint.anchor = GridBagConstraints.WEST;		
+		
+		for (int i = 0; i < labels.length; i++) {
+			subPanel.add(new JLabel(labels[i] + ":"), labelConstraint);
+			subPanel.add(elements[i], elementConstraint);
+			labelConstraint.gridy++;
+			elementConstraint.gridy++;
+		}
+		
+		removeConstraint.gridy = labelConstraint.gridy + 1;
+		final JButton removeButton = new DeselectingButton("Remove",
+				new AbstractAction() {
+
+			public void actionPerformed(ActionEvent e) {
+				synchronized (viewerList) {
+					viewerList.remove(viewer);
+				}
+				innerPanel.remove(subPanel);
+				innerPanel.revalidate();
+				innerPanel.repaint();
+				outerPanel.revalidate();
+				outerPanel.repaint();
+			}
+
+		});
+		subPanel.add(removeButton, removeConstraint);
+		innerPanel.add(subPanel, subPanelConstraint);
+	}
+	
+	public static boolean isStringReplacement(ScriptInputUser si) {
+		return !si.isList() && !si.isFile() && !si.isTempFile();
+	}
+	
+	public static boolean isInputFile(ScriptInputUser si) {
+		return !si.isList() && si.isFile();
+	}
+
+	public static boolean isFileList(ScriptInputUser si) {
+		return si.isList() && si.isFile();
+	}
+	
+	public static boolean isUnderstood(ScriptInputUser si) {
+		return isStringReplacement(si) || isInputFile(si) || isFileList(si);
+	}
+	
+	public static boolean areAllUnderstood(Map<String, ScriptInput> inputs) {
+		for (ScriptInput si : inputs.values()) {
+			if ((si instanceof ScriptInputUser) && !isUnderstood((ScriptInputUser) si)) {
+				return false;
+			}
+		}
+		return true;
+	}
+}
diff --git a/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/views/AnnotationPanel.java b/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/views/AnnotationPanel.java
new file mode 100644
index 0000000..83e75e8
--- /dev/null
+++ b/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/views/AnnotationPanel.java
@@ -0,0 +1,41 @@
+/**
+ * 
+ */
+package net.sf.taverna.t2.activities.externaltool.views;
+
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.FlowLayout;
+
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+
+/**
+ * @author alanrw
+ *
+ */
+public class AnnotationPanel extends JPanel {
+	
+	public AnnotationPanel(Component nameField, Component descriptionArea, Component groupField) {
+		super();
+		this.setLayout(new BorderLayout());
+		JPanel subPanel = new JPanel(new BorderLayout());
+		JPanel namePanel = new JPanel();
+		namePanel.setLayout(new FlowLayout(FlowLayout.LEFT));
+		namePanel.add(new JLabel("Name: "));
+		namePanel.add(nameField);
+		subPanel.add(namePanel, BorderLayout.NORTH);
+		JPanel groupPanel = new JPanel();
+		groupPanel.setLayout(new FlowLayout(FlowLayout.LEFT));
+		groupPanel.add(new JLabel("Group: "));
+		groupPanel.add(groupField);
+		subPanel.add(groupPanel, BorderLayout.SOUTH);
+		this.add(subPanel, BorderLayout.NORTH);
+		JPanel descriptionPanel = new JPanel();
+		descriptionPanel.setLayout(new BorderLayout());
+		descriptionPanel.add(new JLabel("Description:"), BorderLayout.NORTH);
+		descriptionPanel.add(descriptionArea, BorderLayout.CENTER);
+		this.add(descriptionPanel, BorderLayout.CENTER);
+	}
+
+}
diff --git a/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/views/EditablePanel.java b/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/views/EditablePanel.java
new file mode 100644
index 0000000..b395983
--- /dev/null
+++ b/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/views/EditablePanel.java
@@ -0,0 +1,76 @@
+/**
+ * 
+ */
+package net.sf.taverna.t2.activities.externaltool.views;
+
+import java.awt.FlowLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.swing.AbstractAction;
+import javax.swing.JButton;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+
+import de.uni_luebeck.inb.knowarc.usecases.UseCaseDescription;
+import de.uni_luebeck.inb.knowarc.usecases.UseCaseEnumeration;
+
+import net.sf.taverna.t2.activities.externaltool.ExternalToolActivityConfigurationBean;
+import net.sf.taverna.t2.activities.externaltool.servicedescriptions.ExternalToolServiceDescription;
+import net.sf.taverna.t2.activities.externaltool.utils.Tools;
+import net.sf.taverna.t2.lang.ui.DeselectingButton;
+
+/**
+ * @author alanrw
+ *
+ */
+public class EditablePanel extends JPanel {
+	public EditablePanel(final ExternalToolConfigView view) {
+		super(new FlowLayout());
+		
+		JButton update = new DeselectingButton("Update tool description",
+				new AbstractAction() {
+
+			@Override
+			public void actionPerformed(ActionEvent e) {
+				ExternalToolActivityConfigurationBean bean = view.getConfiguration();
+				String repositoryUrl = bean.getRepositoryUrl();
+				String id = bean.getExternaltoolid();
+				UseCaseDescription usecase = null;
+				try {
+					usecase = UseCaseEnumeration.readDescriptionFromUrl(
+						repositoryUrl, id);
+				}
+				catch (IOException ex) {
+					// Already logged
+				}
+				if (usecase != null) {
+					bean.setUseCaseDescription(usecase);
+					view.refreshConfiguration(bean);
+				} else {
+					JOptionPane.showMessageDialog(view, "Unable to find tool description " + id, "Missing tool description", JOptionPane.ERROR_MESSAGE);
+				}
+			}});
+		this.add(update);
+		
+		JButton makeEditable = new DeselectingButton("Edit tool description",
+				new AbstractAction() {
+
+			@Override
+			public void actionPerformed(ActionEvent arg0) {
+				ExternalToolActivityConfigurationBean config = view.makeConfiguration();
+				view.setEditable(true, config);
+				
+			}
+		});
+		makeEditable.setToolTipText("Edit the tool description");
+		if (Tools.areAllUnderstood(view.getConfiguration().getUseCaseDescription().getInputs())) {
+		this.add(makeEditable);
+		}
+		
+	}
+
+}
diff --git a/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/views/ExternalToolActivityContextualView.java b/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/views/ExternalToolActivityContextualView.java
new file mode 100644
index 0000000..46c14be
--- /dev/null
+++ b/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/views/ExternalToolActivityContextualView.java
@@ -0,0 +1,181 @@
+/*******************************************************************************
+ * Copyright (C) 2010 Hajo Nils Krabbenhoeft, INB, University of Luebeck
+ *
+ *  Modifications to the initial code base are copyright of their
+ *  respective authors, or their employers as appropriate.
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1 of
+ *  the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+
+package net.sf.taverna.t2.activities.externaltool.views;
+
+import java.awt.Frame;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.TreeMap;
+
+import javax.swing.Action;
+
+import net.sf.taverna.t2.activities.externaltool.ExternalToolActivity;
+import net.sf.taverna.t2.activities.externaltool.ExternalToolActivityConfigurationBean;
+import net.sf.taverna.t2.activities.externaltool.actions.ExternalToolActivityConfigureAction;
+import net.sf.taverna.t2.activities.externaltool.servicedescriptions.ExternalToolActivityIcon;
+import net.sf.taverna.t2.workbench.activityicons.ActivityIconManager;
+import net.sf.taverna.t2.workbench.configuration.colour.ColourManager;
+import net.sf.taverna.t2.workbench.edits.EditManager;
+import net.sf.taverna.t2.workbench.file.FileManager;
+import net.sf.taverna.t2.workbench.ui.actions.activity.HTMLBasedActivityContextualView;
+import net.sf.taverna.t2.workflowmodel.processor.activity.Activity;
+import de.uni_luebeck.inb.knowarc.usecases.ScriptInput;
+import de.uni_luebeck.inb.knowarc.usecases.ScriptInputStatic;
+import de.uni_luebeck.inb.knowarc.usecases.ScriptOutput;
+import de.uni_luebeck.inb.knowarc.usecases.UseCaseDescription;
+
+/**
+ * ExternalToolActivityContextualView displays the use case information in a HTML table. Currently,
+ * this is only the use case ID.
+ *
+ * @author Hajo Nils Krabbenhoeft
+ */
+public class ExternalToolActivityContextualView extends
+		HTMLBasedActivityContextualView<ExternalToolActivityConfigurationBean> {
+	private static final long serialVersionUID = 1L;
+	private final EditManager editManager;
+	private final FileManager fileManager;
+	private final ActivityIconManager activityIconManager;
+
+	public ExternalToolActivityContextualView(Activity<?> activity, EditManager editManager,
+			FileManager fileManager, ColourManager colourManager, ActivityIconManager activityIconManager) {
+		super(activity, colourManager);
+		this.editManager = editManager;
+		this.fileManager = fileManager;
+		this.activityIconManager = activityIconManager;
+	}
+
+	@Override
+	protected String getRawTableRowsHtml() {
+		String html = "";
+		ExternalToolActivityConfigurationBean bean = getConfigBean();
+		String repositoryUrl = bean.getRepositoryUrl();
+		if ((repositoryUrl == null) || repositoryUrl.isEmpty()) {
+			repositoryUrl = "<b>Not specified</b>";
+		}
+		html += "<tr><td>Repository URL</td><td>" + repositoryUrl + "</td></tr>";
+
+		String id = bean.getExternaltoolid();
+		if ((id == null) || id.isEmpty()) {
+			id = "<b>Not specified</b>";
+		}
+		html += "<tr><td>Id</td><td>" + id + "</td></tr>";
+
+		UseCaseDescription useCaseDescription = bean.getUseCaseDescription();
+		String name = useCaseDescription.getUsecaseid();
+		if ((name == null) || name.isEmpty()) {
+			name = "<b>Not specified</b>";
+		}
+		html += "<tr><td>Name</td><td>" + name + "</td></tr>";
+
+		Map<String, ScriptInput> stringReplacements = new TreeMap<String, ScriptInput>();
+		Map<String, ScriptInput> fileInputs = new TreeMap<String, ScriptInput>();
+
+		for (Entry<String, ScriptInput> entry : useCaseDescription.getInputs().entrySet()) {
+			String key = entry.getKey();
+			ScriptInput value = entry.getValue();
+			if (value.isFile()) {
+				fileInputs.put(key, value);
+			} else if (value.isTempFile()) {
+				// Nothing
+			} else {
+				stringReplacements.put(key, value);
+			}
+		}
+
+		if (!stringReplacements.isEmpty()) {
+			html += "<tr><td colspan=2 align=center><b>String replacements</b></td></tr>";
+			html += "<tr><td><b>Port name</b></td><td><b>Replaces</b></td></tr>";
+			for (String siName : stringReplacements.keySet()) {
+				html += "<tr><td>" + siName + "</td>";
+				ScriptInput si = stringReplacements.get(siName);
+				html += "<td>%%" + si.getTag() + "%%</td>";
+
+				html += "</tr>";
+			}
+		}
+
+		if (!fileInputs.isEmpty()) {
+			html += "<tr><td colspan=2 align=center><b>File inputs</b></td></tr>";
+			html += "<tr><td><b>Port name</b></td><td><b>To file</b></td></tr>";
+			for (String siName : fileInputs.keySet()) {
+				html += "<tr><td>" + siName + "</td>";
+				ScriptInput si = fileInputs.get(siName);
+				html += "<td>" + si.getTag() + "</td>";
+
+				html += "</tr>";
+			}
+		}
+
+		List<ScriptInputStatic> staticInputs = useCaseDescription.getStatic_inputs();
+		if (!staticInputs.isEmpty()) {
+			html += "<tr><td colspan=2 align=center><b>Static inputs</b></td></tr>";
+			html += "<tr><td><b>Type</b></td><td><b>To file</b></td></tr>";
+			for (ScriptInputStatic si : staticInputs) {
+				if (si.getUrl() != null) {
+					html += "<td><b>URL</b></td>";
+				} else {
+					html += "<td><b>Explicit content</b></td>";
+				}
+				if (si.isFile()) {
+					html += "<td>" + si.getTag() + "</td>";
+				}
+				html += "</tr>";
+			}
+		}
+		Map<String, ScriptOutput> outputs = useCaseDescription.getOutputs();
+		if (!outputs.isEmpty()) {
+			html += "<tr><td colspan=2 align=center><b>File outputs</b></td></tr>";
+			html += "<tr><td><b>Port name</b></td><td><b>From file</b></td></tr>";
+			for (String soName : outputs.keySet()) {
+				html += "<tr><td>" + soName + "</td>";
+				ScriptOutput so = outputs.get(soName);
+				html += "<td>" + so.getPath() + "</td>";
+				html += "</tr>";
+			}
+		}
+		return html;
+	}
+
+	@Override
+	public String getViewTitle() {
+		return "Tool service";
+	}
+
+	@Override
+	public Action getConfigureAction(final Frame owner) {
+		return new ExternalToolActivityConfigureAction((ExternalToolActivity) getActivity(), owner,
+				editManager, fileManager, activityIconManager);
+	}
+
+	public String getBackgroundColour() {
+
+		return ExternalToolActivityIcon.getColourString();
+	}
+
+	@Override
+	public int getPreferredPosition() {
+		return 100;
+	}
+
+}
diff --git a/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/views/ExternalToolActivityViewFactory.java b/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/views/ExternalToolActivityViewFactory.java
new file mode 100644
index 0000000..902c736
--- /dev/null
+++ b/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/views/ExternalToolActivityViewFactory.java
@@ -0,0 +1,76 @@
+/*******************************************************************************
+ * Copyright (C) 2010 Hajo Nils Krabbenhoeft, INB, University of Luebeck
+ *
+ *  Modifications to the initial code base are copyright of their
+ *  respective authors, or their employers as appropriate.
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1 of
+ *  the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+
+package net.sf.taverna.t2.activities.externaltool.views;
+
+import java.util.Arrays;
+import java.util.List;
+
+import net.sf.taverna.t2.activities.externaltool.ExternalToolActivity;
+import net.sf.taverna.t2.workbench.activityicons.ActivityIconManager;
+import net.sf.taverna.t2.workbench.configuration.colour.ColourManager;
+import net.sf.taverna.t2.workbench.edits.EditManager;
+import net.sf.taverna.t2.workbench.file.FileManager;
+import net.sf.taverna.t2.workbench.ui.views.contextualviews.ContextualView;
+import net.sf.taverna.t2.workbench.ui.views.contextualviews.activity.ContextualViewFactory;
+
+/**
+ * ExternalToolActivityViewFactory produces an ExternalToolActivityContextualView to show
+ * information for a use case activity.
+ *
+ * @author Hajo Nils Krabbenhoeft
+ */
+public class ExternalToolActivityViewFactory implements ContextualViewFactory<ExternalToolActivity> {
+
+	private EditManager editManager;
+	private FileManager fileManager;
+	private ActivityIconManager activityIconManager;
+	private ColourManager colourManager;
+
+	public boolean canHandle(Object object) {
+		if (object instanceof ExternalToolActivity) {
+			return true;
+		}
+		return false;
+	}
+
+	public List<ContextualView> getViews(ExternalToolActivity selection) {
+		return Arrays.asList(new ContextualView[] { new ExternalToolActivityContextualView(
+				selection, editManager, fileManager, colourManager, activityIconManager) });
+	}
+
+	public void setEditManager(EditManager editManager) {
+		this.editManager = editManager;
+	}
+
+	public void setFileManager(FileManager fileManager) {
+		this.fileManager = fileManager;
+	}
+
+	public void setActivityIconManager(ActivityIconManager activityIconManager) {
+		this.activityIconManager = activityIconManager;
+	}
+
+	public void setColourManager(ColourManager colourManager) {
+		this.colourManager = colourManager;
+	}
+
+}
diff --git a/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/views/ExternalToolConfigView.java b/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/views/ExternalToolConfigView.java
new file mode 100644
index 0000000..4723a78
--- /dev/null
+++ b/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/views/ExternalToolConfigView.java
@@ -0,0 +1,868 @@
+/*******************************************************************************
+ * Copyright (C) 2007 The University of Manchester   
+ * 
+ *  Modifications to the initial code base are copyright of their
+ *  respective authors, or their employers as appropriate.
+ * 
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1 of
+ *  the License, or (at your option) any later version.
+ *    
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *    
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+package net.sf.taverna.t2.activities.externaltool.views;
+
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.Map.Entry;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.help.CSH;
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JEditorPane;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JTabbedPane;
+import javax.swing.JTextArea;
+import javax.swing.JTextField;
+import javax.swing.JTextPane;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+
+import net.sf.taverna.t2.activities.externaltool.ExternalToolActivity;
+import net.sf.taverna.t2.activities.externaltool.ExternalToolActivityConfigurationBean;
+import net.sf.taverna.t2.activities.externaltool.ExternalToolActivityHealthChecker;
+import net.sf.taverna.t2.activities.externaltool.utils.Tools;
+import net.sf.taverna.t2.lang.ui.KeywordDocument;
+import net.sf.taverna.t2.lang.ui.LinePainter;
+import net.sf.taverna.t2.lang.ui.NoWrapEditorKit;
+import net.sf.taverna.t2.workbench.ui.views.contextualviews.activity.ActivityConfigurationPanel;
+
+import org.apache.log4j.Logger;
+
+import de.uni_luebeck.inb.knowarc.usecases.ScriptInput;
+import de.uni_luebeck.inb.knowarc.usecases.ScriptInputStatic;
+import de.uni_luebeck.inb.knowarc.usecases.ScriptInputUser;
+import de.uni_luebeck.inb.knowarc.usecases.ScriptOutput;
+import de.uni_luebeck.inb.knowarc.usecases.UseCaseDescription;
+
+/**
+ * Provides the configurable view for a {@link ExternalToolActivity} through
+ * it's {@link ExternalToolActivityConfigurationBean}. Has 3 main tabs - Script,
+ * Ports & Dependencies. The {@link #inputViewList} contains the
+ * {@link ExternalToolInputViewer}s describing the input ports and
+ * {@link #outputViewList} has the {@link ExternalToolFileViewer}s
+ * 
+ * @author Ian Dunlop
+ * @author Alex Nenadic
+ * @author Alan R Williams
+ * 
+ */
+@SuppressWarnings("serial")
+public class ExternalToolConfigView
+		extends
+		ActivityConfigurationPanel<ExternalToolActivity, ExternalToolActivityConfigurationBean> {
+	
+	private static final Color LINE_COLOR = new Color(225,225,225);
+
+	private static final String FILE_INPUT_DESCRIPTION = "You can use a file input to feed data into " +
+			"the service via an input port and have that data written to the specified file.";
+
+	private static final String FILE_OUTPUT_DESCRIPTION = "You can use a file output to take the " +
+			"content of a file produced by the tool and send it to an output port of the service.";
+
+	private static final String FILE_LIST_DESCRIPTION = "If you feed a list of data into a file list " +
+			"input, then each data item is written to a temporary file. A file is produced containing " +
+			"the names of those temporary file. That index file can then be used as part of the tool " +
+			"command.";
+
+	private static final String VALID_NAME_REGEX = "[\\p{L}\\p{Digit}_]+";
+
+	private static Logger logger = Logger
+			.getLogger(ExternalToolConfigView.class);
+
+	/** The activity which this view describes */
+	protected ExternalToolActivity activity;
+
+	/** The configuration bean used to configure the activity */
+	private ExternalToolActivityConfigurationBean configuration;
+
+	private JTabbedPane tabbedPane = null;
+	private JPanel advancedPanel = null;
+	private JTabbedPane advancedTab = null;
+	private AnnotationPanel annotationPanel = null;
+	
+	private int stringReplacementGridy = 1;
+	private List<ExternalToolStringReplacementViewer> stringReplacementViewList = new ArrayList<ExternalToolStringReplacementViewer>();
+
+	private List<ExternalToolFileViewer> inputFileViewList = new ArrayList<ExternalToolFileViewer>();
+
+	private List<ExternalToolFileViewer> fileListViewList = new ArrayList<ExternalToolFileViewer>();
+
+	private int inputGridy = 1;
+
+	private int outputGridy = 1;
+	private List<ExternalToolFileViewer> outputViewList = new ArrayList<ExternalToolFileViewer>();
+
+	private int staticGridy = 1;
+	private List<ExternalToolStaticUrlViewer> staticUrlViewList = new ArrayList<ExternalToolStaticUrlViewer>();
+
+	private List<ExternalToolStaticStringViewer> staticStringViewList = new ArrayList<ExternalToolStaticStringViewer>();
+
+/*	private List<ExternalToolRuntimeEnvironmentViewer> runtimeEnvironmentViewList = new ArrayList<ExternalToolRuntimeEnvironmentViewer>();
+*/
+
+	private JTextField nameField = new JTextField(20);
+	private JTextField groupField = new JTextField(20);
+	private JTextArea descriptionArea = new JTextArea(6, 40);
+
+	private JEditorPane scriptTextArea;
+
+	private InvocationPanel invocationPanel;
+
+	private JCheckBox stdInCheckBox = new JCheckBox("Show STDIN");
+	private JCheckBox stdOutCheckBox = new JCheckBox("Show STDOUT");
+	private JCheckBox stdErrCheckBox = new JCheckBox("Show STDERR");
+	
+	private JTextField returnCodesField = new JTextField(20);
+
+	/**
+	 * Stores the {@link ExternalToolActivity}, gets its
+	 * {@link ExternalToolActivityConfigurationBean}, sets the layout and calls
+	 * {@link #initialise()} to get the view going
+	 * 
+	 * @param activity
+	 *            the {@link ExternalToolActivity} that the view is over
+	 */
+	public ExternalToolConfigView(ExternalToolActivity activity) {
+		this.activity = activity;
+		ExternalToolActivityHealthChecker.updateLocation(activity.getConfiguration());
+		configuration = (ExternalToolActivityConfigurationBean) cloneBean(activity
+				.getConfiguration());
+		setLayout(new GridBagLayout());
+		initialise(configuration);
+	}
+
+	public void noteConfiguration() {
+		configuration = makeConfiguration();
+	}
+
+	public ExternalToolActivityConfigurationBean makeConfiguration() {
+		ExternalToolActivityConfigurationBean newConfiguration = (ExternalToolActivityConfigurationBean) cloneBean(configuration);
+		ExternalToolActivityHealthChecker.updateLocation(newConfiguration);
+		
+
+		if (!isFromRepository()) {
+			UseCaseDescription ucd = newConfiguration.getUseCaseDescription();
+
+			ucd.setUsecaseid(nameField.getText());
+			if (groupField.getText().isEmpty()) {
+				ucd.setGroup(null);
+			} else {
+				ucd.setGroup(groupField.getText());
+			}
+			ucd.setDescription(descriptionArea.getText());
+			ucd.setCommand(scriptTextArea.getText());
+			ucd.setReturnCodesAsText(returnCodesField.getText());
+			ucd.setIncludeStdIn(stdInCheckBox.isSelected());
+			ucd.setIncludeStdOut(stdOutCheckBox.isSelected());
+			ucd.setIncludeStdErr(stdErrCheckBox.isSelected());
+
+			ucd.getInputs().clear();
+			ucd.getTags().clear();
+			synchronized (fileListViewList) {
+				for (ExternalToolFileViewer viewer : fileListViewList) {
+					ScriptInputUser si = new ScriptInputUser();
+					si.setBinary(viewer.isBinary());
+					si.setList(true);
+					si.setTag(viewer.getValue());
+					si.setTempFile(false);
+					si.setFile(true);
+					ucd.getInputs().put(viewer.getName(), si);
+				}
+			}
+
+			synchronized (stringReplacementViewList) {
+				for (ExternalToolStringReplacementViewer viewer : stringReplacementViewList) {
+					ScriptInputUser si = new ScriptInputUser();
+					si.setBinary(false);
+					si.setList(false);
+					si.setTag(viewer.getValue());
+					si.setTempFile(false);
+					si.setFile(false);
+					ucd.getTags().add(si.getTag());
+					ucd.getInputs().put(viewer.getName(), si);
+				}
+			}
+
+			synchronized (inputFileViewList) {
+				for (ExternalToolFileViewer viewer : inputFileViewList) {
+					ScriptInputUser si = new ScriptInputUser();
+					si.setBinary(viewer.isBinary());
+					si.setList(false);
+					si.setTag(viewer.getValue());
+					si.setTempFile(false);
+					si.setFile(true);
+					ucd.getInputs().put(viewer.getName(), si);
+				}
+			}
+
+			synchronized (outputViewList) {
+				ucd.getOutputs().clear();
+				for (ExternalToolFileViewer viewer : outputViewList) {
+					ScriptOutput so = new ScriptOutput();
+					so.setBinary(viewer.isBinary());
+					so.setPath(viewer.getValue());
+					ucd.getOutputs().put(viewer.getName(), so);
+				}
+			}
+			ucd.getStatic_inputs().clear();
+			synchronized (staticStringViewList) {
+				for (ExternalToolStaticStringViewer viewer : staticStringViewList) {
+					ScriptInputStatic sis = new ScriptInputStatic();
+					sis.setContent(viewer.getContent());
+					sis.setTag(viewer.getValue());
+					sis.setTempFile(false);
+					sis.setFile(true);
+					ucd.getStatic_inputs().add(sis);
+				}
+			}
+			synchronized (staticUrlViewList) {
+				for (ExternalToolStaticUrlViewer viewer : staticUrlViewList) {
+					ScriptInputStatic sis = new ScriptInputStatic();
+					sis.setUrl(viewer.getContent());
+					sis.setTag(viewer.getValue());
+					sis.setTempFile(false);
+					sis.setFile(true);
+					ucd.getStatic_inputs().add(sis);
+				}
+			}
+
+/*			synchronized (runtimeEnvironmentViewList) {
+				ucd.getREs().clear();
+				for (ExternalToolRuntimeEnvironmentViewer viewer : runtimeEnvironmentViewList) {
+					RuntimeEnvironmentConstraint newConstraint = new RuntimeEnvironmentConstraint(
+							viewer.getId(), viewer.getRelation());
+					ucd.getREs().add(newConstraint);
+				}
+			}*/
+		}
+		invocationPanel.fillInConfiguration(newConfiguration);
+
+		return newConfiguration;
+	}
+
+	public boolean isConfigurationChanged() {
+		String configurationString = convertBeanToString(activity
+				.getConfiguration());
+		return (!convertBeanToString(makeConfiguration()).equals(
+				configurationString));
+	}
+
+	/**
+	 * Adds a {@link JButton} which handles the reconfiguring of the
+	 * {@link ExternalToolActivity} through the altered
+	 * {@link ExternalToolActivityConfigurationBean}. Sets up the initial tabs -
+	 * Script (also sets the initial value), Ports & Dependencies and their
+	 * initial values through {@link #setDependencies()},
+	 * {@link #getPortPanel()}
+	 */
+	private void initialise(ExternalToolActivityConfigurationBean configuration) {
+		CSH.setHelpIDString(
+				this,
+				"net.sf.taverna.t2.workbench.ui.views.contextualviews.activity.ExternalToolConfigView");
+		this.configuration = configuration;
+		setBorder(javax.swing.BorderFactory.createTitledBorder(null, null,
+				javax.swing.border.TitledBorder.DEFAULT_JUSTIFICATION,
+				javax.swing.border.TitledBorder.DEFAULT_POSITION,
+				new java.awt.Font("Lucida Grande", 1, 12)));
+
+		tabbedPane = new JTabbedPane();
+		
+		if (invocationPanel != null) {
+			invocationPanel.stopObserving();
+		}
+
+		if (!isFromRepository()) {
+			UseCaseDescription useCaseDescription = configuration
+					.getUseCaseDescription();
+
+			nameField.setText(useCaseDescription.getUsecaseid());
+			if (useCaseDescription.getGroup() != null) {
+				groupField.setText(useCaseDescription.getGroup());
+			}
+			descriptionArea.setText(useCaseDescription.getDescription());
+			stringReplacementViewList = new ArrayList<ExternalToolStringReplacementViewer>();
+			inputFileViewList = new ArrayList<ExternalToolFileViewer>();
+			fileListViewList = new ArrayList<ExternalToolFileViewer>();
+			outputViewList = new ArrayList<ExternalToolFileViewer>();
+			staticUrlViewList = new ArrayList<ExternalToolStaticUrlViewer>();
+			staticStringViewList = new ArrayList<ExternalToolStaticStringViewer>();
+/*			runtimeEnvironmentViewList = new ArrayList<ExternalToolRuntimeEnvironmentViewer>();*/
+
+			for (Entry<String, ScriptInput> entry : useCaseDescription
+					.getInputs().entrySet()) {
+				String name = entry.getKey();
+				ScriptInputUser si = (ScriptInputUser) entry.getValue();
+				if (Tools.isStringReplacement(si)) {
+					final ExternalToolStringReplacementViewer inputView = new ExternalToolStringReplacementViewer(
+							name, si);
+					stringReplacementViewList.add(inputView);
+				}
+
+			}
+			Collections.sort(stringReplacementViewList,
+					new Comparator<ExternalToolStringReplacementViewer>() {
+
+						@Override
+						public int compare(
+								ExternalToolStringReplacementViewer o1,
+								ExternalToolStringReplacementViewer o2) {
+							return o1.getName().compareTo(o2.getName());
+						}
+					});
+
+			for (Entry<String, ScriptInput> entry : useCaseDescription
+					.getInputs().entrySet()) {
+				String name = entry.getKey();
+				ScriptInputUser si = (ScriptInputUser) entry.getValue();
+				if (Tools.isInputFile(si)) {
+					final ExternalToolFileViewer inputView = new ExternalToolFileViewer(
+							name, si.getTag(), si.isBinary());
+					inputFileViewList.add(inputView);
+				}
+
+			}
+			Collections.sort(inputFileViewList,
+					new Comparator<ExternalToolFileViewer>() {
+
+						@Override
+						public int compare(ExternalToolFileViewer o1,
+								ExternalToolFileViewer o2) {
+							return o1.getName().compareTo(o2.getName());
+						}
+					});
+
+			for (Entry<String, ScriptInput> entry : useCaseDescription
+					.getInputs().entrySet()) {
+				String name = entry.getKey();
+				ScriptInputUser si = (ScriptInputUser) entry.getValue();
+				if (Tools.isFileList(si)) {
+					final ExternalToolFileViewer inputView = new ExternalToolFileViewer(
+							name, si.getTag(), si.isBinary());
+					fileListViewList.add(inputView);
+				}
+
+			}
+			Collections.sort(fileListViewList,
+					new Comparator<ExternalToolFileViewer>() {
+
+						@Override
+						public int compare(ExternalToolFileViewer o1,
+								ExternalToolFileViewer o2) {
+							return o1.getName().compareTo(o2.getName());
+						}
+					});
+
+			for (Entry<String, ScriptOutput> entry : useCaseDescription
+					.getOutputs().entrySet()) {
+				ScriptOutput so = entry.getValue();
+				final ExternalToolFileViewer outputView = new ExternalToolFileViewer(
+						entry.getKey(), so.getPath(), so.isBinary());
+				outputViewList.add(outputView);
+			}
+			Collections.sort(outputViewList,
+					new Comparator<ExternalToolFileViewer>() {
+
+						@Override
+						public int compare(ExternalToolFileViewer o1,
+								ExternalToolFileViewer o2) {
+							return o1.getName().compareTo(o2.getName());
+						}
+					});
+
+			for (ScriptInputStatic siss : useCaseDescription.getStatic_inputs()) {
+				if ((siss.getUrl() == null) && siss.isFile()) {
+					final ExternalToolStaticStringViewer staticView = new ExternalToolStaticStringViewer(
+							siss);
+					staticStringViewList.add(staticView);
+				}
+			}
+			Collections.sort(staticStringViewList,
+					new Comparator<ExternalToolStaticStringViewer>() {
+
+						@Override
+						public int compare(ExternalToolStaticStringViewer o1,
+								ExternalToolStaticStringViewer o2) {
+							return o1.getContent().compareTo(o2.getContent());
+						}
+					});
+
+			for (ScriptInputStatic sis : useCaseDescription.getStatic_inputs()) {
+				if ((sis.getUrl() != null) && sis.isFile()) {
+					final ExternalToolStaticUrlViewer staticView = new ExternalToolStaticUrlViewer(
+							sis);
+					staticUrlViewList.add(staticView);
+				}
+			}
+			Collections.sort(staticUrlViewList,
+					new Comparator<ExternalToolStaticUrlViewer>() {
+
+						@Override
+						public int compare(ExternalToolStaticUrlViewer o1,
+								ExternalToolStaticUrlViewer o2) {
+							return o1.getContent().compareTo(o2.getContent());
+						}
+					});
+
+/*			for (RuntimeEnvironmentConstraint rec : useCaseDescription.getREs()) {
+				final ExternalToolRuntimeEnvironmentViewer newView = new ExternalToolRuntimeEnvironmentViewer(
+						rec.getID(), rec.getRelation());
+				runtimeEnvironmentViewList.add(newView);
+			}
+			Collections.sort(runtimeEnvironmentViewList,
+					new Comparator<ExternalToolRuntimeEnvironmentViewer>() {
+
+						@Override
+						public int compare(
+								ExternalToolRuntimeEnvironmentViewer o1,
+								ExternalToolRuntimeEnvironmentViewer o2) {
+							return o1.getId().compareTo(o2.getId());
+						}
+					});*/
+
+			scriptTextArea = new JTextPane();
+			new LinePainter(scriptTextArea, LINE_COLOR);
+
+			final KeywordDocument doc = new KeywordDocument(
+					new HashSet<String>());
+			// NOTE: Due to T2-1145 - always set editor kit BEFORE setDocument
+			scriptTextArea.setEditorKit(new NoWrapEditorKit());
+			scriptTextArea.setFont(new Font("Monospaced", Font.PLAIN, 14));
+			scriptTextArea.setDocument(doc);
+			scriptTextArea.setText(useCaseDescription.getCommand());
+			scriptTextArea.setCaretPosition(0);
+			scriptTextArea.setPreferredSize(new Dimension(200, 100));
+
+			tabbedPane.addTab("Command", new ScriptPanel(this, scriptTextArea, stdInCheckBox, stdOutCheckBox, stdErrCheckBox, returnCodesField));
+			tabbedPane.addTab("String replacements",
+					new StringReplacementPanel(this, stringReplacementViewList));
+			tabbedPane.addTab(
+					"File inputs",
+					new FilePanel(this, inputFileViewList, "To file", "File type",
+							"in", FILE_INPUT_DESCRIPTION, "Add file input"));
+			tabbedPane.addTab(
+					"File outputs",
+					new FilePanel(this, outputViewList, "From file", "File type",
+							"out", FILE_OUTPUT_DESCRIPTION, "Add file output"));
+			advancedPanel = new JPanel();
+			advancedPanel.setLayout(new GridBagLayout());
+			GridBagConstraints advancedConstraint = new GridBagConstraints();
+			advancedConstraint.anchor = GridBagConstraints.FIRST_LINE_START;
+			advancedConstraint.gridx = 0;
+			advancedConstraint.gridy = 0;
+
+			advancedConstraint.fill = GridBagConstraints.BOTH;
+			advancedConstraint.weighty = 0.1;
+			advancedConstraint.weightx = 0.1;
+			advancedTab = new JTabbedPane();
+			advancedTab.addTab("Strings", new StaticStringPanel(staticStringViewList));
+			advancedTab.addTab("URLs", new StaticUrlPanel(staticUrlViewList));
+			advancedTab.addTab(
+					"File lists",
+					new FilePanel(this, fileListViewList,
+							"To file containing list", "Individual file type",
+							"in", FILE_LIST_DESCRIPTION, "Add file list"));
+			annotationPanel = new AnnotationPanel(nameField, descriptionArea, groupField);
+			advancedTab.addTab("Annotation", annotationPanel);
+			final ToolXMLPanel toolXMLPanel = new ToolXMLPanel(configuration.getUseCaseDescription());
+			advancedTab.addTab("XML", toolXMLPanel);
+			advancedTab.addChangeListener(new ChangeListener() {
+
+				@Override
+				public void stateChanged(ChangeEvent e) {
+					if (advancedTab.getSelectedComponent() == toolXMLPanel) {
+						toolXMLPanel.regenerateTree(makeConfiguration().getUseCaseDescription());
+					}
+				}});
+			tabbedPane.addChangeListener(new ChangeListener() {
+
+				@Override
+				public void stateChanged(ChangeEvent e) {
+					if ((tabbedPane.getSelectedComponent() == advancedPanel) &&
+							(advancedTab.getSelectedComponent() == toolXMLPanel)) {
+						toolXMLPanel.regenerateTree(makeConfiguration().getUseCaseDescription());						
+					}
+				}
+				
+			});
+/*			advancedTab.addTab("Runtime environments",
+					createRuntimeEnvironmentPanel(runtimeEnvironmentViewList));*/
+			advancedPanel.add(advancedTab, advancedConstraint);
+			tabbedPane.addTab("Advanced", advancedPanel);
+		}
+		invocationPanel = new InvocationPanel(configuration);
+		
+		tabbedPane.addTab("Location", invocationPanel);
+		if (isFromRepository()) {
+			tabbedPane.addTab("Edit", new EditablePanel(this));
+		}
+		GridBagConstraints outerConstraint = new GridBagConstraints();
+		outerConstraint.anchor = GridBagConstraints.FIRST_LINE_START;
+		outerConstraint.gridx = 0;
+		outerConstraint.gridy = 0;
+
+		outerConstraint.fill = GridBagConstraints.BOTH;
+		outerConstraint.weighty = 0.1;
+		outerConstraint.weightx = 0.1;
+		add(tabbedPane, outerConstraint);
+
+		setPreferredSize(new Dimension(700, 500));
+		this.validate();
+	}
+
+	public void whenOpened() {
+		if (scriptTextArea != null) {
+			scriptTextArea.requestFocus();
+		}
+	}
+
+	private boolean isFromRepository() {
+		return (!this.configuration.isEdited() && isOriginallyFromRepository());
+	}
+	
+	public boolean isOriginallyFromRepository() {
+		String repositoryUrl = this.configuration.getRepositoryUrl();
+		return ((repositoryUrl != null) && !repositoryUrl
+				.isEmpty());
+		
+	}
+
+
+	@Override
+	public ExternalToolActivityConfigurationBean getConfiguration() {
+		return configuration;
+	}
+
+	public void refreshConfiguration(
+			ExternalToolActivityConfigurationBean config) {
+		int visibleTab = -1;
+		int secondaryTab = -1;
+		if (tabbedPane != null) {
+			visibleTab = tabbedPane.getSelectedIndex();
+			if (tabbedPane.getSelectedComponent().equals(advancedTab)) {
+				secondaryTab = advancedTab.getSelectedIndex();
+			}
+		}
+		this.removeAll();
+		initialise(config);
+		if (visibleTab != -1) {
+			tabbedPane.setSelectedIndex(visibleTab);
+		}
+		if (secondaryTab != -1) {
+			advancedTab.setSelectedIndex(secondaryTab);
+		}
+	}
+	
+	public void showAnnotationPanel() {
+		tabbedPane.setSelectedComponent(advancedPanel);
+		advancedTab.setSelectedComponent(annotationPanel);
+	}
+
+	@Override
+	public void refreshConfiguration() {
+		refreshConfiguration(activity.getConfiguration());
+	}
+
+	static Pattern tagPattern = Pattern.compile("%%([^%]*)%%");
+
+	@Override
+	/**
+	 * Need to check that the script contains the string replacements and only them - done
+	 * 
+	 * Need to check the input port names are valid and unique - done
+	 * Need to check the output port names are valid and unique - done
+	 * 
+	 * Need to check the input files and static files are unique - done
+	 * Need to check the file names are valid
+	 * Need to check the URLs are valid
+	 * Need to check the replacement tags are unique - done
+	 */
+	public boolean checkValues() {
+		if (isFromRepository()) {
+			return true;
+		}
+		boolean result = true;
+		String text = "";
+		Set<String> stringReplacementPortNames = new HashSet<String>();
+		Set<String> stringReplacementTags = new HashSet<String>();
+		for (ExternalToolStringReplacementViewer v : stringReplacementViewList) {
+			String name = v.getName();
+			if (name.equalsIgnoreCase("stdin") || name.equalsIgnoreCase("stdout") || name.equalsIgnoreCase("stderr")) {
+				text += "A string replacement port has a reserved name \"" + name + "\"\n";
+				result = false;
+			}
+			else if (stringReplacementPortNames.contains(name)) {
+				text += "Two string replacement ports have the name \"" + name
+						+ "\"\n";
+				result = false;
+			} else if (!name.matches(VALID_NAME_REGEX)) {
+				text += "String replacement port name \"" + name
+						+ "\" is invalid\n";
+				result = false;
+			} else {
+				stringReplacementPortNames.add(name);
+			}
+
+			String tag = v.getValue();
+			if (stringReplacementTags.contains(tag)) {
+				text += "Two string replacement ports replace \"%%" + tag
+						+ "%%\"\n";
+				result = false;
+			} else if (!tag.matches(VALID_NAME_REGEX)) {
+				text += "String replacement tag \"%%" + tag
+						+ "%%\" is invalid\n";
+				result = false;
+			} else {
+				stringReplacementTags.add(tag);
+			}
+		}
+
+		Matcher m = tagPattern.matcher(scriptTextArea.getText());
+		Set<String> tags = new HashSet<String>();
+		while (m.find()) {
+			String tag = m.group(1);
+			if (tag != null) {
+				if (tag.isEmpty()) {
+					text += "The command contains an empty tag i.e. %%%%\n";
+					result = false;
+				} else {
+					if (!tag.matches(VALID_NAME_REGEX)) {
+						text += "The command contains an invalid tag \"%%"
+								+ tag + "\"%%\n";
+						result = false;
+					}
+					if (!stringReplacementTags.contains(tag)) {
+						text += "There is no string replacement for %%" + tag
+								+ "%%\n";
+						result = false;
+					} else {
+						tags.add(tag);
+					}
+				}
+			}
+		}
+
+		for (String tag : stringReplacementTags) {
+			if (!tags.contains(tag)) {
+				text += "String replacement for %%" + tag
+						+ "%% is not used in the command\n";
+				result = false;
+			}
+		}
+
+		Set<String> inputFilePortNames = new HashSet<String>();
+		Set<String> inputFileNames = new HashSet<String>();
+		for (ExternalToolFileViewer v : inputFileViewList) {
+			String name = v.getName();
+			if (name.equalsIgnoreCase("stdin") || name.equalsIgnoreCase("stdout") || name.equalsIgnoreCase("stderr")) {
+				text += "An input file port has a reserved name \"" + name + "\"\n";
+				result = false;
+			}
+			else if (stringReplacementPortNames.contains(name)) {
+				text += "A string replacement port and an input file port have the name \""
+						+ name + "\"\n";
+				result = false;
+			} else if (inputFilePortNames.contains(name)) {
+				text += "Two file input ports have the name \"" + name + "\"\n";
+				result = false;
+			} else if (!name.matches(VALID_NAME_REGEX)) {
+				text += "File input port name \"" + name + "\" is invalid\n";
+				result = false;
+			} else {
+				inputFilePortNames.add(name);
+			}
+
+			String fileName = v.getValue();
+			if (inputFileNames.contains(fileName)) {
+				text += "Two file inputs ports write to the same file \""
+						+ fileName + "\"\n";
+				result = false;
+			} else {
+				inputFileNames.add(fileName);
+			}
+		}
+
+		Set<String> fileListPortNames = new HashSet<String>();
+		Set<String> fileListFileNames = new HashSet<String>();
+		for (ExternalToolFileViewer v : fileListViewList) {
+			String name = v.getName();
+			if (name.equalsIgnoreCase("stdin") || name.equalsIgnoreCase("stdout") || name.equalsIgnoreCase("stderr")) {
+				text += "A file list port has a reserved name \"" + name + "\"\n";
+				result = false;
+			} else if (stringReplacementPortNames.contains(name)) {
+				text += "A string replacement port and a file list port have the name \""
+						+ name + "\"\n";
+				result = false;
+			} else if (inputFilePortNames.contains(name)) {
+				text += "A file input port and a file list port have the name \""
+						+ name + "\"\n";
+				result = false;
+			} else if (fileListPortNames.contains(name)) {
+				text += "Two file list ports have the name \"" + name + "\"\n";
+				result = false;
+			} else if (!name.matches(VALID_NAME_REGEX)) {
+				text += "File list port name \"" + name + "\" is invalid\n";
+				result = false;
+			} else {
+				fileListPortNames.add(name);
+			}
+
+			String fileName = v.getValue();
+			if (fileListFileNames.contains(fileName)) {
+				text += "Two file list ports write to the same file \""
+						+ fileName + "\"\n";
+				result = false;
+			} else if (inputFileNames.contains(fileName)) {
+				text += "A file input port and a file list port write to the same file \""
+						+ fileName + "\"\n";
+				result = false;
+			} else {
+				fileListFileNames.add(fileName);
+			}
+		}
+
+		Set<String> staticStringFileNames = new HashSet<String>();
+		for (ExternalToolStaticStringViewer v : staticStringViewList) {
+			String fileName = v.getValue();
+			if (staticStringFileNames.contains(fileName)) {
+				text += "Two static strings write to the same file \""
+						+ fileName + "\"\n";
+				result = false;
+			} else if (inputFileNames.contains(fileName)) {
+				text += "A file input port and a static string write to the same file \""
+						+ fileName + "\"\n";
+				result = false;
+			} else if (fileListFileNames.contains(fileName)) {
+				text += "A file list port and a static string write to the same file \""
+						+ fileName + "\"\n";
+				result = false;
+			} else {
+				staticStringFileNames.add(fileName);
+			}
+		}
+
+		Set<String> staticUrlFileNames = new HashSet<String>();
+		for (ExternalToolStaticUrlViewer v : staticUrlViewList) {
+			String fileName = v.getValue();
+			if (staticUrlFileNames.contains(fileName)) {
+				text += "Two static URLss write to the same file \"" + fileName
+						+ "\"\n";
+				result = false;
+			} else if (inputFileNames.contains(fileName)) {
+				text += "A file input port and a static URL write to the same file \""
+						+ fileName + "\"\n";
+				result = false;
+			} else if (fileListFileNames.contains(fileName)) {
+				text += "A file list port and a static URL write to the same file \""
+						+ fileName + "\"\n";
+				result = false;
+			} else if (staticStringFileNames.contains(fileName)) {
+				text += "A static string and a static URL write to the same file \""
+						+ fileName + "\"\n";
+				result = false;
+			} else {
+				staticUrlFileNames.add(fileName);
+			}
+		}
+		Set<String> outputPortNames = new HashSet<String>();
+		for (ExternalToolFileViewer v : outputViewList) {
+			String name = v.getName();
+			if (name.equalsIgnoreCase("stdin") || name.equalsIgnoreCase("stdout") || name.equalsIgnoreCase("stderr")) {
+				text += "An output port has a reserved name \"" + name + "\"\n";
+				result = false;
+			} else if (outputPortNames.contains(name)) {
+				text += "Two output file ports have the name \"" + name
+						+ "\"\n";
+				result = false;
+			} else if (!name.matches(VALID_NAME_REGEX)) {
+				text += "Output file port name \"" + name + "\" is invalid\n";
+				result = false;
+			} else {
+				outputPortNames.add(name);
+			}
+		}
+		if (!result) {
+			JOptionPane.showMessageDialog(this, text, "Problems",
+					JOptionPane.ERROR_MESSAGE);
+		}
+		return result;
+	}
+
+	/**
+	 * Check the proposed port name against the set of ports
+	 * 
+	 * @return
+	 */
+	public boolean portNameExists(String name) {
+		if (name.equalsIgnoreCase("stdin") || name.equalsIgnoreCase("stdout") || name.equalsIgnoreCase("stderr")) {
+			return true;
+		}
+		
+		for (ExternalToolFileViewer v : inputFileViewList) {
+			if (name.equals(v.getName())) {
+				return true;
+			}
+		}
+		for (ExternalToolFileViewer v : fileListViewList) {
+			if (name.equals(v.getName())) {
+				return true;
+			}
+		}
+		for (ExternalToolStringReplacementViewer v : stringReplacementViewList) {
+			if (name.equals(v.getName())) {
+				return true;
+			}
+		}
+		for (ExternalToolFileViewer v : outputViewList) {
+			if (name.equals(v.getName())) {
+				return true;
+			}
+		}
+		return false;
+	}
+
+
+	public void setEditable(boolean editable, ExternalToolActivityConfigurationBean config) {
+		ExternalToolActivityConfigurationBean newConfig = (ExternalToolActivityConfigurationBean) cloneBean(config);
+		ExternalToolActivityHealthChecker.updateLocation(newConfig);
+		newConfig.setEdited(editable);
+		refreshConfiguration(newConfig);		
+	}
+	
+	public void whenClosed() {
+		if (invocationPanel != null) {
+			invocationPanel.stopObserving();
+		}
+	}
+
+}
diff --git a/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/views/ExternalToolFileViewer.java b/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/views/ExternalToolFileViewer.java
new file mode 100644
index 0000000..11fb0c4
--- /dev/null
+++ b/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/views/ExternalToolFileViewer.java
@@ -0,0 +1,103 @@
+/**
+ * 
+ */
+package net.sf.taverna.t2.activities.externaltool.views;
+
+import java.awt.event.ActionEvent;
+
+import javax.swing.AbstractAction;
+import javax.swing.JCheckBox;
+import javax.swing.JComboBox;
+import javax.swing.JTextField;
+
+import de.uni_luebeck.inb.knowarc.usecases.ScriptInput;
+import de.uni_luebeck.inb.knowarc.usecases.ScriptInputUser;
+import de.uni_luebeck.inb.knowarc.usecases.ScriptOutput;
+
+/**
+ * @author alanrw
+ *
+ */
+public class ExternalToolFileViewer {
+	
+	private JTextField nameField;
+	private String name;
+	private JTextField valueField;
+	private JCheckBox valueFromField;
+	private JComboBox typeSelector;
+
+	public ExternalToolFileViewer(String name, String value, boolean isBinary) {
+		this(name);
+		nameField.setText(name);
+		if (!value.equals(name)) {
+			valueFromField.setSelected(false);
+			valueField.setText(value);
+			valueField.setEnabled(true);
+		}
+		if (isBinary) {
+			typeSelector.setSelectedItem("Binary");
+		} else {
+			typeSelector.setSelectedItem("Text");
+		}
+	}
+
+	public ExternalToolFileViewer(final String name) {
+		this.name = name;
+		nameField = new JTextField(20);
+		valueField = new JTextField(20);
+		valueFromField = new JCheckBox(new AbstractAction() {
+
+			@Override
+			public void actionPerformed(ActionEvent e) {
+				if (valueFromField.isSelected()) {
+					valueField.setText("");
+					valueField.setEnabled(false);
+				} else {
+					valueField.setText(getName());
+					valueField.setEnabled(true);
+				}
+			}});
+		valueFromField.setSelected(true);
+		valueField.setEnabled(false);
+		typeSelector = new JComboBox(new String[] {"Binary", "Text"});
+		nameField.setText(name);
+		typeSelector.setSelectedItem("Text");
+		
+	}
+
+	public JTextField getNameField() {
+		return nameField;
+	}
+
+	public JTextField getValueField() {
+		return valueField;
+	}
+
+	public JComboBox getTypeSelector() {
+		return typeSelector;
+	}
+
+	public String getName() {
+		return nameField.getText();
+	}
+
+	public boolean isBinary() {
+		return (typeSelector.getSelectedItem().equals("Binary"));
+	}
+
+	public String getValue() {
+		if (valueFromField.isSelected()) {
+			return getName();
+		}
+		return valueField.getText();
+	}
+	
+	/**
+	 * @return the valueFromField
+	 */
+	public JCheckBox getValueFromField() {
+		return valueFromField;
+	}
+
+
+}
diff --git a/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/views/ExternalToolRuntimeEnvironmentViewer.java b/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/views/ExternalToolRuntimeEnvironmentViewer.java
new file mode 100644
index 0000000..1451660
--- /dev/null
+++ b/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/views/ExternalToolRuntimeEnvironmentViewer.java
@@ -0,0 +1,56 @@
+/**
+ * 
+ */
+package net.sf.taverna.t2.activities.externaltool.views;
+
+import javax.swing.JComboBox;
+import javax.swing.JTextField;
+
+import de.uni_luebeck.inb.knowarc.usecases.RuntimeEnvironmentConstraint;
+import de.uni_luebeck.inb.knowarc.usecases.ScriptInput;
+import de.uni_luebeck.inb.knowarc.usecases.ScriptInputUser;
+import de.uni_luebeck.inb.knowarc.usecases.ScriptOutput;
+
+/**
+ * @author alanrw
+ *
+ */
+public class ExternalToolRuntimeEnvironmentViewer {
+	
+	private JTextField idField;
+	private JComboBox relationSelector;
+
+	public ExternalToolRuntimeEnvironmentViewer(String id, String relation) {
+		this(id);
+		idField.setText(id);
+		relationSelector.setSelectedItem(relation);
+	}
+
+	public ExternalToolRuntimeEnvironmentViewer(String id) {
+		this();
+		idField.setText(id);	
+	}
+	
+	public ExternalToolRuntimeEnvironmentViewer() {
+		idField = new JTextField(20);
+		relationSelector = new JComboBox(RuntimeEnvironmentConstraint.getAcceptedRelations());
+		relationSelector.setSelectedItem(RuntimeEnvironmentConstraint.getDefaultRelation());			
+	}
+
+	public JTextField getIdField() {
+		return idField;
+	}
+
+	public JComboBox getRelationSelector() {
+		return relationSelector;
+	}
+
+	public String getId() {
+		return idField.getText();
+	}
+
+	public String getRelation() {
+		return (String) relationSelector.getSelectedItem();
+	}
+
+}
diff --git a/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/views/ExternalToolStaticStringViewer.java b/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/views/ExternalToolStaticStringViewer.java
new file mode 100644
index 0000000..d82d9b7
--- /dev/null
+++ b/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/views/ExternalToolStaticStringViewer.java
@@ -0,0 +1,53 @@
+/**
+ * 
+ */
+package net.sf.taverna.t2.activities.externaltool.views;
+
+import javax.swing.JTextArea;
+import javax.swing.JTextField;
+
+import de.uni_luebeck.inb.knowarc.usecases.ScriptInputStatic;
+
+/**
+ * @author alanrw
+ *
+ */
+public class ExternalToolStaticStringViewer {
+	
+	ScriptInputStatic input;
+	private JTextArea contentField = new JTextArea();
+	private JTextField valueField;
+
+
+	public ExternalToolStaticStringViewer(ScriptInputStatic input) {
+		this();
+		this.input = input;
+			contentField.setText((String) input.getContent());
+		valueField.setText(input.getTag());
+	}
+
+	public ExternalToolStaticStringViewer() {
+		contentField = new JTextArea(5, 40);
+		contentField.setText("");
+		valueField = new JTextField(20);
+		valueField.setText("");
+	}
+
+	public String getContent() {
+		return contentField.getText();
+	}
+
+	public JTextArea getContentField() {
+		return contentField;
+	}
+
+
+	public JTextField getValueField() {
+		return valueField;
+	}
+
+	public String getValue() {
+		return valueField.getText();
+	}
+
+}
diff --git a/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/views/ExternalToolStaticUrlViewer.java b/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/views/ExternalToolStaticUrlViewer.java
new file mode 100644
index 0000000..f7a1793
--- /dev/null
+++ b/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/views/ExternalToolStaticUrlViewer.java
@@ -0,0 +1,56 @@
+/**
+ * 
+ */
+package net.sf.taverna.t2.activities.externaltool.views;
+
+import javax.swing.JComboBox;
+import javax.swing.JTextArea;
+import javax.swing.JTextField;
+
+import de.uni_luebeck.inb.knowarc.usecases.ScriptInput;
+import de.uni_luebeck.inb.knowarc.usecases.ScriptInputStatic;
+import de.uni_luebeck.inb.knowarc.usecases.ScriptInputUser;
+
+/**
+ * @author alanrw
+ *
+ */
+public class ExternalToolStaticUrlViewer {
+	
+	ScriptInputStatic input;
+	private JTextField contentField = new JTextField();
+	private JTextField valueField;
+
+
+	public ExternalToolStaticUrlViewer(ScriptInputStatic input) {
+		this();
+		this.input = input;
+		contentField.setText(input.getUrl());
+		valueField.setText(input.getTag());
+	}
+
+	public ExternalToolStaticUrlViewer() {
+		contentField = new JTextField(40);
+		contentField.setText("");
+		valueField = new JTextField(20);
+		valueField.setText("");
+	}
+
+	public String getContent() {
+		return contentField.getText();
+	}
+
+	public JTextField getContentField() {
+		return contentField;
+	}
+
+
+	public JTextField getValueField() {
+		return valueField;
+	}
+
+	public String getValue() {
+		return valueField.getText();
+	}
+
+}
diff --git a/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/views/ExternalToolStringReplacementViewer.java b/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/views/ExternalToolStringReplacementViewer.java
new file mode 100644
index 0000000..8e24183
--- /dev/null
+++ b/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/views/ExternalToolStringReplacementViewer.java
@@ -0,0 +1,97 @@
+/**
+ * 
+ */
+package net.sf.taverna.t2.activities.externaltool.views;
+
+import java.awt.event.ActionEvent;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.swing.AbstractAction;
+import javax.swing.JCheckBox;
+import javax.swing.JComboBox;
+import javax.swing.JTextField;
+
+import de.uni_luebeck.inb.knowarc.usecases.ScriptInput;
+import de.uni_luebeck.inb.knowarc.usecases.ScriptInputUser;
+
+/**
+ * @author alanrw
+ *
+ */
+public class ExternalToolStringReplacementViewer {
+	
+	private static Pattern p = Pattern.compile("\\w+");
+	private static final String PERCENTS = "%%";
+	ScriptInput input;
+	private JTextField nameField;
+	private String name;
+	private JTextField valueField;
+	private JCheckBox valueFromField;
+
+	public ExternalToolStringReplacementViewer(String name, ScriptInputUser input) {
+		this(name);
+		this.input = input;
+		nameField.setText(name);
+		if (!input.getTag().equals(name)) {
+			valueFromField.setSelected(false);
+			valueField.setText(PERCENTS + input.getTag() + PERCENTS);
+			valueField.setEnabled(true);
+		}
+	}
+
+	public ExternalToolStringReplacementViewer(String name) {
+		this.name = name;
+		nameField = new JTextField(20);
+		nameField.setText(name);
+		valueField = new JTextField(20);
+		valueFromField = new JCheckBox(new AbstractAction() {
+
+			@Override
+			public void actionPerformed(ActionEvent e) {
+				if (valueFromField.isSelected()) {
+					valueField.setText("");
+					valueField.setEnabled(false);
+				} else {
+					valueField.setText(PERCENTS + getName() + PERCENTS);
+					valueField.setEnabled(true);
+				}
+			}});
+		valueFromField.setSelected(true);
+		valueField.setEnabled(false);
+	}
+
+	public JTextField getNameField() {
+		return nameField;
+	}
+	
+	public JTextField getValueField() {
+		return valueField;
+	}
+
+	public String getName() {
+		return nameField.getText();
+	}
+
+	public String getValue() {
+		if (valueFromField.isSelected()) {
+			return getName();
+		}
+		String enteredValue = valueField.getText();
+
+		Matcher m = p.matcher(enteredValue);
+		String result = "";
+		if (m.find()) {
+			result = m.group();
+		}
+		return result;
+	}
+
+	/**
+	 * @return the valueFromField
+	 */
+	public JCheckBox getValueFromField() {
+		return valueFromField;
+	}
+
+}
diff --git a/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/views/FilePanel.java b/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/views/FilePanel.java
new file mode 100644
index 0000000..678711c
--- /dev/null
+++ b/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/views/FilePanel.java
@@ -0,0 +1,119 @@
+/**
+ * 
+ */
+package net.sf.taverna.t2.activities.externaltool.views;
+
+import java.awt.BorderLayout;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+import java.awt.event.ActionEvent;
+import java.util.List;
+
+import javax.swing.AbstractAction;
+import javax.swing.JButton;
+import javax.swing.JComponent;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTextArea;
+import javax.swing.border.EmptyBorder;
+
+import net.sf.taverna.t2.activities.externaltool.utils.Tools;
+import net.sf.taverna.t2.lang.ui.DeselectingButton;
+import net.sf.taverna.t2.lang.ui.ReadOnlyTextArea;
+
+/**
+ * @author alanrw
+ *
+ */
+public class FilePanel extends JPanel {
+	
+	private int outputGridy = 1;
+	private final ExternalToolConfigView view;
+	
+	public FilePanel(final ExternalToolConfigView view,
+			final List<ExternalToolFileViewer> viewList,
+			String fileHeader, String typeHeader, final String portPrefix,
+			final String description, String addText) {
+		super();
+		this.view = view;
+		this.setLayout(new BorderLayout());
+		final JPanel fileEditPanel = new JPanel(new GridBagLayout());
+
+		final GridBagConstraints fileConstraint = new GridBagConstraints();
+		fileConstraint.insets = new Insets(5, 5, 5, 5);
+		fileConstraint.anchor = GridBagConstraints.FIRST_LINE_START;
+		fileConstraint.gridx = 0;
+		fileConstraint.gridy = 0;
+		fileConstraint.weightx = 0.1;
+		fileConstraint.fill = GridBagConstraints.BOTH;
+		
+		final String[] elementLabels = new String[] {"Taverna port name",
+				"Use port name for file",
+				fileHeader,
+				typeHeader
+		};
+
+		fileConstraint.gridx = 0;
+		synchronized (viewList) {
+			for (ExternalToolFileViewer outputView : viewList) {
+				addFileViewer(viewList, this, fileEditPanel,
+						outputView, elementLabels);
+			}
+		}
+		JButton addFilePortButton = new DeselectingButton(addText,
+				new AbstractAction() {
+			public void actionPerformed(ActionEvent e) {
+
+				int portNumber = 1;
+
+				String name2 = portPrefix + portNumber++;
+				boolean nameExists = true;
+				while (nameExists == true) {
+					nameExists = view.portNameExists(name2);
+					if (nameExists) {
+						name2 = portPrefix + portNumber++;
+					}
+				}
+
+				ExternalToolFileViewer newViewer = new ExternalToolFileViewer(
+						name2);
+				synchronized (viewList) {
+					viewList.add(newViewer);
+					addFileViewer(viewList, FilePanel.this, fileEditPanel,
+							newViewer, elementLabels);
+					fileEditPanel.revalidate();
+					fileEditPanel.repaint();
+				}
+			}
+
+		});
+		JTextArea descriptionText = new ReadOnlyTextArea(description);
+		descriptionText.setEditable(false);
+		descriptionText.setFocusable(false);
+		descriptionText.setBorder(new EmptyBorder(5, 5, 10, 5));
+
+		this.add(descriptionText, BorderLayout.NORTH);
+
+		this.add(new JScrollPane(fileEditPanel), BorderLayout.CENTER);
+
+		JPanel buttonPanel = new JPanel(new BorderLayout());
+
+		buttonPanel.add(addFilePortButton, BorderLayout.EAST);
+
+		this.add(buttonPanel, BorderLayout.SOUTH);
+	
+	}
+	
+	private void addFileViewer(final List<ExternalToolFileViewer> viewList,
+			final JPanel outerPanel, final JPanel panel,
+			ExternalToolFileViewer viewer, String[] elementLabels) {
+		Tools.addViewer(panel,
+				elementLabels,
+				new JComponent[] {viewer.getNameField(), viewer.getValueFromField(), viewer.getValueField(), viewer.getTypeSelector()},
+				viewList,
+				viewer,
+				outerPanel);
+	}
+
+}
diff --git a/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/views/InvocationPanel.java b/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/views/InvocationPanel.java
new file mode 100644
index 0000000..803328b
--- /dev/null
+++ b/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/views/InvocationPanel.java
@@ -0,0 +1,396 @@
+/**
+ * 
+ */
+package net.sf.taverna.t2.activities.externaltool.views;
+
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.FlowLayout;
+import java.awt.GridLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.util.Arrays;
+import java.util.Comparator;
+
+import javax.swing.AbstractAction;
+import javax.swing.Box;
+import javax.swing.BoxLayout;
+import javax.swing.ButtonGroup;
+import javax.swing.DefaultComboBoxModel;
+import javax.swing.DefaultListCellRenderer;
+import javax.swing.JButton;
+import javax.swing.JComboBox;
+import javax.swing.JList;
+import javax.swing.JPanel;
+import javax.swing.JRadioButton;
+import javax.swing.JTextArea;
+import javax.swing.SwingUtilities;
+import javax.swing.border.EmptyBorder;
+
+import net.sf.taverna.t2.activities.externaltool.ExternalToolActivityConfigurationBean;
+import net.sf.taverna.t2.activities.externaltool.ExternalToolActivityHealthChecker;
+import net.sf.taverna.t2.activities.externaltool.configuration.ToolInvocationConfiguration;
+import net.sf.taverna.t2.activities.externaltool.manager.InvocationGroup;
+import net.sf.taverna.t2.activities.externaltool.manager.InvocationGroupAddedEvent;
+import net.sf.taverna.t2.activities.externaltool.manager.InvocationGroupRemovedEvent;
+import net.sf.taverna.t2.activities.externaltool.manager.InvocationManagerEvent;
+import net.sf.taverna.t2.activities.externaltool.manager.InvocationMechanism;
+import net.sf.taverna.t2.activities.externaltool.manager.InvocationMechanismAddedEvent;
+import net.sf.taverna.t2.activities.externaltool.manager.InvocationMechanismRemovedEvent;
+import net.sf.taverna.t2.activities.externaltool.manager.ToolInvocationConfigurationPanel;
+import net.sf.taverna.t2.activities.externaltool.manager.impl.InvocationGroupManagerImpl;
+import net.sf.taverna.t2.lang.observer.Observable;
+import net.sf.taverna.t2.lang.observer.Observer;
+import net.sf.taverna.t2.lang.ui.DeselectingButton;
+import net.sf.taverna.t2.workbench.ui.impl.configuration.ui.T2ConfigurationFrame;
+
+import org.apache.log4j.Logger;
+
+/**
+ * @author alanrw
+ *
+ */
+public class InvocationPanel extends JPanel implements Observer<InvocationManagerEvent> {
+	
+	private static final String LOCATION_DESCRIPTION = ToolInvocationConfigurationPanel.HEADER_TEXT;
+	private final JComboBox mechanismSelection;
+	private final JComboBox groupSelection;
+	
+	private DefaultComboBoxModel mechanismSelectionModel = new DefaultComboBoxModel();
+	private DefaultComboBoxModel groupSelectionModel = new DefaultComboBoxModel();
+
+	private static InvocationGroupManagerImpl manager = InvocationGroupManagerImpl.getInstance();
+	
+	private static Logger logger = Logger
+	.getLogger(InvocationPanel.class);
+	
+	private JRadioButton unmanagedLocation;
+	private JRadioButton groupSelected;
+	private JRadioButton mechanismSelected;
+	private JButton manageInvocation;
+	private ButtonGroup mechanismOrGroup;
+	private ExternalToolActivityConfigurationBean configuration;
+	
+	private ActionListener radioChangeListener;
+	
+	boolean unmanagedShown = false;
+
+	public InvocationPanel(ExternalToolActivityConfigurationBean configuration) {
+		super();
+		manager.addObserver(this);
+		
+		mechanismSelection = new JComboBox();
+		populateMechanismList();
+		mechanismSelection.setModel(mechanismSelectionModel);
+		
+		groupSelection = new JComboBox();
+		populateGroupList();
+		groupSelection.setModel(groupSelectionModel);
+		populateInvocationPanel(configuration);
+		
+		radioChangeListener = new AbstractAction() {
+
+			@Override
+			public void actionPerformed(ActionEvent e) {
+				if (unmanagedShown && unmanagedLocation.isSelected()) {
+					setUnmanagedLocationSelectability(true);
+					setMechanismSelectability(false);
+					setGroupSelectability(false);
+					return;
+				}
+				if (mechanismSelected.isSelected()) {
+					if (unmanagedShown) {
+						setUnmanagedLocationSelectability(false);
+					}
+					setMechanismSelectability(true);
+					setGroupSelectability(false);
+					return;
+				}
+				if (unmanagedShown) {
+					setUnmanagedLocationSelectability(false);
+				}
+				setMechanismSelectability(false);
+				setGroupSelectability(true);
+				return;			}
+			
+		};
+		if (unmanagedShown) {
+			unmanagedLocation.addActionListener(radioChangeListener);
+		}
+		groupSelected.addActionListener(radioChangeListener);
+		mechanismSelected.addActionListener(radioChangeListener);
+	}
+	
+	private void populateMechanismList() {
+		InvocationMechanism currentSelection = (InvocationMechanism) mechanismSelection.getSelectedItem();
+		InvocationMechanism[] mechanisms = InvocationGroupManagerImpl.getInstance()
+				.getMechanisms().toArray(new InvocationMechanism[] {});
+		Arrays.sort(mechanisms, new Comparator<InvocationMechanism>() {
+
+			@Override
+			public int compare(InvocationMechanism arg0, InvocationMechanism arg1) {
+				return arg0.getName().compareTo(
+						arg1.getName());
+			}
+		});
+		mechanismSelectionModel.removeAllElements();
+		for (InvocationMechanism mechanism : mechanisms) {
+			mechanismSelectionModel.addElement(mechanism);
+			logger.info("Added mechanism " + mechanism.hashCode());
+		}
+		if (currentSelection != null) {
+			mechanismSelection.setSelectedItem(currentSelection);
+		}
+		
+	}
+
+	private void populateGroupList() {
+		InvocationGroup currentSelection = (InvocationGroup) groupSelection.getSelectedItem();
+		InvocationGroup[] groups = InvocationGroupManagerImpl.getInstance()
+				.getInvocationGroups().toArray(new InvocationGroup[] {});
+		Arrays.sort(groups, new Comparator<InvocationGroup>() {
+
+			@Override
+			public int compare(InvocationGroup arg0, InvocationGroup arg1) {
+				return arg0.getName().compareTo(
+						arg1.getName());
+			}
+		});
+		groupSelectionModel.removeAllElements();
+		for (InvocationGroup group : groups) {
+			groupSelectionModel.addElement(group);
+			logger.info("Added group " + group.hashCode());
+		}
+		if (currentSelection != null) {
+			groupSelection.setSelectedItem(currentSelection);
+		}
+		
+	}
+
+	
+	private void populateInvocationPanel(ExternalToolActivityConfigurationBean configuration) {
+		this.configuration = configuration;
+		this.removeAll();
+		this.setLayout(new BorderLayout());
+
+		JTextArea descriptionText = new JTextArea(
+				LOCATION_DESCRIPTION);
+		descriptionText.setEditable(false);
+		descriptionText.setFocusable(false);
+		descriptionText.setBorder(new EmptyBorder(5, 5, 10, 5));
+		descriptionText.setLineWrap(true);
+		descriptionText.setWrapStyleWord(true);
+		descriptionText.setRows(3);
+		this.add(descriptionText, BorderLayout.NORTH);
+		
+		JPanel innerPanel = new JPanel(new BorderLayout());
+		
+		mechanismOrGroup = new ButtonGroup();
+
+		JPanel subPanel = new JPanel(new GridLayout(4,1));
+		
+		if (isUnmanaged(configuration)) {
+			createUnmanagedLocation(subPanel);
+			unmanagedShown = true;
+		}
+		
+		subPanel.add(createMechanismPanel());
+		
+		subPanel.add(createGroupPanel());
+		
+		subPanel.add(createButtonPanel());
+		
+		innerPanel.add(subPanel, BorderLayout.NORTH);
+		innerPanel.add(new JPanel(), BorderLayout.CENTER);
+		
+		initializeSelectability();
+		this.add(innerPanel, BorderLayout.CENTER);
+		this.repaint();
+	}
+
+	private boolean isUnmanaged(
+			ExternalToolActivityConfigurationBean configuration2) {
+		return (!ExternalToolActivityHealthChecker.updateLocation(configuration2));
+	}
+
+	private void initializeSelectability() {
+		if (isUnmanaged(configuration)) {
+			unmanagedLocation.setSelected(true);
+			setUnmanagedLocationSelectability(true);
+			setMechanismSelectability(false);
+			setGroupSelectability(false);
+			return;
+		}
+		if (configuration.getInvocationGroup() == null) {
+			mechanismSelected.setSelected(true);
+			if (unmanagedShown) {
+				setUnmanagedLocationSelectability(false);
+			}
+			setMechanismSelectability(true);
+			setGroupSelectability(false);
+			return;
+		}
+		groupSelected.setSelected(true);
+		if (unmanagedShown) {
+			setUnmanagedLocationSelectability(false);
+		}
+		setMechanismSelectability(false);
+		setGroupSelectability(true);
+		return;
+	}
+
+	private void setGroupSelectability(boolean b) {
+		groupSelection.setEnabled(b);
+	}
+
+	private void setMechanismSelectability(boolean b) {
+		mechanismSelection.setEnabled(b);
+	}
+
+	private void setUnmanagedLocationSelectability(boolean b) {
+		// Nothing to do
+	}
+
+	private JPanel createGroupPanel() {
+		JPanel groupPanel = new JPanel(new BorderLayout());
+		
+		JPanel groupSelectionPanel = new JPanel(new GridLayout(1, 2));
+		groupSelected = new JRadioButton("Select a symbolic location");
+		mechanismOrGroup.add(groupSelected);
+		groupSelected.setBorder(new EmptyBorder(10, 10, 10, 10));
+		groupSelectionPanel.add(groupSelected);
+
+		groupSelection.setRenderer(new DefaultListCellRenderer() {
+
+			@Override
+			public Component getListCellRendererComponent(JList arg0,
+					Object arg1, int arg2, boolean arg3, boolean arg4) {
+				if (arg1 instanceof InvocationGroup) {
+					return super.getListCellRendererComponent(arg0,
+							((InvocationGroup) arg1).getName(),
+							arg2, arg3, arg4);
+				}
+				return super.getListCellRendererComponent(arg0, arg1, arg2,
+						arg3, arg4);
+			}
+		});
+
+		groupSelectionPanel.add(groupSelection); 
+
+		groupPanel.add(groupSelectionPanel, BorderLayout.CENTER);
+		
+		if (configuration.getInvocationGroup() != null) {
+			groupSelection.setSelectedItem(configuration.getInvocationGroup());
+		} else {
+			groupSelection.setSelectedItem(manager.getDefaultGroup());
+		}
+
+		return groupPanel;
+	}
+
+	private JPanel createMechanismPanel() {
+		JPanel mechanismPanel = new JPanel(new BorderLayout());
+		JPanel mechanismSelectionPanel = new JPanel(new GridLayout(1, 3));
+		mechanismSelected = new JRadioButton("Select an explicit location");
+		mechanismOrGroup.add(mechanismSelected);
+		mechanismSelected.setBorder(new EmptyBorder(10, 10, 10, 10));
+		mechanismSelectionPanel.add(mechanismSelected);
+
+		mechanismSelection.setRenderer(new DefaultListCellRenderer() {
+
+			@Override
+			public Component getListCellRendererComponent(JList arg0,
+					Object arg1, int arg2, boolean arg3, boolean arg4) {
+				if (arg1 instanceof InvocationMechanism) {
+					return super.getListCellRendererComponent(arg0,
+							((InvocationMechanism) arg1).getName(),
+							arg2, arg3, arg4);
+				}
+				return super.getListCellRendererComponent(arg0, arg1, arg2,
+						arg3, arg4);
+			}
+		});
+
+		mechanismSelectionPanel.add(mechanismSelection);
+
+		mechanismPanel.add(mechanismSelectionPanel, BorderLayout.CENTER);
+		if (configuration.getMechanism() != null) {
+			mechanismSelection.setSelectedItem(configuration.getMechanism());
+		} else {
+			mechanismSelection.setSelectedItem(manager.getDefaultMechanism());
+		}
+		return mechanismPanel;
+
+	}
+	
+	private JPanel createButtonPanel() {
+		JPanel buttonPanel = new JPanel(new FlowLayout());
+		manageInvocation = new DeselectingButton("Manage locations",
+				new AbstractAction() {
+
+			@Override
+			public void actionPerformed(ActionEvent e) {
+				T2ConfigurationFrame.showConfiguration(ToolInvocationConfiguration.getInstance().getDisplayName());
+			}});
+		buttonPanel.add(manageInvocation); 
+		return buttonPanel;		
+	}
+
+	private void createUnmanagedLocation(JPanel subPanel) {
+		unmanagedLocation = new JRadioButton("Continue using unmanaged location");
+		subPanel.add(unmanagedLocation);
+		mechanismOrGroup.add(unmanagedLocation);
+	}
+
+	private void handleInvocationManagerMessage(InvocationManagerEvent message) {
+		if (message instanceof InvocationMechanismRemovedEvent) {
+			InvocationMechanism removedMechanism = ((InvocationMechanismRemovedEvent) message).getRemovedMechanism();
+			InvocationMechanism replacementMechanism = ((InvocationMechanismRemovedEvent) message).getReplacementMechanism();
+			if (mechanismSelection.getSelectedItem().equals(removedMechanism)) {
+				mechanismSelection.setSelectedItem(replacementMechanism);
+			}
+			mechanismSelectionModel.removeElement(removedMechanism);
+		} else if (message instanceof InvocationMechanismAddedEvent) {
+			populateMechanismList();
+		}
+		else if (message instanceof InvocationGroupRemovedEvent) {
+			InvocationGroup removedGroup = ((InvocationGroupRemovedEvent) message).getRemovedGroup();
+			InvocationGroup replacementGroup = ((InvocationGroupRemovedEvent) message).getReplacementGroup();
+			if (groupSelection.getSelectedItem().equals(removedGroup)) {
+				groupSelection.setSelectedItem(replacementGroup);
+			}
+			groupSelectionModel.removeElement(removedGroup);
+		} else if (message instanceof InvocationGroupAddedEvent) {
+			populateGroupList();
+		}	
+	}
+	
+	@Override
+	public void notify(Observable<InvocationManagerEvent> sender,
+			final InvocationManagerEvent message) throws Exception {
+		if (SwingUtilities.isEventDispatchThread()) {
+			handleInvocationManagerMessage(message);
+		} else {
+			SwingUtilities.invokeLater(new Runnable() {
+				public void run() {
+					handleInvocationManagerMessage(message);
+				}
+			});
+		}	}
+
+	public void fillInConfiguration(
+			ExternalToolActivityConfigurationBean newConfiguration) {
+		if (unmanagedShown && unmanagedLocation.isSelected()) {
+			return;
+		}
+		if (mechanismSelected.isSelected()) {
+			newConfiguration.setMechanism((InvocationMechanism) mechanismSelection.getSelectedItem());
+			return;
+		}
+		newConfiguration.setInvocationGroup((InvocationGroup) groupSelection.getSelectedItem());	
+	}
+
+	public void stopObserving() {
+		manager.removeObserver(this);
+	}
+}
diff --git a/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/views/LoadDescriptionAction.java b/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/views/LoadDescriptionAction.java
new file mode 100644
index 0000000..7f0d82f
--- /dev/null
+++ b/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/views/LoadDescriptionAction.java
@@ -0,0 +1,89 @@
+/**
+ * 
+ */
+package net.sf.taverna.t2.activities.externaltool.views;
+
+import java.awt.event.ActionEvent;
+import java.io.IOException;
+import java.io.StringBufferInputStream;
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import javax.swing.AbstractAction;
+import javax.swing.JOptionPane;
+
+import net.sf.taverna.t2.lang.ui.FileTools;
+
+import org.jdom.Document;
+import org.jdom.JDOMException;
+
+import de.uni_luebeck.inb.knowarc.usecases.UseCaseDescription;
+import de.uni_luebeck.inb.knowarc.usecases.UseCaseEnumeration;
+
+final class LoadDescriptionAction extends AbstractAction {
+	/**
+	 * 
+	 */
+	private final ScriptPanel scriptPanel;
+	private final ExternalToolConfigView view;
+
+	LoadDescriptionAction(ScriptPanel scriptPanel, ExternalToolConfigView view) {
+		this.scriptPanel = scriptPanel;
+		this.view = view;
+	}
+
+	public void actionPerformed(ActionEvent e) {
+		String descriptionsString = FileTools.readStringFromFile(
+				this.scriptPanel, "Load tool description",
+				".xml");
+		if (descriptionsString != null) {
+			String errorMessage = null;
+			try {
+				Document doc = ScriptPanel.builder
+						.build(new StringReader(descriptionsString));
+				List<UseCaseDescription> descriptions = UseCaseEnumeration.readDescriptionsFromStream(new StringBufferInputStream(descriptionsString));
+				if (descriptions.isEmpty()) {
+					JOptionPane.showMessageDialog(this.scriptPanel, "No tool descriptions found", "File content", JOptionPane.ERROR_MESSAGE);
+					return;
+				}
+				
+				if (descriptions.size() == 1) {
+					view.getConfiguration().setUseCaseDescription(descriptions.get(0));
+					view.refreshConfiguration(view.getConfiguration());
+					return;
+				}
+				
+				List<String> descriptionNames = new ArrayList();
+				for (UseCaseDescription ud : descriptions) {
+					descriptionNames.add(ud.getUsecaseid());
+				}
+				Collections.sort(descriptionNames);
+				String chosenName = (String) JOptionPane.showInputDialog(this.scriptPanel, "Please select a tool description",
+						"Select tool description", JOptionPane.PLAIN_MESSAGE, null, descriptionNames.toArray(), descriptionNames.get(0));
+				if (chosenName != null) {
+					for (UseCaseDescription ud : descriptions) {
+						if (ud.getUsecaseid().equals(chosenName)) {
+							view.getConfiguration().setUseCaseDescription(ud);
+							view.refreshConfiguration(view.getConfiguration());
+							return;
+							
+						}
+					}
+				}
+			} catch (JDOMException e1) {
+				errorMessage = e1.getMessage();
+			} catch (IOException e1) {
+				errorMessage = e1.getMessage();
+			} catch (Exception e1) {
+				errorMessage = e1.getMessage();
+			}
+			if (errorMessage != null) {
+				JOptionPane.showMessageDialog(null, errorMessage,
+						"Tool description load error",
+						JOptionPane.ERROR_MESSAGE);
+			}
+		}
+	}
+}
\ No newline at end of file
diff --git a/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/views/SaveDescriptionAction.java b/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/views/SaveDescriptionAction.java
new file mode 100644
index 0000000..31266b4
--- /dev/null
+++ b/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/views/SaveDescriptionAction.java
@@ -0,0 +1,124 @@
+/**
+ * 
+ */
+package net.sf.taverna.t2.activities.externaltool.views;
+
+import java.awt.Component;
+import java.awt.event.ActionEvent;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.prefs.Preferences;
+
+import javax.swing.AbstractAction;
+import javax.swing.JFileChooser;
+import javax.swing.JOptionPane;
+
+import net.sf.taverna.t2.lang.ui.ExtensionFileFilter;
+import net.sf.taverna.t2.lang.ui.FileTools;
+
+import org.apache.log4j.Logger;
+import org.jdom.Element;
+import org.jdom.output.Format;
+import org.jdom.output.XMLOutputter;
+
+import de.uni_luebeck.inb.knowarc.usecases.UseCaseDescription;
+import de.uni_luebeck.inb.knowarc.usecases.UseCaseEnumeration;
+
+final class SaveDescriptionAction extends AbstractAction {
+	/**
+	 * 
+	 */
+	private final ScriptPanel scriptPanel;
+	private final ExternalToolConfigView view;
+	
+	private static Logger logger = Logger.getLogger(SaveDescriptionAction.class);
+
+	private static XMLOutputter outputter = new XMLOutputter(Format
+			.getPrettyFormat());
+
+	SaveDescriptionAction(ScriptPanel scriptPanel, ExternalToolConfigView view) {
+		this.scriptPanel = scriptPanel;
+		this.view = view;
+	}
+
+	public void actionPerformed(ActionEvent e) {
+		UseCaseDescription currentDescription = view.makeConfiguration().getUseCaseDescription();
+		String usecaseid = currentDescription.getUsecaseid();
+		String description = currentDescription.getDescription();
+		String group = currentDescription.getGroup();
+		if ((usecaseid == null) || usecaseid.isEmpty() || (description == null) || description.isEmpty() || (group == null) || group.isEmpty()) {
+			JOptionPane.showMessageDialog(view, "Please fill in the tool annotation and\nthen re-export the description", "Missing annotation", JOptionPane.PLAIN_MESSAGE, null);
+			view.showAnnotationPanel();
+		} else {
+		saveStringToFile(this.scriptPanel,
+				"Save tool description", ".xml", currentDescription);
+		}
+	}
+	
+	public static boolean saveStringToFile(Component parent, String dialogTitle, String extension, UseCaseDescription description) {
+		JFileChooser fileChooser = new JFileChooser();
+		fileChooser.setDialogTitle(dialogTitle);
+
+		fileChooser.resetChoosableFileFilters();
+		fileChooser.setAcceptAllFileFilterUsed(true);
+		
+		fileChooser.setFileFilter(new ExtensionFileFilter(new String[] { extension }));
+
+		Preferences prefs = Preferences.userNodeForPackage(FileTools.class);
+		String curDir = prefs
+				.get("currentDir", System.getProperty("user.home"));
+		fileChooser.setCurrentDirectory(new File(curDir));
+
+		boolean tryAgain = true;
+		while (tryAgain) {
+			tryAgain = false;
+			int returnVal = fileChooser.showSaveDialog(parent);
+			if (returnVal == JFileChooser.APPROVE_OPTION) {
+				prefs.put("currentDir", fileChooser.getCurrentDirectory()
+						.toString());
+				File file = fileChooser.getSelectedFile();
+				if (!file.getName().contains(".")) {
+					String newName = file.getName() + extension;
+					file = new File(file.getParentFile(), newName);
+				}
+
+				// TODO: Open in separate thread to avoid hanging UI
+				try {
+					List<UseCaseDescription> currentDescriptions;
+					if (file.exists()) {
+						currentDescriptions = UseCaseEnumeration.readDescriptionsFromStream(new FileInputStream(file));
+					} else {
+						currentDescriptions = new ArrayList<UseCaseDescription>();
+					}
+					Element overallElement = new Element("usecases");
+					for (UseCaseDescription ud : currentDescriptions) {
+						if (!ud.getUsecaseid().equals(description.getUsecaseid())) {
+							overallElement.addContent(ud.writeToXMLElement());
+						}
+					}
+
+					overallElement.addContent(description.writeToXMLElement());
+					BufferedWriter out = new BufferedWriter(new FileWriter(file));
+			        out.write(outputter.outputString(overallElement));
+			        out.close();
+					logger.info("Saved content by overwriting " + file);
+					return true;
+				} catch (IOException ex) {
+					logger.warn("Could not save content to " + file, ex);
+					JOptionPane.showMessageDialog(parent,
+							"Could not save to " + file + ": \n\n"
+									+ ex.getMessage(), "Warning",
+							JOptionPane.WARNING_MESSAGE);
+					return false;
+				}
+			}
+		}
+		return false;
+	}
+	
+}
\ No newline at end of file
diff --git a/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/views/ScriptPanel.java b/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/views/ScriptPanel.java
new file mode 100644
index 0000000..ba15219
--- /dev/null
+++ b/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/views/ScriptPanel.java
@@ -0,0 +1,149 @@
+/**
+ * 
+ */
+package net.sf.taverna.t2.activities.externaltool.views;
+
+import java.awt.BorderLayout;
+import java.awt.FlowLayout;
+import java.awt.GridLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.io.IOException;
+
+import javax.swing.AbstractAction;
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JTextArea;
+import javax.swing.JTextField;
+import javax.swing.border.EmptyBorder;
+import javax.swing.text.JTextComponent;
+
+import net.sf.taverna.t2.activities.externaltool.ExternalToolActivityConfigurationBean;
+import net.sf.taverna.t2.lang.ui.DeselectingButton;
+import net.sf.taverna.t2.lang.ui.LineEnabledTextPanel;
+
+import org.jdom.input.SAXBuilder;
+
+import de.uni_luebeck.inb.knowarc.usecases.UseCaseDescription;
+import de.uni_luebeck.inb.knowarc.usecases.UseCaseEnumeration;
+
+
+/**
+ * @author alanrw
+ *
+ */
+public class ScriptPanel extends JPanel {
+	
+	private static final String SCRIPT_DESCRIPTION = "Specify the commands that you want to run. You can use data arriving at an input port to replace parts of the command or to write to a file. You can also take data written to a file and send it to an output port.";
+	static SAXBuilder builder = new SAXBuilder();
+	private final JTextComponent scriptTextArea;
+	
+	public ScriptPanel(final ExternalToolConfigView view, JTextComponent scriptTextArea, JCheckBox stdInCheckBox, JCheckBox stdOutCheckBox, JCheckBox stdErrCheckBox, JTextField returnCodesField) {
+		super();
+		this.setLayout(new BorderLayout());
+	
+		JTextArea descriptionText = new JTextArea(
+				SCRIPT_DESCRIPTION);
+		descriptionText.setEditable(false);
+		descriptionText.setFocusable(false);
+		descriptionText.setBorder(new EmptyBorder(5, 5, 10, 5));
+		descriptionText.setLineWrap(true);
+		descriptionText.setWrapStyleWord(true);
+		this.add(descriptionText, BorderLayout.NORTH);
+
+		this.scriptTextArea = scriptTextArea;
+		
+		this.add(new LineEnabledTextPanel(scriptTextArea),
+				BorderLayout.CENTER);
+		
+
+		UseCaseDescription useCaseDescription = view.getConfiguration().getUseCaseDescription();
+		stdInCheckBox.setSelected(useCaseDescription.isIncludeStdIn());
+		stdOutCheckBox.setSelected(useCaseDescription.isIncludeStdOut());
+		stdErrCheckBox.setSelected(useCaseDescription.isIncludeStdErr());
+		returnCodesField.setText(useCaseDescription.getReturnCodesAsText());
+		
+		JPanel codesPanel = new JPanel(new FlowLayout());
+		codesPanel.add(new JLabel("Valid return codes:"));
+		codesPanel.add(returnCodesField);
+
+		JPanel streamPanel = new JPanel(new FlowLayout());
+		streamPanel.add(stdInCheckBox);
+		streamPanel.add(stdOutCheckBox);
+		streamPanel.add(stdErrCheckBox);
+
+		JPanel buttonPanel = new JPanel(new FlowLayout());
+		if (view.isOriginallyFromRepository()) {
+			JButton revertButton = new DeselectingButton("Revert to original description",
+					new AbstractAction(){
+
+				@Override
+				public void actionPerformed(ActionEvent e) {
+					ExternalToolActivityConfigurationBean bean = view.makeConfiguration();
+					String repositoryUrl = bean.getRepositoryUrl();
+					String id = bean.getExternaltoolid();
+					UseCaseDescription usecase = null;
+					try {
+						usecase = UseCaseEnumeration.readDescriptionFromUrl(
+							repositoryUrl, id);
+					}
+					catch (IOException ex) {
+						// Already logged
+					}
+					if (usecase != null) {
+						bean.setUseCaseDescription(usecase);
+						view.setEditable(false, bean);
+					} else {
+						JOptionPane.showMessageDialog(view, "Unable to find tool description " + id, "Missing tool description", JOptionPane.ERROR_MESSAGE);
+					}
+				}});
+			revertButton.setToolTipText("Revert to the tool description from the repository");
+			buttonPanel.add(revertButton);
+		}
+		JButton loadScriptButton = new DeselectingButton("Load description",
+				new LoadDescriptionAction(this, view));
+		loadScriptButton.setToolTipText("Load tool description from a file");
+
+		JButton saveScriptButton = new DeselectingButton("Export description",
+				new SaveDescriptionAction(this, view));
+		saveScriptButton.setToolTipText("Export the tool description to a file");
+
+		JButton clearScriptButton = new DeselectingButton("Clear script",
+				new AbstractAction() {
+
+			public void actionPerformed(ActionEvent e) {
+				clearScript();
+			}
+
+		});
+		clearScriptButton.setToolTipText("Clear the script from the edit area");
+
+		buttonPanel.add(loadScriptButton);
+		buttonPanel.add(saveScriptButton);
+		buttonPanel.add(clearScriptButton);
+
+		JPanel subPanel = new JPanel(new GridLayout(3,1));
+		subPanel.add(codesPanel);
+		subPanel.add(streamPanel);
+		subPanel.add(buttonPanel);
+
+		this.add(subPanel, BorderLayout.SOUTH);
+	}
+
+	/**
+	 * Method for clearing the script
+	 * 
+	 */
+	private void clearScript() {
+		if (JOptionPane.showConfirmDialog(this,
+				"Do you really want to clear the tool description?",
+				"Clearing the tool description", JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
+			scriptTextArea.setText("");
+		}
+
+	}
+
+}
diff --git a/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/views/StaticStringPanel.java b/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/views/StaticStringPanel.java
new file mode 100644
index 0000000..885cab5
--- /dev/null
+++ b/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/views/StaticStringPanel.java
@@ -0,0 +1,106 @@
+/**
+ * 
+ */
+package net.sf.taverna.t2.activities.externaltool.views;
+
+import java.awt.BorderLayout;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+import java.awt.event.ActionEvent;
+import java.util.List;
+
+import javax.swing.AbstractAction;
+import javax.swing.JButton;
+import javax.swing.JComponent;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTextArea;
+import javax.swing.JTextField;
+import javax.swing.border.EmptyBorder;
+
+import net.sf.taverna.t2.activities.externaltool.utils.Tools;
+import net.sf.taverna.t2.lang.ui.DeselectingButton;
+import net.sf.taverna.t2.lang.ui.ReadOnlyTextArea;
+
+/**
+ * @author alanrw
+ *
+ */
+public class StaticStringPanel extends JPanel {
+	
+	private static final String STATIC_STRING_DESCRIPTION = "A fixed string can be written to the specified file.";
+	private final List<ExternalToolStaticStringViewer> staticStringViewList;
+	
+	int staticGridy = 1;
+	
+	private static String[] elementLabels = new String[] {"String to copy", "To file"};
+	
+	public StaticStringPanel(final List<ExternalToolStaticStringViewer> staticStringViewList) {
+		super(new BorderLayout());
+		this.staticStringViewList = staticStringViewList;
+		final JPanel staticEditPanel = new JPanel(new GridBagLayout());
+
+		final GridBagConstraints staticConstraint = new GridBagConstraints();
+		staticConstraint.insets = new Insets(5, 5, 5, 5);
+		staticConstraint.anchor = GridBagConstraints.FIRST_LINE_START;
+		staticConstraint.gridx = 0;
+		staticConstraint.gridy = 0;
+		staticConstraint.weightx = 0.1;
+		staticConstraint.fill = GridBagConstraints.BOTH;
+
+		staticConstraint.gridx = 0;
+		synchronized (staticStringViewList) {
+			for (ExternalToolStaticStringViewer staticView : staticStringViewList) {
+				addStaticStringViewer(StaticStringPanel.this, staticEditPanel,
+						staticView);
+			}
+		}
+
+		JTextArea descriptionText = new ReadOnlyTextArea(
+				STATIC_STRING_DESCRIPTION);
+		descriptionText.setEditable(false);
+		descriptionText.setFocusable(false);
+		descriptionText.setBorder(new EmptyBorder(5, 5, 10, 5));
+		this.add(descriptionText, BorderLayout.NORTH);
+
+		this.add(new JScrollPane(staticEditPanel),
+				BorderLayout.CENTER);
+		JButton addStaticStringButton = new DeselectingButton("Add string",
+				new AbstractAction() {
+			// FIXME refactor this into a method
+			public void actionPerformed(ActionEvent e) {
+
+				ExternalToolStaticStringViewer newViewer = new ExternalToolStaticStringViewer();
+				synchronized (staticStringViewList) {
+					staticStringViewList.add(newViewer);
+					addStaticStringViewer(StaticStringPanel.this, staticEditPanel,
+							newViewer);
+					staticEditPanel.revalidate();
+					staticEditPanel.repaint();
+				}
+			}
+
+		});
+
+		JPanel buttonPanel = new JPanel(new BorderLayout());
+
+		buttonPanel.add(addStaticStringButton, BorderLayout.EAST);
+
+		this.add(buttonPanel, BorderLayout.SOUTH);
+	
+	}
+	
+	private void addStaticStringViewer(final JPanel outerPanel,
+			final JPanel panel, ExternalToolStaticStringViewer viewer) {
+		Tools.addViewer(panel,
+				elementLabels,
+				new JComponent[] {new JScrollPane(viewer.getContentField()), viewer.getValueField()},
+				staticStringViewList,
+				viewer,
+				outerPanel);
+	}
+
+
+}
diff --git a/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/views/StaticUrlPanel.java b/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/views/StaticUrlPanel.java
new file mode 100644
index 0000000..ba441f4
--- /dev/null
+++ b/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/views/StaticUrlPanel.java
@@ -0,0 +1,108 @@
+/**
+ * 
+ */
+package net.sf.taverna.t2.activities.externaltool.views;
+
+import java.awt.BorderLayout;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+import java.awt.event.ActionEvent;
+import java.util.List;
+
+import javax.swing.AbstractAction;
+import javax.swing.JButton;
+import javax.swing.JComponent;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTextArea;
+import javax.swing.JTextField;
+import javax.swing.border.EmptyBorder;
+
+import net.sf.taverna.t2.activities.externaltool.utils.Tools;
+import net.sf.taverna.t2.lang.ui.DeselectingButton;
+import net.sf.taverna.t2.lang.ui.ReadOnlyTextArea;
+
+/**
+ * @author alanrw
+ *
+ */
+public class StaticUrlPanel extends JPanel {
+	
+	private static final String STATIC_URL_DESCRIPTION = "The data at a URL can be downloaded and stored in the specified file.";
+	private final List<ExternalToolStaticUrlViewer> staticUrlViewList;
+	private int staticGridy = 1;
+
+	private static String[] elementLabels = new String[] {"Copy from URL", "To file"};
+	
+
+	public StaticUrlPanel(final List<ExternalToolStaticUrlViewer> staticUrlViewList) {
+	
+	super(new BorderLayout());
+	this.staticUrlViewList = staticUrlViewList;
+	final JPanel staticEditPanel = new JPanel(new GridBagLayout());
+
+	final GridBagConstraints staticConstraint = new GridBagConstraints();
+	staticConstraint.insets = new Insets(5, 5, 5, 5);
+	staticConstraint.anchor = GridBagConstraints.FIRST_LINE_START;
+	staticConstraint.gridx = 0;
+	staticConstraint.gridy = 0;
+	staticConstraint.weightx = 0.1;
+	staticConstraint.fill = GridBagConstraints.BOTH;
+
+	staticConstraint.gridx = 0;
+	synchronized (staticUrlViewList) {
+		for (ExternalToolStaticUrlViewer staticView : staticUrlViewList) {
+			addStaticUrlViewer(this, staticEditPanel,
+					staticView);
+		}
+	}
+
+	this.add(new JScrollPane(staticEditPanel),
+			BorderLayout.CENTER);
+
+	JTextArea descriptionText = new ReadOnlyTextArea(
+			STATIC_URL_DESCRIPTION);
+	descriptionText.setEditable(false);
+	descriptionText.setFocusable(false);
+	descriptionText.setBorder(new EmptyBorder(5, 5, 10, 5));
+
+	this.add(descriptionText, BorderLayout.NORTH);
+
+	JButton addstaticPortButton = new DeselectingButton("Add URL",
+			new AbstractAction() {
+		// FIXME refactor this into a method
+		public void actionPerformed(ActionEvent e) {
+
+			ExternalToolStaticUrlViewer newViewer = new ExternalToolStaticUrlViewer();
+			synchronized (staticUrlViewList) {
+				staticUrlViewList.add(newViewer);
+				addStaticUrlViewer(StaticUrlPanel.this, staticEditPanel,
+						newViewer);
+				staticEditPanel.revalidate();
+				staticEditPanel.repaint();
+			}
+		}
+
+	});
+	JPanel buttonPanel = new JPanel(new BorderLayout());
+
+	buttonPanel.add(addstaticPortButton, BorderLayout.EAST);
+
+	this.add(buttonPanel, BorderLayout.SOUTH);
+
+	}
+	
+	private void addStaticUrlViewer(final JPanel outerPanel,
+			final JPanel panel, ExternalToolStaticUrlViewer viewer) {
+		Tools.addViewer(panel,
+				elementLabels,
+				new JComponent[] {viewer.getContentField(), viewer.getValueField()},
+				staticUrlViewList,
+				viewer,
+				outerPanel);
+	}
+
+
+}
diff --git a/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/views/StringReplacementPanel.java b/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/views/StringReplacementPanel.java
new file mode 100644
index 0000000..1f85d3a
--- /dev/null
+++ b/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/views/StringReplacementPanel.java
@@ -0,0 +1,134 @@
+/**
+ * 
+ */
+package net.sf.taverna.t2.activities.externaltool.views;
+
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+import java.awt.event.ActionEvent;
+import java.util.List;
+
+import javax.swing.AbstractAction;
+import javax.swing.BorderFactory;
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JComponent;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTextArea;
+import javax.swing.JTextField;
+import javax.swing.border.CompoundBorder;
+import javax.swing.border.EmptyBorder;
+
+import net.sf.taverna.t2.activities.externaltool.manager.ssh.ExternalToolSshNodeViewer;
+import net.sf.taverna.t2.activities.externaltool.utils.Tools;
+import net.sf.taverna.t2.lang.ui.DeselectingButton;
+
+/**
+ * @author alanrw
+ *
+ */
+public class StringReplacementPanel extends JPanel {
+	
+	private static final String STRING_REPLACEMENT_DESCRIPTION = "You can use a string replacement to " +
+	"feed data into the service via an input port and have that data replace part of the " +
+	"command.";
+	private final List<ExternalToolStringReplacementViewer> stringReplacementViewList;
+	private int stringReplacementGridy = 1;
+	private final ExternalToolConfigView view;
+	
+	private static Insets insets = new Insets(1,5,1,5);
+	
+	private static String[] elementLabels = new String[] {"Taverna port name", "Replace port name", "String to replace"};
+	
+	private static CompoundBorder border = BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(5,5,5,5), BorderFactory.createLineBorder(Color.BLACK, 1));
+
+	
+	public StringReplacementPanel(final ExternalToolConfigView view, final List<ExternalToolStringReplacementViewer> stringReplacementViewList) {
+		super(new BorderLayout());
+		this.view = view;
+		this.stringReplacementViewList = stringReplacementViewList;
+
+		final JPanel inputEditPanel = new JPanel(new GridBagLayout());
+
+		final GridBagConstraints inputConstraint = new GridBagConstraints();
+
+		inputConstraint.anchor = GridBagConstraints.FIRST_LINE_START;
+		inputConstraint.gridx = 0;
+		inputConstraint.gridy = 0;
+		inputConstraint.weightx = 0.1;
+		inputConstraint.fill = GridBagConstraints.BOTH;
+
+		inputConstraint.gridx = 0;
+		synchronized (stringReplacementViewList) {
+			for (ExternalToolStringReplacementViewer inputView : stringReplacementViewList) {
+				addStringReplacementViewer(this, inputEditPanel,
+						inputView, elementLabels);
+
+			}
+		}
+
+		JTextArea descriptionText = new JTextArea(
+				STRING_REPLACEMENT_DESCRIPTION);
+		descriptionText.setEditable(false);
+		descriptionText.setFocusable(false);
+		descriptionText.setBorder(new EmptyBorder(5, 5, 10, 5));
+		descriptionText.setLineWrap(true);
+		descriptionText.setWrapStyleWord(true);
+
+		this.add(descriptionText, BorderLayout.NORTH);
+		this.add(new JScrollPane(inputEditPanel),
+				BorderLayout.CENTER);
+		JButton addInputPortButton = new DeselectingButton("Add string replacement",
+				new AbstractAction() {
+
+			public void actionPerformed(ActionEvent e) {
+
+				int portNumber = 1;
+				String name2 = "in" + portNumber++;
+				boolean nameExists = true;
+				while (nameExists == true) {
+					nameExists = view.portNameExists(name2);
+					if (nameExists) {
+						name2 = "in" + portNumber++;
+					}
+				}
+
+				ExternalToolStringReplacementViewer newViewer = new ExternalToolStringReplacementViewer(
+						name2);
+				synchronized (stringReplacementViewList) {
+					stringReplacementViewList.add(newViewer);
+					addStringReplacementViewer(StringReplacementPanel.this, inputEditPanel,
+							newViewer, elementLabels);
+					inputEditPanel.revalidate();
+					inputEditPanel.repaint();
+				}
+
+			}
+
+		});
+
+		JPanel buttonPanel = new JPanel();
+		buttonPanel.setLayout(new BorderLayout());
+
+		buttonPanel.add(addInputPortButton, BorderLayout.EAST);
+
+		this.add(buttonPanel, BorderLayout.SOUTH);
+	}
+	
+	private void addStringReplacementViewer(final JPanel outerPanel,
+			final JPanel innerPanel, final ExternalToolStringReplacementViewer viewer, String[] elementLabels) {
+		Tools.addViewer(innerPanel,
+				elementLabels,
+				new JComponent[] {viewer.getNameField(), viewer.getValueFromField(), viewer.getValueField()},
+				stringReplacementViewList,
+				viewer,
+				outerPanel);
+	}
+
+
+}
diff --git a/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/views/ToolXMLPanel.java b/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/views/ToolXMLPanel.java
new file mode 100644
index 0000000..b49211f
--- /dev/null
+++ b/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/views/ToolXMLPanel.java
@@ -0,0 +1,33 @@
+/**
+ * 
+ */
+package net.sf.taverna.t2.activities.externaltool.views;
+
+import java.awt.BorderLayout;
+
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+
+import net.sf.taverna.t2.renderers.impl.XMLTree;
+
+import de.uni_luebeck.inb.knowarc.usecases.UseCaseDescription;
+
+/**
+ * @author alanrw
+ *
+ */
+public class ToolXMLPanel extends JPanel {
+
+	public ToolXMLPanel(UseCaseDescription useCaseDescription) {
+		super(new BorderLayout());
+		XMLTree xmlTree = new XMLTree(useCaseDescription.writeToXMLElement());
+		this.add(new JScrollPane(xmlTree), BorderLayout.CENTER);
+	}
+
+	public void regenerateTree(UseCaseDescription useCaseDescription) {
+		this.removeAll();
+		XMLTree xmlTree = new XMLTree(useCaseDescription.writeToXMLElement());
+		this.add(new JScrollPane(xmlTree), BorderLayout.CENTER);		
+	}
+
+}
diff --git a/taverna-external-tool-activity-ui/src/main/resources/META-INF/services/net.sf.taverna.t2.activities.externaltool.manager.InvocationMechanismEditor b/taverna-external-tool-activity-ui/src/main/resources/META-INF/services/net.sf.taverna.t2.activities.externaltool.manager.InvocationMechanismEditor
new file mode 100644
index 0000000..9307977
--- /dev/null
+++ b/taverna-external-tool-activity-ui/src/main/resources/META-INF/services/net.sf.taverna.t2.activities.externaltool.manager.InvocationMechanismEditor
@@ -0,0 +1,2 @@
+net.sf.taverna.t2.activities.externaltool.manager.local.LocalInvocationMechanismEditor
+net.sf.taverna.t2.activities.externaltool.manager.ssh.SshInvocationMechanismEditor
diff --git a/taverna-external-tool-activity-ui/src/main/resources/META-INF/services/net.sf.taverna.t2.servicedescriptions.ServiceDescriptionProvider b/taverna-external-tool-activity-ui/src/main/resources/META-INF/services/net.sf.taverna.t2.servicedescriptions.ServiceDescriptionProvider
new file mode 100644
index 0000000..e94cf6e
--- /dev/null
+++ b/taverna-external-tool-activity-ui/src/main/resources/META-INF/services/net.sf.taverna.t2.servicedescriptions.ServiceDescriptionProvider
@@ -0,0 +1,2 @@
+net.sf.taverna.t2.activities.externaltool.servicedescriptions.ExternalToolServiceProvider
+net.sf.taverna.t2.activities.externaltool.servicedescriptions.ExternalToolTemplateServiceDescription
diff --git a/taverna-external-tool-activity-ui/src/main/resources/META-INF/services/net.sf.taverna.t2.ui.menu.MenuComponent b/taverna-external-tool-activity-ui/src/main/resources/META-INF/services/net.sf.taverna.t2.ui.menu.MenuComponent
new file mode 100644
index 0000000..db316f2
--- /dev/null
+++ b/taverna-external-tool-activity-ui/src/main/resources/META-INF/services/net.sf.taverna.t2.ui.menu.MenuComponent
@@ -0,0 +1,4 @@
+net.sf.taverna.t2.activities.externaltool.menu.ConfigureExternalToolMenuAction
+# net.sf.taverna.t2.activities.externaltool.menu.FeedbackMenuAction
+net.sf.taverna.t2.activities.externaltool.menu.AddExternalToolContextualMenuAction
+net.sf.taverna.t2.activities.externaltool.menu.AddExternalToolMenuAction
diff --git a/taverna-external-tool-activity-ui/src/main/resources/META-INF/services/net.sf.taverna.t2.workbench.ShutdownSPI b/taverna-external-tool-activity-ui/src/main/resources/META-INF/services/net.sf.taverna.t2.workbench.ShutdownSPI
new file mode 100644
index 0000000..e6686a0
--- /dev/null
+++ b/taverna-external-tool-activity-ui/src/main/resources/META-INF/services/net.sf.taverna.t2.workbench.ShutdownSPI
@@ -0,0 +1 @@
+net.sf.taverna.t2.activities.externaltool.manager.InvocationGroupManagerShutdownHook
\ No newline at end of file
diff --git a/taverna-external-tool-activity-ui/src/main/resources/META-INF/services/net.sf.taverna.t2.workbench.StartupSPI b/taverna-external-tool-activity-ui/src/main/resources/META-INF/services/net.sf.taverna.t2.workbench.StartupSPI
new file mode 100644
index 0000000..0dd97e4
--- /dev/null
+++ b/taverna-external-tool-activity-ui/src/main/resources/META-INF/services/net.sf.taverna.t2.workbench.StartupSPI
@@ -0,0 +1 @@
+net.sf.taverna.t2.activities.externaltool.manager.InvocationGroupManagerStartupHook
diff --git a/taverna-external-tool-activity-ui/src/main/resources/META-INF/services/net.sf.taverna.t2.workbench.activityicons.ActivityIconSPI b/taverna-external-tool-activity-ui/src/main/resources/META-INF/services/net.sf.taverna.t2.workbench.activityicons.ActivityIconSPI
new file mode 100644
index 0000000..cdafd5d
--- /dev/null
+++ b/taverna-external-tool-activity-ui/src/main/resources/META-INF/services/net.sf.taverna.t2.workbench.activityicons.ActivityIconSPI
@@ -0,0 +1 @@
+net.sf.taverna.t2.activities.externaltool.servicedescriptions.ExternalToolActivityIcon
diff --git a/taverna-external-tool-activity-ui/src/main/resources/META-INF/services/net.sf.taverna.t2.workbench.configuration.ConfigurationUIFactory b/taverna-external-tool-activity-ui/src/main/resources/META-INF/services/net.sf.taverna.t2.workbench.configuration.ConfigurationUIFactory
new file mode 100644
index 0000000..b3d1525
--- /dev/null
+++ b/taverna-external-tool-activity-ui/src/main/resources/META-INF/services/net.sf.taverna.t2.workbench.configuration.ConfigurationUIFactory
@@ -0,0 +1 @@
+net.sf.taverna.t2.activities.externaltool.manager.ToolInvocationConfigurationUIFactory
\ No newline at end of file
diff --git a/taverna-external-tool-activity-ui/src/main/resources/META-INF/services/net.sf.taverna.t2.workbench.ui.views.contextualviews.activity.ContextualViewFactory b/taverna-external-tool-activity-ui/src/main/resources/META-INF/services/net.sf.taverna.t2.workbench.ui.views.contextualviews.activity.ContextualViewFactory
new file mode 100644
index 0000000..ca0d30f
--- /dev/null
+++ b/taverna-external-tool-activity-ui/src/main/resources/META-INF/services/net.sf.taverna.t2.workbench.ui.views.contextualviews.activity.ContextualViewFactory
@@ -0,0 +1 @@
+net.sf.taverna.t2.activities.externaltool.views.ExternalToolActivityViewFactory
diff --git a/taverna-external-tool-activity-ui/src/main/resources/META-INF/spring/external-tool-activity-ui-context-osgi.xml b/taverna-external-tool-activity-ui/src/main/resources/META-INF/spring/external-tool-activity-ui-context-osgi.xml
new file mode 100644
index 0000000..3d7110c
--- /dev/null
+++ b/taverna-external-tool-activity-ui/src/main/resources/META-INF/spring/external-tool-activity-ui-context-osgi.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans:beans xmlns="http://www.springframework.org/schema/osgi" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xmlns:beans="http://www.springframework.org/schema/beans"
+	xsi:schemaLocation="http://www.springframework.org/schema/beans
+                      http://www.springframework.org/schema/beans/spring-beans.xsd
+                      http://www.springframework.org/schema/osgi
+                      http://www.springframework.org/schema/osgi/spring-osgi.xsd">
+
+	<service ref="ToolInvocationConfigurationUIFactory" interface="uk.org.taverna.configuration.ConfigurationUIFactory" />
+
+	<service ref="InvocationGroupManagerStartupHook" interface="net.sf.taverna.t2.workbench.StartupSPI" />
+
+	<service ref="ExternalToolActivityIcon" interface="net.sf.taverna.t2.workbench.activityicons.ActivityIconSPI" />
+
+	<service ref="LocalInvocationMechanismEditor" interface="net.sf.taverna.t2.activities.externaltool.manager.InvocationMechanismEditor" />
+	<service ref="SshInvocationMechanismEditor" interface="net.sf.taverna.t2.activities.externaltool.manager.InvocationMechanismEditor" />
+
+	<service ref="ExternalToolServiceProvider" interface="net.sf.taverna.t2.servicedescriptions.ServiceDescriptionProvider" />
+	<service ref="ExternalToolTemplateServiceDescription" interface="net.sf.taverna.t2.servicedescriptions.ServiceDescriptionProvider" />
+
+	<service ref="ConfigureExternalToolMenuAction" auto-export="interfaces" />
+	<service ref="AddExternalToolContextualMenuAction" auto-export="interfaces" />
+	<service ref="AddExternalToolMenuAction" auto-export="interfaces" />
+
+	<service ref="InvocationGroupManagerShutdownHook" interface="net.sf.taverna.t2.workbench.ShutdownSPI" />
+
+	<service ref="ExternalToolActivityViewFactory" interface="net.sf.taverna.t2.workbench.ui.views.contextualviews.activity.ContextualViewFactory" />
+
+	<list id="mechanismCreators" interface="net.sf.taverna.t2.activities.externaltool.manager.MechanismCreator" cardinality="0..N" />
+	<list id="invocationMechanismEditors" interface="net.sf.taverna.t2.activities.externaltool.manager.InvocationMechanismEditor" cardinality="0..N" />
+
+	<reference id="editManager" interface="net.sf.taverna.t2.workbench.edits.EditManager" />
+	<reference id="fileManager" interface="net.sf.taverna.t2.workbench.file.FileManager" />
+	<reference id="menuManager" interface="net.sf.taverna.t2.ui.menu.MenuManager" />
+	<reference id="selectionManager" interface="net.sf.taverna.t2.workbench.selection.SelectionManager" />
+	<reference id="activityIconManager" interface="net.sf.taverna.t2.workbench.activityicons.ActivityIconManager" />
+	<reference id="colourManager" interface="net.sf.taverna.t2.workbench.configuration.colour.ColourManager" />
+
+</beans:beans>
diff --git a/taverna-external-tool-activity-ui/src/main/resources/META-INF/spring/external-tool-activity-ui-context.xml b/taverna-external-tool-activity-ui/src/main/resources/META-INF/spring/external-tool-activity-ui-context.xml
new file mode 100644
index 0000000..7cf7f63
--- /dev/null
+++ b/taverna-external-tool-activity-ui/src/main/resources/META-INF/spring/external-tool-activity-ui-context.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://www.springframework.org/schema/beans
+                      http://www.springframework.org/schema/beans/spring-beans.xsd">
+
+	<bean id="ToolInvocationConfigurationUIFactory" class="net.sf.taverna.t2.activities.externaltool.manager.ToolInvocationConfigurationUIFactory">
+		<property name="mechanismCreators" ref="mechanismCreators" />
+		<property name="invocationMechanismEditors" ref="invocationMechanismEditors" />
+	</bean>
+
+	<bean id="InvocationGroupManagerStartupHook" class="net.sf.taverna.t2.activities.externaltool.manager.InvocationGroupManagerStartupHook" />
+
+	<bean id="ExternalToolActivityIcon" class="net.sf.taverna.t2.activities.externaltool.servicedescriptions.ExternalToolActivityIcon">
+			<property name="colourManager" ref="colourManager" />
+	</bean>
+
+	<bean id="LocalInvocationMechanismEditor" class="net.sf.taverna.t2.activities.externaltool.manager.local.LocalInvocationMechanismEditor" />
+	<bean id="SshInvocationMechanismEditor" class="net.sf.taverna.t2.activities.externaltool.manager.ssh.SshInvocationMechanismEditor" />
+
+	<bean id="ExternalToolServiceProvider" class="net.sf.taverna.t2.activities.externaltool.servicedescriptions.ExternalToolServiceProvider" />
+	<bean id="ExternalToolTemplateServiceDescription" class="net.sf.taverna.t2.activities.externaltool.servicedescriptions.ExternalToolTemplateServiceDescription" />
+
+	<bean id="ConfigureExternalToolMenuAction" class="net.sf.taverna.t2.activities.externaltool.menu.ConfigureExternalToolMenuAction">
+			<property name="editManager" ref="editManager" />
+			<property name="fileManager" ref="fileManager" />
+			<property name="activityIconManager" ref="activityIconManager" />
+	</bean>
+	<bean id="AddExternalToolContextualMenuAction" class="net.sf.taverna.t2.activities.externaltool.menu.AddExternalToolContextualMenuAction">
+			<property name="editManager" ref="editManager" />
+			<property name="menuManager" ref="menuManager" />
+			<property name="selectionManager" ref="selectionManager" />
+			<property name="activityIconManager" ref="activityIconManager" />
+	</bean>
+	<bean id="AddExternalToolMenuAction" class="net.sf.taverna.t2.activities.externaltool.menu.AddExternalToolMenuAction">
+			<property name="editManager" ref="editManager" />
+			<property name="menuManager" ref="menuManager" />
+			<property name="selectionManager" ref="selectionManager" />
+			<property name="activityIconManager" ref="activityIconManager" />
+	</bean>
+
+	<bean id="InvocationGroupManagerShutdownHook" class="net.sf.taverna.t2.activities.externaltool.manager.InvocationGroupManagerShutdownHook" />
+
+	<bean id="ExternalToolActivityViewFactory" class="net.sf.taverna.t2.activities.externaltool.views.ExternalToolActivityViewFactory">
+			<property name="editManager" ref="editManager" />
+			<property name="fileManager" ref="fileManager" />
+			<property name="activityIconManager" ref="activityIconManager" />
+			<property name="colourManager" ref="colourManager" />
+	</bean>
+
+</beans>
diff --git a/taverna-external-tool-activity-ui/src/main/resources/externaltool.png b/taverna-external-tool-activity-ui/src/main/resources/externaltool.png
new file mode 100644
index 0000000..a9e84e6
--- /dev/null
+++ b/taverna-external-tool-activity-ui/src/main/resources/externaltool.png
Binary files differ
diff --git a/taverna-localworker-activity-ui/pom.xml b/taverna-localworker-activity-ui/pom.xml
new file mode 100644
index 0000000..556de86
--- /dev/null
+++ b/taverna-localworker-activity-ui/pom.xml
@@ -0,0 +1,142 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+	<parent>
+                <groupId>net.sf.taverna</groupId>
+                <artifactId>taverna-parent</artifactId>
+                <version>3.0.1-SNAPSHOT</version>
+	</parent>
+	<groupId>net.sf.taverna.t2.ui-activities</groupId>
+	<artifactId>localworker-activity-ui</artifactId>
+        <version>2.0-SNAPSHOT</version>
+	<packaging>bundle</packaging>
+	<name>Taverna 2 Localworker Activity UI</name>
+	<dependencies>
+		<dependency>
+			<groupId>net.sf.taverna.t2.ui-activities</groupId>
+			<artifactId>beanshell-activity-ui</artifactId>
+			<version>${t2.activities.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>net.sf.taverna.t2.ui-api</groupId>
+			<artifactId>activity-icons-api</artifactId>
+			<version>${t2.ui.api.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>net.sf.taverna.t2.ui-api</groupId>
+			<artifactId>activity-palette-api</artifactId>
+			<version>${t2.ui.api.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>net.sf.taverna.t2.ui-api</groupId>
+			<artifactId>edits-api</artifactId>
+			<version>${t2.ui.api.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>net.sf.taverna.t2.ui-api</groupId>
+			<artifactId>file-api</artifactId>
+			<version>${t2.ui.api.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>net.sf.taverna.t2.ui-api</groupId>
+			<artifactId>menu-api</artifactId>
+			<version>${t2.ui.api.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>uk.org.taverna.configuration</groupId>
+			<artifactId>taverna-app-configuration-api</artifactId>
+			<version>${taverna.configuration.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>uk.org.taverna.scufl2</groupId>
+			<artifactId>scufl2-api</artifactId>
+			<version>${scufl2.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>com.fasterxml.jackson.core</groupId>
+			<artifactId>jackson-databind</artifactId>
+			<version>2.2.2</version>
+		</dependency>
+
+		<!-- category:biojava -->
+		<!-- net.sourceforge.taverna.scuflworkers.biojava.GenBankParserWorker -->
+		<!-- net.sourceforge.taverna.scuflworkers.biojava.ReverseCompWorker -->
+		<!-- net.sourceforge.taverna.scuflworkers.biojava.SwissProtParserWorker -->
+		<!-- net.sourceforge.taverna.scuflworkers.biojava.TranscribeWorker -->
+		<dependency>
+			<groupId>uk.org.mygrid.resources</groupId>
+			<artifactId>biojava</artifactId>
+			<version>1.4pre1</version>
+		</dependency>
+		<!-- category:xml -->
+		<!-- net.sourceforge.taverna.scuflworkers.xml.XPathTextWorker -->
+		<dependency>
+			<groupId>org.dom4j</groupId>
+			<artifactId>com.springsource.org.dom4j</artifactId>
+			<version>${dom4j.version}</version>
+		</dependency>
+		<!-- <dependency>
+			<groupId>dom4j</groupId>
+			<artifactId>dom4j</artifactId>
+			<version>1.6</version>
+		</dependency> -->
+		<!-- category:net -->
+		<!-- org.embl.ebi.escience.scuflworkers.java.SendEmail -->
+		<dependency>
+			<groupId>javax.mail</groupId>
+			<artifactId>com.springsource.javax.mail</artifactId>
+			<version>${mail.version}</version>
+		</dependency>
+		<!-- <dependency>
+			<groupId>javax.mail</groupId>
+			<artifactId>mail</artifactId>
+			<version>1.4</version>
+		</dependency> -->
+		<dependency>
+			<groupId>javax.activation</groupId>
+			<artifactId>com.springsource.javax.activation</artifactId>
+			<version>1.1.1</version>
+		</dependency>
+		<!-- <dependency>
+			<groupId>javax.activation</groupId>
+			<artifactId>activation</artifactId>
+			<version>1.1</version>
+		</dependency> -->
+		<!-- category:base64 -->
+		<!-- org.embl.ebi.escience.scuflworkers.java.EncodeBase64 -->
+		<!-- org.embl.ebi.escience.scuflworkers.java.DecodeBase64 -->
+		<dependency>
+			<groupId>commons-codec</groupId>
+			<artifactId>commons-codec</artifactId>
+			<version>${commons.codec.version}</version>
+		</dependency>
+		<!-- <dependency>
+			<groupId>commons-codec</groupId>
+			<artifactId>commons-codec</artifactId>
+			<version>1.3</version>
+		</dependency> -->
+	</dependencies>
+	<repositories>
+		<repository>
+			<releases />
+			<snapshots>
+				<enabled>false</enabled>
+			</snapshots>
+			<id>mygrid-repository</id>
+			<name>myGrid Repository</name>
+			<url>http://www.mygrid.org.uk/maven/repository
+			</url>
+		</repository>
+		<repository>
+			<releases>
+				<enabled>false</enabled>
+			</releases>
+			<snapshots />
+			<id>mygrid-snapshot-repository</id>
+			<name>myGrid Snapshot Repository</name>
+			<url>http://www.mygrid.org.uk/maven/snapshot-repository</url>
+		</repository>
+	</repositories>
+</project>
+
diff --git a/taverna-localworker-activity-ui/src/main/java/net/sf/taverna/t2/activities/localworker/actions/LocalworkerActivityConfigurationAction.java b/taverna-localworker-activity-ui/src/main/java/net/sf/taverna/t2/activities/localworker/actions/LocalworkerActivityConfigurationAction.java
new file mode 100644
index 0000000..2016ad0
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/java/net/sf/taverna/t2/activities/localworker/actions/LocalworkerActivityConfigurationAction.java
@@ -0,0 +1,117 @@
+/*******************************************************************************
+ * Copyright (C) 2007 The University of Manchester
+ *
+ *  Modifications to the initial code base are copyright of their
+ *  respective authors, or their employers as appropriate.
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1 of
+ *  the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+package net.sf.taverna.t2.activities.localworker.actions;
+
+import java.awt.Frame;
+import java.awt.event.ActionEvent;
+
+import javax.swing.Action;
+import javax.swing.JOptionPane;
+
+import net.sf.taverna.t2.activities.localworker.views.LocalworkerActivityConfigView;
+import net.sf.taverna.t2.servicedescriptions.ServiceDescriptionRegistry;
+import net.sf.taverna.t2.workbench.activityicons.ActivityIconManager;
+import net.sf.taverna.t2.workbench.edits.EditManager;
+import net.sf.taverna.t2.workbench.file.FileManager;
+import net.sf.taverna.t2.workbench.ui.actions.activity.ActivityConfigurationAction;
+import net.sf.taverna.t2.workbench.ui.views.contextualviews.activity.ActivityConfigurationDialog;
+import uk.org.taverna.configuration.app.ApplicationConfiguration;
+import uk.org.taverna.scufl2.api.activity.Activity;
+import uk.org.taverna.scufl2.api.common.Scufl2Tools;
+import uk.org.taverna.scufl2.api.configurations.Configuration;
+
+import com.fasterxml.jackson.databind.JsonNode;
+
+/**
+ * The {@link LocalworkerActivity}s have pre-defined scripts, ports etc in a serialised form on
+ * disk. So if the user wants to change them they have to do so at own risk.
+ *
+ * @author Ian Dunlop
+ */
+@SuppressWarnings("serial")
+public class LocalworkerActivityConfigurationAction extends ActivityConfigurationAction {
+
+	public static final String EDIT_LOCALWORKER_SCRIPT = "Edit beanshell script";
+
+	private final EditManager editManager;
+
+	private final FileManager fileManager;
+
+	private final ApplicationConfiguration applicationConfiguration;
+
+	private Scufl2Tools scufl2Tools = new Scufl2Tools();
+
+	public LocalworkerActivityConfigurationAction(Activity activity, Frame owner,
+			EditManager editManager, FileManager fileManager,
+			ActivityIconManager activityIconManager,
+			ServiceDescriptionRegistry serviceDescriptionRegistry,
+			ApplicationConfiguration applicationConfiguration) {
+		super(activity, activityIconManager, serviceDescriptionRegistry);
+		this.editManager = editManager;
+		this.fileManager = fileManager;
+		this.applicationConfiguration = applicationConfiguration;
+		putValue(Action.NAME, EDIT_LOCALWORKER_SCRIPT);
+	}
+
+	/**
+	 * If the localworker has not been changed it pops up a {@link JOptionPane} warning the user
+	 * that they change things at their own risk. Otherwise just show the config view
+	 */
+	public void actionPerformed(ActionEvent e) {
+		Object[] options = { "Continue", "Cancel" };
+		Configuration configuration = scufl2Tools.configurationFor(activity, activity.getParent());
+		JsonNode json = configuration.getJson();
+		if (!json.get("isAltered").booleanValue()) {
+			int n = JOptionPane
+					.showOptionDialog(
+							null,
+							"Changing the properties of a Local Worker may affect its behaviour. Do you want to continue?",
+							"WARNING", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE,
+							null, // do not use a
+							// custom Icon
+							options, options[0]);
+
+			if (n == 0) {
+				// continue was clicked so prepare for config
+				openDialog();
+			} else {
+				// do nothing
+			}
+		} else {
+			openDialog();
+		}
+	}
+
+	private void openDialog() {
+		ActivityConfigurationDialog currentDialog = ActivityConfigurationAction
+				.getDialog(getActivity());
+		if (currentDialog != null) {
+			currentDialog.toFront();
+			return;
+		}
+		final LocalworkerActivityConfigView localworkerConfigView = new LocalworkerActivityConfigView(
+				getActivity(), applicationConfiguration);
+		final ActivityConfigurationDialog dialog = new ActivityConfigurationDialog(getActivity(),
+				localworkerConfigView, editManager);
+		ActivityConfigurationAction.setDialog(getActivity(), dialog, fileManager);
+
+	}
+}
diff --git a/taverna-localworker-activity-ui/src/main/java/net/sf/taverna/t2/activities/localworker/menu/ConfigureLocalworkerMenuAction.java b/taverna-localworker-activity-ui/src/main/java/net/sf/taverna/t2/activities/localworker/menu/ConfigureLocalworkerMenuAction.java
new file mode 100644
index 0000000..3afed8d
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/java/net/sf/taverna/t2/activities/localworker/menu/ConfigureLocalworkerMenuAction.java
@@ -0,0 +1,62 @@
+package net.sf.taverna.t2.activities.localworker.menu;
+
+import javax.swing.Action;
+
+import uk.org.taverna.configuration.app.ApplicationConfiguration;
+
+import net.sf.taverna.t2.activities.beanshell.actions.BeanshellActivityConfigurationAction;
+import net.sf.taverna.t2.activities.localworker.actions.LocalworkerActivityConfigurationAction;
+import net.sf.taverna.t2.activities.localworker.servicedescriptions.LocalworkerServiceDescription;
+import net.sf.taverna.t2.servicedescriptions.ServiceDescriptionRegistry;
+import net.sf.taverna.t2.ui.menu.ContextualMenuComponent;
+import net.sf.taverna.t2.ui.menu.MenuComponent;
+import net.sf.taverna.t2.workbench.activityicons.ActivityIconManager;
+import net.sf.taverna.t2.workbench.activitytools.AbstractConfigureActivityMenuAction;
+import net.sf.taverna.t2.workbench.edits.EditManager;
+import net.sf.taverna.t2.workbench.file.FileManager;
+
+public class ConfigureLocalworkerMenuAction extends AbstractConfigureActivityMenuAction implements
+		MenuComponent, ContextualMenuComponent {
+
+	private EditManager editManager;
+	private FileManager fileManager;
+	private ActivityIconManager activityIconManager;
+	private ServiceDescriptionRegistry serviceDescriptionRegistry;
+	private ApplicationConfiguration applicationConfiguration;
+
+	public ConfigureLocalworkerMenuAction() {
+		super(LocalworkerServiceDescription.ACTIVITY_TYPE);
+	}
+
+	@Override
+	protected Action createAction() {
+		Action result = null;
+		result = new LocalworkerActivityConfigurationAction(findActivity(), getParentFrame(),
+				editManager, fileManager, activityIconManager, serviceDescriptionRegistry,
+				applicationConfiguration);
+		result.putValue(Action.NAME, BeanshellActivityConfigurationAction.EDIT_BEANSHELL_SCRIPT);
+		addMenuDots(result);
+		return result;
+	}
+
+	public void setEditManager(EditManager editManager) {
+		this.editManager = editManager;
+	}
+
+	public void setFileManager(FileManager fileManager) {
+		this.fileManager = fileManager;
+	}
+
+	public void setActivityIconManager(ActivityIconManager activityIconManager) {
+		this.activityIconManager = activityIconManager;
+	}
+
+	public void setServiceDescriptionRegistry(ServiceDescriptionRegistry serviceDescriptionRegistry) {
+		this.serviceDescriptionRegistry = serviceDescriptionRegistry;
+	}
+
+	public void setApplicationConfiguration(ApplicationConfiguration applicationConfiguration) {
+		this.applicationConfiguration = applicationConfiguration;
+	}
+
+}
diff --git a/taverna-localworker-activity-ui/src/main/java/net/sf/taverna/t2/activities/localworker/servicedescriptions/LocalworkerActivityIcon.java b/taverna-localworker-activity-ui/src/main/java/net/sf/taverna/t2/activities/localworker/servicedescriptions/LocalworkerActivityIcon.java
new file mode 100644
index 0000000..7d6bb5a
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/java/net/sf/taverna/t2/activities/localworker/servicedescriptions/LocalworkerActivityIcon.java
@@ -0,0 +1,58 @@
+/*******************************************************************************
+ * Copyright (C) 2007 The University of Manchester
+ *
+ *  Modifications to the initial code base are copyright of their
+ *  respective authors, or their employers as appropriate.
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1 of
+ *  the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+package net.sf.taverna.t2.activities.localworker.servicedescriptions;
+
+import java.net.URI;
+
+import javax.swing.Icon;
+import javax.swing.ImageIcon;
+
+import net.sf.taverna.t2.workbench.activityicons.ActivityIconSPI;
+
+/**
+ *
+ * @author Alex Nenadic
+ * @author David Withers
+ */
+public class LocalworkerActivityIcon implements ActivityIconSPI {
+
+	private static Icon icon;
+
+	public int canProvideIconScore(URI activityType) {
+		if (LocalworkerServiceDescription.ACTIVITY_TYPE.equals(activityType))
+			return DEFAULT_ICON + 1;
+		else
+			return NO_ICON;
+	}
+
+	public Icon getIcon(URI activityType) {
+		return getLocalworkerIcon();
+	}
+
+	public static Icon getLocalworkerIcon() {
+		if (icon == null) {
+			icon = new ImageIcon(LocalworkerActivityIcon.class
+					.getResource("/localworker.png"));
+		}
+		return icon;
+	}
+}
+
diff --git a/taverna-localworker-activity-ui/src/main/java/net/sf/taverna/t2/activities/localworker/servicedescriptions/LocalworkerServiceDescription.java b/taverna-localworker-activity-ui/src/main/java/net/sf/taverna/t2/activities/localworker/servicedescriptions/LocalworkerServiceDescription.java
new file mode 100644
index 0000000..38718b8
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/java/net/sf/taverna/t2/activities/localworker/servicedescriptions/LocalworkerServiceDescription.java
@@ -0,0 +1,105 @@
+package net.sf.taverna.t2.activities.localworker.servicedescriptions;
+
+import java.net.URI;
+import java.util.Arrays;
+import java.util.List;
+
+import javax.swing.Icon;
+
+import net.sf.taverna.t2.servicedescriptions.ServiceDescription;
+import uk.org.taverna.scufl2.api.configurations.Configuration;
+
+import com.fasterxml.jackson.databind.JsonNode;
+
+public class LocalworkerServiceDescription extends ServiceDescription {
+
+	public static final URI ACTIVITY_TYPE = URI.create("http://ns.taverna.org.uk/2010/activity/localworker");
+
+	private static final String LOCALWORKER = ServiceDescription.LOCAL_SERVICES;
+
+	private JsonNode json;
+	private String operation;
+	private String category;
+	private String provider;
+	private String localworkerName;
+
+	public JsonNode getJson() {
+		return json;
+	}
+
+	public void setJson(JsonNode json) {
+		this.json = json;
+	}
+
+	public String getOperation() {
+		return operation;
+	}
+
+	public void setOperation(String operation) {
+		this.operation = operation;
+	}
+
+	public String getCategory() {
+		return category;
+	}
+
+	public void setCategory(String category) {
+		this.category = category;
+	}
+
+	public String getProvider() {
+		return provider;
+	}
+
+	public void setProvider(String provider) {
+		this.provider = provider;
+	}
+
+	public String getLocalworkerName() {
+		return localworkerName;
+	}
+
+	public void setLocalworkerName(String localworkerName) {
+		this.localworkerName = localworkerName;
+	}
+
+	public String getType() {
+		return "Localworker";
+	}
+
+	@Override
+	public URI getActivityType() {
+		return ACTIVITY_TYPE;
+	}
+
+	@Override
+	public Configuration getActivityConfiguration() {
+		Configuration configuration = new Configuration();
+		configuration.setType(ACTIVITY_TYPE.resolve("#Config"));
+		configuration.setJson(getJson());
+		return configuration;
+	}
+
+	@Override
+	public Icon getIcon() {
+		return LocalworkerActivityIcon.getLocalworkerIcon();
+	}
+
+	@Override
+	public String getName() {
+		return operation;
+	}
+
+	@Override
+	public List<? extends Comparable<?>> getPath() {
+		List<String> result =
+		Arrays.asList (LOCALWORKER, category);
+		return result;
+	}
+
+	@Override
+	protected List<Object> getIdentifyingData() {
+		return Arrays.<Object>asList(getJson());
+	}
+
+}
diff --git a/taverna-localworker-activity-ui/src/main/java/net/sf/taverna/t2/activities/localworker/servicedescriptions/LocalworkerServiceProvider.java b/taverna-localworker-activity-ui/src/main/java/net/sf/taverna/t2/activities/localworker/servicedescriptions/LocalworkerServiceProvider.java
new file mode 100644
index 0000000..42345db
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/java/net/sf/taverna/t2/activities/localworker/servicedescriptions/LocalworkerServiceProvider.java
@@ -0,0 +1,297 @@
+package net.sf.taverna.t2.activities.localworker.servicedescriptions;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.swing.Icon;
+
+import net.sf.taverna.t2.servicedescriptions.ServiceDescription;
+import net.sf.taverna.t2.servicedescriptions.ServiceDescriptionProvider;
+import net.sf.taverna.t2.workflowmodel.processor.activity.Activity;
+
+import org.apache.log4j.Logger;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+public class LocalworkerServiceProvider implements ServiceDescriptionProvider {
+
+	private static final String LOCALWORKER_NAMES = "/localworker_names";
+
+	private static final String LOCALWORKER_SERVICE = "Local service";
+
+	private static Logger logger = Logger.getLogger(Logger.class);
+
+	private static final URI providerId = URI
+			.create("http://taverna.sf.net/2010/service-provider/localworker");
+
+	/** Used to deserialize the Activities stored on disk */
+	private ObjectMapper objectMapper = new ObjectMapper();
+
+	private static Map<String, String> localWorkerToScript = new HashMap<String, String>();
+
+	static {
+		localWorkerToScript.put("org.embl.ebi.escience.scuflworkers.java.ByteArrayToString",
+				"Byte Array To String");
+		localWorkerToScript.put("org.embl.ebi.escience.scuflworkers.java.DecodeBase64",
+				"Decode Base 64 to byte Array");
+		localWorkerToScript.put("org.embl.ebi.escience.scuflworkers.java.EchoList", "Echo List");
+		localWorkerToScript.put("org.embl.ebi.escience.scuflworkers.java.EmitLotsOfStrings",
+				"Create Lots Of Strings");
+		localWorkerToScript.put("org.embl.ebi.escience.scuflworkers.java.EncodeBase64",
+				"Encode Byte Array to Base 64");
+		localWorkerToScript.put("org.embl.ebi.escience.scuflworkers.java.ExtractImageLinks",
+				"Get image URLs from HTTP document");
+		localWorkerToScript.put("org.embl.ebi.escience.scuflworkers.java.FilterStringList",
+				"Filter List of Strings by regex");
+		localWorkerToScript.put("org.embl.ebi.escience.scuflworkers.java.FlattenList",
+				"Flatten List");
+		localWorkerToScript.put("org.embl.ebi.escience.scuflworkers.java.PadNumber",
+				"Pad numeral with leading 0s");
+		localWorkerToScript.put(
+				"org.embl.ebi.escience.scuflworkers.java.RegularExpressionStringList",
+				"Filter list of strings extracting match to a regex");
+		localWorkerToScript.put("org.embl.ebi.escience.scuflworkers.java.SendEmail",
+				"Send an Email");
+		localWorkerToScript.put("org.embl.ebi.escience.scuflworkers.java.SliceList",
+				"Extract Elements from a List");
+		localWorkerToScript.put("org.embl.ebi.escience.scuflworkers.java.SplitByRegex",
+				"Split string into string list by regular expression");
+		localWorkerToScript.put("org.embl.ebi.escience.scuflworkers.java.StringConcat",
+				"Concatenate two strings");
+		localWorkerToScript.put("org.embl.ebi.escience.scuflworkers.java.StringListMerge",
+				"Merge String List to a String");
+		localWorkerToScript.put("org.embl.ebi.escience.scuflworkers.java.StringSetDifference",
+				"String List Difference");
+		localWorkerToScript.put("org.embl.ebi.escience.scuflworkers.java.StringSetIntersection",
+				"String List Intersection");
+		localWorkerToScript.put("org.embl.ebi.escience.scuflworkers.java.StringSetUnion",
+				"String List Union");
+		localWorkerToScript.put("org.embl.ebi.escience.scuflworkers.java.StringStripDuplicates",
+				"Remove String Duplicates");
+		localWorkerToScript.put(
+				"org.embl.ebi.escience.scuflworkers.java.TestAlwaysFailingProcessor",
+				"Always Fails");
+		localWorkerToScript.put("org.embl.ebi.escience.scuflworkers.java.TestSometimesFails",
+				"Sometimes Fails");
+		localWorkerToScript.put("org.embl.ebi.escience.scuflworkers.java.WebImageFetcher",
+				"Get Image From URL");
+		localWorkerToScript.put("org.embl.ebi.escience.scuflworkers.java.WebPageFetcher",
+				"Get Web Page from URL");
+
+		// xml:XPathText
+		localWorkerToScript.put("net.sourceforge.taverna.scuflworkers.xml.XPathTextWorker",
+				"XPath From Text");
+		localWorkerToScript.put("net.sourceforge.taverna.scuflworkers.xml.XSLTWorker",
+				"Transform XML");
+		localWorkerToScript.put(
+				"net.sourceforge.taverna.scuflworkers.xml.XSLTWorkerWithParameters",
+				"Transform XML with parameters");
+
+		// biojava
+		localWorkerToScript.put("net.sourceforge.taverna.scuflworkers.biojava.GenBankParserWorker",
+				"Read Gen Bank File");
+		localWorkerToScript.put("net.sourceforge.taverna.scuflworkers.biojava.ReverseCompWorker",
+				"Reverse Complement DNA");
+		localWorkerToScript.put(
+				"net.sourceforge.taverna.scuflworkers.biojava.SwissProtParserWorker",
+				"Read Swiss Prot File");
+		localWorkerToScript.put("net.sourceforge.taverna.scuflworkers.biojava.TranscribeWorker",
+				"Transcribe DNA");
+
+		// io
+		localWorkerToScript.put("net.sourceforge.taverna.scuflworkers.io.TextFileReader",
+				"Read Text File");
+		localWorkerToScript.put("net.sourceforge.taverna.scuflworkers.io.TextFileWriter",
+				"Write Text File");
+		localWorkerToScript.put("net.sourceforge.taverna.scuflworkers.io.LocalCommand",
+				"Execute Command Line App");
+		localWorkerToScript.put("net.sourceforge.taverna.scuflworkers.io.FileListByExtTask",
+				"List Files by Extension");
+		localWorkerToScript.put("net.sourceforge.taverna.scuflworkers.io.FileListByRegexTask",
+				"List Files By Regex");
+		localWorkerToScript.put("net.sourceforge.taverna.scuflworkers.io.DataRangeTask",
+				"Select Data Range From File");
+		localWorkerToScript.put(
+				"net.sourceforge.taverna.scuflworkers.io.ConcatenateFileListWorker",
+				"Concatenate Files");
+		localWorkerToScript.put("net.sourceforge.taverna.scuflworkers.io.EnvVariableWorker",
+				"Get Environment Variables as XML");
+
+		// ui
+		localWorkerToScript.put("net.sourceforge.taverna.scuflworkers.ui.AskWorker", "Ask");
+		localWorkerToScript.put("net.sourceforge.taverna.scuflworkers.ui.SelectWorker", "Select");
+		localWorkerToScript.put("net.sourceforge.taverna.scuflworkers.ui.ChooseWorker", "Choose");
+		localWorkerToScript.put("net.sourceforge.taverna.scuflworkers.ui.TellWorker", "Tell");
+		localWorkerToScript.put("net.sourceforge.taverna.scuflworkers.ui.WarnWorker", "Warn");
+		localWorkerToScript.put("net.sourceforge.taverna.scuflworkers.ui.SelectFileWorker",
+				"Select File");
+		// ncbi
+		localWorkerToScript.put("net.sourceforge.taverna.scuflworkers.ncbi.NucleotideFastaWorker",
+				"Get Nucleotide FASTA");
+		localWorkerToScript.put("net.sourceforge.taverna.scuflworkers.ncbi.NucleotideGBSeqWorker",
+				"Get Nucleotide GBSeq XML");
+		localWorkerToScript.put(
+				"net.sourceforge.taverna.scuflworkers.ncbi.NucleotideINSDSeqXMLWorker",
+				"Get Nucleotide INSDSeq XML");
+		localWorkerToScript.put(
+				"net.sourceforge.taverna.scuflworkers.ncbi.NucleotideTinySeqXMLWorker",
+				"Get Nucleotide TinySeq XML");
+
+		localWorkerToScript.put("net.sourceforge.taverna.scuflworkers.ncbi.ProteinFastaWorker",
+				"Get Protein FASTA");
+		localWorkerToScript.put(
+				"net.sourceforge.taverna.scuflworkers.ncbi.ProteinINSDSeqXMLWorker",
+				"Get Protein INSDSeq XML");
+		localWorkerToScript.put("net.sourceforge.taverna.scuflworkers.ncbi.ProteinGBSeqWorker",
+				"Get Protein GBSeq XML");
+		localWorkerToScript.put(
+				"net.sourceforge.taverna.scuflworkers.ncbi.ProteinTinySeqXMLWorker",
+				"Get Protein TinySeq XML");
+
+		localWorkerToScript.put("net.sourceforge.taverna.scuflworkers.ncbi.PubMedESearchWorker",
+				"Search PubMed XML");
+		localWorkerToScript.put("net.sourceforge.taverna.scuflworkers.ncbi.PubMedEFetchWorker",
+				"Get PubMed XML By PMID");
+
+		localWorkerToScript.put("net.sourceforge.taverna.scuflworkers.jdbc.SQLQueryWorker",
+				"Execute SQL Query");
+		localWorkerToScript.put("net.sourceforge.taverna.scuflworkers.jdbc.SQLUpdateWorker",
+				"Execute SQL Update");
+
+		localWorkerToScript.put("net.sourceforge.taverna.scuflworkers.net.BrowseUrl",
+				"Open web browser at a URL");
+		localWorkerToScript.put("net.sourceforge.taverna.scuflworkers.net.ExtractHeader",
+				"Extract HTTP Header");
+	}
+
+	public String getName() {
+		return LOCALWORKER_SERVICE;
+	}
+
+	/**
+	 * Use the {@link net.sf.taverna.t2.activities.localworker.translator.LocalworkerTranslator} to
+	 * get a {@link Map} of all the local workers. Use the keys in this map
+	 * to load all the serialized activities from disk by using
+	 * <code> getClass().getResourceAsStream("/" + className) </code> to get
+	 * them and then the {@link ActivityXMLDeserializer} to get the actual {@link Activity}. Create
+	 * the {@link LocalworkerActivityItem} by
+	 * populating them with the correct ports and depths. Sets the category to
+	 * match the T1 version so that a query by category will split the local
+	 * workers in to the correct place.
+	 */
+	public void findServiceDescriptionsAsync(FindServiceDescriptionsCallBack callBack) {
+
+		List<ServiceDescription> items = new ArrayList<ServiceDescription>();
+
+		InputStream inputStream = getClass().getResourceAsStream(LOCALWORKER_NAMES);
+		if (inputStream == null) {
+			logger.error("Could not find resource " + LOCALWORKER_NAMES);
+			return;
+		}
+		BufferedReader inputReader = new BufferedReader(new InputStreamReader(inputStream));
+		String line = "";
+		String category = null;
+		try {
+			while ((line = inputReader.readLine()) != null) {
+				if (line.startsWith("category")) {
+					String[] split = line.split(":");
+					category = split[1];
+				} else {
+					LocalworkerServiceDescription createItem;
+					try {
+						createItem = createItem(line);
+					} catch (ItemCreationException e) {
+						logger.warn("Could not create item for: " + line, e);
+						continue;
+					}
+					createItem.setCategory(category);
+					createItem.setProvider("myGrid");
+					items.add(createItem);
+				}
+			}
+		} catch (IOException e1) {
+			logger.warn("Could not read local worker definitions from " + LOCALWORKER_NAMES);
+		}
+		callBack.partialResults(items);
+		callBack.finished();
+
+	}
+
+	@SuppressWarnings("serial")
+	public class ItemCreationException extends Exception {
+
+		public ItemCreationException() {
+			super();
+		}
+
+		public ItemCreationException(String message, Throwable cause) {
+			super(message, cause);
+		}
+
+		public ItemCreationException(String message) {
+			super(message);
+		}
+
+		public ItemCreationException(Throwable cause) {
+			super(cause);
+		}
+
+	}
+
+	/**
+	 * Loads the deserialised local worker from disk and creates a {@link LocalworkerActivityItem}
+	 * with the correct ports and script from it
+	 *
+	 * @param line
+	 * @return a LocalWorker with the appropriate Input/Output ports and script
+	 * @throws ItemCreationException
+	 */
+	private LocalworkerServiceDescription createItem(String line) throws ItemCreationException {
+		// get the file from disk
+		String resource = "/" + line + ".json";
+		InputStream resourceAsStream = getClass().getResourceAsStream(resource);
+		if (resourceAsStream == null) {
+			throw new ItemCreationException("Could not find resource " + resource);
+		}
+
+		JsonNode json;
+		try {
+			json = objectMapper.readTree(resourceAsStream);
+		} catch (IOException e) {
+			throw new ItemCreationException("Could not read resource " + resource, e);
+		}
+
+		LocalworkerServiceDescription item = new LocalworkerServiceDescription();
+		item.setJson(json);
+		item.setLocalworkerName(line);
+		item.setOperation(localWorkerToScript.get(line));
+		return item;
+
+	}
+
+	public Icon getIcon() {
+		return LocalworkerActivityIcon.getLocalworkerIcon();
+	}
+
+	@Override
+	public String toString() {
+		return "Local workers provider";
+	}
+
+	public static String getServiceNameFromClassname(String classname) {
+		return (localWorkerToScript.get(classname));
+	}
+
+	public String getId() {
+		return providerId.toString();
+	}
+
+}
diff --git a/taverna-localworker-activity-ui/src/main/java/net/sf/taverna/t2/activities/localworker/views/LocalworkerActivityConfigView.java b/taverna-localworker-activity-ui/src/main/java/net/sf/taverna/t2/activities/localworker/views/LocalworkerActivityConfigView.java
new file mode 100644
index 0000000..155c631
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/java/net/sf/taverna/t2/activities/localworker/views/LocalworkerActivityConfigView.java
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * Copyright (C) 2007 The University of Manchester
+ *
+ *  Modifications to the initial code base are copyright of their
+ *  respective authors, or their employers as appropriate.
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1 of
+ *  the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+package net.sf.taverna.t2.activities.localworker.views;
+
+import net.sf.taverna.t2.activities.beanshell.views.BeanshellConfigurationPanel;
+import uk.org.taverna.configuration.app.ApplicationConfiguration;
+import uk.org.taverna.scufl2.api.activity.Activity;
+
+@SuppressWarnings("serial")
+public class LocalworkerActivityConfigView extends BeanshellConfigurationPanel {
+
+	public LocalworkerActivityConfigView(Activity activity, ApplicationConfiguration applicationConfiguration) {
+		super(activity, applicationConfiguration);
+	}
+
+	public boolean isConfigurationChanged() {
+		boolean configurationChanged = super.isConfigurationChanged();
+		if (configurationChanged) {
+			getJson().put("isAltered", true);
+		}
+		return configurationChanged;
+	}
+
+}
diff --git a/taverna-localworker-activity-ui/src/main/java/net/sf/taverna/t2/activities/localworker/views/LocalworkerActivityContextualView.java b/taverna-localworker-activity-ui/src/main/java/net/sf/taverna/t2/activities/localworker/views/LocalworkerActivityContextualView.java
new file mode 100644
index 0000000..fc09d57
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/java/net/sf/taverna/t2/activities/localworker/views/LocalworkerActivityContextualView.java
@@ -0,0 +1,115 @@
+/*******************************************************************************
+ * Copyright (C) 2007 The University of Manchester
+ *
+ *  Modifications to the initial code base are copyright of their
+ *  respective authors, or their employers as appropriate.
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1 of
+ *  the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+package net.sf.taverna.t2.activities.localworker.views;
+
+import java.awt.Frame;
+
+import javax.swing.Action;
+
+import net.sf.taverna.t2.activities.localworker.actions.LocalworkerActivityConfigurationAction;
+import net.sf.taverna.t2.activities.localworker.servicedescriptions.LocalworkerServiceProvider;
+import net.sf.taverna.t2.servicedescriptions.ServiceDescriptionRegistry;
+import net.sf.taverna.t2.workbench.activityicons.ActivityIconManager;
+import net.sf.taverna.t2.workbench.configuration.colour.ColourManager;
+import net.sf.taverna.t2.workbench.edits.EditManager;
+import net.sf.taverna.t2.workbench.file.FileManager;
+import net.sf.taverna.t2.workbench.ui.actions.activity.HTMLBasedActivityContextualView;
+import uk.org.taverna.configuration.app.ApplicationConfiguration;
+import uk.org.taverna.scufl2.api.activity.Activity;
+import uk.org.taverna.scufl2.api.configurations.Configuration;
+import uk.org.taverna.scufl2.api.port.InputActivityPort;
+import uk.org.taverna.scufl2.api.port.OutputActivityPort;
+
+import com.fasterxml.jackson.databind.JsonNode;
+
+@SuppressWarnings("serial")
+public class LocalworkerActivityContextualView extends HTMLBasedActivityContextualView {
+
+	private final EditManager editManager;
+	private final FileManager fileManager;
+	private final ActivityIconManager activityIconManager;
+	private final ServiceDescriptionRegistry serviceDescriptionRegistry;
+
+	private final ApplicationConfiguration applicationConfiguration;
+
+	public LocalworkerActivityContextualView(Activity activity, EditManager editManager,
+			FileManager fileManager, ColourManager colourManager,
+			ActivityIconManager activityIconManager,
+			ServiceDescriptionRegistry serviceDescriptionRegistry,
+			ApplicationConfiguration applicationConfiguration) {
+		super(activity, colourManager);
+		this.editManager = editManager;
+		this.fileManager = fileManager;
+		this.activityIconManager = activityIconManager;
+		this.serviceDescriptionRegistry = serviceDescriptionRegistry;
+		this.applicationConfiguration = applicationConfiguration;
+	}
+
+	@Override
+	protected String getRawTableRowsHtml() {
+		StringBuilder html = new StringBuilder();
+		html.append("<tr><th>Input Port Name</th><th>Depth</th></tr>");
+		for (InputActivityPort inputActivityPort : getActivity().getInputPorts()) {
+			html.append("<tr><td>" + inputActivityPort.getName() + "</td><td>");
+			html.append(inputActivityPort.getDepth() + "</td></tr>");
+		}
+		html.append("<tr><th>Output Port Name</th><th>Depth</th></tr>");
+		for (OutputActivityPort outputActivityPort : getActivity().getOutputPorts()) {
+			html.append("<tr><td>" + outputActivityPort.getName() + "</td><td>");
+			html.append(outputActivityPort.getDepth() + "</td></tr>");
+		}
+		return html.toString();
+	}
+
+	@Override
+	public String getViewTitle() {
+		String result = "";
+		Configuration configuration = getConfigBean();
+		JsonNode json = configuration.getJson();
+		String workerName = LocalworkerServiceProvider.getServiceNameFromClassname(json.get(
+				"localworkerName").textValue());
+		if (json.get("isAltered").booleanValue()) {
+			result = "Altered local worker service";
+			if ((workerName != null) && !workerName.equals("")) {
+				result += " - originally " + workerName;
+			}
+		} else {
+			result = "Local worker service";
+			if ((workerName != null) && !workerName.equals("")) {
+				result += " - " + workerName;
+			}
+		}
+		return result;
+	}
+
+	@Override
+	public Action getConfigureAction(Frame owner) {
+		return new LocalworkerActivityConfigurationAction(getActivity(), owner, editManager,
+				fileManager, activityIconManager, serviceDescriptionRegistry,
+				applicationConfiguration);
+	}
+
+	@Override
+	public int getPreferredPosition() {
+		return 100;
+	}
+
+}
diff --git a/taverna-localworker-activity-ui/src/main/java/net/sf/taverna/t2/activities/localworker/views/LocalworkerActivityViewFactory.java b/taverna-localworker-activity-ui/src/main/java/net/sf/taverna/t2/activities/localworker/views/LocalworkerActivityViewFactory.java
new file mode 100644
index 0000000..4fec0a2
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/java/net/sf/taverna/t2/activities/localworker/views/LocalworkerActivityViewFactory.java
@@ -0,0 +1,82 @@
+/*******************************************************************************
+ * Copyright (C) 2007 The University of Manchester
+ *
+ *  Modifications to the initial code base are copyright of their
+ *  respective authors, or their employers as appropriate.
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1 of
+ *  the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+package net.sf.taverna.t2.activities.localworker.views;
+
+import java.util.Arrays;
+import java.util.List;
+
+import net.sf.taverna.t2.activities.localworker.servicedescriptions.LocalworkerServiceDescription;
+import net.sf.taverna.t2.servicedescriptions.ServiceDescriptionRegistry;
+import net.sf.taverna.t2.workbench.activityicons.ActivityIconManager;
+import net.sf.taverna.t2.workbench.configuration.colour.ColourManager;
+import net.sf.taverna.t2.workbench.edits.EditManager;
+import net.sf.taverna.t2.workbench.file.FileManager;
+import net.sf.taverna.t2.workbench.ui.views.contextualviews.ContextualView;
+import net.sf.taverna.t2.workbench.ui.views.contextualviews.activity.ContextualViewFactory;
+import uk.org.taverna.configuration.app.ApplicationConfiguration;
+import uk.org.taverna.scufl2.api.activity.Activity;
+
+public class LocalworkerActivityViewFactory implements ContextualViewFactory<Activity> {
+
+	private EditManager editManager;
+	private FileManager fileManager;
+	private ActivityIconManager activityIconManager;
+	private ColourManager colourManager;
+	private ServiceDescriptionRegistry serviceDescriptionRegistry;
+	private ApplicationConfiguration applicationConfiguration;
+
+	public boolean canHandle(Object object) {
+		return object instanceof Activity
+				&& ((Activity) object).getType()
+						.equals(LocalworkerServiceDescription.ACTIVITY_TYPE);
+	}
+
+	public List<ContextualView> getViews(Activity activity) {
+		return Arrays.asList(new ContextualView[] { new LocalworkerActivityContextualView(activity,
+				editManager, fileManager, colourManager, activityIconManager,
+				serviceDescriptionRegistry, applicationConfiguration) });
+	}
+
+	public void setEditManager(EditManager editManager) {
+		this.editManager = editManager;
+	}
+
+	public void setFileManager(FileManager fileManager) {
+		this.fileManager = fileManager;
+	}
+
+	public void setActivityIconManager(ActivityIconManager activityIconManager) {
+		this.activityIconManager = activityIconManager;
+	}
+
+	public void setColourManager(ColourManager colourManager) {
+		this.colourManager = colourManager;
+	}
+
+	public void setServiceDescriptionRegistry(ServiceDescriptionRegistry serviceDescriptionRegistry) {
+		this.serviceDescriptionRegistry = serviceDescriptionRegistry;
+	}
+
+	public void setApplicationConfiguration(ApplicationConfiguration applicationConfiguration) {
+		this.applicationConfiguration = applicationConfiguration;
+	}
+
+}
diff --git a/taverna-localworker-activity-ui/src/main/resources/META-INF/services/net.sf.taverna.t2.servicedescriptions.ServiceDescriptionProvider b/taverna-localworker-activity-ui/src/main/resources/META-INF/services/net.sf.taverna.t2.servicedescriptions.ServiceDescriptionProvider
new file mode 100644
index 0000000..c3c01e0
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/resources/META-INF/services/net.sf.taverna.t2.servicedescriptions.ServiceDescriptionProvider
@@ -0,0 +1 @@
+net.sf.taverna.t2.activities.localworker.servicedescriptions.LocalworkerServiceProvider
diff --git a/taverna-localworker-activity-ui/src/main/resources/META-INF/services/net.sf.taverna.t2.ui.menu.MenuComponent b/taverna-localworker-activity-ui/src/main/resources/META-INF/services/net.sf.taverna.t2.ui.menu.MenuComponent
new file mode 100644
index 0000000..5911ddf
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/resources/META-INF/services/net.sf.taverna.t2.ui.menu.MenuComponent
@@ -0,0 +1 @@
+net.sf.taverna.t2.activities.localworker.menu.ConfigureLocalworkerMenuAction
diff --git a/taverna-localworker-activity-ui/src/main/resources/META-INF/services/net.sf.taverna.t2.workbench.activityicons.ActivityIconSPI b/taverna-localworker-activity-ui/src/main/resources/META-INF/services/net.sf.taverna.t2.workbench.activityicons.ActivityIconSPI
new file mode 100644
index 0000000..720a022
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/resources/META-INF/services/net.sf.taverna.t2.workbench.activityicons.ActivityIconSPI
@@ -0,0 +1 @@
+net.sf.taverna.t2.activities.localworker.servicedescriptions.LocalworkerActivityIcon
\ No newline at end of file
diff --git a/taverna-localworker-activity-ui/src/main/resources/META-INF/services/net.sf.taverna.t2.workbench.ui.views.contextualviews.activity.ContextualViewFactory b/taverna-localworker-activity-ui/src/main/resources/META-INF/services/net.sf.taverna.t2.workbench.ui.views.contextualviews.activity.ContextualViewFactory
new file mode 100644
index 0000000..f1d2c0d
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/resources/META-INF/services/net.sf.taverna.t2.workbench.ui.views.contextualviews.activity.ContextualViewFactory
@@ -0,0 +1 @@
+net.sf.taverna.t2.activities.localworker.views.LocalworkerActivityViewFactory
\ No newline at end of file
diff --git a/taverna-localworker-activity-ui/src/main/resources/META-INF/spring/localworker-activity-ui-context-osgi.xml b/taverna-localworker-activity-ui/src/main/resources/META-INF/spring/localworker-activity-ui-context-osgi.xml
new file mode 100644
index 0000000..dd4c7a8
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/resources/META-INF/spring/localworker-activity-ui-context-osgi.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans:beans xmlns="http://www.springframework.org/schema/osgi" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xmlns:beans="http://www.springframework.org/schema/beans"
+	xsi:schemaLocation="http://www.springframework.org/schema/beans
+                      http://www.springframework.org/schema/beans/spring-beans.xsd
+                      http://www.springframework.org/schema/osgi
+                      http://www.springframework.org/schema/osgi/spring-osgi.xsd">
+
+	<service ref="LocalworkerActivityIcon" interface="net.sf.taverna.t2.workbench.activityicons.ActivityIconSPI" />
+
+	<service ref="LocalworkerServiceProvider" interface="net.sf.taverna.t2.servicedescriptions.ServiceDescriptionProvider" />
+
+	<service ref="ConfigureLocalworkerMenuAction" auto-export="interfaces" />
+
+	<service ref="LocalworkerActivityViewFactory" interface="net.sf.taverna.t2.workbench.ui.views.contextualviews.activity.ContextualViewFactory" />
+
+	<reference id="editManager" interface="net.sf.taverna.t2.workbench.edits.EditManager" />
+	<reference id="fileManager" interface="net.sf.taverna.t2.workbench.file.FileManager" />
+	<reference id="activityIconManager" interface="net.sf.taverna.t2.workbench.activityicons.ActivityIconManager" />
+	<reference id="colourManager" interface="net.sf.taverna.t2.workbench.configuration.colour.ColourManager" />
+	<reference id="serviceDescriptionRegistry" interface="net.sf.taverna.t2.servicedescriptions.ServiceDescriptionRegistry" />
+	<reference id="applicationConfiguration" interface="uk.org.taverna.configuration.app.ApplicationConfiguration" />
+
+</beans:beans>
diff --git a/taverna-localworker-activity-ui/src/main/resources/META-INF/spring/localworker-activity-ui-context.xml b/taverna-localworker-activity-ui/src/main/resources/META-INF/spring/localworker-activity-ui-context.xml
new file mode 100644
index 0000000..edcd6be
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/resources/META-INF/spring/localworker-activity-ui-context.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://www.springframework.org/schema/beans
+                      http://www.springframework.org/schema/beans/spring-beans.xsd">
+
+	<bean id="LocalworkerActivityIcon" class="net.sf.taverna.t2.activities.localworker.servicedescriptions.LocalworkerActivityIcon" />
+
+	<bean id="LocalworkerServiceProvider" class="net.sf.taverna.t2.activities.localworker.servicedescriptions.LocalworkerServiceProvider" />
+
+	<bean id="ConfigureLocalworkerMenuAction" class="net.sf.taverna.t2.activities.localworker.menu.ConfigureLocalworkerMenuAction">
+			<property name="editManager" ref="editManager" />
+			<property name="fileManager" ref="fileManager" />
+			<property name="activityIconManager" ref="activityIconManager" />
+			<property name="serviceDescriptionRegistry" ref="serviceDescriptionRegistry" />
+			<property name="applicationConfiguration" ref="applicationConfiguration" />
+	</bean>
+
+	<bean id="LocalworkerActivityViewFactory" class="net.sf.taverna.t2.activities.localworker.views.LocalworkerActivityViewFactory">
+			<property name="editManager" ref="editManager" />
+			<property name="fileManager" ref="fileManager" />
+			<property name="activityIconManager" ref="activityIconManager" />
+			<property name="colourManager" ref="colourManager" />
+			<property name="serviceDescriptionRegistry" ref="serviceDescriptionRegistry" />
+			<property name="applicationConfiguration" ref="applicationConfiguration" />
+	</bean>
+
+</beans>
diff --git a/taverna-localworker-activity-ui/src/main/resources/localworker.png b/taverna-localworker-activity-ui/src/main/resources/localworker.png
new file mode 100644
index 0000000..758a457
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/resources/localworker.png
Binary files differ
diff --git a/taverna-localworker-activity-ui/src/main/resources/localworker_names b/taverna-localworker-activity-ui/src/main/resources/localworker_names
new file mode 100644
index 0000000..3df452c
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/resources/localworker_names
@@ -0,0 +1,67 @@
+category:biojava
+net.sourceforge.taverna.scuflworkers.biojava.GenBankParserWorker
+net.sourceforge.taverna.scuflworkers.biojava.ReverseCompWorker
+net.sourceforge.taverna.scuflworkers.biojava.SwissProtParserWorker
+net.sourceforge.taverna.scuflworkers.biojava.TranscribeWorker
+category:io
+net.sourceforge.taverna.scuflworkers.io.ConcatenateFileListWorker
+net.sourceforge.taverna.scuflworkers.io.FileListByExtTask
+net.sourceforge.taverna.scuflworkers.io.FileListByRegexTask
+net.sourceforge.taverna.scuflworkers.io.EnvVariableWorker
+net.sourceforge.taverna.scuflworkers.io.LocalCommand
+net.sourceforge.taverna.scuflworkers.io.TextFileReader
+net.sourceforge.taverna.scuflworkers.io.TextFileWriter
+category:ui
+net.sourceforge.taverna.scuflworkers.ui.AskWorker
+net.sourceforge.taverna.scuflworkers.ui.ChooseWorker
+net.sourceforge.taverna.scuflworkers.ui.SelectFileWorker
+net.sourceforge.taverna.scuflworkers.ui.SelectWorker
+net.sourceforge.taverna.scuflworkers.ui.TellWorker
+net.sourceforge.taverna.scuflworkers.ui.WarnWorker
+category:xml
+net.sourceforge.taverna.scuflworkers.xml.XPathTextWorker
+net.sourceforge.taverna.scuflworkers.xml.XSLTWorker
+net.sourceforge.taverna.scuflworkers.xml.XSLTWorkerWithParameters
+category:list
+org.embl.ebi.escience.scuflworkers.java.EchoList
+org.embl.ebi.escience.scuflworkers.java.FlattenList
+org.embl.ebi.escience.scuflworkers.java.StringStripDuplicates
+org.embl.ebi.escience.scuflworkers.java.StringListMerge
+category:test
+org.embl.ebi.escience.scuflworkers.java.TestAlwaysFailingProcessor
+org.embl.ebi.escience.scuflworkers.java.EmitLotsOfStrings
+org.embl.ebi.escience.scuflworkers.java.TestSometimesFails
+category:text
+org.embl.ebi.escience.scuflworkers.java.ByteArrayToString
+org.embl.ebi.escience.scuflworkers.java.StringSetDifference
+org.embl.ebi.escience.scuflworkers.java.StringSetIntersection
+org.embl.ebi.escience.scuflworkers.java.StringSetUnion
+org.embl.ebi.escience.scuflworkers.java.PadNumber
+org.embl.ebi.escience.scuflworkers.java.RegularExpressionStringList
+org.embl.ebi.escience.scuflworkers.java.SplitByRegex
+org.embl.ebi.escience.scuflworkers.java.StringConcat
+org.embl.ebi.escience.scuflworkers.java.FilterStringList
+category:net
+org.embl.ebi.escience.scuflworkers.java.WebImageFetcher
+org.embl.ebi.escience.scuflworkers.java.WebPageFetcher
+org.embl.ebi.escience.scuflworkers.java.ExtractImageLinks
+org.embl.ebi.escience.scuflworkers.java.SendEmail
+net.sourceforge.taverna.scuflworkers.net.BrowseUrl
+net.sourceforge.taverna.scuflworkers.net.ExtractHeader
+category:base64
+org.embl.ebi.escience.scuflworkers.java.EncodeBase64
+org.embl.ebi.escience.scuflworkers.java.DecodeBase64
+category:ncbi
+net.sourceforge.taverna.scuflworkers.ncbi.NucleotideFastaWorker
+net.sourceforge.taverna.scuflworkers.ncbi.NucleotideGBSeqWorker
+net.sourceforge.taverna.scuflworkers.ncbi.NucleotideINSDSeqXMLWorker
+net.sourceforge.taverna.scuflworkers.ncbi.NucleotideTinySeqXMLWorker
+net.sourceforge.taverna.scuflworkers.ncbi.ProteinFastaWorker
+net.sourceforge.taverna.scuflworkers.ncbi.ProteinINSDSeqXMLWorker
+net.sourceforge.taverna.scuflworkers.ncbi.ProteinGBSeqWorker
+net.sourceforge.taverna.scuflworkers.ncbi.ProteinTinySeqXMLWorker
+net.sourceforge.taverna.scuflworkers.ncbi.PubMedESearchWorker
+net.sourceforge.taverna.scuflworkers.ncbi.PubMedEFetchWorker
+category:jdbc
+net.sourceforge.taverna.scuflworkers.jdbc.SQLQueryWorker
+net.sourceforge.taverna.scuflworkers.jdbc.SQLUpdateWorker
diff --git a/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.biojava.GenBankParserWorker b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.biojava.GenBankParserWorker
new file mode 100644
index 0000000..d6c62b2
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.biojava.GenBankParserWorker
@@ -0,0 +1,74 @@
+<activity xmlns="http://taverna.sf.net/2008/xml/t2flow">

+

+

+<class>net.sf.taverna.t2.activities.localworker.LocalworkerActivity</class><inputMap /><outputMap /><configBean encoding="xstream"><net.sf.taverna.t2.activities.localworker.LocalworkerActivityConfigurationBean xmlns="">

+  <script>import org.biojava.bio.seq.Sequence;

+import org.biojava.bio.seq.SequenceIterator;

+import org.biojava.bio.seq.io.SeqIOTools;

+import org.biojava.bio.seq.io.agave.AgaveWriter;

+

+BufferedReader getReader (String fileUrl) throws IOException {

+		InputStreamReader reader;

+		try {

+			reader = new FileReader(fileUrl);

+		}

+		catch (FileNotFoundException e) {

+			// try a real URL instead

+			URL url = new URL(fileUrl);

+			reader = new InputStreamReader (url.openStream());

+		}

+		return new BufferedReader(reader);

+	}

+

+if ((fileUrl == void) || (fileUrl == null)) {

+    throw new RuntimeException("The fileUrl must be specified");

+}

+

+BufferedReader br  = getReader(fileUrl);

+

+// read the GenBank File

+SequenceIterator sequences = SeqIOTools.readGenbank(br);

+

+// iterate through the sequences

+ByteArrayOutputStream os = new ByteArrayOutputStream();

+StringBuffer sb = new StringBuffer();

+AgaveWriter writer = new AgaveWriter();

+PrintStream ps = new PrintStream(os);

+

+while (sequences.hasNext()) {

+	Sequence seq = sequences.nextSequence();

+	writer.writeSequence(seq, ps);

+	sb.append(os.toString());

+}

+

+genbankdata = sb.toString();

+br.close();

+ps.close();

+  

+</script>

+  <dependencies class="java.util.Collections$SingletonList">

+    <element class="string">uk.org.mygrid.resources:biojava:1.4pre1</element>

+  </dependencies>

+  <inputs>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+      <handledReferenceSchemes />

+      <translatedElementType>java.lang.String</translatedElementType>

+      <allowsLiteralValues>true</allowsLiteralValues>

+      <name>fileUrl</name>

+      <depth>0</depth>

+      <mimeTypes>

+        <string>'text/plain'</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+  </inputs>

+  <outputs>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>

+      <granularDepth>0</granularDepth>

+      <name>genbankdata</name>

+      <depth>0</depth>

+      <mimeTypes>

+        <string>'text/xml'</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>

+  </outputs>

+</net.sf.taverna.t2.activities.localworker.LocalworkerActivityConfigurationBean></configBean></activity>
\ No newline at end of file
diff --git a/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.biojava.GenBankParserWorker.json b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.biojava.GenBankParserWorker.json
new file mode 100644
index 0000000..452850f
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.biojava.GenBankParserWorker.json
@@ -0,0 +1,16 @@
+{
+  "classLoaderSharing" : "workflow",
+  "script" : "import org.biojava.bio.seq.Sequence;\nimport org.biojava.bio.seq.SequenceIterator;\nimport org.biojava.bio.seq.io.SeqIOTools;\nimport org.biojava.bio.seq.io.agave.AgaveWriter;\n\nBufferedReader getReader (String fileUrl) throws IOException {\n\t\tInputStreamReader reader;\n\t\ttry {\n\t\t\treader = new FileReader(fileUrl);\n\t\t}\n\t\tcatch (FileNotFoundException e) {\n\t\t\t// try a real URL instead\n\t\t\tURL url = new URL(fileUrl);\n\t\t\treader = new InputStreamReader (url.openStream());\n\t\t}\n\t\treturn new BufferedReader(reader);\n\t}\n\nif ((fileUrl == void) || (fileUrl == null)) {\n    throw new RuntimeException(\"The fileUrl must be specified\");\n}\n\nBufferedReader br  = getReader(fileUrl);\n\n// read the GenBank File\nSequenceIterator sequences = SeqIOTools.readGenbank(br);\n\n// iterate through the sequences\nByteArrayOutputStream os = new ByteArrayOutputStream();\nStringBuffer sb = new StringBuffer();\nAgaveWriter writer = new AgaveWriter();\nPrintStream ps = new PrintStream(os);\n\nwhile (sequences.hasNext()) {\n\tSequence seq = sequences.nextSequence();\n\twriter.writeSequence(seq, ps);\n\tsb.append(os.toString());\n}\n\ngenbankdata = sb.toString();\nbr.close();\nps.close();\n  \n",
+  "localworkerName" : "net.sourceforge.taverna.scuflworkers.biojava.GenBankParserWorker",
+  "inputPorts" : [ {
+    "name" : "fileUrl",
+    "depth" : 0,
+    "type" : "String"
+  } ],
+  "outputPorts" : [ {
+    "name" : "genbankdata",
+    "depth" : 0,
+    "granularDepth" : 0
+  } ],
+  "isAltered" : false
+}
\ No newline at end of file
diff --git a/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.biojava.ReverseCompWorker b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.biojava.ReverseCompWorker
new file mode 100644
index 0000000..0044c82
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.biojava.ReverseCompWorker
@@ -0,0 +1,43 @@
+<activity xmlns="http://taverna.sf.net/2008/xml/t2flow"><class>net.sf.taverna.t2.activities.localworker.LocalworkerActivity</class><inputMap /><outputMap /><configBean encoding="xstream"><net.sf.taverna.t2.activities.localworker.LocalworkerActivityConfigurationBean xmlns="">

+  <script>import org.biojava.bio.seq.DNATools;

+import org.biojava.bio.symbol.SymbolList;

+

+if ((rawSeq == void) || (rawSeq == null)) {

+    throw new RuntimeException("The rawSeq must be specified");

+}

+

+// make a DNA SymbolListbena

+SymbolList symL = DNATools.createDNA(rawSeq);

+

+// reverse complement it

+symL = DNATools.reverseComplement(symL);

+

+// prove that it worked

+revSeq = symL.seqString();

+</script>

+  <dependencies class="java.util.Collections$SingletonList">

+    <element class="string">uk.org.mygrid.resources:biojava:1.4pre1</element>

+  </dependencies>

+  <inputs>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+      <handledReferenceSchemes />

+      <translatedElementType>java.lang.String</translatedElementType>

+      <allowsLiteralValues>true</allowsLiteralValues>

+      <name>rawSeq</name>

+      <depth>0</depth>

+      <mimeTypes>

+        <string>'text/plain'</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+  </inputs>

+  <outputs>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>

+      <granularDepth>0</granularDepth>

+      <name>revSeq</name>

+      <depth>0</depth>

+      <mimeTypes>

+        <string>'text/plain'</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>

+  </outputs>

+</net.sf.taverna.t2.activities.localworker.LocalworkerActivityConfigurationBean></configBean></activity>
\ No newline at end of file
diff --git a/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.biojava.ReverseCompWorker.json b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.biojava.ReverseCompWorker.json
new file mode 100644
index 0000000..c214819
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.biojava.ReverseCompWorker.json
@@ -0,0 +1,16 @@
+{
+  "classLoaderSharing" : "workflow",
+  "script" : "import org.biojava.bio.seq.DNATools;\nimport org.biojava.bio.symbol.SymbolList;\n\nif ((rawSeq == void) || (rawSeq == null)) {\n    throw new RuntimeException(\"The rawSeq must be specified\");\n}\n\n// make a DNA SymbolListbena\nSymbolList symL = DNATools.createDNA(rawSeq);\n\n// reverse complement it\nsymL = DNATools.reverseComplement(symL);\n\n// prove that it worked\nrevSeq = symL.seqString();\n",
+  "localworkerName" : "net.sourceforge.taverna.scuflworkers.biojava.ReverseCompWorker",
+  "inputPorts" : [ {
+    "name" : "rawSeq",
+    "depth" : 0,
+    "type" : "String"
+  } ],
+  "outputPorts" : [ {
+    "name" : "revSeq",
+    "depth" : 0,
+    "granularDepth" : 0
+  } ],
+  "isAltered" : false
+}
\ No newline at end of file
diff --git a/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.biojava.SwissProtParserWorker b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.biojava.SwissProtParserWorker
new file mode 100644
index 0000000..7f64778
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.biojava.SwissProtParserWorker
@@ -0,0 +1,72 @@
+<activity xmlns="http://taverna.sf.net/2008/xml/t2flow"><class>net.sf.taverna.t2.activities.localworker.LocalworkerActivity</class><inputMap /><outputMap /><configBean encoding="xstream"><net.sf.taverna.t2.activities.localworker.LocalworkerActivityConfigurationBean xmlns="">

+  <script>import org.biojava.bio.seq.Sequence;

+import org.biojava.bio.seq.SequenceIterator;

+import org.biojava.bio.seq.io.SeqIOTools;

+import org.biojava.bio.seq.io.agave.AgaveWriter;

+

+BufferedReader getReader (String fileUrl) throws IOException {

+		InputStreamReader reader;

+		try {

+			reader = new FileReader(fileUrl);

+		}

+		catch (FileNotFoundException e) {

+			// try a real URL instead

+			URL url = new URL(fileUrl);

+			reader = new InputStreamReader (url.openStream());

+		}

+		return new BufferedReader(reader);

+	}

+	

+if ((fileUrl == void) || (fileUrl == null)) {

+    throw new RuntimeException("The fileUrl must be specified");

+}

+	

+BufferedReader br = getReader(fileUrl);

+

+// read the EMBL File

+SequenceIterator sequences = SeqIOTools.readSwissprot(br);

+

+// Prepare the writer

+AgaveWriter writer = new AgaveWriter();

+ByteArrayOutputStream os = new ByteArrayOutputStream();

+StringBuffer sb = new StringBuffer();

+PrintStream ps = new PrintStream(os);

+

+// iterate through the sequences

+while (sequences.hasNext()) {

+	Sequence seq = sequences.nextSequence();

+	writer.writeSequence(seq, ps);

+	sb.append(os.toString());

+}

+results = sb.toString();

+

+br.close();

+ps.close();

+  

+</script>

+  <dependencies class="java.util.Collections$SingletonList">

+    <element class="string">uk.org.mygrid.resources:biojava:1.4pre1</element>

+  </dependencies>

+  <inputs>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+      <handledReferenceSchemes />

+      <translatedElementType>java.lang.String</translatedElementType>

+      <allowsLiteralValues>true</allowsLiteralValues>

+      <name>fileUrl</name>

+      <depth>0</depth>

+      <mimeTypes>

+        <string>'text/plain</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+  </inputs>

+  <outputs>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>

+      <granularDepth>0</granularDepth>

+      <name>results</name>

+      <depth>0</depth>

+      <mimeTypes>

+        <string>'text/plain'</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>

+  </outputs>

+</net.sf.taverna.t2.activities.localworker.LocalworkerActivityConfigurationBean></configBean></activity>
\ No newline at end of file
diff --git a/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.biojava.SwissProtParserWorker.json b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.biojava.SwissProtParserWorker.json
new file mode 100644
index 0000000..929c316
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.biojava.SwissProtParserWorker.json
@@ -0,0 +1,16 @@
+{
+  "classLoaderSharing" : "workflow",
+  "script" : "import org.biojava.bio.seq.Sequence;\nimport org.biojava.bio.seq.SequenceIterator;\nimport org.biojava.bio.seq.io.SeqIOTools;\nimport org.biojava.bio.seq.io.agave.AgaveWriter;\n\nBufferedReader getReader (String fileUrl) throws IOException {\n\t\tInputStreamReader reader;\n\t\ttry {\n\t\t\treader = new FileReader(fileUrl);\n\t\t}\n\t\tcatch (FileNotFoundException e) {\n\t\t\t// try a real URL instead\n\t\t\tURL url = new URL(fileUrl);\n\t\t\treader = new InputStreamReader (url.openStream());\n\t\t}\n\t\treturn new BufferedReader(reader);\n\t}\n\t\nif ((fileUrl == void) || (fileUrl == null)) {\n    throw new RuntimeException(\"The fileUrl must be specified\");\n}\n\t\nBufferedReader br = getReader(fileUrl);\n\n// read the EMBL File\nSequenceIterator sequences = SeqIOTools.readSwissprot(br);\n\n// Prepare the writer\nAgaveWriter writer = new AgaveWriter();\nByteArrayOutputStream os = new ByteArrayOutputStream();\nStringBuffer sb = new StringBuffer();\nPrintStream ps = new PrintStream(os);\n\n// iterate through the sequences\nwhile (sequences.hasNext()) {\n\tSequence seq = sequences.nextSequence();\n\twriter.writeSequence(seq, ps);\n\tsb.append(os.toString());\n}\nresults = sb.toString();\n\nbr.close();\nps.close();\n  \n",
+  "localworkerName" : "net.sourceforge.taverna.scuflworkers.biojava.SwissProtParserWorker",
+  "inputPorts" : [ {
+    "name" : "fileUrl",
+    "depth" : 0,
+    "type" : "String"
+  } ],
+  "outputPorts" : [ {
+    "name" : "results",
+    "depth" : 0,
+    "granularDepth" : 0
+  } ],
+  "isAltered" : false
+}
\ No newline at end of file
diff --git a/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.biojava.TranscribeWorker b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.biojava.TranscribeWorker
new file mode 100644
index 0000000..e46e219
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.biojava.TranscribeWorker
@@ -0,0 +1,48 @@
+<activity xmlns="http://taverna.sf.net/2008/xml/t2flow"><class>net.sf.taverna.t2.activities.localworker.LocalworkerActivity</class><inputMap /><outputMap /><configBean encoding="xstream"><net.sf.taverna.t2.activities.localworker.LocalworkerActivityConfigurationBean xmlns="">

+  <script>import org.biojava.bio.seq.DNATools;

+import org.biojava.bio.seq.RNATools;

+import org.biojava.bio.symbol.SymbolList;

+

+if ((dna_seq == void) || (dna_seq == null)) {

+	throw new RuntimeException("The dna_seq must be specified");

+}

+

+// make a DNA SymbolList

+SymbolList symL = DNATools.createDNA(dna_seq);

+

+// transcribe it to RNA (after BioJava 1.4 this method is

+// deprecated)

+symL = RNATools.transcribe(symL);

+

+// (after BioJava 1.4 use this method instead)

+// symL = DNATools.toRNA(symL);

+

+// just to prove it worked

+rna_seq = symL.seqString();

+</script>

+  <dependencies class="java.util.Collections$SingletonList">

+    <element class="string">uk.org.mygrid.resources:biojava:1.4pre1</element>

+  </dependencies>

+  <inputs>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+      <handledReferenceSchemes />

+      <translatedElementType>java.lang.String</translatedElementType>

+      <allowsLiteralValues>true</allowsLiteralValues>

+      <name>dna_seq</name>

+      <depth>0</depth>

+      <mimeTypes>

+        <string>'text/plain'</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+  </inputs>

+  <outputs>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>

+      <granularDepth>0</granularDepth>

+      <name>rna_seq</name>

+      <depth>0</depth>

+      <mimeTypes>

+        <string>'text/plain'</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>

+  </outputs>

+</net.sf.taverna.t2.activities.localworker.LocalworkerActivityConfigurationBean></configBean></activity>
\ No newline at end of file
diff --git a/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.biojava.TranscribeWorker.json b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.biojava.TranscribeWorker.json
new file mode 100644
index 0000000..767852c
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.biojava.TranscribeWorker.json
@@ -0,0 +1,16 @@
+{
+  "classLoaderSharing" : "workflow",
+  "script" : "import org.biojava.bio.seq.DNATools;\nimport org.biojava.bio.seq.RNATools;\nimport org.biojava.bio.symbol.SymbolList;\n\nif ((dna_seq == void) || (dna_seq == null)) {\n\tthrow new RuntimeException(\"The dna_seq must be specified\");\n}\n\n// make a DNA SymbolList\nSymbolList symL = DNATools.createDNA(dna_seq);\n\n// transcribe it to RNA (after BioJava 1.4 this method is\n// deprecated)\nsymL = RNATools.transcribe(symL);\n\n// (after BioJava 1.4 use this method instead)\n// symL = DNATools.toRNA(symL);\n\n// just to prove it worked\nrna_seq = symL.seqString();\n",
+  "localworkerName" : "net.sourceforge.taverna.scuflworkers.biojava.TranscribeWorker",
+  "inputPorts" : [ {
+    "name" : "dna_seq",
+    "depth" : 0,
+    "type" : "String"
+  } ],
+  "outputPorts" : [ {
+    "name" : "rna_seq",
+    "depth" : 0,
+    "granularDepth" : 0
+  } ],
+  "isAltered" : false
+}
\ No newline at end of file
diff --git a/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.io.ConcatenateFileListWorker b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.io.ConcatenateFileListWorker
new file mode 100644
index 0000000..9ed72e4
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.io.ConcatenateFileListWorker
@@ -0,0 +1,101 @@
+<activity xmlns="http://taverna.sf.net/2008/xml/t2flow"><class>net.sf.taverna.t2.activities.localworker.LocalworkerActivity</class><inputMap /><outputMap /><configBean encoding="xstream"><net.sf.taverna.t2.activities.localworker.LocalworkerActivityConfigurationBean xmlns="">

+  <script>BufferedReader getReader (String fileUrl) throws IOException {

+		InputStreamReader reader;

+		try {

+			reader = new FileReader(fileUrl);

+		}

+		catch (FileNotFoundException e) {

+			// try a real URL instead

+			URL url = new URL(fileUrl);

+			reader = new InputStreamReader (url.openStream());

+		}

+		return new BufferedReader(reader);

+	}

+

+String NEWLINE = System.getProperty("line.separator");

+

+boolean displayResults = false;

+if (displayresults != void) {

+	displayResults = Boolean.valueOf(displayresults).booleanValue();

+}

+

+StringBuffer sb = new StringBuffer(2000);

+

+if (outputfile == void) {

+	throw new RuntimeException("The 'outputfile' parameter cannot be null");

+}

+

+if (filelist == null) {

+	throw new RuntimeException("The 'filelist' parameter cannot be null");

+}

+

+String str = null;

+

+Writer writer = new FileWriter(outputfile);

+for (int i = 0; i &lt; filelist.size(); i++) {

+	BufferedReader reader = getReader(filelist.get(i));

+	while ((str = reader.readLine()) != null) {

+		writer.write(str);

+		writer.write(NEWLINE);

+

+		if (displayResults) {

+			sb.append(str);

+			sb.append(NEWLINE);

+		}

+	}

+

+	reader.close();

+

+}

+writer.flush();

+writer.close();

+

+if (displayResults) {

+	results= sb.toString();

+}

+

+</script>

+  <dependencies />

+  <inputs>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+      <handledReferenceSchemes />

+      <translatedElementType>java.lang.String</translatedElementType>

+      <allowsLiteralValues>true</allowsLiteralValues>

+      <name>filelist</name>

+      <depth>1</depth>

+      <mimeTypes>

+        <string>l('text/plain')</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+      <handledReferenceSchemes />

+      <translatedElementType>java.lang.String</translatedElementType>

+      <allowsLiteralValues>true</allowsLiteralValues>

+      <name>outputfile</name>

+      <depth>0</depth>

+      <mimeTypes>

+        <string>'text/plain'</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+      <handledReferenceSchemes />

+      <translatedElementType>java.lang.String</translatedElementType>

+      <allowsLiteralValues>true</allowsLiteralValues>

+      <name>displayresults</name>

+      <depth>0</depth>

+      <mimeTypes>

+        <string>'text/plain'</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+  </inputs>

+  <outputs>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>

+      <granularDepth>0</granularDepth>

+      <name>results</name>

+      <depth>0</depth>

+      <mimeTypes>

+        <string>'text/plain'</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>

+  </outputs>

+</net.sf.taverna.t2.activities.localworker.LocalworkerActivityConfigurationBean></configBean></activity>
\ No newline at end of file
diff --git a/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.io.ConcatenateFileListWorker.json b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.io.ConcatenateFileListWorker.json
new file mode 100644
index 0000000..d91d466
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.io.ConcatenateFileListWorker.json
@@ -0,0 +1,24 @@
+{
+  "classLoaderSharing" : "workflow",
+  "script" : "BufferedReader getReader (String fileUrl) throws IOException {\n\t\tInputStreamReader reader;\n\t\ttry {\n\t\t\treader = new FileReader(fileUrl);\n\t\t}\n\t\tcatch (FileNotFoundException e) {\n\t\t\t// try a real URL instead\n\t\t\tURL url = new URL(fileUrl);\n\t\t\treader = new InputStreamReader (url.openStream());\n\t\t}\n\t\treturn new BufferedReader(reader);\n\t}\n\nString NEWLINE = System.getProperty(\"line.separator\");\n\nboolean displayResults = false;\nif (displayresults != void) {\n\tdisplayResults = Boolean.valueOf(displayresults).booleanValue();\n}\n\nStringBuffer sb = new StringBuffer(2000);\n\nif (outputfile == void) {\n\tthrow new RuntimeException(\"The 'outputfile' parameter cannot be null\");\n}\n\nif (filelist == null) {\n\tthrow new RuntimeException(\"The 'filelist' parameter cannot be null\");\n}\n\nString str = null;\n\nWriter writer = new FileWriter(outputfile);\nfor (int i = 0; i < filelist.size(); i++) {\n\tBufferedReader reader = getReader(filelist.get(i));\n\twhile ((str = reader.readLine()) != null) {\n\t\twriter.write(str);\n\t\twriter.write(NEWLINE);\n\n\t\tif (displayResults) {\n\t\t\tsb.append(str);\n\t\t\tsb.append(NEWLINE);\n\t\t}\n\t}\n\n\treader.close();\n\n}\nwriter.flush();\nwriter.close();\n\nif (displayResults) {\n\tresults= sb.toString();\n}\n\n",
+  "localworkerName" : "net.sourceforge.taverna.scuflworkers.io.ConcatenateFileListWorker",
+  "inputPorts" : [ {
+    "name" : "filelist",
+    "depth" : 1,
+    "type" : "String"
+  }, {
+    "name" : "outputfile",
+    "depth" : 0,
+    "type" : "String"
+  }, {
+    "name" : "displayresults",
+    "depth" : 0,
+    "type" : "String"
+  } ],
+  "outputPorts" : [ {
+    "name" : "results",
+    "depth" : 0,
+    "granularDepth" : 0
+  } ],
+  "isAltered" : false
+}
\ No newline at end of file
diff --git a/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.io.EnvVariableWorker b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.io.EnvVariableWorker
new file mode 100644
index 0000000..410ceb0
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.io.EnvVariableWorker
@@ -0,0 +1,33 @@
+<activity  xmlns="http://taverna.sf.net/2008/xml/t2flow"><class>net.sf.taverna.t2.activities.localworker.LocalworkerActivity</class><inputMap /><outputMap><map from="properties" to="properties" /></outputMap><configBean encoding="xstream"><net.sf.taverna.t2.activities.localworker.LocalworkerActivityConfigurationBean xmlns="">
+  <script>import java.net.URLEncoder;
+
+Properties sysProps = System.getProperties();
+Set keys = sysProps.keySet();
+Iterator it = keys.iterator();
+String currKey = null;
+StringBuffer sb = new StringBuffer();
+sb.append("&lt;?xml version=\"1.0\"?&gt;\n");
+sb.append("&lt;property-list&gt;\n");
+while (it.hasNext()) {
+	currKey = (String) it.next();
+	sb.append("&lt;property ");
+	sb.append(" name=\"" + URLEncoder.encode(currKey) + "\"");
+	sb.append(" value=\"" + URLEncoder.encode(sysProps.getProperty(currKey)) + "\"/&gt;\n");
+}
+sb.append("&lt;/property-list&gt;");
+
+properties = sb.toString();
+</script>
+  <dependencies />
+  <inputs />
+  <outputs>
+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>
+      <granularDepth>0</granularDepth>
+      <name>properties</name>
+      <depth>0</depth>
+      <mimeTypes>
+        <string>'text/xml'</string>
+      </mimeTypes>
+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>
+  </outputs>
+</net.sf.taverna.t2.activities.localworker.LocalworkerActivityConfigurationBean></configBean></activity>
\ No newline at end of file
diff --git a/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.io.EnvVariableWorker.json b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.io.EnvVariableWorker.json
new file mode 100644
index 0000000..5dc2349
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.io.EnvVariableWorker.json
@@ -0,0 +1,11 @@
+{
+  "classLoaderSharing" : "workflow",
+  "script" : "import java.net.URLEncoder;\n\nProperties sysProps = System.getProperties();\nSet keys = sysProps.keySet();\nIterator it = keys.iterator();\nString currKey = null;\nStringBuffer sb = new StringBuffer();\nsb.append(\"<?xml version=\\\"1.0\\\"?>\\n\");\nsb.append(\"<property-list>\\n\");\nwhile (it.hasNext()) {\n\tcurrKey = (String) it.next();\n\tsb.append(\"<property \");\n\tsb.append(\" name=\\\"\" + URLEncoder.encode(currKey) + \"\\\"\");\n\tsb.append(\" value=\\\"\" + URLEncoder.encode(sysProps.getProperty(currKey)) + \"\\\"/>\\n\");\n}\nsb.append(\"</property-list>\");\n\nproperties = sb.toString();\n",
+  "localworkerName" : "net.sourceforge.taverna.scuflworkers.io.EnvVariableWorker",
+  "outputPorts" : [ {
+    "name" : "properties",
+    "depth" : 0,
+    "granularDepth" : 0
+  } ],
+  "isAltered" : false
+}
\ No newline at end of file
diff --git a/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.io.FileListByExtTask b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.io.FileListByExtTask
new file mode 100644
index 0000000..910d0d6
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.io.FileListByExtTask
@@ -0,0 +1,73 @@
+<activity xmlns="http://taverna.sf.net/2008/xml/t2flow"><class>net.sf.taverna.t2.activities.localworker.LocalworkerActivity</class><inputMap /><outputMap /><configBean encoding="xstream"><net.sf.taverna.t2.activities.localworker.LocalworkerActivityConfigurationBean xmlns="">

+  <script>class FileExtFilter implements FileFilter {

+

+	public FileExtFilter(String ext) {

+		this.ext = ext;

+	}

+

+	public boolean accept(File file) {

+		return file.getName().endsWith(ext);

+	}

+

+	String ext = null;

+}

+

+if (extension == void || extension.equals("")) {

+	throw new RuntimeException(

+			"The 'extension' parameter cannot be null.  Please enter a valid file extension.");

+}

+

+if (directory == void || directory.equals("")) {

+	throw new RuntimeException(

+			"The 'directory' parameter cannot be null.  Please enter a valid file directory.");

+}

+

+File dirObj = new File(directory);

+

+if (!dirObj.exists()) {

+	throw new RuntimeException("The 'directory' parameter specified:" + directory

+			+ "does not exist.  Please enter a valid file directory.");

+}

+

+File[] fileObjList = dirObj.listFiles(new FileExtFilter(extension));

+List filelist = new ArrayList();

+for (int i = 0; i &lt; fileObjList.length; i++) {

+	filelist.add(fileObjList[i].getAbsolutePath());

+}

+

+

+</script>

+  <dependencies />

+  <inputs>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+      <handledReferenceSchemes />

+      <translatedElementType>java.lang.String</translatedElementType>

+      <allowsLiteralValues>true</allowsLiteralValues>

+      <name>directory</name>

+      <depth>0</depth>

+      <mimeTypes>

+        <string>'text/plain'</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+      <handledReferenceSchemes />

+      <translatedElementType>java.lang.String</translatedElementType>

+      <allowsLiteralValues>true</allowsLiteralValues>

+      <name>extension</name>

+      <depth>0</depth>

+      <mimeTypes>

+        <string>'text/plain'</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+  </inputs>

+  <outputs>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>

+      <granularDepth>1</granularDepth>

+      <name>filelist</name>

+      <depth>1</depth>

+      <mimeTypes>

+        <string>l('text/plain')</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>

+  </outputs>

+</net.sf.taverna.t2.activities.localworker.LocalworkerActivityConfigurationBean></configBean></activity>
\ No newline at end of file
diff --git a/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.io.FileListByExtTask.json b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.io.FileListByExtTask.json
new file mode 100644
index 0000000..656453e
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.io.FileListByExtTask.json
@@ -0,0 +1,20 @@
+{
+  "classLoaderSharing" : "workflow",
+  "script" : "class FileExtFilter implements FileFilter {\n\n\tpublic FileExtFilter(String ext) {\n\t\tthis.ext = ext;\n\t}\n\n\tpublic boolean accept(File file) {\n\t\treturn file.getName().endsWith(ext);\n\t}\n\n\tString ext = null;\n}\n\nif (extension == void || extension.equals(\"\")) {\n\tthrow new RuntimeException(\n\t\t\t\"The 'extension' parameter cannot be null.  Please enter a valid file extension.\");\n}\n\nif (directory == void || directory.equals(\"\")) {\n\tthrow new RuntimeException(\n\t\t\t\"The 'directory' parameter cannot be null.  Please enter a valid file directory.\");\n}\n\nFile dirObj = new File(directory);\n\nif (!dirObj.exists()) {\n\tthrow new RuntimeException(\"The 'directory' parameter specified:\" + directory\n\t\t\t+ \"does not exist.  Please enter a valid file directory.\");\n}\n\nFile[] fileObjList = dirObj.listFiles(new FileExtFilter(extension));\nList filelist = new ArrayList();\nfor (int i = 0; i < fileObjList.length; i++) {\n\tfilelist.add(fileObjList[i].getAbsolutePath());\n}\n\n\n",
+  "localworkerName" : "net.sourceforge.taverna.scuflworkers.io.FileListByExtTask",
+  "inputPorts" : [ {
+    "name" : "directory",
+    "depth" : 0,
+    "type" : "String"
+  }, {
+    "name" : "extension",
+    "depth" : 0,
+    "type" : "String"
+  } ],
+  "outputPorts" : [ {
+    "name" : "filelist",
+    "depth" : 1,
+    "granularDepth" : 1
+  } ],
+  "isAltered" : false
+}
\ No newline at end of file
diff --git a/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.io.FileListByRegexTask b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.io.FileListByRegexTask
new file mode 100644
index 0000000..06906b6
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.io.FileListByRegexTask
@@ -0,0 +1,71 @@
+<activity xmlns="http://taverna.sf.net/2008/xml/t2flow"><class>net.sf.taverna.t2.activities.localworker.LocalworkerActivity</class><inputMap /><outputMap /><configBean encoding="xstream"><net.sf.taverna.t2.activities.localworker.LocalworkerActivityConfigurationBean xmlns="">

+  <script>class FileRegexFilter implements FileFilter {

+

+	public FileRegexFilter(String regex) {

+		this.regex = regex;

+	}

+

+	public boolean accept(File file) {

+		return file.getName().matches(regex);

+	}

+

+	String regex = null;

+}

+

+if (regex == void || regex.equals("")) {

+	throw new RuntimeException(

+			"The 'regex' parameter cannot be null.  Please enter a valid file extension.");

+}

+

+if (directory == void || directory.equals("")) {

+	throw new RuntimeException(

+			"The 'directory' parameter cannot be null.  Please enter a valid file directory.");

+}

+

+File dirObj = new File(directory);

+

+if (!dirObj.exists()) {

+	throw new RuntimeException("The 'directory' parameter specified:" + directory

+			+ "does not exist.  Please enter a valid file directory.");

+}

+

+File[] fileObjList = dirObj.listFiles(new FileRegexFilter(regex));

+List filelist = new ArrayList();

+for (int i = 0; i &lt; fileObjList.length; i++) {

+	filelist.add(fileObjList[i].getAbsolutePath());

+}

+</script>

+  <dependencies />

+  <inputs>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+      <handledReferenceSchemes />

+      <translatedElementType>java.lang.String</translatedElementType>

+      <allowsLiteralValues>true</allowsLiteralValues>

+      <name>directory</name>

+      <depth>0</depth>

+      <mimeTypes>

+        <string>'text/plain'</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+      <handledReferenceSchemes />

+      <translatedElementType>java.lang.String</translatedElementType>

+      <allowsLiteralValues>true</allowsLiteralValues>

+      <name>regex</name>

+      <depth>0</depth>

+      <mimeTypes>

+        <string>'text/plain'</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+  </inputs>

+  <outputs>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>

+      <granularDepth>1</granularDepth>

+      <name>filelist</name>

+      <depth>1</depth>

+      <mimeTypes>

+        <string>l('text/plain')</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>

+  </outputs>

+</net.sf.taverna.t2.activities.localworker.LocalworkerActivityConfigurationBean></configBean></activity>
\ No newline at end of file
diff --git a/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.io.FileListByRegexTask.json b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.io.FileListByRegexTask.json
new file mode 100644
index 0000000..35cdb01
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.io.FileListByRegexTask.json
@@ -0,0 +1,20 @@
+{
+  "classLoaderSharing" : "workflow",
+  "script" : "class FileRegexFilter implements FileFilter {\n\n\tpublic FileRegexFilter(String regex) {\n\t\tthis.regex = regex;\n\t}\n\n\tpublic boolean accept(File file) {\n\t\treturn file.getName().matches(regex);\n\t}\n\n\tString regex = null;\n}\n\nif (regex == void || regex.equals(\"\")) {\n\tthrow new RuntimeException(\n\t\t\t\"The 'regex' parameter cannot be null.  Please enter a valid file extension.\");\n}\n\nif (directory == void || directory.equals(\"\")) {\n\tthrow new RuntimeException(\n\t\t\t\"The 'directory' parameter cannot be null.  Please enter a valid file directory.\");\n}\n\nFile dirObj = new File(directory);\n\nif (!dirObj.exists()) {\n\tthrow new RuntimeException(\"The 'directory' parameter specified:\" + directory\n\t\t\t+ \"does not exist.  Please enter a valid file directory.\");\n}\n\nFile[] fileObjList = dirObj.listFiles(new FileRegexFilter(regex));\nList filelist = new ArrayList();\nfor (int i = 0; i < fileObjList.length; i++) {\n\tfilelist.add(fileObjList[i].getAbsolutePath());\n}\n",
+  "localworkerName" : "net.sourceforge.taverna.scuflworkers.io.FileListByRegexTask",
+  "inputPorts" : [ {
+    "name" : "directory",
+    "depth" : 0,
+    "type" : "String"
+  }, {
+    "name" : "regex",
+    "depth" : 0,
+    "type" : "String"
+  } ],
+  "outputPorts" : [ {
+    "name" : "filelist",
+    "depth" : 1,
+    "granularDepth" : 1
+  } ],
+  "isAltered" : false
+}
\ No newline at end of file
diff --git a/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.io.LocalCommand b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.io.LocalCommand
new file mode 100644
index 0000000..c0adc09
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.io.LocalCommand
@@ -0,0 +1,80 @@
+<activity xmlns="http://taverna.sf.net/2008/xml/t2flow"><class>net.sf.taverna.t2.activities.localworker.LocalworkerActivity</class><inputMap /><outputMap /><configBean encoding="xstream"><net.sf.taverna.t2.activities.localworker.LocalworkerActivityConfigurationBean xmlns="">

+  <script>if (command == void || command.equals("")) {

+	throw new RuntimeException("The 'command' port cannot be null.");

+}

+Process proc = null;

+Runtime rt = Runtime.getRuntime();

+

+String osName = System.getProperty("os.name");

+String[] cmdArray = null;

+if (osName.contains("Windows")) {

+	cmdArray = new String[] { "cmd.exe", "/c", command };

+} else {// TODO: investigate if this will work in Linux and OSX

+	cmdArray = new String[] { command };

+}

+

+// concatenate the arrays

+if ((args == void) || (args == null)) {

+	args = new ArrayList();

+}

+

+int argSize = cmdArray.length + args.size();

+ArrayList appArray = new ArrayList(argSize);

+for (int i = 0; i &lt; cmdArray.length; i++) {

+	appArray.add(cmdArray[i]);

+}

+

+for (int i = 0; i &lt; args.size(); i++) {

+	appArray.add(args.get(i));

+}

+

+String[] applist = new String[argSize];

+appArray.toArray(applist);

+proc = rt.exec(applist);

+

+// Get the input stream and read from it

+InputStream in = proc.getInputStream();

+

+int c;

+StringBuffer sb = new StringBuffer();

+while ((c = in.read()) != -1) {

+	sb.append((char) c);

+}

+in.close();

+result = sb.toString();

+  

+</script>

+  <dependencies />

+  <inputs>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+      <handledReferenceSchemes />

+      <translatedElementType>java.lang.String</translatedElementType>

+      <allowsLiteralValues>true</allowsLiteralValues>

+      <name>command</name>

+      <depth>0</depth>

+      <mimeTypes>

+        <string>'text/plain'</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+      <handledReferenceSchemes />

+      <translatedElementType>java.lang.String</translatedElementType>

+      <allowsLiteralValues>true</allowsLiteralValues>

+      <name>args</name>

+      <depth>1</depth>

+      <mimeTypes>

+        <string>l('text/plain')</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+  </inputs>

+  <outputs>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>

+      <granularDepth>0</granularDepth>

+      <name>result</name>

+      <depth>0</depth>

+      <mimeTypes>

+        <string>'text/plain'</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>

+  </outputs>

+</net.sf.taverna.t2.activities.localworker.LocalworkerActivityConfigurationBean></configBean></activity>
\ No newline at end of file
diff --git a/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.io.LocalCommand.json b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.io.LocalCommand.json
new file mode 100644
index 0000000..f6ddf4f
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.io.LocalCommand.json
@@ -0,0 +1,20 @@
+{
+  "classLoaderSharing" : "workflow",
+  "script" : "if (command == void || command.equals(\"\")) {\n\tthrow new RuntimeException(\"The 'command' port cannot be null.\");\n}\nProcess proc = null;\nRuntime rt = Runtime.getRuntime();\n\nString osName = System.getProperty(\"os.name\");\nString[] cmdArray = null;\nif (osName.contains(\"Windows\")) {\n\tcmdArray = new String[] { \"cmd.exe\", \"/c\", command };\n} else {// TODO: investigate if this will work in Linux and OSX\n\tcmdArray = new String[] { command };\n}\n\n// concatenate the arrays\nif ((args == void) || (args == null)) {\n\targs = new ArrayList();\n}\n\nint argSize = cmdArray.length + args.size();\nArrayList appArray = new ArrayList(argSize);\nfor (int i = 0; i < cmdArray.length; i++) {\n\tappArray.add(cmdArray[i]);\n}\n\nfor (int i = 0; i < args.size(); i++) {\n\tappArray.add(args.get(i));\n}\n\nString[] applist = new String[argSize];\nappArray.toArray(applist);\nproc = rt.exec(applist);\n\n// Get the input stream and read from it\nInputStream in = proc.getInputStream();\n\nint c;\nStringBuffer sb = new StringBuffer();\nwhile ((c = in.read()) != -1) {\n\tsb.append((char) c);\n}\nin.close();\nresult = sb.toString();\n  \n",
+  "localworkerName" : "net.sourceforge.taverna.scuflworkers.io.LocalCommand",
+  "inputPorts" : [ {
+    "name" : "command",
+    "depth" : 0,
+    "type" : "String"
+  }, {
+    "name" : "args",
+    "depth" : 1,
+    "type" : "String"
+  } ],
+  "outputPorts" : [ {
+    "name" : "result",
+    "depth" : 0,
+    "granularDepth" : 0
+  } ],
+  "isAltered" : false
+}
\ No newline at end of file
diff --git a/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.io.TextFileReader b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.io.TextFileReader
new file mode 100644
index 0000000..6e9adb4
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.io.TextFileReader
@@ -0,0 +1,76 @@
+<activity xmlns="http://taverna.sf.net/2008/xml/t2flow"><class>net.sf.taverna.t2.activities.localworker.LocalworkerActivity</class><inputMap /><outputMap /><configBean encoding="xstream"><net.sf.taverna.t2.activities.localworker.LocalworkerActivityConfigurationBean xmlns="">

+  <script>BufferedReader getReader (String fileUrl, String encoding) throws IOException {

+		InputStreamReader reader;

+		try {

+			if (encoding == null) {

+				reader = new FileReader(fileUrl);

+			} else {

+				reader = new InputStreamReader(new FileInputStream(fileUrl),encoding); 

+			}

+		}

+		catch (FileNotFoundException e) {

+			// try a real URL instead

+			URL url = new URL(fileUrl);

+			if (encoding == null) {

+				reader = new InputStreamReader (url.openStream());

+			} else {

+				reader = new InputStreamReader (url.openStream(), encoding);

+			}

+		}

+		return new BufferedReader(reader);

+	}

+

+

+

+StringBuffer sb = new StringBuffer(4000);

+

+if (encoding == void) {

+	encoding = null;

+}

+

+BufferedReader in = getReader(fileurl, encoding);

+String str;

+String lineEnding = System.getProperty("line.separator");

+

+while ((str = in.readLine()) != null) {

+	sb.append(str);

+	sb.append(lineEnding);

+}

+in.close();

+filecontents = sb.toString();

+  

+</script>

+  <dependencies />

+  <inputs>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+      <handledReferenceSchemes />

+      <translatedElementType>java.lang.String</translatedElementType>

+      <allowsLiteralValues>true</allowsLiteralValues>

+      <name>fileurl</name>

+      <depth>0</depth>

+      <mimeTypes>

+        <string>'text/plain'</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+      <handledReferenceSchemes />

+      <translatedElementType>java.lang.String</translatedElementType>

+      <allowsLiteralValues>true</allowsLiteralValues>

+      <name>encoding</name>

+      <depth>0</depth>

+      <mimeTypes>

+        <string>'text/plain'</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+  </inputs>

+  <outputs>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>

+      <granularDepth>0</granularDepth>

+      <name>filecontents</name>

+      <depth>0</depth>

+      <mimeTypes>

+        <string>'text/plain'</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>

+  </outputs>

+</net.sf.taverna.t2.activities.localworker.LocalworkerActivityConfigurationBean></configBean></activity>
\ No newline at end of file
diff --git a/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.io.TextFileReader.json b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.io.TextFileReader.json
new file mode 100644
index 0000000..1424433
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.io.TextFileReader.json
@@ -0,0 +1,20 @@
+{
+  "classLoaderSharing" : "workflow",
+  "script" : "BufferedReader getReader (String fileUrl, String encoding) throws IOException {\n\t\tInputStreamReader reader;\n\t\ttry {\n\t\t\tif (encoding == null) {\n\t\t\t\treader = new FileReader(fileUrl);\n\t\t\t} else {\n\t\t\t\treader = new InputStreamReader(new FileInputStream(fileUrl),encoding); \n\t\t\t}\n\t\t}\n\t\tcatch (FileNotFoundException e) {\n\t\t\t// try a real URL instead\n\t\t\tURL url = new URL(fileUrl);\n\t\t\tif (encoding == null) {\n\t\t\t\treader = new InputStreamReader (url.openStream());\n\t\t\t} else {\n\t\t\t\treader = new InputStreamReader (url.openStream(), encoding);\n\t\t\t}\n\t\t}\n\t\treturn new BufferedReader(reader);\n\t}\n\n\n\nStringBuffer sb = new StringBuffer(4000);\n\nif (encoding == void) {\n\tencoding = null;\n}\n\nBufferedReader in = getReader(fileurl, encoding);\nString str;\nString lineEnding = System.getProperty(\"line.separator\");\n\nwhile ((str = in.readLine()) != null) {\n\tsb.append(str);\n\tsb.append(lineEnding);\n}\nin.close();\nfilecontents = sb.toString();\n  \n",
+  "localworkerName" : "net.sourceforge.taverna.scuflworkers.io.TextFileReader",
+  "inputPorts" : [ {
+    "name" : "fileurl",
+    "depth" : 0,
+    "type" : "String"
+  }, {
+    "name" : "encoding",
+    "depth" : 0,
+    "type" : "String"
+  } ],
+  "outputPorts" : [ {
+    "name" : "filecontents",
+    "depth" : 0,
+    "granularDepth" : 0
+  } ],
+  "isAltered" : false
+}
\ No newline at end of file
diff --git a/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.io.TextFileWriter b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.io.TextFileWriter
new file mode 100644
index 0000000..88ac962
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.io.TextFileWriter
@@ -0,0 +1,57 @@
+<activity xmlns="http://taverna.sf.net/2008/xml/t2flow"><class>net.sf.taverna.t2.activities.localworker.LocalworkerActivity</class><inputMap /><outputMap /><configBean encoding="xstream"><net.sf.taverna.t2.activities.localworker.LocalworkerActivityConfigurationBean xmlns="">

+  <script>

+  BufferedWriter out;

+  if (encoding == void) {

+  	out = new BufferedWriter(new FileWriter(outputFile));

+  }

+  else {

+  	out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outputFile), encoding)); 

+  }

+out.write(filecontents);

+out.flush();

+out.close();

+outputFile = filecontents;

+</script>

+  <dependencies />

+  <inputs>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+      <handledReferenceSchemes />

+      <translatedElementType>java.lang.String</translatedElementType>

+      <allowsLiteralValues>true</allowsLiteralValues>

+      <name>outputFile</name>

+      <depth>0</depth>

+      <mimeTypes>

+        <string>'text/plain'</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+      <handledReferenceSchemes />

+      <translatedElementType>java.lang.String</translatedElementType>

+      <allowsLiteralValues>true</allowsLiteralValues>

+      <name>filecontents</name>

+      <depth>0</depth>

+      <mimeTypes>

+        <string>'text/plain'</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+      <handledReferenceSchemes />

+      <translatedElementType>java.lang.String</translatedElementType>

+      <allowsLiteralValues>true</allowsLiteralValues>

+      <name>encoding</name>

+      <depth>0</depth>

+      <mimeTypes>

+        <string>'text/plain'</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>  </inputs>

+  <outputs>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>

+      <granularDepth>0</granularDepth>

+      <name>outputFile</name>

+      <depth>0</depth>

+      <mimeTypes>

+        <string>'text/plain'</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>

+  </outputs>

+</net.sf.taverna.t2.activities.localworker.LocalworkerActivityConfigurationBean></configBean></activity>
\ No newline at end of file
diff --git a/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.io.TextFileWriter.json b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.io.TextFileWriter.json
new file mode 100644
index 0000000..5a9f368
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.io.TextFileWriter.json
@@ -0,0 +1,24 @@
+{
+  "classLoaderSharing" : "workflow",
+  "script" : "\n  BufferedWriter out;\n  if (encoding == void) {\n  \tout = new BufferedWriter(new FileWriter(outputFile));\n  }\n  else {\n  \tout = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outputFile), encoding)); \n  }\nout.write(filecontents);\nout.flush();\nout.close();\noutputFile = filecontents;\n",
+  "localworkerName" : "net.sourceforge.taverna.scuflworkers.io.TextFileWriter",
+  "inputPorts" : [ {
+    "name" : "outputFile",
+    "depth" : 0,
+    "type" : "String"
+  }, {
+    "name" : "filecontents",
+    "depth" : 0,
+    "type" : "String"
+  }, {
+    "name" : "encoding",
+    "depth" : 0,
+    "type" : "String"
+  } ],
+  "outputPorts" : [ {
+    "name" : "outputFile",
+    "depth" : 0,
+    "granularDepth" : 0
+  } ],
+  "isAltered" : false
+}
\ No newline at end of file
diff --git a/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.jdbc.SQLQueryWorker b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.jdbc.SQLQueryWorker
new file mode 100644
index 0000000..b6263cf
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.jdbc.SQLQueryWorker
@@ -0,0 +1,309 @@
+<activity  xmlns="http://taverna.sf.net/2008/xml/t2flow"><class>net.sf.taverna.t2.activities.localworker.LocalworkerActivity</class><inputMap><map from="password" to="password" /><map from="userid" to="userid" /><map from="params" to="params" /><map from="url" to="url" /><map from="provideXml" to="provideXml" /><map from="driver" to="driver" /><map from="sql" to="sql" /></inputMap><outputMap><map from="resultList" to="resultList" /><map from="xmlresults" to="xmlresults" /></outputMap><configBean encoding="xstream"><net.sf.taverna.t2.activities.localworker.LocalworkerActivityConfigurationBean xmlns="">
+
+  <script>
+ import java.sql.Driver;
+import java.sql.DriverManager;
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+import java.sql.SQLException;
+
+import javax.sql.rowset.WebRowSet;
+
+import com.sun.rowset.WebRowSetImpl;
+
+
+
+if ((driver == void) || (driver == null) || driver.equals("")) {
+	throw new RuntimeException("The driver must be specified");
+}
+
+if ((url == void) || (url == null) || url.equals("")) {
+	throw new RuntimeException("The url must be specified");
+}
+
+boolean provideXmlBoolean = ((provideXml != void) &amp;&amp; (provideXml != null) &amp;&amp; Boolean.valueOf(provideXml));
+
+if ((params == void) || (params == null)) {
+   params = new ArrayList();
+}
+
+if ((sql == void) || (sql == null) || sql.equals("")) {
+	throw new RuntimeException("The sql must be specified");
+}
+
+Class c = Thread.currentThread().getContextClassLoader().loadClass(driver);
+
+if (c == null) {
+	throw new RuntimeException("Class " + driver + " not found");
+}
+
+Driver d = c.newInstance();
+if (d == null) {
+	throw new RuntimeException("Could not create instance of driver");
+}
+
+Properties p = new Properties();
+
+if ((userid == void) || (userid == null)) {
+	userid = "";
+}
+
+p.setProperty("user", userid);
+
+if ((password == void) || (password == null)) {
+	password = "";
+}
+
+p.setProperty("password", password);
+
+Connection con = null;
+PreparedStatement ps = null;
+ResultSet rs = null;
+try {
+
+	con = d.connect(url, p);
+	ps = con.prepareStatement(sql);
+
+	int paramSize = params.size();
+	for (int i = 0; i &lt; paramSize; i++) {
+		ps.setObject(i + 1, params.get(i));
+	}
+
+	rs = ps.executeQuery();
+
+	if (provideXmlBoolean) {
+		WebRowSet webrs = new WebRowSetImpl();
+		StringWriter sw = new StringWriter();
+		webrs.writeXml(rs, sw);
+		xmlresults = sw.toString();
+	} else {
+		xmlresults = "";
+	}
+
+	try {
+		rs.beforeFirst();
+	} catch (SQLException e) {
+		// redo the query
+		rs = ps.executeQuery();
+	}
+
+	ResultSetMetaData rsmd = rs.getMetaData();
+	int numCols = rsmd.getColumnCount();
+	resultList = new ArrayList();
+	
+	// put the results into the results list.
+	while (rs.next()) {
+		List row = new ArrayList(numCols);
+		for (int i = 0; i &lt; numCols; i++) {
+			String str = rs.getString(i + 1); 
+			row.add(str == null ? "null" : str); 
+		}
+		resultList.add(row);
+	}
+}
+finally {
+	if (rs != null) {
+		rs.close();
+	}
+	if (ps != null) {
+		ps.close();
+	}
+	if (con != null) {
+		con.close();
+	}
+}
+  
+
+ </script>
+
+  <dependencies />
+
+  <classLoaderSharing>system</classLoaderSharing>
+
+  <localDependencies />
+
+  <artifactDependencies />
+
+  <inputs>
+
+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>
+
+      <handledReferenceSchemes />
+
+      <translatedElementType>java.lang.String</translatedElementType>
+
+      <allowsLiteralValues>true</allowsLiteralValues>
+
+      <name>driver</name>
+
+      <depth>0</depth>
+
+      <mimeTypes>
+
+        <string>text/plain</string>
+
+      </mimeTypes>
+
+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>
+
+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>
+
+      <handledReferenceSchemes />
+
+      <translatedElementType>java.lang.String</translatedElementType>
+
+      <allowsLiteralValues>true</allowsLiteralValues>
+
+      <name>password</name>
+
+      <depth>0</depth>
+
+      <mimeTypes>
+
+        <string>text/plain</string>
+
+      </mimeTypes>
+
+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>
+
+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>
+
+      <handledReferenceSchemes />
+
+      <translatedElementType>java.lang.String</translatedElementType>
+
+      <allowsLiteralValues>true</allowsLiteralValues>
+
+      <name>userid</name>
+
+      <depth>0</depth>
+
+      <mimeTypes>
+
+        <string>text/plain</string>
+
+      </mimeTypes>
+
+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>
+
+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>
+
+      <handledReferenceSchemes />
+
+      <translatedElementType>java.lang.String</translatedElementType>
+
+      <allowsLiteralValues>true</allowsLiteralValues>
+
+      <name>url</name>
+
+      <depth>0</depth>
+
+      <mimeTypes>
+
+        <string>text/plain</string>
+
+      </mimeTypes>
+
+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>
+
+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>
+
+      <handledReferenceSchemes />
+
+      <translatedElementType>java.lang.String</translatedElementType>
+
+      <allowsLiteralValues>true</allowsLiteralValues>
+
+      <name>provideXml</name>
+
+      <depth>0</depth>
+
+      <mimeTypes>
+
+        <string>text/plain</string>
+
+      </mimeTypes>
+
+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>
+
+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>
+
+      <handledReferenceSchemes />
+
+      <translatedElementType>java.lang.String</translatedElementType>
+
+      <allowsLiteralValues>true</allowsLiteralValues>
+
+      <name>sql</name>
+
+      <depth>0</depth>
+
+      <mimeTypes>
+
+        <string>text/plain</string>
+
+      </mimeTypes>
+
+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>
+
+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>
+
+      <handledReferenceSchemes />
+
+      <translatedElementType>java.lang.String</translatedElementType>
+
+      <allowsLiteralValues>true</allowsLiteralValues>
+
+      <name>params</name>
+
+      <depth>1</depth>
+
+      <mimeTypes>
+
+        <string>text/plain</string>
+
+      </mimeTypes>
+
+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>
+
+  </inputs>
+
+  <outputs>
+
+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>
+
+      <granularDepth>2</granularDepth>
+
+      <name>resultList</name>
+
+      <depth>2</depth>
+
+      <mimeTypes>
+
+        <string>text/plain</string>
+
+      </mimeTypes>
+
+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>
+
+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>
+
+      <granularDepth>0</granularDepth>
+
+      <name>xmlresults</name>
+
+      <depth>0</depth>
+
+      <mimeTypes>
+
+        <string>text/plain</string>
+
+      </mimeTypes>
+
+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>
+
+  </outputs>
+
+</net.sf.taverna.t2.activities.localworker.LocalworkerActivityConfigurationBean></configBean><annotations /></activity>
\ No newline at end of file
diff --git a/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.jdbc.SQLQueryWorker.json b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.jdbc.SQLQueryWorker.json
new file mode 100644
index 0000000..da1f005
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.jdbc.SQLQueryWorker.json
@@ -0,0 +1,44 @@
+{
+  "classLoaderSharing" : "workflow",
+  "script" : "\n import java.sql.Driver;\nimport java.sql.DriverManager;\nimport java.sql.Connection;\nimport java.sql.PreparedStatement;\nimport java.sql.ResultSet;\nimport java.sql.ResultSetMetaData;\nimport java.sql.SQLException;\n\nimport javax.sql.rowset.WebRowSet;\n\nimport com.sun.rowset.WebRowSetImpl;\n\n\n\nif ((driver == void) || (driver == null) || driver.equals(\"\")) {\n\tthrow new RuntimeException(\"The driver must be specified\");\n}\n\nif ((url == void) || (url == null) || url.equals(\"\")) {\n\tthrow new RuntimeException(\"The url must be specified\");\n}\n\nboolean provideXmlBoolean = ((provideXml != void) && (provideXml != null) && Boolean.valueOf(provideXml));\n\nif ((params == void) || (params == null)) {\n   params = new ArrayList();\n}\n\nif ((sql == void) || (sql == null) || sql.equals(\"\")) {\n\tthrow new RuntimeException(\"The sql must be specified\");\n}\n\nClass c = Thread.currentThread().getContextClassLoader().loadClass(driver);\n\nif (c == null) {\n\tthrow new RuntimeException(\"Class \" + driver + \" not found\");\n}\n\nDriver d = c.newInstance();\nif (d == null) {\n\tthrow new RuntimeException(\"Could not create instance of driver\");\n}\n\nProperties p = new Properties();\n\nif ((userid == void) || (userid == null)) {\n\tuserid = \"\";\n}\n\np.setProperty(\"user\", userid);\n\nif ((password == void) || (password == null)) {\n\tpassword = \"\";\n}\n\np.setProperty(\"password\", password);\n\nConnection con = null;\nPreparedStatement ps = null;\nResultSet rs = null;\ntry {\n\n\tcon = d.connect(url, p);\n\tps = con.prepareStatement(sql);\n\n\tint paramSize = params.size();\n\tfor (int i = 0; i < paramSize; i++) {\n\t\tps.setObject(i + 1, params.get(i));\n\t}\n\n\trs = ps.executeQuery();\n\n\tif (provideXmlBoolean) {\n\t\tWebRowSet webrs = new WebRowSetImpl();\n\t\tStringWriter sw = new StringWriter();\n\t\twebrs.writeXml(rs, sw);\n\t\txmlresults = sw.toString();\n\t} else {\n\t\txmlresults = \"\";\n\t}\n\n\ttry {\n\t\trs.beforeFirst();\n\t} catch (SQLException e) {\n\t\t// redo the query\n\t\trs = ps.executeQuery();\n\t}\n\n\tResultSetMetaData rsmd = rs.getMetaData();\n\tint numCols = rsmd.getColumnCount();\n\tresultList = new ArrayList();\n\t\n\t// put the results into the results list.\n\twhile (rs.next()) {\n\t\tList row = new ArrayList(numCols);\n\t\tfor (int i = 0; i < numCols; i++) {\n\t\t\tString str = rs.getString(i + 1); \n\t\t\trow.add(str == null ? \"null\" : str); \n\t\t}\n\t\tresultList.add(row);\n\t}\n}\nfinally {\n\tif (rs != null) {\n\t\trs.close();\n\t}\n\tif (ps != null) {\n\t\tps.close();\n\t}\n\tif (con != null) {\n\t\tcon.close();\n\t}\n}\n  \n\n ",
+  "localworkerName" : "net.sourceforge.taverna.scuflworkers.jdbc.SQLQueryWorker",
+  "inputPorts" : [ {
+    "name" : "driver",
+    "depth" : 0,
+    "type" : "String"
+  }, {
+    "name" : "password",
+    "depth" : 0,
+    "type" : "String"
+  }, {
+    "name" : "userid",
+    "depth" : 0,
+    "type" : "String"
+  }, {
+    "name" : "url",
+    "depth" : 0,
+    "type" : "String"
+  }, {
+    "name" : "provideXml",
+    "depth" : 0,
+    "type" : "String"
+  }, {
+    "name" : "sql",
+    "depth" : 0,
+    "type" : "String"
+  }, {
+    "name" : "params",
+    "depth" : 1,
+    "type" : "String"
+  } ],
+  "outputPorts" : [ {
+    "name" : "resultList",
+    "depth" : 2,
+    "granularDepth" : 2
+  }, {
+    "name" : "xmlresults",
+    "depth" : 0,
+    "granularDepth" : 0
+  } ],
+  "isAltered" : false
+}
\ No newline at end of file
diff --git a/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.jdbc.SQLUpdateWorker b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.jdbc.SQLUpdateWorker
new file mode 100644
index 0000000..fa0748c
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.jdbc.SQLUpdateWorker
@@ -0,0 +1,229 @@
+<activity  xmlns="http://taverna.sf.net/2008/xml/t2flow"><class>net.sf.taverna.t2.activities.localworker.LocalworkerActivity</class><inputMap><map from="password" to="password" /><map from="userid" to="userid" /><map from="params" to="params" /><map from="url" to="url" /><map from="provideXml" to="provideXml" /><map from="driver" to="driver" /><map from="sql" to="sql" /></inputMap><outputMap><map from="resultList" to="resultList" /><map from="xmlresults" to="xmlresults" /></outputMap><configBean encoding="xstream"><net.sf.taverna.t2.activities.localworker.LocalworkerActivityConfigurationBean xmlns="">
+
+  <script>import java.sql.Driver;
+import java.sql.DriverManager;
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+
+if ((driver == void) || (driver == null) || driver.equals("")) {
+	throw new RuntimeException("The driver must be specified");
+}
+
+if ((url == void) || (url == null) || url.equals("")) {
+	throw new RuntimeException("The url must be specified");
+}
+
+if ((params == void) || (params == null)) {
+   params = new ArrayList();
+}
+
+if ((sql == void) || (sql == null) || sql.equals("")) {
+	throw new RuntimeException("The sql must be specified");
+}
+
+Class c = Thread.currentThread().getContextClassLoader().loadClass(driver);
+
+if (c == null) {
+	throw new RuntimeException("Class " + driver + " not found");
+}
+
+Driver d = c.newInstance();
+if (d == null) {
+	throw new RuntimeException("Could not create instance of driver");
+}
+
+Properties p = new Properties();
+
+if ((userid == void) || (userid == null)) {
+	userid = "";
+}
+
+p.setProperty("user", userid);
+
+if ((password == void) || (password == null)) {
+	password = "";
+}
+
+p.setProperty("password", password);
+
+Connection con = null;
+PreparedStatement ps = null;
+
+try {
+	con = d.connect(url, p);
+	ps = con.prepareStatement(sql);
+
+	int paramsSize = params.size();
+	for (int i = 0; i &lt; paramsSize; i++) {
+		ps.setObject(i + 1, params.get(i));
+	}
+
+	ps.executeUpdate();
+
+	resultList = "update successful";
+}
+finally {
+	if (ps != null) {
+		ps.close();
+	}
+	if (con != null) {
+		con.close();
+	}
+}
+
+</script>
+
+  <dependencies />
+
+  <classLoaderSharing>system</classLoaderSharing>
+    <localDependencies />
+
+  <artifactDependencies />
+
+  <inputs>
+
+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>
+
+      <handledReferenceSchemes />
+
+      <translatedElementType>java.lang.String</translatedElementType>
+
+      <allowsLiteralValues>true</allowsLiteralValues>
+
+      <name>driver</name>
+
+      <depth>0</depth>
+
+      <mimeTypes>
+
+        <string>text/plain</string>
+
+      </mimeTypes>
+
+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>
+
+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>
+
+      <handledReferenceSchemes />
+
+      <translatedElementType>java.lang.String</translatedElementType>
+
+      <allowsLiteralValues>true</allowsLiteralValues>
+
+      <name>password</name>
+
+      <depth>0</depth>
+
+      <mimeTypes>
+
+        <string>text/plain</string>
+
+      </mimeTypes>
+
+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>
+
+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>
+
+      <handledReferenceSchemes />
+
+      <translatedElementType>java.lang.String</translatedElementType>
+
+      <allowsLiteralValues>true</allowsLiteralValues>
+
+      <name>userid</name>
+
+      <depth>0</depth>
+
+      <mimeTypes>
+
+        <string>text/plain</string>
+
+      </mimeTypes>
+
+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>
+
+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>
+
+      <handledReferenceSchemes />
+
+      <translatedElementType>java.lang.String</translatedElementType>
+
+      <allowsLiteralValues>true</allowsLiteralValues>
+
+      <name>url</name>
+
+      <depth>0</depth>
+
+      <mimeTypes>
+
+        <string>text/plain</string>
+
+      </mimeTypes>
+
+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>
+
+
+
+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>
+
+      <handledReferenceSchemes />
+
+      <translatedElementType>java.lang.String</translatedElementType>
+
+      <allowsLiteralValues>true</allowsLiteralValues>
+
+      <name>sql</name>
+
+      <depth>0</depth>
+
+      <mimeTypes>
+
+        <string>text/plain</string>
+
+      </mimeTypes>
+
+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>
+
+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>
+
+      <handledReferenceSchemes />
+
+      <translatedElementType>java.lang.String</translatedElementType>
+
+      <allowsLiteralValues>true</allowsLiteralValues>
+
+      <name>params</name>
+
+      <depth>1</depth>
+
+      <mimeTypes>
+
+        <string>text/plain</string>
+
+      </mimeTypes>
+
+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>
+
+  </inputs>
+
+  <outputs>
+
+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>
+
+      <granularDepth>0</granularDepth>
+
+      <name>resultList</name>
+
+      <depth>0</depth>
+
+      <mimeTypes>
+
+        <string>text/plain</string>
+
+      </mimeTypes>
+
+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>
+
+  </outputs>
+
+</net.sf.taverna.t2.activities.localworker.LocalworkerActivityConfigurationBean></configBean><annotations /></activity>
\ No newline at end of file
diff --git a/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.jdbc.SQLUpdateWorker.json b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.jdbc.SQLUpdateWorker.json
new file mode 100644
index 0000000..3144afd
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.jdbc.SQLUpdateWorker.json
@@ -0,0 +1,36 @@
+{
+  "classLoaderSharing" : "workflow",
+  "script" : "import java.sql.Driver;\nimport java.sql.DriverManager;\nimport java.sql.Connection;\nimport java.sql.PreparedStatement;\n\nif ((driver == void) || (driver == null) || driver.equals(\"\")) {\n\tthrow new RuntimeException(\"The driver must be specified\");\n}\n\nif ((url == void) || (url == null) || url.equals(\"\")) {\n\tthrow new RuntimeException(\"The url must be specified\");\n}\n\nif ((params == void) || (params == null)) {\n   params = new ArrayList();\n}\n\nif ((sql == void) || (sql == null) || sql.equals(\"\")) {\n\tthrow new RuntimeException(\"The sql must be specified\");\n}\n\nClass c = Thread.currentThread().getContextClassLoader().loadClass(driver);\n\nif (c == null) {\n\tthrow new RuntimeException(\"Class \" + driver + \" not found\");\n}\n\nDriver d = c.newInstance();\nif (d == null) {\n\tthrow new RuntimeException(\"Could not create instance of driver\");\n}\n\nProperties p = new Properties();\n\nif ((userid == void) || (userid == null)) {\n\tuserid = \"\";\n}\n\np.setProperty(\"user\", userid);\n\nif ((password == void) || (password == null)) {\n\tpassword = \"\";\n}\n\np.setProperty(\"password\", password);\n\nConnection con = null;\nPreparedStatement ps = null;\n\ntry {\n\tcon = d.connect(url, p);\n\tps = con.prepareStatement(sql);\n\n\tint paramsSize = params.size();\n\tfor (int i = 0; i < paramsSize; i++) {\n\t\tps.setObject(i + 1, params.get(i));\n\t}\n\n\tps.executeUpdate();\n\n\tresultList = \"update successful\";\n}\nfinally {\n\tif (ps != null) {\n\t\tps.close();\n\t}\n\tif (con != null) {\n\t\tcon.close();\n\t}\n}\n\n",
+  "localworkerName" : "net.sourceforge.taverna.scuflworkers.jdbc.SQLUpdateWorker",
+  "inputPorts" : [ {
+    "name" : "driver",
+    "depth" : 0,
+    "type" : "String"
+  }, {
+    "name" : "password",
+    "depth" : 0,
+    "type" : "String"
+  }, {
+    "name" : "userid",
+    "depth" : 0,
+    "type" : "String"
+  }, {
+    "name" : "url",
+    "depth" : 0,
+    "type" : "String"
+  }, {
+    "name" : "sql",
+    "depth" : 0,
+    "type" : "String"
+  }, {
+    "name" : "params",
+    "depth" : 1,
+    "type" : "String"
+  } ],
+  "outputPorts" : [ {
+    "name" : "resultList",
+    "depth" : 0,
+    "granularDepth" : 0
+  } ],
+  "isAltered" : false
+}
\ No newline at end of file
diff --git a/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.ncbi.NucleotideFastaWorker b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.ncbi.NucleotideFastaWorker
new file mode 100644
index 0000000..8b7a680
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.ncbi.NucleotideFastaWorker
@@ -0,0 +1,45 @@
+<activity xmlns="http://taverna.sf.net/2008/xml/t2flow"><class>net.sf.taverna.t2.activities.localworker.LocalworkerActivity</class><inputMap /><outputMap><map from="outputText" to="outputText" /></outputMap><configBean encoding="xstream"><net.sf.taverna.t2.activities.localworker.LocalworkerActivityConfigurationBean xmlns="">

+  <script>if ((id == void) || (id == null) || id.equals("")) {

+	throw new RunTimeException("port id must have a non-empty value");

+}

+

+URL url = new URL ("http://eutils.ncbi.nlm.nih.gov/entrez/eutils/efetch.fcgi?rettype=fasta&amp;db=nucleotide&amp;retmode=text&amp;id=" + id);

+

+BufferedReader reader = new BufferedReader (new InputStreamReader(url.openStream()));

+StringWriter writer = new StringWriter();

+

+char[] buffer = new char[1024];

+    while (true) {

+        int r = reader.read(buffer);

+        if (r &lt;= 0) {

+            break;

+        }

+        writer.write(buffer, 0, r);

+    }

+reader.close();

+outputText = writer.toString();

+</script>

+  <dependencies />

+  <inputs>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+      <handledReferenceSchemes />

+      <translatedElementType>java.lang.String</translatedElementType>

+      <allowsLiteralValues>true</allowsLiteralValues>

+      <name>id</name>

+      <depth>0</depth>

+      <mimeTypes>

+        <string>'text/plain'</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+  </inputs>

+  <outputs>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>

+      <granularDepth>0</granularDepth>

+      <name>outputText</name>

+      <depth>0</depth>

+      <mimeTypes>

+        <string>'text/plain'</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>

+  </outputs>

+</net.sf.taverna.t2.activities.localworker.LocalworkerActivityConfigurationBean></configBean></activity>
\ No newline at end of file
diff --git a/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.ncbi.NucleotideFastaWorker.json b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.ncbi.NucleotideFastaWorker.json
new file mode 100644
index 0000000..feb26cc
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.ncbi.NucleotideFastaWorker.json
@@ -0,0 +1,16 @@
+{
+  "classLoaderSharing" : "workflow",
+  "script" : "if ((id == void) || (id == null) || id.equals(\"\")) {\n\tthrow new RunTimeException(\"port id must have a non-empty value\");\n}\n\nURL url = new URL (\"http://eutils.ncbi.nlm.nih.gov/entrez/eutils/efetch.fcgi?rettype=fasta&db=nucleotide&retmode=text&id=\" + id);\n\nBufferedReader reader = new BufferedReader (new InputStreamReader(url.openStream()));\nStringWriter writer = new StringWriter();\n\nchar[] buffer = new char[1024];\n    while (true) {\n        int r = reader.read(buffer);\n        if (r <= 0) {\n            break;\n        }\n        writer.write(buffer, 0, r);\n    }\nreader.close();\noutputText = writer.toString();\n",
+  "localworkerName" : "net.sourceforge.taverna.scuflworkers.ncbi.NucleotideFastaWorker",
+  "inputPorts" : [ {
+    "name" : "id",
+    "depth" : 0,
+    "type" : "String"
+  } ],
+  "outputPorts" : [ {
+    "name" : "outputText",
+    "depth" : 0,
+    "granularDepth" : 0
+  } ],
+  "isAltered" : false
+}
\ No newline at end of file
diff --git a/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.ncbi.NucleotideGBSeqWorker b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.ncbi.NucleotideGBSeqWorker
new file mode 100644
index 0000000..80f791a
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.ncbi.NucleotideGBSeqWorker
@@ -0,0 +1,45 @@
+<activity xmlns="http://taverna.sf.net/2008/xml/t2flow"><class>net.sf.taverna.t2.activities.localworker.LocalworkerActivity</class><inputMap /><outputMap><map from="outputText" to="outputText" /></outputMap><configBean encoding="xstream"><net.sf.taverna.t2.activities.localworker.LocalworkerActivityConfigurationBean xmlns="">

+  <script>if ((id == void) || (id == null) || id.equals("")) {

+	throw new RunTimeException("port id must have a non-empty value");

+}

+

+URL url = new URL ("http://eutils.ncbi.nlm.nih.gov/entrez/eutils/efetch.fcgi?rettype=gb&amp;db=nucleotide&amp;retmode=xml&amp;id=" + id);

+

+BufferedReader reader = new BufferedReader (new InputStreamReader(url.openStream()));

+StringWriter writer = new StringWriter();

+

+char[] buffer = new char[1024];

+    while (true) {

+        int r = reader.read(buffer);

+        if (r &lt;= 0) {

+            break;

+        }

+        writer.write(buffer, 0, r);

+    }

+reader.close();

+outputText = writer.toString();

+</script>

+  <dependencies />

+  <inputs>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+      <handledReferenceSchemes />

+      <translatedElementType>java.lang.String</translatedElementType>

+      <allowsLiteralValues>true</allowsLiteralValues>

+      <name>id</name>

+      <depth>0</depth>

+      <mimeTypes>

+        <string>'text/plain'</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+  </inputs>

+  <outputs>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>

+      <granularDepth>0</granularDepth>

+      <name>outputText</name>

+      <depth>0</depth>

+      <mimeTypes>

+        <string>'text/plain'</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>

+  </outputs>

+</net.sf.taverna.t2.activities.localworker.LocalworkerActivityConfigurationBean></configBean></activity>
\ No newline at end of file
diff --git a/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.ncbi.NucleotideGBSeqWorker.json b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.ncbi.NucleotideGBSeqWorker.json
new file mode 100644
index 0000000..e616f51
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.ncbi.NucleotideGBSeqWorker.json
@@ -0,0 +1,16 @@
+{
+  "classLoaderSharing" : "workflow",
+  "script" : "if ((id == void) || (id == null) || id.equals(\"\")) {\n\tthrow new RunTimeException(\"port id must have a non-empty value\");\n}\n\nURL url = new URL (\"http://eutils.ncbi.nlm.nih.gov/entrez/eutils/efetch.fcgi?rettype=gb&db=nucleotide&retmode=xml&id=\" + id);\n\nBufferedReader reader = new BufferedReader (new InputStreamReader(url.openStream()));\nStringWriter writer = new StringWriter();\n\nchar[] buffer = new char[1024];\n    while (true) {\n        int r = reader.read(buffer);\n        if (r <= 0) {\n            break;\n        }\n        writer.write(buffer, 0, r);\n    }\nreader.close();\noutputText = writer.toString();\n",
+  "localworkerName" : "net.sourceforge.taverna.scuflworkers.ncbi.NucleotideGBSeqWorker",
+  "inputPorts" : [ {
+    "name" : "id",
+    "depth" : 0,
+    "type" : "String"
+  } ],
+  "outputPorts" : [ {
+    "name" : "outputText",
+    "depth" : 0,
+    "granularDepth" : 0
+  } ],
+  "isAltered" : false
+}
\ No newline at end of file
diff --git a/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.ncbi.NucleotideINSDSeqXMLWorker b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.ncbi.NucleotideINSDSeqXMLWorker
new file mode 100644
index 0000000..2ce601b
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.ncbi.NucleotideINSDSeqXMLWorker
@@ -0,0 +1,45 @@
+<activity xmlns="http://taverna.sf.net/2008/xml/t2flow"><class>net.sf.taverna.t2.activities.localworker.LocalworkerActivity</class><inputMap /><outputMap><map from="outputText" to="outputText" /></outputMap><configBean encoding="xstream"><net.sf.taverna.t2.activities.localworker.LocalworkerActivityConfigurationBean xmlns="">

+  <script>if ((id == void) || (id == null) || id.equals("")) {

+	throw new RunTimeException("port id must have a non-empty value");

+}

+

+URL url = new URL ("http://eutils.ncbi.nlm.nih.gov/entrez/eutils/efetch.fcgi?rettype=gbc&amp;db=nucleotide&amp;retmode=xml&amp;id=" + id);

+

+BufferedReader reader = new BufferedReader (new InputStreamReader(url.openStream()));

+StringWriter writer = new StringWriter();

+

+char[] buffer = new char[1024];

+    while (true) {

+        int r = reader.read(buffer);

+        if (r &lt;= 0) {

+            break;

+        }

+        writer.write(buffer, 0, r);

+    }

+reader.close();

+outputText = writer.toString();

+</script>

+  <dependencies />

+  <inputs>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+      <handledReferenceSchemes />

+      <translatedElementType>java.lang.String</translatedElementType>

+      <allowsLiteralValues>true</allowsLiteralValues>

+      <name>id</name>

+      <depth>0</depth>

+      <mimeTypes>

+        <string>'text/plain'</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+  </inputs>

+  <outputs>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>

+      <granularDepth>0</granularDepth>

+      <name>outputText</name>

+      <depth>0</depth>

+      <mimeTypes>

+        <string>'text/plain'</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>

+  </outputs>

+</net.sf.taverna.t2.activities.localworker.LocalworkerActivityConfigurationBean></configBean></activity>
\ No newline at end of file
diff --git a/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.ncbi.NucleotideINSDSeqXMLWorker.json b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.ncbi.NucleotideINSDSeqXMLWorker.json
new file mode 100644
index 0000000..8dfbdbe
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.ncbi.NucleotideINSDSeqXMLWorker.json
@@ -0,0 +1,16 @@
+{
+  "classLoaderSharing" : "workflow",
+  "script" : "if ((id == void) || (id == null) || id.equals(\"\")) {\n\tthrow new RunTimeException(\"port id must have a non-empty value\");\n}\n\nURL url = new URL (\"http://eutils.ncbi.nlm.nih.gov/entrez/eutils/efetch.fcgi?rettype=gbc&db=nucleotide&retmode=xml&id=\" + id);\n\nBufferedReader reader = new BufferedReader (new InputStreamReader(url.openStream()));\nStringWriter writer = new StringWriter();\n\nchar[] buffer = new char[1024];\n    while (true) {\n        int r = reader.read(buffer);\n        if (r <= 0) {\n            break;\n        }\n        writer.write(buffer, 0, r);\n    }\nreader.close();\noutputText = writer.toString();\n",
+  "localworkerName" : "net.sourceforge.taverna.scuflworkers.ncbi.NucleotideINSDSeqXMLWorker",
+  "inputPorts" : [ {
+    "name" : "id",
+    "depth" : 0,
+    "type" : "String"
+  } ],
+  "outputPorts" : [ {
+    "name" : "outputText",
+    "depth" : 0,
+    "granularDepth" : 0
+  } ],
+  "isAltered" : false
+}
\ No newline at end of file
diff --git a/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.ncbi.NucleotideTinySeqXMLWorker b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.ncbi.NucleotideTinySeqXMLWorker
new file mode 100644
index 0000000..aad694a
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.ncbi.NucleotideTinySeqXMLWorker
@@ -0,0 +1,45 @@
+<activity xmlns="http://taverna.sf.net/2008/xml/t2flow"><class>net.sf.taverna.t2.activities.localworker.LocalworkerActivity</class><inputMap /><outputMap><map from="outputText" to="outputText" /></outputMap><configBean encoding="xstream"><net.sf.taverna.t2.activities.localworker.LocalworkerActivityConfigurationBean xmlns="">

+  <script>if ((id == void) || (id == null) || id.equals("")) {

+	throw new RunTimeException("port id must have a non-empty value");

+}

+

+URL url = new URL ("http://eutils.ncbi.nlm.nih.gov/entrez/eutils/efetch.fcgi?rettype=fasta&amp;db=nucleotide&amp;retmode=xml&amp;id=" + id);

+

+BufferedReader reader = new BufferedReader (new InputStreamReader(url.openStream()));

+StringWriter writer = new StringWriter();

+

+char[] buffer = new char[1024];

+    while (true) {

+        int r = reader.read(buffer);

+        if (r &lt;= 0) {

+            break;

+        }

+        writer.write(buffer, 0, r);

+    }

+reader.close();

+outputText = writer.toString();

+</script>

+  <dependencies />

+  <inputs>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+      <handledReferenceSchemes />

+      <translatedElementType>java.lang.String</translatedElementType>

+      <allowsLiteralValues>true</allowsLiteralValues>

+      <name>id</name>

+      <depth>0</depth>

+      <mimeTypes>

+        <string>'text/plain'</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+  </inputs>

+  <outputs>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>

+      <granularDepth>0</granularDepth>

+      <name>outputText</name>

+      <depth>0</depth>

+      <mimeTypes>

+        <string>'text/plain'</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>

+  </outputs>

+</net.sf.taverna.t2.activities.localworker.LocalworkerActivityConfigurationBean></configBean></activity>
\ No newline at end of file
diff --git a/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.ncbi.NucleotideTinySeqXMLWorker.json b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.ncbi.NucleotideTinySeqXMLWorker.json
new file mode 100644
index 0000000..3867455
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.ncbi.NucleotideTinySeqXMLWorker.json
@@ -0,0 +1,16 @@
+{
+  "classLoaderSharing" : "workflow",
+  "script" : "if ((id == void) || (id == null) || id.equals(\"\")) {\n\tthrow new RunTimeException(\"port id must have a non-empty value\");\n}\n\nURL url = new URL (\"http://eutils.ncbi.nlm.nih.gov/entrez/eutils/efetch.fcgi?rettype=fasta&db=nucleotide&retmode=xml&id=\" + id);\n\nBufferedReader reader = new BufferedReader (new InputStreamReader(url.openStream()));\nStringWriter writer = new StringWriter();\n\nchar[] buffer = new char[1024];\n    while (true) {\n        int r = reader.read(buffer);\n        if (r <= 0) {\n            break;\n        }\n        writer.write(buffer, 0, r);\n    }\nreader.close();\noutputText = writer.toString();\n",
+  "localworkerName" : "net.sourceforge.taverna.scuflworkers.ncbi.NucleotideTinySeqXMLWorker",
+  "inputPorts" : [ {
+    "name" : "id",
+    "depth" : 0,
+    "type" : "String"
+  } ],
+  "outputPorts" : [ {
+    "name" : "outputText",
+    "depth" : 0,
+    "granularDepth" : 0
+  } ],
+  "isAltered" : false
+}
\ No newline at end of file
diff --git a/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.ncbi.ProteinFastaWorker b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.ncbi.ProteinFastaWorker
new file mode 100644
index 0000000..c07b04e
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.ncbi.ProteinFastaWorker
@@ -0,0 +1,45 @@
+<activity  xmlns="http://taverna.sf.net/2008/xml/t2flow"><class>net.sf.taverna.t2.activities.localworker.LocalworkerActivity</class><inputMap /><outputMap><map from="outputText" to="outputText" /></outputMap><configBean encoding="xstream"><net.sf.taverna.t2.activities.localworker.LocalworkerActivityConfigurationBean xmlns="">

+  <script>if ((id == void) || (id == null) || id.equals("")) {

+	throw new RunTimeException("port id must have a non-empty value");

+}

+

+URL url = new URL ("http://eutils.ncbi.nlm.nih.gov/entrez/eutils/efetch.fcgi?rettype=fasta&amp;db=protein&amp;retmode=text&amp;id=" + id);

+

+BufferedReader reader = new BufferedReader (new InputStreamReader(url.openStream()));

+StringWriter writer = new StringWriter();

+

+char[] buffer = new char[1024];

+    while (true) {

+        int r = reader.read(buffer);

+        if (r &lt;= 0) {

+            break;

+        }

+        writer.write(buffer, 0, r);

+    }

+reader.close();

+outputText = writer.toString();

+</script>

+  <dependencies />

+  <inputs>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+      <handledReferenceSchemes />

+      <translatedElementType>java.lang.String</translatedElementType>

+      <allowsLiteralValues>true</allowsLiteralValues>

+      <name>id</name>

+      <depth>0</depth>

+      <mimeTypes>

+        <string>'text/plain'</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+  </inputs>

+  <outputs>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>

+      <granularDepth>0</granularDepth>

+      <name>outputText</name>

+      <depth>0</depth>

+      <mimeTypes>

+        <string>'text/plain'</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>

+  </outputs>

+</net.sf.taverna.t2.activities.localworker.LocalworkerActivityConfigurationBean></configBean></activity>
\ No newline at end of file
diff --git a/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.ncbi.ProteinFastaWorker.json b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.ncbi.ProteinFastaWorker.json
new file mode 100644
index 0000000..fc5b181
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.ncbi.ProteinFastaWorker.json
@@ -0,0 +1,16 @@
+{
+  "classLoaderSharing" : "workflow",
+  "script" : "if ((id == void) || (id == null) || id.equals(\"\")) {\n\tthrow new RunTimeException(\"port id must have a non-empty value\");\n}\n\nURL url = new URL (\"http://eutils.ncbi.nlm.nih.gov/entrez/eutils/efetch.fcgi?rettype=fasta&db=protein&retmode=text&id=\" + id);\n\nBufferedReader reader = new BufferedReader (new InputStreamReader(url.openStream()));\nStringWriter writer = new StringWriter();\n\nchar[] buffer = new char[1024];\n    while (true) {\n        int r = reader.read(buffer);\n        if (r <= 0) {\n            break;\n        }\n        writer.write(buffer, 0, r);\n    }\nreader.close();\noutputText = writer.toString();\n",
+  "localworkerName" : "net.sourceforge.taverna.scuflworkers.ncbi.ProteinFastaWorker",
+  "inputPorts" : [ {
+    "name" : "id",
+    "depth" : 0,
+    "type" : "String"
+  } ],
+  "outputPorts" : [ {
+    "name" : "outputText",
+    "depth" : 0,
+    "granularDepth" : 0
+  } ],
+  "isAltered" : false
+}
\ No newline at end of file
diff --git a/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.ncbi.ProteinGBSeqWorker b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.ncbi.ProteinGBSeqWorker
new file mode 100644
index 0000000..bf85c2b
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.ncbi.ProteinGBSeqWorker
@@ -0,0 +1,45 @@
+<activity  xmlns="http://taverna.sf.net/2008/xml/t2flow"><class>net.sf.taverna.t2.activities.localworker.LocalworkerActivity</class><inputMap /><outputMap><map from="outputText" to="outputText" /></outputMap><configBean encoding="xstream"><net.sf.taverna.t2.activities.localworker.LocalworkerActivityConfigurationBean xmlns="">

+  <script>if ((id == void) || (id == null) || id.equals("")) {

+	throw new RunTimeException("port id must have a non-empty value");

+}

+

+URL url = new URL ("http://eutils.ncbi.nlm.nih.gov/entrez/eutils/efetch.fcgi?rettype=gb&amp;db=protein&amp;retmode=xml&amp;id=" + id);

+

+BufferedReader reader = new BufferedReader (new InputStreamReader(url.openStream()));

+StringWriter writer = new StringWriter();

+

+char[] buffer = new char[1024];

+    while (true) {

+        int r = reader.read(buffer);

+        if (r &lt;= 0) {

+            break;

+        }

+        writer.write(buffer, 0, r);

+    }

+reader.close();

+outputText = writer.toString();

+</script>

+  <dependencies />

+  <inputs>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+      <handledReferenceSchemes />

+      <translatedElementType>java.lang.String</translatedElementType>

+      <allowsLiteralValues>true</allowsLiteralValues>

+      <name>id</name>

+      <depth>0</depth>

+      <mimeTypes>

+        <string>'text/plain'</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+  </inputs>

+  <outputs>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>

+      <granularDepth>0</granularDepth>

+      <name>outputText</name>

+      <depth>0</depth>

+      <mimeTypes>

+        <string>'text/plain'</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>

+  </outputs>

+</net.sf.taverna.t2.activities.localworker.LocalworkerActivityConfigurationBean></configBean></activity>
\ No newline at end of file
diff --git a/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.ncbi.ProteinGBSeqWorker.json b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.ncbi.ProteinGBSeqWorker.json
new file mode 100644
index 0000000..160ce92
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.ncbi.ProteinGBSeqWorker.json
@@ -0,0 +1,16 @@
+{
+  "classLoaderSharing" : "workflow",
+  "script" : "if ((id == void) || (id == null) || id.equals(\"\")) {\n\tthrow new RunTimeException(\"port id must have a non-empty value\");\n}\n\nURL url = new URL (\"http://eutils.ncbi.nlm.nih.gov/entrez/eutils/efetch.fcgi?rettype=gb&db=protein&retmode=xml&id=\" + id);\n\nBufferedReader reader = new BufferedReader (new InputStreamReader(url.openStream()));\nStringWriter writer = new StringWriter();\n\nchar[] buffer = new char[1024];\n    while (true) {\n        int r = reader.read(buffer);\n        if (r <= 0) {\n            break;\n        }\n        writer.write(buffer, 0, r);\n    }\nreader.close();\noutputText = writer.toString();\n",
+  "localworkerName" : "net.sourceforge.taverna.scuflworkers.ncbi.ProteinGBSeqWorker",
+  "inputPorts" : [ {
+    "name" : "id",
+    "depth" : 0,
+    "type" : "String"
+  } ],
+  "outputPorts" : [ {
+    "name" : "outputText",
+    "depth" : 0,
+    "granularDepth" : 0
+  } ],
+  "isAltered" : false
+}
\ No newline at end of file
diff --git a/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.ncbi.ProteinINSDSeqXMLWorker b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.ncbi.ProteinINSDSeqXMLWorker
new file mode 100644
index 0000000..c82209f
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.ncbi.ProteinINSDSeqXMLWorker
@@ -0,0 +1,45 @@
+<activity  xmlns="http://taverna.sf.net/2008/xml/t2flow"><class>net.sf.taverna.t2.activities.localworker.LocalworkerActivity</class><inputMap /><outputMap><map from="outputText" to="outputText" /></outputMap><configBean encoding="xstream"><net.sf.taverna.t2.activities.localworker.LocalworkerActivityConfigurationBean xmlns="">

+  <script>if ((id == void) || (id == null) || id.equals("")) {

+	throw new RunTimeException("port id must have a non-empty value");

+}

+

+URL url = new URL ("http://eutils.ncbi.nlm.nih.gov/entrez/eutils/efetch.fcgi?rettype=gbc&amp;db=protein&amp;retmode=xml&amp;id=" + id);

+

+BufferedReader reader = new BufferedReader (new InputStreamReader(url.openStream()));

+StringWriter writer = new StringWriter();

+

+char[] buffer = new char[1024];

+    while (true) {

+        int r = reader.read(buffer);

+        if (r &lt;= 0) {

+            break;

+        }

+        writer.write(buffer, 0, r);

+    }

+reader.close();

+outputText = writer.toString();

+</script>

+  <dependencies />

+  <inputs>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+      <handledReferenceSchemes />

+      <translatedElementType>java.lang.String</translatedElementType>

+      <allowsLiteralValues>true</allowsLiteralValues>

+      <name>id</name>

+      <depth>0</depth>

+      <mimeTypes>

+        <string>'text/plain'</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+  </inputs>

+  <outputs>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>

+      <granularDepth>0</granularDepth>

+      <name>outputText</name>

+      <depth>0</depth>

+      <mimeTypes>

+        <string>'text/plain'</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>

+  </outputs>

+</net.sf.taverna.t2.activities.localworker.LocalworkerActivityConfigurationBean></configBean></activity>
\ No newline at end of file
diff --git a/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.ncbi.ProteinINSDSeqXMLWorker.json b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.ncbi.ProteinINSDSeqXMLWorker.json
new file mode 100644
index 0000000..6e36120
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.ncbi.ProteinINSDSeqXMLWorker.json
@@ -0,0 +1,16 @@
+{
+  "classLoaderSharing" : "workflow",
+  "script" : "if ((id == void) || (id == null) || id.equals(\"\")) {\n\tthrow new RunTimeException(\"port id must have a non-empty value\");\n}\n\nURL url = new URL (\"http://eutils.ncbi.nlm.nih.gov/entrez/eutils/efetch.fcgi?rettype=gbc&db=protein&retmode=xml&id=\" + id);\n\nBufferedReader reader = new BufferedReader (new InputStreamReader(url.openStream()));\nStringWriter writer = new StringWriter();\n\nchar[] buffer = new char[1024];\n    while (true) {\n        int r = reader.read(buffer);\n        if (r <= 0) {\n            break;\n        }\n        writer.write(buffer, 0, r);\n    }\nreader.close();\noutputText = writer.toString();\n",
+  "localworkerName" : "net.sourceforge.taverna.scuflworkers.ncbi.ProteinINSDSeqXMLWorker",
+  "inputPorts" : [ {
+    "name" : "id",
+    "depth" : 0,
+    "type" : "String"
+  } ],
+  "outputPorts" : [ {
+    "name" : "outputText",
+    "depth" : 0,
+    "granularDepth" : 0
+  } ],
+  "isAltered" : false
+}
\ No newline at end of file
diff --git a/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.ncbi.ProteinTinySeqXMLWorker b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.ncbi.ProteinTinySeqXMLWorker
new file mode 100644
index 0000000..b6f9337
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.ncbi.ProteinTinySeqXMLWorker
@@ -0,0 +1,45 @@
+<activity xmlns="http://taverna.sf.net/2008/xml/t2flow"><class>net.sf.taverna.t2.activities.localworker.LocalworkerActivity</class><inputMap /><outputMap><map from="outputText" to="outputText" /></outputMap><configBean encoding="xstream"><net.sf.taverna.t2.activities.localworker.LocalworkerActivityConfigurationBean xmlns="">

+  <script>if ((id == void) || (id == null) || id.equals("")) {

+	throw new RunTimeException("port id must have a non-empty value");

+}

+

+URL url = new URL ("http://eutils.ncbi.nlm.nih.gov/entrez/eutils/efetch.fcgi?rettype=fasta&amp;db=protein&amp;retmode=xml&amp;id=" + id);

+

+BufferedReader reader = new BufferedReader (new InputStreamReader(url.openStream()));

+StringWriter writer = new StringWriter();

+

+char[] buffer = new char[1024];

+    while (true) {

+        int r = reader.read(buffer);

+        if (r &lt;= 0) {

+            break;

+        }

+        writer.write(buffer, 0, r);

+    }

+reader.close();

+outputText = writer.toString();

+</script>

+  <dependencies />

+  <inputs>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+      <handledReferenceSchemes />

+      <translatedElementType>java.lang.String</translatedElementType>

+      <allowsLiteralValues>true</allowsLiteralValues>

+      <name>id</name>

+      <depth>0</depth>

+      <mimeTypes>

+        <string>'text/plain'</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+  </inputs>

+  <outputs>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>

+      <granularDepth>0</granularDepth>

+      <name>outputText</name>

+      <depth>0</depth>

+      <mimeTypes>

+        <string>'text/plain'</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>

+  </outputs>

+</net.sf.taverna.t2.activities.localworker.LocalworkerActivityConfigurationBean></configBean></activity>
\ No newline at end of file
diff --git a/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.ncbi.ProteinTinySeqXMLWorker.json b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.ncbi.ProteinTinySeqXMLWorker.json
new file mode 100644
index 0000000..471e000
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.ncbi.ProteinTinySeqXMLWorker.json
@@ -0,0 +1,16 @@
+{
+  "classLoaderSharing" : "workflow",
+  "script" : "if ((id == void) || (id == null) || id.equals(\"\")) {\n\tthrow new RunTimeException(\"port id must have a non-empty value\");\n}\n\nURL url = new URL (\"http://eutils.ncbi.nlm.nih.gov/entrez/eutils/efetch.fcgi?rettype=fasta&db=protein&retmode=xml&id=\" + id);\n\nBufferedReader reader = new BufferedReader (new InputStreamReader(url.openStream()));\nStringWriter writer = new StringWriter();\n\nchar[] buffer = new char[1024];\n    while (true) {\n        int r = reader.read(buffer);\n        if (r <= 0) {\n            break;\n        }\n        writer.write(buffer, 0, r);\n    }\nreader.close();\noutputText = writer.toString();\n",
+  "localworkerName" : "net.sourceforge.taverna.scuflworkers.ncbi.ProteinTinySeqXMLWorker",
+  "inputPorts" : [ {
+    "name" : "id",
+    "depth" : 0,
+    "type" : "String"
+  } ],
+  "outputPorts" : [ {
+    "name" : "outputText",
+    "depth" : 0,
+    "granularDepth" : 0
+  } ],
+  "isAltered" : false
+}
\ No newline at end of file
diff --git a/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.ncbi.PubMedEFetchWorker b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.ncbi.PubMedEFetchWorker
new file mode 100644
index 0000000..71fef3c
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.ncbi.PubMedEFetchWorker
@@ -0,0 +1,68 @@
+<activity xmlns="http://taverna.sf.net/2008/xml/t2flow"><class>net.sf.taverna.t2.activities.localworker.LocalworkerActivity</class><inputMap /><outputMap><map from="outputText" to="outputText" /></outputMap><configBean encoding="xstream"><net.sf.taverna.t2.activities.localworker.LocalworkerActivityConfigurationBean xmlns="">

+  <script>if ((id == void) || (id == null) || id.equals("")) {

+	throw new RunTimeException("port id must have a non-empty value");

+}

+

+URL url = new URL ("http://eutils.ncbi.nlm.nih.gov/entrez/eutils/efetch.fcgi?db=pubmed" +

+"&amp;rettype=" + (((rettype == void ) || (rettype == null)) ? "full" : rettype) +

+"&amp;retmode=" + (((retmode == void) || (retmode == null)) ? "xml" : retmode) +

+"&amp;id=" + id);

+

+BufferedReader reader = new BufferedReader (new InputStreamReader(url.openStream()));

+StringWriter writer = new StringWriter();

+

+char[] buffer = new char[1024];

+    while (true) {

+        int r = reader.read(buffer);

+        if (r &lt;= 0) {

+            break;

+        }

+        writer.write(buffer, 0, r);

+    }

+reader.close();

+outputText = writer.toString();

+</script>

+  <dependencies />

+  <inputs>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+      <handledReferenceSchemes />

+      <translatedElementType>java.lang.String</translatedElementType>

+      <allowsLiteralValues>true</allowsLiteralValues>

+      <name>id</name>

+      <depth>0</depth>

+      <mimeTypes>

+        <string>'text/plain'</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+      <handledReferenceSchemes />

+      <translatedElementType>java.lang.String</translatedElementType>

+      <allowsLiteralValues>true</allowsLiteralValues>

+      <name>rettype</name>

+      <depth>0</depth>

+      <mimeTypes>

+        <string>'text/plain'</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+      <handledReferenceSchemes />

+      <translatedElementType>java.lang.String</translatedElementType>

+      <allowsLiteralValues>true</allowsLiteralValues>

+      <name>retmode</name>

+      <depth>0</depth>

+      <mimeTypes>

+        <string>'text/plain'</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+  </inputs>

+  <outputs>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>

+      <granularDepth>0</granularDepth>

+      <name>outputText</name>

+      <depth>0</depth>

+      <mimeTypes>

+        <string>'text/plain'</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>

+  </outputs>

+</net.sf.taverna.t2.activities.localworker.LocalworkerActivityConfigurationBean></configBean></activity>
\ No newline at end of file
diff --git a/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.ncbi.PubMedEFetchWorker.json b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.ncbi.PubMedEFetchWorker.json
new file mode 100644
index 0000000..5e2a7df
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.ncbi.PubMedEFetchWorker.json
@@ -0,0 +1,24 @@
+{
+  "classLoaderSharing" : "workflow",
+  "script" : "if ((id == void) || (id == null) || id.equals(\"\")) {\n\tthrow new RunTimeException(\"port id must have a non-empty value\");\n}\n\nURL url = new URL (\"http://eutils.ncbi.nlm.nih.gov/entrez/eutils/efetch.fcgi?db=pubmed\" +\n\"&rettype=\" + (((rettype == void ) || (rettype == null)) ? \"full\" : rettype) +\n\"&retmode=\" + (((retmode == void) || (retmode == null)) ? \"xml\" : retmode) +\n\"&id=\" + id);\n\nBufferedReader reader = new BufferedReader (new InputStreamReader(url.openStream()));\nStringWriter writer = new StringWriter();\n\nchar[] buffer = new char[1024];\n    while (true) {\n        int r = reader.read(buffer);\n        if (r <= 0) {\n            break;\n        }\n        writer.write(buffer, 0, r);\n    }\nreader.close();\noutputText = writer.toString();\n",
+  "localworkerName" : "net.sourceforge.taverna.scuflworkers.ncbi.PubMedEFetchWorker",
+  "inputPorts" : [ {
+    "name" : "id",
+    "depth" : 0,
+    "type" : "String"
+  }, {
+    "name" : "rettype",
+    "depth" : 0,
+    "type" : "String"
+  }, {
+    "name" : "retmode",
+    "depth" : 0,
+    "type" : "String"
+  } ],
+  "outputPorts" : [ {
+    "name" : "outputText",
+    "depth" : 0,
+    "granularDepth" : 0
+  } ],
+  "isAltered" : false
+}
\ No newline at end of file
diff --git a/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.ncbi.PubMedESearchWorker b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.ncbi.PubMedESearchWorker
new file mode 100644
index 0000000..37c440c
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.ncbi.PubMedESearchWorker
@@ -0,0 +1,124 @@
+<activity xmlns="http://taverna.sf.net/2008/xml/t2flow"><class>net.sf.taverna.t2.activities.localworker.LocalworkerActivity</class><inputMap /><outputMap><map from="outputText" to="outputText" /></outputMap><configBean encoding="xstream"><net.sf.taverna.t2.activities.localworker.LocalworkerActivityConfigurationBean xmlns="">

+  <script>if ((term == void) || (term == null) || term.equals("")) {

+	throw new RunTimeException("port term must have a non-empty value");

+}

+

+URL url = new URL ("http://eutils.ncbi.nlm.nih.gov/entrez/eutils/esearch.fcgi?db=pubmed" +

+(field == void ? "" : ("&amp;field=" + field)) +

+(retstart == void ? "" : ("&amp;retstart=" + retstart)) +

+(retmax == void ? "" : ("&amp;retmax=" + retmax)) +

+(mindate == void ? "" : ("&amp;mindate=" + mindate)) +

+(maxdate == void ? "" : ("&amp;maxdate=" + maxdate)) +

+"&amp;rettype=" + (rettype == void ? "full" : rettype) +

+"&amp;retmode=" + (retmode == void ? "xml" : retmode) +

+"&amp;tool=taverna" +

+"&amp;term=" + term);

+

+BufferedReader reader = new BufferedReader (new InputStreamReader(url.openStream()));

+StringWriter writer = new StringWriter();

+

+char[] buffer = new char[1024];

+    while (true) {

+        int r = reader.read(buffer);

+        if (r &lt;= 0) {

+            break;

+        }

+        writer.write(buffer, 0, r);

+    }

+reader.close();

+outputText = writer.toString();

+</script>

+  <dependencies />

+  <inputs>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+      <handledReferenceSchemes />

+      <translatedElementType>java.lang.String</translatedElementType>

+      <allowsLiteralValues>true</allowsLiteralValues>

+      <name>term</name>

+      <depth>0</depth>

+      <mimeTypes>

+        <string>'text/plain'</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+      <handledReferenceSchemes />

+      <translatedElementType>java.lang.String</translatedElementType>

+      <allowsLiteralValues>true</allowsLiteralValues>

+      <name>db</name>

+      <depth>0</depth>

+      <mimeTypes>

+        <string>'text/plain'</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+      <handledReferenceSchemes />

+      <translatedElementType>java.lang.String</translatedElementType>

+      <allowsLiteralValues>true</allowsLiteralValues>

+      <name>field</name>

+      <depth>0</depth>

+      <mimeTypes>

+        <string>'text/plain'</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+      <handledReferenceSchemes />

+      <translatedElementType>java.lang.String</translatedElementType>

+      <allowsLiteralValues>true</allowsLiteralValues>

+      <name>retstart</name>

+      <depth>0</depth>

+      <mimeTypes>

+        <string>'text/plain'</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+      <handledReferenceSchemes />

+      <translatedElementType>java.lang.String</translatedElementType>

+      <allowsLiteralValues>true</allowsLiteralValues>

+      <name>retmax</name>

+      <depth>0</depth>

+      <mimeTypes>

+        <string>'text/plain'</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+      <handledReferenceSchemes />

+      <translatedElementType>java.lang.String</translatedElementType>

+      <allowsLiteralValues>true</allowsLiteralValues>

+      <name>mindate</name>

+      <depth>0</depth>

+      <mimeTypes>

+        <string>'text/plain'</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+      <handledReferenceSchemes />

+      <translatedElementType>java.lang.String</translatedElementType>

+      <allowsLiteralValues>true</allowsLiteralValues>

+      <name>maxdate</name>

+      <depth>0</depth>

+      <mimeTypes>

+        <string>'text/plain'</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+      <handledReferenceSchemes />

+      <translatedElementType>java.lang.String</translatedElementType>

+      <allowsLiteralValues>true</allowsLiteralValues>

+      <name>rettype</name>

+      <depth>0</depth>

+      <mimeTypes>

+        <string>'text/plain'</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+  </inputs>

+  <outputs>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>

+      <granularDepth>0</granularDepth>

+      <name>outputText</name>

+      <depth>0</depth>

+      <mimeTypes>

+        <string>'text/plain'</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>

+  </outputs>

+</net.sf.taverna.t2.activities.localworker.LocalworkerActivityConfigurationBean></configBean></activity>
\ No newline at end of file
diff --git a/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.ncbi.PubMedESearchWorker.json b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.ncbi.PubMedESearchWorker.json
new file mode 100644
index 0000000..bd29f82
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.ncbi.PubMedESearchWorker.json
@@ -0,0 +1,44 @@
+{
+  "classLoaderSharing" : "workflow",
+  "script" : "if ((term == void) || (term == null) || term.equals(\"\")) {\n\tthrow new RunTimeException(\"port term must have a non-empty value\");\n}\n\nURL url = new URL (\"http://eutils.ncbi.nlm.nih.gov/entrez/eutils/esearch.fcgi?db=pubmed\" +\n(field == void ? \"\" : (\"&field=\" + field)) +\n(retstart == void ? \"\" : (\"&retstart=\" + retstart)) +\n(retmax == void ? \"\" : (\"&retmax=\" + retmax)) +\n(mindate == void ? \"\" : (\"&mindate=\" + mindate)) +\n(maxdate == void ? \"\" : (\"&maxdate=\" + maxdate)) +\n\"&rettype=\" + (rettype == void ? \"full\" : rettype) +\n\"&retmode=\" + (retmode == void ? \"xml\" : retmode) +\n\"&tool=taverna\" +\n\"&term=\" + term);\n\nBufferedReader reader = new BufferedReader (new InputStreamReader(url.openStream()));\nStringWriter writer = new StringWriter();\n\nchar[] buffer = new char[1024];\n    while (true) {\n        int r = reader.read(buffer);\n        if (r <= 0) {\n            break;\n        }\n        writer.write(buffer, 0, r);\n    }\nreader.close();\noutputText = writer.toString();\n",
+  "localworkerName" : "net.sourceforge.taverna.scuflworkers.ncbi.PubMedESearchWorker",
+  "inputPorts" : [ {
+    "name" : "term",
+    "depth" : 0,
+    "type" : "String"
+  }, {
+    "name" : "db",
+    "depth" : 0,
+    "type" : "String"
+  }, {
+    "name" : "field",
+    "depth" : 0,
+    "type" : "String"
+  }, {
+    "name" : "retstart",
+    "depth" : 0,
+    "type" : "String"
+  }, {
+    "name" : "retmax",
+    "depth" : 0,
+    "type" : "String"
+  }, {
+    "name" : "mindate",
+    "depth" : 0,
+    "type" : "String"
+  }, {
+    "name" : "maxdate",
+    "depth" : 0,
+    "type" : "String"
+  }, {
+    "name" : "rettype",
+    "depth" : 0,
+    "type" : "String"
+  } ],
+  "outputPorts" : [ {
+    "name" : "outputText",
+    "depth" : 0,
+    "granularDepth" : 0
+  } ],
+  "isAltered" : false
+}
\ No newline at end of file
diff --git a/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.net.BrowseUrl b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.net.BrowseUrl
new file mode 100644
index 0000000..a2317c5
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.net.BrowseUrl
@@ -0,0 +1,31 @@
+<activity xmlns="http://taverna.sf.net/2008/xml/t2flow"><class>net.sf.taverna.t2.activities.localworker.LocalworkerActivity</class><inputMap /><outputMap /><configBean encoding="xstream"><net.sf.taverna.t2.activities.localworker.LocalworkerActivityConfigurationBean xmlns="">

+  <inputs>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+      <name>url</name>

+      <depth>0</depth>

+      <mimeTypes>

+        <string>text/plain</string>

+      </mimeTypes>

+      <handledReferenceSchemes />

+      <translatedElementType>java.lang.String</translatedElementType>

+      <allowsLiteralValues>true</allowsLiteralValues>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+  </inputs>

+  <outputs />

+  <classLoaderSharing>workflow</classLoaderSharing>

+  <localDependencies />

+  <artifactDependencies />

+  <script>import java.awt.Desktop;

+import java.net.URI;

+

+if ((url == void) || (url == null)) {

+	throw new RuntimeException("Url must be specified");

+}

+

+URI uri = null;

+

+uri = new URI(url);

+

+Desktop.getDesktop().browse(uri);</script>

+  <dependencies />

+</net.sf.taverna.t2.activities.localworker.LocalworkerActivityConfigurationBean></configBean><annotations /></activity>
\ No newline at end of file
diff --git a/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.net.BrowseUrl.json b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.net.BrowseUrl.json
new file mode 100644
index 0000000..1a2155e
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.net.BrowseUrl.json
@@ -0,0 +1,11 @@
+{
+  "classLoaderSharing" : "workflow",
+  "script" : "import java.awt.Desktop;\nimport java.net.URI;\n\nif ((url == void) || (url == null)) {\n\tthrow new RuntimeException(\"Url must be specified\");\n}\n\nURI uri = null;\n\nuri = new URI(url);\n\nDesktop.getDesktop().browse(uri);",
+  "localworkerName" : "net.sourceforge.taverna.scuflworkers.net.BrowseUrl",
+  "inputPorts" : [ {
+    "name" : "url",
+    "depth" : 0,
+    "type" : "String"
+  } ],
+  "isAltered" : false
+}
\ No newline at end of file
diff --git a/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.net.ExtractHeader b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.net.ExtractHeader
new file mode 100644
index 0000000..d3149d6
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.net.ExtractHeader
@@ -0,0 +1,55 @@
+<activity xmlns="http://taverna.sf.net/2008/xml/t2flow"><class>net.sf.taverna.t2.activities.localworker.LocalworkerActivity</class><inputMap /><outputMap /><configBean encoding="xstream"><net.sf.taverna.t2.activities.localworker.LocalworkerActivityConfigurationBean xmlns="">
+  <inputs>
+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>
+      <name>headers</name>
+      <depth>1</depth>
+      <mimeTypes>
+        <string>text/plain</string>
+      </mimeTypes>
+      <handledReferenceSchemes />
+      <translatedElementType>java.lang.String</translatedElementType>
+      <allowsLiteralValues>true</allowsLiteralValues>
+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>
+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>
+      <name>header_key</name>
+      <depth>0</depth>
+      <mimeTypes>
+        <string>text/plain</string>
+      </mimeTypes>
+      <handledReferenceSchemes />
+      <translatedElementType>java.lang.String</translatedElementType>
+      <allowsLiteralValues>true</allowsLiteralValues>
+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>
+  </inputs>
+  <outputs>
+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>
+      <name>header_value</name>
+      <depth>0</depth>
+      <mimeTypes />
+      <granularDepth>0</granularDepth>
+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>
+  </outputs>
+  <classLoaderSharing>workflow</classLoaderSharing>
+  <localDependencies />
+  <artifactDependencies />
+  <script>if ((headers == void) || (headers == null)) {
+	throw new RuntimeException("Headers must be specified");
+}
+
+if ((header_key == void) || (header_key == null)) {
+	throw new RuntimeException("Header_key must be specified");
+}
+
+String header_value = "";
+if (!header_key.endsWith(":")) {
+	header_key += ":";
+}
+for (String h : headers) {
+	if (h.startsWith(header_key)) {
+		header_value = h.substring(header_key.length());
+		header_value = header_value.trim();
+		break;
+	}
+}</script>
+  <dependencies />
+</net.sf.taverna.t2.activities.localworker.LocalworkerActivityConfigurationBean></configBean><annotations /></activity>
\ No newline at end of file
diff --git a/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.net.ExtractHeader.json b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.net.ExtractHeader.json
new file mode 100644
index 0000000..0e510fa
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.net.ExtractHeader.json
@@ -0,0 +1,20 @@
+{
+  "classLoaderSharing" : "workflow",
+  "script" : "if ((headers == void) || (headers == null)) {\n\tthrow new RuntimeException(\"Headers must be specified\");\n}\n\nif ((header_key == void) || (header_key == null)) {\n\tthrow new RuntimeException(\"Header_key must be specified\");\n}\n\nString header_value = \"\";\nif (!header_key.endsWith(\":\")) {\n\theader_key += \":\";\n}\nfor (String h : headers) {\n\tif (h.startsWith(header_key)) {\n\t\theader_value = h.substring(header_key.length());\n\t\theader_value = header_value.trim();\n\t\tbreak;\n\t}\n}",
+  "localworkerName" : "net.sourceforge.taverna.scuflworkers.net.ExtractHeader",
+  "inputPorts" : [ {
+    "name" : "headers",
+    "depth" : 1,
+    "type" : "String"
+  }, {
+    "name" : "header_key",
+    "depth" : 0,
+    "type" : "String"
+  } ],
+  "outputPorts" : [ {
+    "name" : "header_value",
+    "depth" : 0,
+    "granularDepth" : 0
+  } ],
+  "isAltered" : false
+}
\ No newline at end of file
diff --git a/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.ui.AskWorker b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.ui.AskWorker
new file mode 100644
index 0000000..f094efa
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.ui.AskWorker
@@ -0,0 +1,41 @@
+<activity xmlns="http://taverna.sf.net/2008/xml/t2flow"><class>net.sf.taverna.t2.activities.localworker.LocalworkerActivity</class><inputMap /><outputMap /><configBean encoding="xstream"><net.sf.taverna.t2.activities.localworker.LocalworkerActivityConfigurationBean xmlns="">

+  <script>import javax.swing.JOptionPane;

+

+answer = JOptionPane.showInputDialog(null, (message == void ? null : message), (title == void ? null : title), JOptionPane.QUESTION_MESSAGE);

+

+

+</script>

+  <dependencies />

+  <inputs>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+      <handledReferenceSchemes />

+      <translatedElementType>java.lang.String</translatedElementType>

+      <allowsLiteralValues>true</allowsLiteralValues>

+      <name>title</name>

+      <depth>0</depth>

+      <mimeTypes>

+        <string>'text/plain'</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+      <handledReferenceSchemes />

+      <translatedElementType>java.lang.String</translatedElementType>

+      <allowsLiteralValues>true</allowsLiteralValues>

+      <name>message</name>

+      <depth>0</depth>

+      <mimeTypes>

+        <string>'text/plain'</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+  </inputs>

+  <outputs>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>

+      <granularDepth>0</granularDepth>

+      <name>answer</name>

+      <depth>0</depth>

+      <mimeTypes>

+        <string>'text/plain'</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>

+  </outputs>

+</net.sf.taverna.t2.activities.localworker.LocalworkerActivityConfigurationBean></configBean></activity>
\ No newline at end of file
diff --git a/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.ui.AskWorker.json b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.ui.AskWorker.json
new file mode 100644
index 0000000..c2095cc
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.ui.AskWorker.json
@@ -0,0 +1,20 @@
+{
+  "classLoaderSharing" : "workflow",
+  "script" : "import javax.swing.JOptionPane;\n\nanswer = JOptionPane.showInputDialog(null, (message == void ? null : message), (title == void ? null : title), JOptionPane.QUESTION_MESSAGE);\n\n\n",
+  "localworkerName" : "net.sourceforge.taverna.scuflworkers.ui.AskWorker",
+  "inputPorts" : [ {
+    "name" : "title",
+    "depth" : 0,
+    "type" : "String"
+  }, {
+    "name" : "message",
+    "depth" : 0,
+    "type" : "String"
+  } ],
+  "outputPorts" : [ {
+    "name" : "answer",
+    "depth" : 0,
+    "granularDepth" : 0
+  } ],
+  "isAltered" : false
+}
\ No newline at end of file
diff --git a/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.ui.ChooseWorker b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.ui.ChooseWorker
new file mode 100644
index 0000000..5244d77
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.ui.ChooseWorker
@@ -0,0 +1,80 @@
+<activity xmlns="http://taverna.sf.net/2008/xml/t2flow"><class>net.sf.taverna.t2.activities.localworker.LocalworkerActivity</class><inputMap /><outputMap /><configBean encoding="xstream"><net.sf.taverna.t2.activities.localworker.LocalworkerActivityConfigurationBean xmlns="">

+  <script>import javax.swing.BoxLayout;

+import javax.swing.ButtonGroup;

+import javax.swing.JLabel;

+import javax.swing.JOptionPane;

+import javax.swing.JPanel;

+import javax.swing.JRadioButton;

+

+if ((selectionValues == void) || (selectionValues == null) || (selectionValues.isEmpty())) {

+    throw new RuntimeException("selectionValues must be specified and non-empty");

+}

+

+ButtonGroup group = new ButtonGroup();

+JPanel messagePanel = new JPanel();

+messagePanel.setLayout(new BoxLayout(messagePanel,BoxLayout.Y_AXIS));

+

+messagePanel.add(new JLabel((message == void ? null : message)));

+		

+JRadioButton[] buttonArray = new JRadioButton[selectionValues.size()];

+for (int i = 0; i &lt; buttonArray.length; i++) {			

+	buttonArray[i] = new JRadioButton(selectionValues.get(i));

+	if (i==0) buttonArray[i].setSelected(true);

+	group.add(buttonArray[i]);

+	messagePanel.add(buttonArray[i]);

+}				

+

+JOptionPane.showOptionDialog(null, messagePanel, (title == void ? null : title),

+		JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, null, new Object[]{"OK"}, null);

+		

+String answer="";

+for (JRadioButton button : buttonArray) {

+	if (button.isSelected()) {

+		answer=button.getText();

+	}

+}

+</script>

+  <dependencies />

+  <inputs>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+      <handledReferenceSchemes />

+      <translatedElementType>java.lang.String</translatedElementType>

+      <allowsLiteralValues>true</allowsLiteralValues>

+      <name>title</name>

+      <depth>0</depth>

+      <mimeTypes>

+        <string>'text/plain'</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+      <handledReferenceSchemes />

+      <translatedElementType>java.lang.String</translatedElementType>

+      <allowsLiteralValues>true</allowsLiteralValues>

+      <name>message</name>

+      <depth>0</depth>

+      <mimeTypes>

+        <string>'text/plain'</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+      <handledReferenceSchemes />

+      <translatedElementType>java.lang.String</translatedElementType>

+      <allowsLiteralValues>true</allowsLiteralValues>

+      <name>selectionValues</name>

+      <depth>1</depth>

+      <mimeTypes>

+        <string>l('text/plain')</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+  </inputs>

+  <outputs>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>

+      <granularDepth>0</granularDepth>

+      <name>answer</name>

+      <depth>0</depth>

+      <mimeTypes>

+        <string>'text/plain'</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>

+  </outputs>

+</net.sf.taverna.t2.activities.localworker.LocalworkerActivityConfigurationBean></configBean></activity>
\ No newline at end of file
diff --git a/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.ui.ChooseWorker.json b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.ui.ChooseWorker.json
new file mode 100644
index 0000000..0410fc7
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.ui.ChooseWorker.json
@@ -0,0 +1,24 @@
+{
+  "classLoaderSharing" : "workflow",
+  "script" : "import javax.swing.BoxLayout;\nimport javax.swing.ButtonGroup;\nimport javax.swing.JLabel;\nimport javax.swing.JOptionPane;\nimport javax.swing.JPanel;\nimport javax.swing.JRadioButton;\n\nif ((selectionValues == void) || (selectionValues == null) || (selectionValues.isEmpty())) {\n    throw new RuntimeException(\"selectionValues must be specified and non-empty\");\n}\n\nButtonGroup group = new ButtonGroup();\nJPanel messagePanel = new JPanel();\nmessagePanel.setLayout(new BoxLayout(messagePanel,BoxLayout.Y_AXIS));\n\nmessagePanel.add(new JLabel((message == void ? null : message)));\n\t\t\nJRadioButton[] buttonArray = new JRadioButton[selectionValues.size()];\nfor (int i = 0; i < buttonArray.length; i++) {\t\t\t\n\tbuttonArray[i] = new JRadioButton(selectionValues.get(i));\n\tif (i==0) buttonArray[i].setSelected(true);\n\tgroup.add(buttonArray[i]);\n\tmessagePanel.add(buttonArray[i]);\n}\t\t\t\t\n\nJOptionPane.showOptionDialog(null, messagePanel, (title == void ? null : title),\n\t\tJOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, null, new Object[]{\"OK\"}, null);\n\t\t\nString answer=\"\";\nfor (JRadioButton button : buttonArray) {\n\tif (button.isSelected()) {\n\t\tanswer=button.getText();\n\t}\n}\n",
+  "localworkerName" : "net.sourceforge.taverna.scuflworkers.ui.ChooseWorker",
+  "inputPorts" : [ {
+    "name" : "title",
+    "depth" : 0,
+    "type" : "String"
+  }, {
+    "name" : "message",
+    "depth" : 0,
+    "type" : "String"
+  }, {
+    "name" : "selectionValues",
+    "depth" : 1,
+    "type" : "String"
+  } ],
+  "outputPorts" : [ {
+    "name" : "answer",
+    "depth" : 0,
+    "granularDepth" : 0
+  } ],
+  "isAltered" : false
+}
\ No newline at end of file
diff --git a/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.ui.SelectFileWorker b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.ui.SelectFileWorker
new file mode 100644
index 0000000..e594b7f
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.ui.SelectFileWorker
@@ -0,0 +1,116 @@
+<activity xmlns="http://taverna.sf.net/2008/xml/t2flow"><class>net.sf.taverna.t2.activities.localworker.LocalworkerActivity</class><inputMap /><outputMap /><configBean encoding="xstream"><net.sf.taverna.t2.activities.localworker.LocalworkerActivityConfigurationBean xmlns="">

+  <script>import java.awt.CardLayout;

+import java.awt.Image;

+import java.awt.Toolkit;

+import java.io.File;

+import java.util.HashMap;

+import java.util.Map;

+

+import javax.swing.ImageIcon;

+import javax.swing.JEditorPane;

+import javax.swing.JFileChooser;

+import javax.swing.JLabel;

+import javax.swing.JPanel;

+import javax.swing.filechooser.FileFilter;

+

+class FileExtFilter extends FileFilter {

+

+	public FileExtFilter(String ext, String label, boolean includeDir) {

+		this.ext = ext;

+		this.label = label;

+		this.includeDir = includeDir;

+	}

+

+	public String getDescription() {

+		return this.label;

+	}

+

+	public boolean accept(File file) {

+		if (file.isDirectory() &amp;&amp; includeDir) {

+			return true;

+		} else {

+			return file.getName().endsWith(this.ext);

+		}

+	}

+

+	String ext, label;

+

+	boolean includeDir;

+}

+

+if (title == void) {

+	title = null;

+}

+

+if ((fileExtensions == void) || (fileExtensions == null)) {

+	fileExtensions = "";

+}

+

+if ((fileExtLabels == void) || (fileExtLabels == null)) {

+	fileExtLabels = "";

+}

+

+JFileChooser chooser = new JFileChooser();

+chooser.setDialogTitle(title);

+

+String[] fileTypeList = fileExtensions.split(",");

+String[] filterLabelList = fileExtLabels.split(",");

+

+if (fileTypeList != null &amp;&amp; filterLabelList != null &amp;&amp; fileTypeList.length != filterLabelList.length) {

+	throw new RuntimeException("The list of extensions and file filter labels must be the same length");

+}

+

+// create the file filters

+for (int i = 0; i &lt; fileTypeList.length; i++) {

+	FileExtFilter filter = new FileExtFilter(fileTypeList[i], filterLabelList[i], true);

+	chooser.setFileFilter(filter);

+}

+

+chooser.showOpenDialog(null);

+File file = chooser.getSelectedFile();

+selectedFile = file.getAbsolutePath();

+</script>

+  <dependencies />

+  <inputs>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+      <handledReferenceSchemes />

+      <translatedElementType>java.lang.String</translatedElementType>

+      <allowsLiteralValues>true</allowsLiteralValues>

+      <name>title</name>

+      <depth>0</depth>

+      <mimeTypes>

+        <string>'text/plain'</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+      <handledReferenceSchemes />

+      <translatedElementType>java.lang.String</translatedElementType>

+      <allowsLiteralValues>true</allowsLiteralValues>

+      <name>fileExtensions</name>

+      <depth>0</depth>

+      <mimeTypes>

+        <string>'text/plain'</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+      <handledReferenceSchemes />

+      <translatedElementType>java.lang.String</translatedElementType>

+      <allowsLiteralValues>true</allowsLiteralValues>

+      <name>fileExtLabels</name>

+      <depth>0</depth>

+      <mimeTypes>

+        <string>'text/plain'</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+  </inputs>

+  <outputs>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>

+      <granularDepth>0</granularDepth>

+      <name>selectedFile</name>

+      <depth>0</depth>

+      <mimeTypes>

+        <string>'text/plain'</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>

+  </outputs>

+</net.sf.taverna.t2.activities.localworker.LocalworkerActivityConfigurationBean></configBean></activity>
\ No newline at end of file
diff --git a/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.ui.SelectFileWorker.json b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.ui.SelectFileWorker.json
new file mode 100644
index 0000000..1d71cef
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.ui.SelectFileWorker.json
@@ -0,0 +1,24 @@
+{
+  "classLoaderSharing" : "workflow",
+  "script" : "import java.awt.CardLayout;\nimport java.awt.Image;\nimport java.awt.Toolkit;\nimport java.io.File;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport javax.swing.ImageIcon;\nimport javax.swing.JEditorPane;\nimport javax.swing.JFileChooser;\nimport javax.swing.JLabel;\nimport javax.swing.JPanel;\nimport javax.swing.filechooser.FileFilter;\n\nclass FileExtFilter extends FileFilter {\n\n\tpublic FileExtFilter(String ext, String label, boolean includeDir) {\n\t\tthis.ext = ext;\n\t\tthis.label = label;\n\t\tthis.includeDir = includeDir;\n\t}\n\n\tpublic String getDescription() {\n\t\treturn this.label;\n\t}\n\n\tpublic boolean accept(File file) {\n\t\tif (file.isDirectory() && includeDir) {\n\t\t\treturn true;\n\t\t} else {\n\t\t\treturn file.getName().endsWith(this.ext);\n\t\t}\n\t}\n\n\tString ext, label;\n\n\tboolean includeDir;\n}\n\nif (title == void) {\n\ttitle = null;\n}\n\nif ((fileExtensions == void) || (fileExtensions == null)) {\n\tfileExtensions = \"\";\n}\n\nif ((fileExtLabels == void) || (fileExtLabels == null)) {\n\tfileExtLabels = \"\";\n}\n\nJFileChooser chooser = new JFileChooser();\nchooser.setDialogTitle(title);\n\nString[] fileTypeList = fileExtensions.split(\",\");\nString[] filterLabelList = fileExtLabels.split(\",\");\n\nif (fileTypeList != null && filterLabelList != null && fileTypeList.length != filterLabelList.length) {\n\tthrow new RuntimeException(\"The list of extensions and file filter labels must be the same length\");\n}\n\n// create the file filters\nfor (int i = 0; i < fileTypeList.length; i++) {\n\tFileExtFilter filter = new FileExtFilter(fileTypeList[i], filterLabelList[i], true);\n\tchooser.setFileFilter(filter);\n}\n\nchooser.showOpenDialog(null);\nFile file = chooser.getSelectedFile();\nselectedFile = file.getAbsolutePath();\n",
+  "localworkerName" : "net.sourceforge.taverna.scuflworkers.ui.SelectFileWorker",
+  "inputPorts" : [ {
+    "name" : "title",
+    "depth" : 0,
+    "type" : "String"
+  }, {
+    "name" : "fileExtensions",
+    "depth" : 0,
+    "type" : "String"
+  }, {
+    "name" : "fileExtLabels",
+    "depth" : 0,
+    "type" : "String"
+  } ],
+  "outputPorts" : [ {
+    "name" : "selectedFile",
+    "depth" : 0,
+    "granularDepth" : 0
+  } ],
+  "isAltered" : false
+}
\ No newline at end of file
diff --git a/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.ui.SelectWorker b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.ui.SelectWorker
new file mode 100644
index 0000000..1745844
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.ui.SelectWorker
@@ -0,0 +1,53 @@
+<activity xmlns="http://taverna.sf.net/2008/xml/t2flow"><class>net.sf.taverna.t2.activities.localworker.LocalworkerActivity</class><inputMap /><outputMap /><configBean encoding="xstream"><net.sf.taverna.t2.activities.localworker.LocalworkerActivityConfigurationBean xmlns="">

+  <script>import javax.swing.JOptionPane;

+

+if ((valueList == void) || (valueList == null) || (valueList.isEmpty())) {

+    throw new RuntimeException("valueList must be specified and non-empty");

+}

+

+answer = (String) JOptionPane.showInputDialog(null, (message == void ? null : message), (title == void ? null : title), JOptionPane.QUESTION_MESSAGE, null, valueList.toArray(), valueList.get(0));

+</script>

+  <dependencies />

+  <inputs>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+      <handledReferenceSchemes />

+      <translatedElementType>java.lang.String</translatedElementType>

+      <allowsLiteralValues>true</allowsLiteralValues>

+      <name>valueList</name>

+      <depth>1</depth>

+      <mimeTypes>

+        <string>l('text/plain')</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+      <handledReferenceSchemes />

+      <translatedElementType>java.lang.String</translatedElementType>

+      <allowsLiteralValues>true</allowsLiteralValues>

+      <name>message</name>

+      <depth>0</depth>

+      <mimeTypes>

+        <string>'text/plain'</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+      <handledReferenceSchemes />

+      <translatedElementType>java.lang.String</translatedElementType>

+      <allowsLiteralValues>true</allowsLiteralValues>

+      <name>title</name>

+      <depth>0</depth>

+      <mimeTypes>

+        <string>'text/plain'</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+  </inputs>

+  <outputs>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>

+      <granularDepth>0</granularDepth>

+      <name>answer</name>

+      <depth>0</depth>

+      <mimeTypes>

+        <string>'text/plain'</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>

+  </outputs>

+</net.sf.taverna.t2.activities.localworker.LocalworkerActivityConfigurationBean></configBean></activity>
\ No newline at end of file
diff --git a/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.ui.SelectWorker.json b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.ui.SelectWorker.json
new file mode 100644
index 0000000..6c287b6
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.ui.SelectWorker.json
@@ -0,0 +1,24 @@
+{
+  "classLoaderSharing" : "workflow",
+  "script" : "import javax.swing.JOptionPane;\n\nif ((valueList == void) || (valueList == null) || (valueList.isEmpty())) {\n    throw new RuntimeException(\"valueList must be specified and non-empty\");\n}\n\nanswer = (String) JOptionPane.showInputDialog(null, (message == void ? null : message), (title == void ? null : title), JOptionPane.QUESTION_MESSAGE, null, valueList.toArray(), valueList.get(0));\n",
+  "localworkerName" : "net.sourceforge.taverna.scuflworkers.ui.SelectWorker",
+  "inputPorts" : [ {
+    "name" : "valueList",
+    "depth" : 1,
+    "type" : "String"
+  }, {
+    "name" : "message",
+    "depth" : 0,
+    "type" : "String"
+  }, {
+    "name" : "title",
+    "depth" : 0,
+    "type" : "String"
+  } ],
+  "outputPorts" : [ {
+    "name" : "answer",
+    "depth" : 0,
+    "granularDepth" : 0
+  } ],
+  "isAltered" : false
+}
\ No newline at end of file
diff --git a/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.ui.TellWorker b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.ui.TellWorker
new file mode 100644
index 0000000..99ee6ab
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.ui.TellWorker
@@ -0,0 +1,42 @@
+<activity xmlns="http://taverna.sf.net/2008/xml/t2flow"><class>net.sf.taverna.t2.activities.localworker.LocalworkerActivity</class><inputMap /><outputMap /><configBean encoding="xstream"><net.sf.taverna.t2.activities.localworker.LocalworkerActivityConfigurationBean xmlns="">

+  <script>import javax.swing.JOptionPane;

+

+JOptionPane.showMessageDialog(null, (message == void ? null : message), (title == void ? null : title),	JOptionPane.INFORMATION_MESSAGE);

+

+answer = "answer";

+

+</script>

+  <dependencies />

+  <inputs>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+      <handledReferenceSchemes />

+      <translatedElementType>java.lang.String</translatedElementType>

+      <allowsLiteralValues>true</allowsLiteralValues>

+      <name>title</name>

+      <depth>0</depth>

+      <mimeTypes>

+        <string>'text/plain'</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+      <handledReferenceSchemes />

+      <translatedElementType>java.lang.String</translatedElementType>

+      <allowsLiteralValues>true</allowsLiteralValues>

+      <name>message</name>

+      <depth>0</depth>

+      <mimeTypes>

+        <string>'text/plain'</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+  </inputs>

+  <outputs>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>

+      <granularDepth>0</granularDepth>

+      <name>answer</name>

+      <depth>0</depth>

+      <mimeTypes>

+        <string>'text/plain'</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>

+  </outputs>

+</net.sf.taverna.t2.activities.localworker.LocalworkerActivityConfigurationBean></configBean></activity>
\ No newline at end of file
diff --git a/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.ui.TellWorker.json b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.ui.TellWorker.json
new file mode 100644
index 0000000..8037a42
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.ui.TellWorker.json
@@ -0,0 +1,20 @@
+{
+  "classLoaderSharing" : "workflow",
+  "script" : "import javax.swing.JOptionPane;\n\nJOptionPane.showMessageDialog(null, (message == void ? null : message), (title == void ? null : title),\tJOptionPane.INFORMATION_MESSAGE);\n\nanswer = \"answer\";\n\n",
+  "localworkerName" : "net.sourceforge.taverna.scuflworkers.ui.TellWorker",
+  "inputPorts" : [ {
+    "name" : "title",
+    "depth" : 0,
+    "type" : "String"
+  }, {
+    "name" : "message",
+    "depth" : 0,
+    "type" : "String"
+  } ],
+  "outputPorts" : [ {
+    "name" : "answer",
+    "depth" : 0,
+    "granularDepth" : 0
+  } ],
+  "isAltered" : false
+}
\ No newline at end of file
diff --git a/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.ui.WarnWorker b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.ui.WarnWorker
new file mode 100644
index 0000000..b211ba5
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.ui.WarnWorker
@@ -0,0 +1,42 @@
+<activity xmlns="http://taverna.sf.net/2008/xml/t2flow"><class>net.sf.taverna.t2.activities.localworker.LocalworkerActivity</class><inputMap /><outputMap /><configBean encoding="xstream"><net.sf.taverna.t2.activities.localworker.LocalworkerActivityConfigurationBean xmlns="">

+  <script>import javax.swing.JOptionPane;

+

+JOptionPane.showMessageDialog(null, (message == void ? null : message), (title == void ? null : title),	JOptionPane.WARNING_MESSAGE);

+

+answer = "answer";

+  

+</script>

+  <dependencies />

+  <inputs>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+      <handledReferenceSchemes />

+      <translatedElementType>java.lang.String</translatedElementType>

+      <allowsLiteralValues>true</allowsLiteralValues>

+      <name>title</name>

+      <depth>0</depth>

+      <mimeTypes>

+        <string>'text/plain'</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+      <handledReferenceSchemes />

+      <translatedElementType>java.lang.String</translatedElementType>

+      <allowsLiteralValues>true</allowsLiteralValues>

+      <name>message</name>

+      <depth>0</depth>

+      <mimeTypes>

+        <string>'text/plain'</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+  </inputs>

+  <outputs>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>

+      <granularDepth>0</granularDepth>

+      <name>answer</name>

+      <depth>0</depth>

+      <mimeTypes>

+        <string>'text/plain'</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>

+  </outputs>

+</net.sf.taverna.t2.activities.localworker.LocalworkerActivityConfigurationBean></configBean></activity>
\ No newline at end of file
diff --git a/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.ui.WarnWorker.json b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.ui.WarnWorker.json
new file mode 100644
index 0000000..eaa8c93
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.ui.WarnWorker.json
@@ -0,0 +1,20 @@
+{
+  "classLoaderSharing" : "workflow",
+  "script" : "import javax.swing.JOptionPane;\n\nJOptionPane.showMessageDialog(null, (message == void ? null : message), (title == void ? null : title),\tJOptionPane.WARNING_MESSAGE);\n\nanswer = \"answer\";\n  \n",
+  "localworkerName" : "net.sourceforge.taverna.scuflworkers.ui.WarnWorker",
+  "inputPorts" : [ {
+    "name" : "title",
+    "depth" : 0,
+    "type" : "String"
+  }, {
+    "name" : "message",
+    "depth" : 0,
+    "type" : "String"
+  } ],
+  "outputPorts" : [ {
+    "name" : "answer",
+    "depth" : 0,
+    "granularDepth" : 0
+  } ],
+  "isAltered" : false
+}
\ No newline at end of file
diff --git a/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.xml.XPathTextWorker b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.xml.XPathTextWorker
new file mode 100644
index 0000000..0395225
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.xml.XPathTextWorker
@@ -0,0 +1,75 @@
+<activity xmlns="http://taverna.sf.net/2008/xml/t2flow"><class>net.sf.taverna.t2.activities.localworker.LocalworkerActivity</class><inputMap /><outputMap /><configBean encoding="xstream"><net.sf.taverna.t2.activities.localworker.LocalworkerActivityConfigurationBean xmlns="">

+  <script>import org.dom4j.Document;

+import org.dom4j.Node;

+import org.dom4j.io.SAXReader;

+

+SAXReader reader = new SAXReader(false);

+reader.setIncludeInternalDTDDeclarations(false);

+reader.setIncludeExternalDTDDeclarations(false);

+

+Document document = reader.read(new StringReader(xmltext));

+List nodelist = document.selectNodes(xpath);

+

+// Process the elements in the nodelist

+ArrayList outputList = new ArrayList();

+ArrayList outputXmlList = new ArrayList();

+

+String val = null;

+String xmlVal = null;

+for (Iterator iter = nodelist.iterator(); iter.hasNext();) {

+	Node element = (Node) iter.next();

+	xmlVal = element.asXML();

+	val = element.getStringValue();

+	if (val != null &amp;&amp; !val.equals("")) {

+		outputList.add(val);

+		outputXmlList.add(xmlVal);

+	}

+

+}

+

+List nodelist=outputList;

+List nodelistAsXML=outputXmlList;</script>

+  <dependencies>

+    <string>dom4j:dom4j:1.6</string>

+  </dependencies>

+  <inputs>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+      <handledReferenceSchemes />

+      <translatedElementType>java.lang.String</translatedElementType>

+      <allowsLiteralValues>true</allowsLiteralValues>

+      <name>xpath</name>

+      <depth>0</depth>

+      <mimeTypes>

+        <string>'text/plain'</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+      <handledReferenceSchemes />

+      <translatedElementType>java.lang.String</translatedElementType>

+      <allowsLiteralValues>true</allowsLiteralValues>

+      <name>xml-text</name>

+      <depth>0</depth>

+      <mimeTypes>

+        <string>'text/xml'</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+  </inputs>

+  <outputs>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>

+      <granularDepth>1</granularDepth>

+      <name>nodelist</name>

+      <depth>1</depth>

+      <mimeTypes>

+        <string>l('text/plain')</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>

+      <granularDepth>1</granularDepth>

+      <name>nodelistAsXML</name>

+      <depth>1</depth>

+      <mimeTypes>

+        <string>l('text/plain')</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>

+  </outputs>

+</net.sf.taverna.t2.activities.localworker.LocalworkerActivityConfigurationBean></configBean></activity>
\ No newline at end of file
diff --git a/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.xml.XPathTextWorker.json b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.xml.XPathTextWorker.json
new file mode 100644
index 0000000..3fa2385
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.xml.XPathTextWorker.json
@@ -0,0 +1,24 @@
+{
+  "classLoaderSharing" : "workflow",
+  "script" : "import org.dom4j.Document;\nimport org.dom4j.Node;\nimport org.dom4j.io.SAXReader;\n\nSAXReader reader = new SAXReader(false);\nreader.setIncludeInternalDTDDeclarations(false);\nreader.setIncludeExternalDTDDeclarations(false);\n\nDocument document = reader.read(new StringReader(xmltext));\nList nodelist = document.selectNodes(xpath);\n\n// Process the elements in the nodelist\nArrayList outputList = new ArrayList();\nArrayList outputXmlList = new ArrayList();\n\nString val = null;\nString xmlVal = null;\nfor (Iterator iter = nodelist.iterator(); iter.hasNext();) {\n\tNode element = (Node) iter.next();\n\txmlVal = element.asXML();\n\tval = element.getStringValue();\n\tif (val != null && !val.equals(\"\")) {\n\t\toutputList.add(val);\n\t\toutputXmlList.add(xmlVal);\n\t}\n\n}\n\nList nodelist=outputList;\nList nodelistAsXML=outputXmlList;",
+  "localworkerName" : "net.sourceforge.taverna.scuflworkers.xml.XPathTextWorker",
+  "inputPorts" : [ {
+    "name" : "xpath",
+    "depth" : 0,
+    "type" : "String"
+  }, {
+    "name" : "xml-text",
+    "depth" : 0,
+    "type" : "String"
+  } ],
+  "outputPorts" : [ {
+    "name" : "nodelist",
+    "depth" : 1,
+    "granularDepth" : 1
+  }, {
+    "name" : "nodelistAsXML",
+    "depth" : 1,
+    "granularDepth" : 1
+  } ],
+  "isAltered" : false
+}
\ No newline at end of file
diff --git a/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.xml.XSLTWorker b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.xml.XSLTWorker
new file mode 100644
index 0000000..1532b63
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.xml.XSLTWorker
@@ -0,0 +1,152 @@
+<activity xmlns="http://taverna.sf.net/2008/xml/t2flow"><class>net.sf.taverna.t2.activities.localworker.LocalworkerActivity</class><inputMap /><outputMap><map from="outputStr" to="outputStr" /></outputMap><configBean encoding="xstream"><net.sf.taverna.t2.activities.localworker.LocalworkerActivityConfigurationBean xmlns="">

+  <script>import java.io.BufferedReader;

+import java.io.BufferedWriter;

+import java.io.FileInputStream;

+import java.io.FileNotFoundException;

+import java.io.FileReader;

+import java.io.FileWriter;

+import java.io.IOException;

+import java.io.InputStreamReader;

+import java.io.OutputStreamWriter;

+import java.io.StringWriter;

+import java.io.Writer;

+import java.net.URL;

+import java.util.HashMap;

+import java.util.Map;

+

+import javax.xml.transform.Result;

+import javax.xml.transform.Source;

+import javax.xml.transform.SourceLocator;

+import javax.xml.transform.Templates;

+import javax.xml.transform.Transformer;

+import javax.xml.transform.TransformerConfigurationException;

+import javax.xml.transform.TransformerException;

+import javax.xml.transform.TransformerFactory;

+import javax.xml.transform.stream.StreamResult;

+import javax.xml.transform.stream.StreamSource;

+

+BufferedReader getReader (String fileUrl) throws IOException {

+		InputStreamReader reader;

+		try {

+			reader = new FileReader(fileUrl);

+		}

+		catch (FileNotFoundException e) {

+			// try a real URL instead

+			URL url = new URL(fileUrl);

+			reader = new InputStreamReader (url.openStream());

+		}

+		return new BufferedReader(reader);

+	}

+	

+BufferedWriter getWriter (String fileUrl) throws IOException {

+		Writer writer;

+		try {

+			writer = new FileWriter(fileUrl);

+		}

+		catch (FileNotFoundException e) {

+			// try a real URL instead

+			URL url = new URL(fileUrl);

+			writer = new OutputStreamWriter (url.openConnection().getOutputStream());

+		}

+		return new BufferedWriter(writer);

+	}

+	

+String xslFilename = xslFileURL;

+String outFilename;

+if (outFileURL != void) {

+    outFilename = outFileURL;

+}

+

+String ext;

+if (outputExt != void) {

+    ext = outputExt;

+}

+

+if (((outFilename == null) || outFilename.equals("")) &amp;&amp; (ext != null)) {

+		outFilename = inFileURL.substring(0, inFileURL.indexOf(".")+1) + ext;

+}

+

+// Create transformer factory

+TransformerFactory factory = TransformerFactory.newInstance();

+

+// Use the factory to create a template containing the xsl file

+Templates template = factory.newTemplates(new StreamSource(getReader(xslFilename)));

+

+// Use the template to create a transformer

+Transformer xformer = template.newTransformer();

+

+// Prepare the input and output files

+Reader sourceReader = getReader(inFileURL);

+Source source = new StreamSource(sourceReader);

+StringWriter resultStr = new StringWriter();

+Result result = new StreamResult(resultStr);

+

+// Apply the xsl file to the source file and write the result to the

+// output file

+xformer.transform(source, result);

+

+outputStr = resultStr.toString();

+

+if ((outFilename != null) &amp;&amp; !outFilename.equals("")) {

+

+	BufferedWriter out = getWriter(outFilename);

+

+	out.write(outputStr);

+	out.close();

+}

+sourceReader.close();

+</script>

+  <dependencies />

+  <inputs>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+      <handledReferenceSchemes />

+      <translatedElementType>java.lang.String</translatedElementType>

+      <allowsLiteralValues>true</allowsLiteralValues>

+      <name>xslFileURL</name>

+      <depth>0</depth>

+      <mimeTypes>

+        <string>'text/plain'</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+      <handledReferenceSchemes />

+      <translatedElementType>java.lang.String</translatedElementType>

+      <allowsLiteralValues>true</allowsLiteralValues>

+      <name>outFileURL</name>

+      <depth>0</depth>

+      <mimeTypes>

+        <string>'text/plain'</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+      <handledReferenceSchemes />

+      <translatedElementType>java.lang.String</translatedElementType>

+      <allowsLiteralValues>true</allowsLiteralValues>

+      <name>inFileURL</name>

+      <depth>0</depth>

+      <mimeTypes>

+        <string>'text/plain'</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+      <handledReferenceSchemes />

+      <translatedElementType>java.lang.String</translatedElementType>

+      <allowsLiteralValues>true</allowsLiteralValues>

+      <name>outputExt</name>

+      <depth>0</depth>

+      <mimeTypes>

+        <string>'text/plain'</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+  </inputs>

+  <outputs>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>

+      <granularDepth>0</granularDepth>

+      <name>outputStr</name>

+      <depth>0</depth>

+      <mimeTypes>

+        <string>'text/xml'</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>

+  </outputs>

+</net.sf.taverna.t2.activities.localworker.LocalworkerActivityConfigurationBean></configBean></activity>
\ No newline at end of file
diff --git a/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.xml.XSLTWorker.json b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.xml.XSLTWorker.json
new file mode 100644
index 0000000..09aff0d
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.xml.XSLTWorker.json
@@ -0,0 +1,28 @@
+{
+  "classLoaderSharing" : "workflow",
+  "script" : "import java.io.BufferedReader;\nimport java.io.BufferedWriter;\nimport java.io.FileInputStream;\nimport java.io.FileNotFoundException;\nimport java.io.FileReader;\nimport java.io.FileWriter;\nimport java.io.IOException;\nimport java.io.InputStreamReader;\nimport java.io.OutputStreamWriter;\nimport java.io.StringWriter;\nimport java.io.Writer;\nimport java.net.URL;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport javax.xml.transform.Result;\nimport javax.xml.transform.Source;\nimport javax.xml.transform.SourceLocator;\nimport javax.xml.transform.Templates;\nimport javax.xml.transform.Transformer;\nimport javax.xml.transform.TransformerConfigurationException;\nimport javax.xml.transform.TransformerException;\nimport javax.xml.transform.TransformerFactory;\nimport javax.xml.transform.stream.StreamResult;\nimport javax.xml.transform.stream.StreamSource;\n\nBufferedReader getReader (String fileUrl) throws IOException {\n\t\tInputStreamReader reader;\n\t\ttry {\n\t\t\treader = new FileReader(fileUrl);\n\t\t}\n\t\tcatch (FileNotFoundException e) {\n\t\t\t// try a real URL instead\n\t\t\tURL url = new URL(fileUrl);\n\t\t\treader = new InputStreamReader (url.openStream());\n\t\t}\n\t\treturn new BufferedReader(reader);\n\t}\n\t\nBufferedWriter getWriter (String fileUrl) throws IOException {\n\t\tWriter writer;\n\t\ttry {\n\t\t\twriter = new FileWriter(fileUrl);\n\t\t}\n\t\tcatch (FileNotFoundException e) {\n\t\t\t// try a real URL instead\n\t\t\tURL url = new URL(fileUrl);\n\t\t\twriter = new OutputStreamWriter (url.openConnection().getOutputStream());\n\t\t}\n\t\treturn new BufferedWriter(writer);\n\t}\n\t\nString xslFilename = xslFileURL;\nString outFilename;\nif (outFileURL != void) {\n    outFilename = outFileURL;\n}\n\nString ext;\nif (outputExt != void) {\n    ext = outputExt;\n}\n\nif (((outFilename == null) || outFilename.equals(\"\")) && (ext != null)) {\n\t\toutFilename = inFileURL.substring(0, inFileURL.indexOf(\".\")+1) + ext;\n}\n\n// Create transformer factory\nTransformerFactory factory = TransformerFactory.newInstance();\n\n// Use the factory to create a template containing the xsl file\nTemplates template = factory.newTemplates(new StreamSource(getReader(xslFilename)));\n\n// Use the template to create a transformer\nTransformer xformer = template.newTransformer();\n\n// Prepare the input and output files\nReader sourceReader = getReader(inFileURL);\nSource source = new StreamSource(sourceReader);\nStringWriter resultStr = new StringWriter();\nResult result = new StreamResult(resultStr);\n\n// Apply the xsl file to the source file and write the result to the\n// output file\nxformer.transform(source, result);\n\noutputStr = resultStr.toString();\n\nif ((outFilename != null) && !outFilename.equals(\"\")) {\n\n\tBufferedWriter out = getWriter(outFilename);\n\n\tout.write(outputStr);\n\tout.close();\n}\nsourceReader.close();\n",
+  "localworkerName" : "net.sourceforge.taverna.scuflworkers.xml.XSLTWorker",
+  "inputPorts" : [ {
+    "name" : "xslFileURL",
+    "depth" : 0,
+    "type" : "String"
+  }, {
+    "name" : "outFileURL",
+    "depth" : 0,
+    "type" : "String"
+  }, {
+    "name" : "inFileURL",
+    "depth" : 0,
+    "type" : "String"
+  }, {
+    "name" : "outputExt",
+    "depth" : 0,
+    "type" : "String"
+  } ],
+  "outputPorts" : [ {
+    "name" : "outputStr",
+    "depth" : 0,
+    "granularDepth" : 0
+  } ],
+  "isAltered" : false
+}
\ No newline at end of file
diff --git a/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.xml.XSLTWorkerWithParameters b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.xml.XSLTWorkerWithParameters
new file mode 100644
index 0000000..768c8f9
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.xml.XSLTWorkerWithParameters
@@ -0,0 +1,100 @@
+<activity xmlns="http://taverna.sf.net/2008/xml/t2flow">
+  <class>net.sf.taverna.t2.activities.localworker.LocalworkerActivity</class>
+  <inputMap>
+    <map from="xsltString" to="xsltString" />
+    <map from="paramList" to="paramList" />
+    <map from="sourceString" to="sourceString" />
+  </inputMap>
+  <outputMap>
+    <map from="outputString" to="outputString" />
+  </outputMap>
+  <configBean encoding="xstream">
+    <net.sf.taverna.t2.activities.localworker.LocalworkerActivityConfigurationBean xmlns="">
+  <inputs>
+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>
+      <name>sourceString</name>
+      <depth>0</depth>
+      <mimeTypes>
+        <string>text/plain</string>
+      </mimeTypes>
+      <handledReferenceSchemes />
+      <translatedElementType>java.lang.String</translatedElementType>
+      <allowsLiteralValues>true</allowsLiteralValues>
+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>
+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>
+      <name>xsltString</name>
+      <depth>0</depth>
+      <mimeTypes>
+        <string>text/plain</string>
+      </mimeTypes>
+      <handledReferenceSchemes />
+      <translatedElementType>java.lang.String</translatedElementType>
+      <allowsLiteralValues>true</allowsLiteralValues>
+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>
+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>
+      <name>paramList</name>
+      <depth>1</depth>
+      <mimeTypes>
+        <string>text/plain</string>
+      </mimeTypes>
+      <handledReferenceSchemes />
+      <translatedElementType>java.lang.String</translatedElementType>
+      <allowsLiteralValues>true</allowsLiteralValues>
+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>
+  </inputs>
+  <outputs>
+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>
+      <name>outputString</name>
+      <depth>0</depth>
+      <mimeTypes />
+      <granularDepth>0</granularDepth>
+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>
+  </outputs>
+  <classLoaderSharing>workflow</classLoaderSharing>
+  <localDependencies />
+  <artifactDependencies />
+  <script>//From a proposal by Mikolaj Rybinski
+import javax.xml.transform.Source;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.stream.StreamResult;
+import javax.xml.transform.stream.StreamSource;
+
+param(paramstr) {
+    nameAndValue = paramstr.split("=");
+    if (nameAndValue.length != 2) {
+        throw new RuntimeException("Wrong parameter format: \"" + paramstr + "\".");
+    }
+    name = nameAndValue[0].trim();
+    value = nameAndValue[1].trim();
+    return this;
+}
+
+if ((sourceString == void) || (sourceString == null)) {
+        throw new RuntimeException("sourceString must be specified");
+}
+
+if ((xsltString == void) || (xsltString == null)) {
+        throw new RuntimeException("xsltString must be specified");
+}
+
+Source inSource = new StreamSource(new StringReader(sourceString));
+Source xslSource = new StreamSource(new StringReader(xsltString));
+
+// the factory pattern supports different XSLT processors
+// e.g. set the "javax.xml.transform.TransformerFactory" system property
+TransformerFactory tnfFact = TransformerFactory.newInstance();
+Transformer tnf = tnfFact.newTransformer(xslSource);
+
+if (paramList != void) {
+  for (String paramstr : paramList) {
+    p = param(paramstr);
+    tnf.setParameter(p.name, p.value);
+  }
+}
+
+Writer outputWriter = new StringWriter();
+tnf.transform(inSource, new StreamResult(outputWriter));
+outputString = outputWriter.toString();</script>
+  <dependencies />
+</net.sf.taverna.t2.activities.localworker.LocalworkerActivityConfigurationBean></configBean><annotations /></activity>
diff --git a/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.xml.XSLTWorkerWithParameters.json b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.xml.XSLTWorkerWithParameters.json
new file mode 100644
index 0000000..0800c76
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/resources/net.sourceforge.taverna.scuflworkers.xml.XSLTWorkerWithParameters.json
@@ -0,0 +1,24 @@
+{
+  "classLoaderSharing" : "workflow",
+  "script" : "//From a proposal by Mikolaj Rybinski\nimport javax.xml.transform.Source;\nimport javax.xml.transform.Transformer;\nimport javax.xml.transform.TransformerFactory;\nimport javax.xml.transform.stream.StreamResult;\nimport javax.xml.transform.stream.StreamSource;\n\nparam(paramstr) {\n    nameAndValue = paramstr.split(\"=\");\n    if (nameAndValue.length != 2) {\n        throw new RuntimeException(\"Wrong parameter format: \\\"\" + paramstr + \"\\\".\");\n    }\n    name = nameAndValue[0].trim();\n    value = nameAndValue[1].trim();\n    return this;\n}\n\nif ((sourceString == void) || (sourceString == null)) {\n        throw new RuntimeException(\"sourceString must be specified\");\n}\n\nif ((xsltString == void) || (xsltString == null)) {\n        throw new RuntimeException(\"xsltString must be specified\");\n}\n\nSource inSource = new StreamSource(new StringReader(sourceString));\nSource xslSource = new StreamSource(new StringReader(xsltString));\n\n// the factory pattern supports different XSLT processors\n// e.g. set the \"javax.xml.transform.TransformerFactory\" system property\nTransformerFactory tnfFact = TransformerFactory.newInstance();\nTransformer tnf = tnfFact.newTransformer(xslSource);\n\nif (paramList != void) {\n  for (String paramstr : paramList) {\n    p = param(paramstr);\n    tnf.setParameter(p.name, p.value);\n  }\n}\n\nWriter outputWriter = new StringWriter();\ntnf.transform(inSource, new StreamResult(outputWriter));\noutputString = outputWriter.toString();",
+  "localworkerName" : "net.sourceforge.taverna.scuflworkers.xml.XSLTWorkerWithParameters",
+  "inputPorts" : [ {
+    "name" : "sourceString",
+    "depth" : 0,
+    "type" : "String"
+  }, {
+    "name" : "xsltString",
+    "depth" : 0,
+    "type" : "String"
+  }, {
+    "name" : "paramList",
+    "depth" : 1,
+    "type" : "String"
+  } ],
+  "outputPorts" : [ {
+    "name" : "outputString",
+    "depth" : 0,
+    "granularDepth" : 0
+  } ],
+  "isAltered" : false
+}
\ No newline at end of file
diff --git a/taverna-localworker-activity-ui/src/main/resources/org.embl.ebi.escience.scuflworkers.java.ByteArrayToString b/taverna-localworker-activity-ui/src/main/resources/org.embl.ebi.escience.scuflworkers.java.ByteArrayToString
new file mode 100644
index 0000000..35b50d0
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/resources/org.embl.ebi.escience.scuflworkers.java.ByteArrayToString
@@ -0,0 +1,44 @@
+<activity xmlns="http://taverna.sf.net/2008/xml/t2flow"><class>net.sf.taverna.t2.activities.localworker.LocalworkerActivity</class><inputMap /><outputMap /><configBean encoding="xstream"><net.sf.taverna.t2.activities.localworker.LocalworkerActivityConfigurationBean xmlns="">

+  <script>if ((bytes == void) || (bytes == null)) {

+	throw new RuntimeException("The 'bytes' parameter must be specified");

+}

+if (encoding == void) {

+	string = new String(bytes);

+} else {

+	string = new String(bytes, encoding);

+}

+</script>

+  <dependencies />

+  <inputs>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+      <handledReferenceSchemes />

+      <translatedElementType>[B</translatedElementType>

+      <allowsLiteralValues>true</allowsLiteralValues>

+      <name>bytes</name>

+      <depth>0</depth>

+      <mimeTypes>

+        <string>'application/octet-stream'</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+      <handledReferenceSchemes />

+      <translatedElementType>java.lang.String</translatedElementType>

+      <allowsLiteralValues>true</allowsLiteralValues>

+      <name>encoding</name>

+      <depth>0</depth>

+      <mimeTypes>

+        <string>'text/plain'</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+  </inputs>

+  <outputs>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>

+      <granularDepth>0</granularDepth>

+      <name>string</name>

+      <depth>0</depth>

+      <mimeTypes>

+        <string>'text/plain'</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>

+  </outputs>

+</net.sf.taverna.t2.activities.localworker.LocalworkerActivityConfigurationBean></configBean></activity>
\ No newline at end of file
diff --git a/taverna-localworker-activity-ui/src/main/resources/org.embl.ebi.escience.scuflworkers.java.ByteArrayToString.json b/taverna-localworker-activity-ui/src/main/resources/org.embl.ebi.escience.scuflworkers.java.ByteArrayToString.json
new file mode 100644
index 0000000..ae7f934
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/resources/org.embl.ebi.escience.scuflworkers.java.ByteArrayToString.json
@@ -0,0 +1,20 @@
+{
+  "classLoaderSharing" : "workflow",
+  "script" : "if ((bytes == void) || (bytes == null)) {\n\tthrow new RuntimeException(\"The 'bytes' parameter must be specified\");\n}\nif (encoding == void) {\n\tstring = new String(bytes);\n} else {\n\tstring = new String(bytes, encoding);\n}\n",
+  "localworkerName" : "org.embl.ebi.escience.scuflworkers.java.ByteArrayToString",
+  "inputPorts" : [ {
+    "name" : "bytes",
+    "depth" : 0,
+    "type" : "byte[]"
+  }, {
+    "name" : "encoding",
+    "depth" : 0,
+    "type" : "String"
+  } ],
+  "outputPorts" : [ {
+    "name" : "string",
+    "depth" : 0,
+    "granularDepth" : 0
+  } ],
+  "isAltered" : false
+}
\ No newline at end of file
diff --git a/taverna-localworker-activity-ui/src/main/resources/org.embl.ebi.escience.scuflworkers.java.DecodeBase64 b/taverna-localworker-activity-ui/src/main/resources/org.embl.ebi.escience.scuflworkers.java.DecodeBase64
new file mode 100644
index 0000000..62c01bd
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/resources/org.embl.ebi.escience.scuflworkers.java.DecodeBase64
@@ -0,0 +1,31 @@
+<activity xmlns="http://taverna.sf.net/2008/xml/t2flow"><class>net.sf.taverna.t2.activities.localworker.LocalworkerActivity</class><inputMap /><outputMap /><configBean encoding="xstream"><net.sf.taverna.t2.activities.localworker.LocalworkerActivityConfigurationBean xmlns="">

+  <script>import org.apache.commons.codec.binary.Base64;

+

+bytes = Base64.decodeBase64(base64.getBytes());

+</script>

+  <dependencies class="java.util.Collections$SingletonList">

+    <element class="string">commons-codec:commons-codec:1.3</element>

+  </dependencies>

+  <inputs>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+      <handledReferenceSchemes />

+      <translatedElementType>java.lang.String</translatedElementType>

+      <allowsLiteralValues>true</allowsLiteralValues>

+      <name>base64</name>

+      <depth>0</depth>

+      <mimeTypes>

+        <string>'text/plain'</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+  </inputs>

+  <outputs>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>

+      <granularDepth>0</granularDepth>

+      <name>bytes</name>

+      <depth>0</depth>

+      <mimeTypes>

+        <string>'application/octet-stream'</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>

+  </outputs>

+</net.sf.taverna.t2.activities.localworker.LocalworkerActivityConfigurationBean></configBean></activity>
\ No newline at end of file
diff --git a/taverna-localworker-activity-ui/src/main/resources/org.embl.ebi.escience.scuflworkers.java.DecodeBase64.json b/taverna-localworker-activity-ui/src/main/resources/org.embl.ebi.escience.scuflworkers.java.DecodeBase64.json
new file mode 100644
index 0000000..1cb0f62
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/resources/org.embl.ebi.escience.scuflworkers.java.DecodeBase64.json
@@ -0,0 +1,16 @@
+{
+  "classLoaderSharing" : "workflow",
+  "script" : "import org.apache.commons.codec.binary.Base64;\n\nbytes = Base64.decodeBase64(base64.getBytes());\n",
+  "localworkerName" : "org.embl.ebi.escience.scuflworkers.java.DecodeBase64",
+  "inputPorts" : [ {
+    "name" : "base64",
+    "depth" : 0,
+    "type" : "String"
+  } ],
+  "outputPorts" : [ {
+    "name" : "bytes",
+    "depth" : 0,
+    "granularDepth" : 0
+  } ],
+  "isAltered" : false
+}
\ No newline at end of file
diff --git a/taverna-localworker-activity-ui/src/main/resources/org.embl.ebi.escience.scuflworkers.java.EchoList b/taverna-localworker-activity-ui/src/main/resources/org.embl.ebi.escience.scuflworkers.java.EchoList
new file mode 100644
index 0000000..615c762
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/resources/org.embl.ebi.escience.scuflworkers.java.EchoList
@@ -0,0 +1,26 @@
+<activity xmlns="http://taverna.sf.net/2008/xml/t2flow"><class>net.sf.taverna.t2.activities.localworker.LocalworkerActivity</class><inputMap /><outputMap /><configBean encoding="xstream"><net.sf.taverna.t2.activities.localworker.LocalworkerActivityConfigurationBean xmlns="">

+  <script>outputlist = inputlist;</script>

+  <dependencies />

+  <inputs>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+      <handledReferenceSchemes />

+      <translatedElementType>[B</translatedElementType>

+      <allowsLiteralValues>true</allowsLiteralValues>

+      <name>inputlist</name>

+      <depth>1</depth>

+      <mimeTypes>

+        <string>l('')</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+  </inputs>

+  <outputs>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>

+      <granularDepth>1</granularDepth>

+      <name>outputlist</name>

+      <depth>1</depth>

+      <mimeTypes>

+        <string>l('')</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>

+  </outputs>

+</net.sf.taverna.t2.activities.localworker.LocalworkerActivityConfigurationBean></configBean></activity>
\ No newline at end of file
diff --git a/taverna-localworker-activity-ui/src/main/resources/org.embl.ebi.escience.scuflworkers.java.EchoList.json b/taverna-localworker-activity-ui/src/main/resources/org.embl.ebi.escience.scuflworkers.java.EchoList.json
new file mode 100644
index 0000000..aa0d198
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/resources/org.embl.ebi.escience.scuflworkers.java.EchoList.json
@@ -0,0 +1,16 @@
+{
+  "classLoaderSharing" : "workflow",
+  "script" : "outputlist = inputlist;",
+  "localworkerName" : "org.embl.ebi.escience.scuflworkers.java.EchoList",
+  "inputPorts" : [ {
+    "name" : "inputlist",
+    "depth" : 1,
+    "type" : "byte[]"
+  } ],
+  "outputPorts" : [ {
+    "name" : "outputlist",
+    "depth" : 1,
+    "granularDepth" : 1
+  } ],
+  "isAltered" : false
+}
\ No newline at end of file
diff --git a/taverna-localworker-activity-ui/src/main/resources/org.embl.ebi.escience.scuflworkers.java.EmitLotsOfStrings b/taverna-localworker-activity-ui/src/main/resources/org.embl.ebi.escience.scuflworkers.java.EmitLotsOfStrings
new file mode 100644
index 0000000..6045d0a
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/resources/org.embl.ebi.escience.scuflworkers.java.EmitLotsOfStrings
@@ -0,0 +1,19 @@
+<activity xmlns="http://taverna.sf.net/2008/xml/t2flow"><class>net.sf.taverna.t2.activities.localworker.LocalworkerActivity</class><inputMap /><outputMap /><configBean encoding="xstream"><net.sf.taverna.t2.activities.localworker.LocalworkerActivityConfigurationBean xmlns="">

+  <script>List strings = new ArrayList();

+for (int i = 0; i &lt; 40; i++) {

+	strings.add("String" + i);

+}

+</script>

+  <dependencies />

+  <inputs />

+  <outputs>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>

+      <granularDepth>1</granularDepth>

+      <name>strings</name>

+      <depth>1</depth>

+      <mimeTypes>

+        <string>l('text/plain')</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>

+  </outputs>

+</net.sf.taverna.t2.activities.localworker.LocalworkerActivityConfigurationBean></configBean></activity>
\ No newline at end of file
diff --git a/taverna-localworker-activity-ui/src/main/resources/org.embl.ebi.escience.scuflworkers.java.EmitLotsOfStrings.json b/taverna-localworker-activity-ui/src/main/resources/org.embl.ebi.escience.scuflworkers.java.EmitLotsOfStrings.json
new file mode 100644
index 0000000..4afc1f8
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/resources/org.embl.ebi.escience.scuflworkers.java.EmitLotsOfStrings.json
@@ -0,0 +1,11 @@
+{
+  "classLoaderSharing" : "workflow",
+  "script" : "List strings = new ArrayList();\nfor (int i = 0; i < 40; i++) {\n\tstrings.add(\"String\" + i);\n}\n",
+  "localworkerName" : "org.embl.ebi.escience.scuflworkers.java.EmitLotsOfStrings",
+  "outputPorts" : [ {
+    "name" : "strings",
+    "depth" : 1,
+    "granularDepth" : 1
+  } ],
+  "isAltered" : false
+}
\ No newline at end of file
diff --git a/taverna-localworker-activity-ui/src/main/resources/org.embl.ebi.escience.scuflworkers.java.EncodeBase64 b/taverna-localworker-activity-ui/src/main/resources/org.embl.ebi.escience.scuflworkers.java.EncodeBase64
new file mode 100644
index 0000000..8f6bcd0
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/resources/org.embl.ebi.escience.scuflworkers.java.EncodeBase64
@@ -0,0 +1,30 @@
+<activity xmlns="http://taverna.sf.net/2008/xml/t2flow"><class>net.sf.taverna.t2.activities.localworker.LocalworkerActivity</class><inputMap /><outputMap /><configBean encoding="xstream"><net.sf.taverna.t2.activities.localworker.LocalworkerActivityConfigurationBean xmlns="">

+  <script>import org.apache.commons.codec.binary.Base64;

+

+base64 = new String(Base64.encodeBase64(bytes));</script>

+  <dependencies class="java.util.Collections$SingletonList">

+    <element class="string">commons-codec:commons-codec:1.3</element>

+  </dependencies>

+  <inputs>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+      <handledReferenceSchemes />

+      <translatedElementType>[B</translatedElementType>

+      <allowsLiteralValues>true</allowsLiteralValues>

+      <name>bytes</name>

+      <depth>0</depth>

+      <mimeTypes>

+        <string>'application/octet-stream'</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+  </inputs>

+  <outputs>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>

+      <granularDepth>0</granularDepth>

+      <name>base64</name>

+      <depth>0</depth>

+      <mimeTypes>

+        <string>'text/plain'</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>

+  </outputs>

+</net.sf.taverna.t2.activities.localworker.LocalworkerActivityConfigurationBean></configBean></activity>
\ No newline at end of file
diff --git a/taverna-localworker-activity-ui/src/main/resources/org.embl.ebi.escience.scuflworkers.java.EncodeBase64.json b/taverna-localworker-activity-ui/src/main/resources/org.embl.ebi.escience.scuflworkers.java.EncodeBase64.json
new file mode 100644
index 0000000..5cbd786
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/resources/org.embl.ebi.escience.scuflworkers.java.EncodeBase64.json
@@ -0,0 +1,16 @@
+{
+  "classLoaderSharing" : "workflow",
+  "script" : "import org.apache.commons.codec.binary.Base64;\n\nbase64 = new String(Base64.encodeBase64(bytes));",
+  "localworkerName" : "org.embl.ebi.escience.scuflworkers.java.EncodeBase64",
+  "inputPorts" : [ {
+    "name" : "bytes",
+    "depth" : 0,
+    "type" : "byte[]"
+  } ],
+  "outputPorts" : [ {
+    "name" : "base64",
+    "depth" : 0,
+    "granularDepth" : 0
+  } ],
+  "isAltered" : false
+}
\ No newline at end of file
diff --git a/taverna-localworker-activity-ui/src/main/resources/org.embl.ebi.escience.scuflworkers.java.ExtractImageLinks b/taverna-localworker-activity-ui/src/main/resources/org.embl.ebi.escience.scuflworkers.java.ExtractImageLinks
new file mode 100644
index 0000000..05946b1
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/resources/org.embl.ebi.escience.scuflworkers.java.ExtractImageLinks
@@ -0,0 +1,41 @@
+<activity xmlns="http://taverna.sf.net/2008/xml/t2flow"><class>net.sf.taverna.t2.activities.localworker.LocalworkerActivity</class><inputMap /><outputMap /><configBean encoding="xstream"><net.sf.taverna.t2.activities.localworker.LocalworkerActivityConfigurationBean xmlns="">

+  <script>String lowerCaseContent = document.toLowerCase();

+int index = 0;

+List imagelinks = new ArrayList();

+while ((index = lowerCaseContent.indexOf("&lt;img", index)) != -1) {

+	if ((index = lowerCaseContent.indexOf("src", index)) == -1)

+		break;

+	if ((index = lowerCaseContent.indexOf("=", index)) == -1)

+		break;

+	index++;

+	String remaining = document.substring(index);

+	StringTokenizer st = new StringTokenizer(remaining, "\t\n\r\"&gt;#");

+	String strLink = st.nextToken();

+	imagelinks.add(strLink);

+}

+

+</script>

+  <dependencies />

+  <inputs>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+      <handledReferenceSchemes />

+      <translatedElementType>java.lang.String</translatedElementType>

+      <allowsLiteralValues>true</allowsLiteralValues>

+      <name>document</name>

+      <depth>0</depth>

+      <mimeTypes>

+        <string>'text/html'</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+  </inputs>

+  <outputs>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>

+      <granularDepth>1</granularDepth>

+      <name>imagelinks</name>

+      <depth>1</depth>

+      <mimeTypes>

+        <string>l('text/x-taverna-web-url')</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>

+  </outputs>

+</net.sf.taverna.t2.activities.localworker.LocalworkerActivityConfigurationBean></configBean></activity>
\ No newline at end of file
diff --git a/taverna-localworker-activity-ui/src/main/resources/org.embl.ebi.escience.scuflworkers.java.ExtractImageLinks.json b/taverna-localworker-activity-ui/src/main/resources/org.embl.ebi.escience.scuflworkers.java.ExtractImageLinks.json
new file mode 100644
index 0000000..2a23a47
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/resources/org.embl.ebi.escience.scuflworkers.java.ExtractImageLinks.json
@@ -0,0 +1,16 @@
+{
+  "classLoaderSharing" : "workflow",
+  "script" : "String lowerCaseContent = document.toLowerCase();\nint index = 0;\nList imagelinks = new ArrayList();\nwhile ((index = lowerCaseContent.indexOf(\"<img\", index)) != -1) {\n\tif ((index = lowerCaseContent.indexOf(\"src\", index)) == -1)\n\t\tbreak;\n\tif ((index = lowerCaseContent.indexOf(\"=\", index)) == -1)\n\t\tbreak;\n\tindex++;\n\tString remaining = document.substring(index);\n\tStringTokenizer st = new StringTokenizer(remaining, \"\\t\\n\\r\\\">#\");\n\tString strLink = st.nextToken();\n\timagelinks.add(strLink);\n}\n\n",
+  "localworkerName" : "org.embl.ebi.escience.scuflworkers.java.ExtractImageLinks",
+  "inputPorts" : [ {
+    "name" : "document",
+    "depth" : 0,
+    "type" : "String"
+  } ],
+  "outputPorts" : [ {
+    "name" : "imagelinks",
+    "depth" : 1,
+    "granularDepth" : 1
+  } ],
+  "isAltered" : false
+}
\ No newline at end of file
diff --git a/taverna-localworker-activity-ui/src/main/resources/org.embl.ebi.escience.scuflworkers.java.FilterStringList b/taverna-localworker-activity-ui/src/main/resources/org.embl.ebi.escience.scuflworkers.java.FilterStringList
new file mode 100644
index 0000000..7b107e6
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/resources/org.embl.ebi.escience.scuflworkers.java.FilterStringList
@@ -0,0 +1,43 @@
+<activity xmlns="http://taverna.sf.net/2008/xml/t2flow"><class>net.sf.taverna.t2.activities.localworker.LocalworkerActivity</class><inputMap /><outputMap /><configBean encoding="xstream"><net.sf.taverna.t2.activities.localworker.LocalworkerActivityConfigurationBean xmlns="">

+  <script>filteredlist = new ArrayList();

+for (Iterator i = stringlist.iterator(); i.hasNext();) {

+	String item = (String) i.next();

+	if (item.matches(regex)) {

+		filteredlist.add(item);

+	}

+}

+</script>

+  <dependencies />

+  <inputs>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+      <handledReferenceSchemes />

+      <translatedElementType>java.lang.String</translatedElementType>

+      <allowsLiteralValues>true</allowsLiteralValues>

+      <name>stringlist</name>

+      <depth>1</depth>

+      <mimeTypes>

+        <string>l('text/plain')</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+      <handledReferenceSchemes />

+      <translatedElementType>java.lang.String</translatedElementType>

+      <allowsLiteralValues>true</allowsLiteralValues>

+      <name>regex</name>

+      <depth>0</depth>

+      <mimeTypes>

+        <string>'text/plain'</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+  </inputs>

+  <outputs>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>

+      <granularDepth>1</granularDepth>

+      <name>filteredlist</name>

+      <depth>1</depth>

+      <mimeTypes>

+        <string>l('text/plain')</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>

+  </outputs>

+</net.sf.taverna.t2.activities.localworker.LocalworkerActivityConfigurationBean></configBean></activity>
\ No newline at end of file
diff --git a/taverna-localworker-activity-ui/src/main/resources/org.embl.ebi.escience.scuflworkers.java.FilterStringList.json b/taverna-localworker-activity-ui/src/main/resources/org.embl.ebi.escience.scuflworkers.java.FilterStringList.json
new file mode 100644
index 0000000..0f26e3e
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/resources/org.embl.ebi.escience.scuflworkers.java.FilterStringList.json
@@ -0,0 +1,20 @@
+{
+  "classLoaderSharing" : "workflow",
+  "script" : "filteredlist = new ArrayList();\nfor (Iterator i = stringlist.iterator(); i.hasNext();) {\n\tString item = (String) i.next();\n\tif (item.matches(regex)) {\n\t\tfilteredlist.add(item);\n\t}\n}\n",
+  "localworkerName" : "org.embl.ebi.escience.scuflworkers.java.FilterStringList",
+  "inputPorts" : [ {
+    "name" : "stringlist",
+    "depth" : 1,
+    "type" : "String"
+  }, {
+    "name" : "regex",
+    "depth" : 0,
+    "type" : "String"
+  } ],
+  "outputPorts" : [ {
+    "name" : "filteredlist",
+    "depth" : 1,
+    "granularDepth" : 1
+  } ],
+  "isAltered" : false
+}
\ No newline at end of file
diff --git a/taverna-localworker-activity-ui/src/main/resources/org.embl.ebi.escience.scuflworkers.java.FlattenList b/taverna-localworker-activity-ui/src/main/resources/org.embl.ebi.escience.scuflworkers.java.FlattenList
new file mode 100644
index 0000000..558cc99
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/resources/org.embl.ebi.escience.scuflworkers.java.FlattenList
@@ -0,0 +1,39 @@
+<activity xmlns="http://taverna.sf.net/2008/xml/t2flow"><class>net.sf.taverna.t2.activities.localworker.LocalworkerActivity</class><inputMap /><outputMap /><configBean encoding="xstream"><net.sf.taverna.t2.activities.localworker.LocalworkerActivityConfigurationBean xmlns="">

+  <script>flatten(inputs, outputs, depth) {

+	for (i = inputs.iterator(); i.hasNext();) {

+	    element = i.next();

+		if (element instanceof Collection &amp;&amp; depth &gt; 0) {

+			flatten(element, outputs, depth - 1);

+		} else {

+			outputs.add(element);

+		}

+	}

+}

+

+outputlist = new ArrayList();

+

+flatten(inputlist, outputlist, 1);</script>

+  <dependencies />

+  <inputs>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+      <handledReferenceSchemes />

+      <translatedElementType>[B</translatedElementType>

+      <allowsLiteralValues>true</allowsLiteralValues>

+      <name>inputlist</name>

+      <depth>2</depth>

+      <mimeTypes>

+        <string>l(l(''))</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+  </inputs>

+  <outputs>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>

+      <granularDepth>1</granularDepth>

+      <name>outputlist</name>

+      <depth>1</depth>

+      <mimeTypes>

+        <string>l('')</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>

+  </outputs>

+</net.sf.taverna.t2.activities.localworker.LocalworkerActivityConfigurationBean></configBean></activity>
\ No newline at end of file
diff --git a/taverna-localworker-activity-ui/src/main/resources/org.embl.ebi.escience.scuflworkers.java.FlattenList.json b/taverna-localworker-activity-ui/src/main/resources/org.embl.ebi.escience.scuflworkers.java.FlattenList.json
new file mode 100644
index 0000000..4992e0b
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/resources/org.embl.ebi.escience.scuflworkers.java.FlattenList.json
@@ -0,0 +1,16 @@
+{
+  "classLoaderSharing" : "workflow",
+  "script" : "flatten(inputs, outputs, depth) {\n\tfor (i = inputs.iterator(); i.hasNext();) {\n\t    element = i.next();\n\t\tif (element instanceof Collection && depth > 0) {\n\t\t\tflatten(element, outputs, depth - 1);\n\t\t} else {\n\t\t\toutputs.add(element);\n\t\t}\n\t}\n}\n\noutputlist = new ArrayList();\n\nflatten(inputlist, outputlist, 1);",
+  "localworkerName" : "org.embl.ebi.escience.scuflworkers.java.FlattenList",
+  "inputPorts" : [ {
+    "name" : "inputlist",
+    "depth" : 2,
+    "type" : "byte[]"
+  } ],
+  "outputPorts" : [ {
+    "name" : "outputlist",
+    "depth" : 1,
+    "granularDepth" : 1
+  } ],
+  "isAltered" : false
+}
\ No newline at end of file
diff --git a/taverna-localworker-activity-ui/src/main/resources/org.embl.ebi.escience.scuflworkers.java.PadNumber b/taverna-localworker-activity-ui/src/main/resources/org.embl.ebi.escience.scuflworkers.java.PadNumber
new file mode 100644
index 0000000..3edd0cf
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/resources/org.embl.ebi.escience.scuflworkers.java.PadNumber
@@ -0,0 +1,44 @@
+<activity xmlns="http://taverna.sf.net/2008/xml/t2flow"><class>net.sf.taverna.t2.activities.localworker.LocalworkerActivity</class><inputMap /><outputMap /><configBean encoding="xstream"><net.sf.taverna.t2.activities.localworker.LocalworkerActivityConfigurationBean xmlns="">

+  <script>int targetLengthInt = 7;

+if (targetlength != void) {

+	targetLengthInt = Integer.parseInt(targetlength);

+}

+int currentLength = input.length();

+while (input.length() &lt; targetLengthInt) {

+	input = "0" + input;

+}

+padded = input;</script>

+  <dependencies />

+  <inputs>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+      <handledReferenceSchemes />

+      <translatedElementType>java.lang.String</translatedElementType>

+      <allowsLiteralValues>true</allowsLiteralValues>

+      <name>input</name>

+      <depth>0</depth>

+      <mimeTypes>

+        <string>'text/plain'</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+      <handledReferenceSchemes />

+      <translatedElementType>java.lang.String</translatedElementType>

+      <allowsLiteralValues>true</allowsLiteralValues>

+      <name>targetlength</name>

+      <depth>0</depth>

+      <mimeTypes>

+        <string>'text/plain'</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+  </inputs>

+  <outputs>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>

+      <granularDepth>0</granularDepth>

+      <name>padded</name>

+      <depth>0</depth>

+      <mimeTypes>

+        <string>'text/plain'</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>

+  </outputs>

+</net.sf.taverna.t2.activities.localworker.LocalworkerActivityConfigurationBean></configBean></activity>
\ No newline at end of file
diff --git a/taverna-localworker-activity-ui/src/main/resources/org.embl.ebi.escience.scuflworkers.java.PadNumber.json b/taverna-localworker-activity-ui/src/main/resources/org.embl.ebi.escience.scuflworkers.java.PadNumber.json
new file mode 100644
index 0000000..37828ea
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/resources/org.embl.ebi.escience.scuflworkers.java.PadNumber.json
@@ -0,0 +1,20 @@
+{
+  "classLoaderSharing" : "workflow",
+  "script" : "int targetLengthInt = 7;\nif (targetlength != void) {\n\ttargetLengthInt = Integer.parseInt(targetlength);\n}\nint currentLength = input.length();\nwhile (input.length() < targetLengthInt) {\n\tinput = \"0\" + input;\n}\npadded = input;",
+  "localworkerName" : "org.embl.ebi.escience.scuflworkers.java.PadNumber",
+  "inputPorts" : [ {
+    "name" : "input",
+    "depth" : 0,
+    "type" : "String"
+  }, {
+    "name" : "targetlength",
+    "depth" : 0,
+    "type" : "String"
+  } ],
+  "outputPorts" : [ {
+    "name" : "padded",
+    "depth" : 0,
+    "granularDepth" : 0
+  } ],
+  "isAltered" : false
+}
\ No newline at end of file
diff --git a/taverna-localworker-activity-ui/src/main/resources/org.embl.ebi.escience.scuflworkers.java.RegularExpressionStringList b/taverna-localworker-activity-ui/src/main/resources/org.embl.ebi.escience.scuflworkers.java.RegularExpressionStringList
new file mode 100644
index 0000000..7a4165a
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/resources/org.embl.ebi.escience.scuflworkers.java.RegularExpressionStringList
@@ -0,0 +1,60 @@
+<activity xmlns="http://taverna.sf.net/2008/xml/t2flow"><class>net.sf.taverna.t2.activities.localworker.LocalworkerActivity</class><inputMap /><outputMap /><configBean encoding="xstream"><net.sf.taverna.t2.activities.localworker.LocalworkerActivityConfigurationBean xmlns="">

+  <script>import java.util.regex.*;

+

+filteredlist = new ArrayList();

+Pattern thePat = Pattern.compile(regex);

+int theGroup = Integer.parseInt(group);

+

+for (Iterator i = stringlist.iterator(); i.hasNext();) {

+	String item = (String) i.next();

+	Matcher matcher = thePat.matcher(item);

+

+	if (matcher.find()) {

+		filteredlist.add(matcher.group(theGroup));

+	}

+}

+</script>

+  <dependencies />

+  <inputs>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+      <handledReferenceSchemes />

+      <translatedElementType>java.lang.String</translatedElementType>

+      <allowsLiteralValues>true</allowsLiteralValues>

+      <name>stringlist</name>

+      <depth>1</depth>

+      <mimeTypes>

+        <string>l('text/plain')</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+      <handledReferenceSchemes />

+      <translatedElementType>java.lang.String</translatedElementType>

+      <allowsLiteralValues>true</allowsLiteralValues>

+      <name>regex</name>

+      <depth>0</depth>

+      <mimeTypes>

+        <string>'text/plain'</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+      <handledReferenceSchemes />

+      <translatedElementType>java.lang.String</translatedElementType>

+      <allowsLiteralValues>true</allowsLiteralValues>

+      <name>group</name>

+      <depth>0</depth>

+      <mimeTypes>

+        <string>'text/plain'</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityInputPortDefinitionBean>

+  </inputs>

+  <outputs>

+    <net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>

+      <granularDepth>1</granularDepth>

+      <name>filteredlist</name>

+      <depth>1</depth>

+      <mimeTypes>

+        <string>l('text/plain')</string>

+      </mimeTypes>

+    </net.sf.taverna.t2.workflowmodel.processor.activity.config.ActivityOutputPortDefinitionBean>

+  </outputs>

+</net.sf.taverna.t2.activities.localworker.LocalworkerActivityConfigurationBean></configBean></activity>
\ No newline at end of file
diff --git a/taverna-localworker-activity-ui/src/main/resources/org.embl.ebi.escience.scuflworkers.java.RegularExpressionStringList.json b/taverna-localworker-activity-ui/src/main/resources/org.embl.ebi.escience.scuflworkers.java.RegularExpressionStringList.json
new file mode 100644
index 0000000..86378fb
--- /dev/null
+++ b/taverna-localworker-activity-ui/src/main/resources/org.embl.ebi.escience.scuflworkers.java.RegularExpressionStringList.json
@@ -0,0 +1,24 @@
+{
+  "classLoaderSharing" : "workflow",
+  "script" : "import java.util.regex.*;\n\nfilteredlist = new ArrayList();\nPattern thePat = Pattern.compile(regex);\nint theGroup = Integer.parseInt(group);\n\nfor (Iterator i = stringlist.iterator(); i.hasNext();) {\n\tString item = (String) i.next();\n\tMatcher matcher = thePat.matcher(item);\n\n\tif (matcher.find()) {\n\t\tfilteredlist.add(matcher.group(theGroup));\n\t}\n}\n",
+  "localworkerName" : "org.embl.ebi.escience.scuflworkers.java.RegularExpressionStringList",