You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@taverna.apache.org by st...@apache.org on 2015/02/17 12:48:32 UTC

[13/50] [abbrv] incubator-taverna-workbench-common-activities git commit: taverna-external-tool-activity-ui/

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench-common-activities/blob/e48c3199/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/manager/ToolInvocationConfigurationPanel.java
----------------------------------------------------------------------
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();
+				}
+			});
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench-common-activities/blob/e48c3199/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/manager/ToolInvocationConfigurationUIFactory.java
----------------------------------------------------------------------
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;
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench-common-activities/blob/e48c3199/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/manager/local/LocalInvocationMechanismEditor.java
----------------------------------------------------------------------
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;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench-common-activities/blob/e48c3199/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/manager/ssh/ExternalToolSshNodeViewer.java
----------------------------------------------------------------------
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;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench-common-activities/blob/e48c3199/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/manager/ssh/SshInvocationMechanismEditor.java
----------------------------------------------------------------------
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");
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench-common-activities/blob/e48c3199/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/menu/AddExternalToolContextualMenuAction.java
----------------------------------------------------------------------
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;
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench-common-activities/blob/e48c3199/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/menu/AddExternalToolMenuAction.java
----------------------------------------------------------------------
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;
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench-common-activities/blob/e48c3199/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/menu/ConfigureExternalToolMenuAction.java
----------------------------------------------------------------------
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;
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench-common-activities/blob/e48c3199/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/menu/FeedbackMenuAction.java
----------------------------------------------------------------------
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);
+			}
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench-common-activities/blob/e48c3199/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/servicedescriptions/AddExternalToolServiceDialog.java
----------------------------------------------------------------------
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();
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench-common-activities/blob/e48c3199/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/servicedescriptions/ExternalToolActivityIcon.java
----------------------------------------------------------------------
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));
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench-common-activities/blob/e48c3199/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/servicedescriptions/ExternalToolServiceDescription.java
----------------------------------------------------------------------
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;
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench-common-activities/blob/e48c3199/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/servicedescriptions/ExternalToolServiceProvider.java
----------------------------------------------------------------------
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();
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench-common-activities/blob/e48c3199/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/servicedescriptions/ExternalToolServiceProviderConfig.java
----------------------------------------------------------------------
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;
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench-common-activities/blob/e48c3199/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/servicedescriptions/ExternalToolTemplateServiceDescription.java
----------------------------------------------------------------------
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;
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench-common-activities/blob/e48c3199/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/utils/Tools.java
----------------------------------------------------------------------
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;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench-common-activities/blob/e48c3199/taverna-external-tool-activity-ui/src/main/java/net/sf/taverna/t2/activities/externaltool/views/AnnotationPanel.java
----------------------------------------------------------------------
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);
+	}
+
+}