http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-loop-ui/src/main/java/net/sf/taverna/t2/workbench/loop/LoopConfigureMenuAction.java
----------------------------------------------------------------------
diff --git 
a/taverna-loop-ui/src/main/java/net/sf/taverna/t2/workbench/loop/LoopConfigureMenuAction.java
 
b/taverna-loop-ui/src/main/java/net/sf/taverna/t2/workbench/loop/LoopConfigureMenuAction.java
deleted file mode 100644
index caf77f5..0000000
--- 
a/taverna-loop-ui/src/main/java/net/sf/taverna/t2/workbench/loop/LoopConfigureMenuAction.java
+++ /dev/null
@@ -1,97 +0,0 @@
-/**********************************************************************
- * 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.workbench.loop;
-
-import java.awt.event.ActionEvent;
-import java.net.URI;
-
-import javax.swing.AbstractAction;
-import javax.swing.Action;
-
-import com.fasterxml.jackson.databind.node.ObjectNode;
-
-import org.apache.taverna.scufl2.api.core.Processor;
-
-import net.sf.taverna.t2.ui.menu.AbstractContextualMenuAction;
-import net.sf.taverna.t2.workbench.edits.EditManager;
-import net.sf.taverna.t2.workbench.file.FileManager;
-
-public class LoopConfigureMenuAction extends AbstractContextualMenuAction {
-
-       public static final URI configureRunningSection = URI
-       .create("http://taverna.sf.net/2009/contextMenu/configureRunning";);
-
-       private static final URI LOOP_CONFIGURE_URI = URI
-       .create("http://taverna.sf.net/2008/t2workbench/loopConfigure";);
-
-       private static final String LOOP_CONFIGURE = "Loop configure";
-
-       private EditManager editManager;
-
-       private FileManager fileManager;
-
-       public LoopConfigureMenuAction() {
-               super(configureRunningSection, 20, LOOP_CONFIGURE_URI);
-       }
-
-       @SuppressWarnings("serial")
-       @Override
-       protected Action createAction() {
-               return new AbstractAction("Looping...") {
-                       public void actionPerformed(ActionEvent e) {
-                               Processor p = (Processor) 
getContextualSelection().getSelection();
-                               configureLoopLayer(p, e);
-                       }
-               };
-       }
-
-       public void configureLoopLayer(Processor p, ActionEvent e) {
-           ObjectNode loopLayer = getLoopLayer(p);
-               if (loopLayer != null) {
-                       LoopConfigureAction loopConfigureAction = new 
LoopConfigureAction(null, null, loopLayer, editManager, fileManager);
-                       loopConfigureAction.actionPerformed(e);
-               }
-       }
-
-       public static ObjectNode getLoopLayer(Processor p) {
-               for (DispatchLayer dl : p.getDispatchStack().getLayers()) {
-                       if (dl instanceof Loop) {
-                               result = (Loop) dl;
-                               break;
-                       }
-               }
-               return result;
-       }
-
-       public boolean isEnabled() {
-               Object selection = getContextualSelection().getSelection();
-               return (super.isEnabled() && (selection instanceof Processor) 
&& (getLoopLayer((Processor)selection) != null));
-       }
-
-       public void setEditManager(EditManager editManager) {
-               this.editManager = editManager;
-       }
-
-       public void setFileManager(FileManager fileManager) {
-               this.fileManager = fileManager;
-       }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-loop-ui/src/main/java/net/sf/taverna/t2/workbench/loop/LoopContextualView.java
----------------------------------------------------------------------
diff --git 
a/taverna-loop-ui/src/main/java/net/sf/taverna/t2/workbench/loop/LoopContextualView.java
 
b/taverna-loop-ui/src/main/java/net/sf/taverna/t2/workbench/loop/LoopContextualView.java
deleted file mode 100644
index 98223da..0000000
--- 
a/taverna-loop-ui/src/main/java/net/sf/taverna/t2/workbench/loop/LoopContextualView.java
+++ /dev/null
@@ -1,172 +0,0 @@
-/*******************************************************************************
- * Copyright (C) 2008 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.workbench.loop;
-
-import java.awt.Frame;
-import java.awt.GridBagConstraints;
-import java.awt.GridBagLayout;
-import java.util.Properties;
-
-import javax.swing.Action;
-import javax.swing.JComponent;
-import javax.swing.JLabel;
-import javax.swing.JPanel;
-
-import net.sf.taverna.t2.workbench.edits.EditManager;
-import net.sf.taverna.t2.workbench.file.FileManager;
-import net.sf.taverna.t2.workbench.loop.comparisons.Comparison;
-import net.sf.taverna.t2.workbench.ui.views.contextualviews.ContextualView;
-
-import org.apache.log4j.Logger;
-
-import org.apache.taverna.scufl2.api.core.Processor;
-
-/**
- * View of a processor, including it's iteration stack, activities, etc.
- *
- * @author Stian Soiland-Reyes
- *
- */
-public class LoopContextualView extends ContextualView {
-
-       private static final long serialVersionUID = 1L;
-
-       private static Logger logger = 
Logger.getLogger(LoopContextualView.class);
-
-       private EditManager editManager;
-       private FileManager fileManager;
-
-       private Loop loopLayer;
-
-       private JPanel panel;
-
-       private Processor processor;
-
-       public LoopContextualView(Processor processor, EditManager editManager, 
FileManager fileManager) {
-               super();
-               this.loopLayer = loopLayer;
-               this.editManager = editManager;
-               this.fileManager = fileManager;
-               this.processor = processor;
-               initialise();
-               initView();
-       }
-
-       @Override
-       public Action getConfigureAction(Frame owner) {
-               return new LoopConfigureAction(owner, this, processor, 
editManager, fileManager);
-       }
-
-       @Override
-       public void refreshView() {
-               initialise();
-       }
-
-       private void initialise() {
-               if (panel == null) {
-                       panel = new JPanel();
-               } else {
-                       panel.removeAll();
-               }
-               panel.setLayout(new GridBagLayout());
-               updateUIByConfig();
-       }
-
-       @Override
-       public JComponent getMainFrame() {
-               return panel;
-       }
-
-       @Override
-       public String getViewTitle() {
-               return "Loop of " + processor.getLocalName();
-       }
-
-       protected void updateUIByConfig() {
-               GridBagConstraints gbc = new GridBagConstraints();
-               gbc.gridx = 0;
-               gbc.gridy = 1;
-               gbc.weightx = 0.1;
-               gbc.fill = GridBagConstraints.HORIZONTAL;
-
-               StringBuilder description = new StringBuilder("<html><body>");
-               Properties properties = 
loopLayer.getConfiguration().getProperties();
-               if (properties.getProperty(ActivityGenerator.COMPARISON,
-                               ActivityGenerator.CUSTOM_COMPARISON).equals(
-                               ActivityGenerator.CUSTOM_COMPARISON)) {
-                       Activity<?> condition = 
loopLayer.getConfiguration().getCondition();
-                       if (condition != null) {
-                               description.append("Looping using custom 
conditional ");
-                               if (condition instanceof BeanshellActivity) {
-                                       String script = 
((BeanshellActivity)condition).getConfiguration().getScript();
-                                       if (script != null) {
-                                               if (script.length() <= 100) {
-                                                       
description.append("<pre>\n");
-                                                       
description.append(script);
-                                                       
description.append("</pre>\n");
-                                               }
-                                       }
-                               }
-                       } else {
-                               description.append("<i>Unconfigured, will not 
loop</i>");
-                       }
-               } else {
-                       description.append("The service will be invoked 
repeatedly ");
-                       description.append("until<br> its output <strong>");
-                       description.append(properties
-                                       
.getProperty(ActivityGenerator.COMPARE_PORT));
-                       description.append("</strong> ");
-
-                       Comparison comparison = ActivityGenerator
-                                       .getComparisonById(properties
-                                                       
.getProperty(ActivityGenerator.COMPARISON));
-                       description.append(comparison.getName());
-
-                       description.append(" the " + comparison.getValueType() 
+ ": <pre>");
-                       description.append(properties
-                                       
.getProperty(ActivityGenerator.COMPARE_VALUE));
-                       description.append("</pre>");
-
-                       String delay = 
properties.getProperty(ActivityGenerator.DELAY, "");
-                       try {
-                               if (Double.parseDouble(delay) > 0) {
-                                       description.append("adding a delay of " 
+ delay
-                                                       + " seconds between 
loops.");
-                               }
-                       } catch (NumberFormatException ex) {
-                       }
-               }
-               description.append("</body></html>");
-
-               panel.add(new JLabel(description.toString()), gbc);
-               gbc.gridy++;
-
-               revalidate();
-       }
-
-
-
-       @Override
-       public int getPreferredPosition() {
-               return 400;
-       }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-loop-ui/src/main/java/net/sf/taverna/t2/workbench/loop/LoopContextualViewFactory.java
----------------------------------------------------------------------
diff --git 
a/taverna-loop-ui/src/main/java/net/sf/taverna/t2/workbench/loop/LoopContextualViewFactory.java
 
b/taverna-loop-ui/src/main/java/net/sf/taverna/t2/workbench/loop/LoopContextualViewFactory.java
deleted file mode 100644
index 7c3451d..0000000
--- 
a/taverna-loop-ui/src/main/java/net/sf/taverna/t2/workbench/loop/LoopContextualViewFactory.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*******************************************************************************
- * Copyright (C) 2008 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.workbench.loop;
-
-import java.util.Arrays;
-import java.util.List;
-
-import org.apache.taverna.scufl2.api.core.Processor;
-
-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;
-
-public class LoopContextualViewFactory implements 
ContextualViewFactory<Processor> {
-
-       private EditManager editManager;
-       private FileManager fileManager;
-
-       public boolean canHandle(Object selection) {
-               return selection instanceof Processor;
-       }
-
-       public List<ContextualView> getViews(Processor selection) {
-               return Arrays.asList(new ContextualView[] {new 
LoopContextualView(selection, editManager, fileManager)});
-       }
-
-       public void setEditManager(EditManager editManager) {
-               this.editManager = editManager;
-       }
-
-       public void setFileManager(FileManager fileManager) {
-               this.fileManager = fileManager;
-       }
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-loop-ui/src/main/java/net/sf/taverna/t2/workbench/loop/LoopRemoveMenuAction.java
----------------------------------------------------------------------
diff --git 
a/taverna-loop-ui/src/main/java/net/sf/taverna/t2/workbench/loop/LoopRemoveMenuAction.java
 
b/taverna-loop-ui/src/main/java/net/sf/taverna/t2/workbench/loop/LoopRemoveMenuAction.java
deleted file mode 100644
index 24a33bc..0000000
--- 
a/taverna-loop-ui/src/main/java/net/sf/taverna/t2/workbench/loop/LoopRemoveMenuAction.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/**********************************************************************
- * 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.workbench.loop;
-
-import java.awt.event.ActionEvent;
-import java.net.URI;
-
-import javax.swing.AbstractAction;
-import javax.swing.Action;
-
-import net.sf.taverna.t2.ui.menu.AbstractContextualMenuAction;
-import net.sf.taverna.t2.workbench.edits.EditManager;
-import net.sf.taverna.t2.workbench.file.FileManager;
-
-import org.apache.log4j.Logger;
-
-import org.apache.taverna.scufl2.api.core.Processor;
-
-public class LoopRemoveMenuAction extends AbstractContextualMenuAction {
-
-       private static Logger logger = Logger
-       .getLogger(LoopRemoveMenuAction.class);
-
-       public static final URI configureRunningSection = URI
-       .create("http://taverna.sf.net/2009/contextMenu/configureRunning";);
-
-       private static final URI LOOP_REMOVE_URI = URI
-       .create("http://taverna.sf.net/2008/t2workbench/loopRemove";);
-
-       private static final String LOOP_REMOVE = "Loop remove";
-
-       public LoopRemoveMenuAction() {
-               super(configureRunningSection, 25, LOOP_REMOVE_URI);
-       }
-
-       private EditManager editManager;
-       private FileManager fileManager;
-
-
-       @SuppressWarnings("serial")
-       @Override
-       protected Action createAction() {
-               return new AbstractAction("Disable looping") {
-                       public void actionPerformed(ActionEvent e) {
-                               Processor p = (Processor) 
getContextualSelection().getSelection();
-                                       Loop loopLayer = 
LoopConfigureMenuAction.getLoopLayer(p);
-                                       Edit<DispatchStack> deleteEdit = 
editManager.getEdits().getDeleteDispatchLayerEdit(
-                                                       p.getDispatchStack(), 
loopLayer);
-                                       // TODO: Should warn before removing 
"essential" layers
-                                       try {
-                                               
editManager.doDataflowEdit(fileManager.getCurrentDataflow(),
-                                                               deleteEdit);
-                                       } catch (EditException ex) {
-                                               logger.warn("Could not remove 
layer " + loopLayer, ex);
-                                       }
-
-                       }
-               };
-       }
-
-       public boolean isEnabled() {
-               Object selection = getContextualSelection().getSelection();
-               return (super.isEnabled() && (selection instanceof Processor) 
&& (LoopConfigureMenuAction.getLoopLayer((Processor)selection) != null));
-       }
-
-       public void setEditManager(EditManager editManager) {
-               this.editManager = editManager;
-       }
-
-       public void setFileManager(FileManager fileManager) {
-               this.fileManager = fileManager;
-       }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-loop-ui/src/main/java/net/sf/taverna/t2/workbench/loop/comparisons/Comparison.java
----------------------------------------------------------------------
diff --git 
a/taverna-loop-ui/src/main/java/net/sf/taverna/t2/workbench/loop/comparisons/Comparison.java
 
b/taverna-loop-ui/src/main/java/net/sf/taverna/t2/workbench/loop/comparisons/Comparison.java
deleted file mode 100644
index 608030c..0000000
--- 
a/taverna-loop-ui/src/main/java/net/sf/taverna/t2/workbench/loop/comparisons/Comparison.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*******************************************************************************
- * Copyright (C) 2008 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.workbench.loop.comparisons;
-
-import net.sf.taverna.t2.workbench.loop.LoopConfigurationPanel;
-
-/**
- * A comparison beanshell template for {@link LoopConfigurationPanel}.
- * <p>
- * A comparison is a template for generating a beanshell that can be used for
- * comparisons in say the {@link Loop} layer.
- * 
- * @author Stian Soiland-Reyes
- * 
- */
-public abstract class Comparison {
-
-       public String toString() {
-               return getName();
-       }
-
-       public abstract String getId();
-
-       public abstract String getName();
-
-       public abstract String getValueType();
-
-       public abstract String getScriptTemplate();
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-loop-ui/src/main/java/net/sf/taverna/t2/workbench/loop/comparisons/EqualTo.java
----------------------------------------------------------------------
diff --git 
a/taverna-loop-ui/src/main/java/net/sf/taverna/t2/workbench/loop/comparisons/EqualTo.java
 
b/taverna-loop-ui/src/main/java/net/sf/taverna/t2/workbench/loop/comparisons/EqualTo.java
deleted file mode 100644
index dbfb8f5..0000000
--- 
a/taverna-loop-ui/src/main/java/net/sf/taverna/t2/workbench/loop/comparisons/EqualTo.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*******************************************************************************
- * Copyright (C) 2008 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.workbench.loop.comparisons;
-
-public class EqualTo extends Comparison {
-
-       public String getId() {
-               return "EqualTo";
-       }
-
-       public String getName() {
-               return "is equal to";
-       }
-
-       public String getScriptTemplate() {
-               return "${loopPort} = \"\" + ! ${port}.equals(${value}); ";
-       }
-
-       public String getValueType() {
-               return "string";
-       }
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-loop-ui/src/main/java/net/sf/taverna/t2/workbench/loop/comparisons/IsGreaterThan.java
----------------------------------------------------------------------
diff --git 
a/taverna-loop-ui/src/main/java/net/sf/taverna/t2/workbench/loop/comparisons/IsGreaterThan.java
 
b/taverna-loop-ui/src/main/java/net/sf/taverna/t2/workbench/loop/comparisons/IsGreaterThan.java
deleted file mode 100644
index fc6f56b..0000000
--- 
a/taverna-loop-ui/src/main/java/net/sf/taverna/t2/workbench/loop/comparisons/IsGreaterThan.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*******************************************************************************
- * Copyright (C) 2008 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.workbench.loop.comparisons;
-
-public class IsGreaterThan extends Comparison {
-
-       public String getId() {
-               return "IsGreaterThan";
-       }
-
-       public String getName() {
-               return "is greater than";
-       }
-
-       public String getScriptTemplate() {
-               return "${loopPort} = \"\" + (! (Double.parseDouble(${port}) > 
Double.parseDouble(${value})));";
-       }
-
-       public String getValueType() {
-               return "number";
-       }
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-loop-ui/src/main/java/net/sf/taverna/t2/workbench/loop/comparisons/IsLessThan.java
----------------------------------------------------------------------
diff --git 
a/taverna-loop-ui/src/main/java/net/sf/taverna/t2/workbench/loop/comparisons/IsLessThan.java
 
b/taverna-loop-ui/src/main/java/net/sf/taverna/t2/workbench/loop/comparisons/IsLessThan.java
deleted file mode 100644
index d5fe38c..0000000
--- 
a/taverna-loop-ui/src/main/java/net/sf/taverna/t2/workbench/loop/comparisons/IsLessThan.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*******************************************************************************
- * Copyright (C) 2008 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.workbench.loop.comparisons;
-
-public class IsLessThan extends Comparison {
-
-       public String getId() {
-               return "IsLessThan";
-       }
-
-       public String getName() {
-               return "is less than";
-       }
-
-       public String getScriptTemplate() {
-               return "${loopPort} = \"\" + (! (Double.parseDouble(${port}) < 
Double.parseDouble(${value})));";
-       }
-
-       public String getValueType() {
-               return "number";
-       }
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-loop-ui/src/main/java/net/sf/taverna/t2/workbench/loop/comparisons/Matches.java
----------------------------------------------------------------------
diff --git 
a/taverna-loop-ui/src/main/java/net/sf/taverna/t2/workbench/loop/comparisons/Matches.java
 
b/taverna-loop-ui/src/main/java/net/sf/taverna/t2/workbench/loop/comparisons/Matches.java
deleted file mode 100644
index fa84aeb..0000000
--- 
a/taverna-loop-ui/src/main/java/net/sf/taverna/t2/workbench/loop/comparisons/Matches.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*******************************************************************************
- * Copyright (C) 2008 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.workbench.loop.comparisons;
-
-public class Matches extends Comparison {
-
-       public String getId() {
-               return "Matches";
-       }
-
-       public String getName() {
-               return "matches";
-       }
-
-       public String getScriptTemplate() {
-               return "${loopPort} = \"\" + ! ${port}.matches(${value});";
-       }
-
-       public String getValueType() {
-               return "regular expression";
-       }
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-loop-ui/src/main/java/net/sf/taverna/t2/workbench/loop/comparisons/NotEqualTo.java
----------------------------------------------------------------------
diff --git 
a/taverna-loop-ui/src/main/java/net/sf/taverna/t2/workbench/loop/comparisons/NotEqualTo.java
 
b/taverna-loop-ui/src/main/java/net/sf/taverna/t2/workbench/loop/comparisons/NotEqualTo.java
deleted file mode 100644
index 9c73835..0000000
--- 
a/taverna-loop-ui/src/main/java/net/sf/taverna/t2/workbench/loop/comparisons/NotEqualTo.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*******************************************************************************
- * Copyright (C) 2008 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.workbench.loop.comparisons;
-
-public class NotEqualTo extends Comparison {
-
-       public String getId() {
-               return "NotEqualTo";
-       }
-
-       public String getName() {
-               return "is not equal to";
-       }
-
-       public String getScriptTemplate() {
-               return "${loopPort} = \"\" + ${port}.equals(${value});";
-       }
-
-       public String getValueType() {
-               return "string";
-       }
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-loop-ui/src/main/java/net/sf/taverna/t2/workbench/loop/comparisons/NotMatches.java
----------------------------------------------------------------------
diff --git 
a/taverna-loop-ui/src/main/java/net/sf/taverna/t2/workbench/loop/comparisons/NotMatches.java
 
b/taverna-loop-ui/src/main/java/net/sf/taverna/t2/workbench/loop/comparisons/NotMatches.java
deleted file mode 100644
index 803d5d7..0000000
--- 
a/taverna-loop-ui/src/main/java/net/sf/taverna/t2/workbench/loop/comparisons/NotMatches.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*******************************************************************************
- * Copyright (C) 2008 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.workbench.loop.comparisons;
-
-public class NotMatches extends Comparison {
-
-       public String getId() {
-               return "NotMatches";
-       }
-
-       public String getName() {
-               return "does not match";
-       }
-
-       public String getScriptTemplate() {
-               return "${loopPort} = \"\" + ${port}.matches(${value});";
-       }
-
-       public String getValueType() {
-               return "regular expression";
-       }
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-loop-ui/src/main/java/org/apache/taverna/workbench/loop/ActivityGenerator.java
----------------------------------------------------------------------
diff --git 
a/taverna-loop-ui/src/main/java/org/apache/taverna/workbench/loop/ActivityGenerator.java
 
b/taverna-loop-ui/src/main/java/org/apache/taverna/workbench/loop/ActivityGenerator.java
new file mode 100644
index 0000000..1239a2a
--- /dev/null
+++ 
b/taverna-loop-ui/src/main/java/org/apache/taverna/workbench/loop/ActivityGenerator.java
@@ -0,0 +1,194 @@
+/*******************************************************************************
+ * Copyright (C) 2008 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 org.apache.taverna.workbench.loop;
+
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import java.util.Map.Entry;
+
+import org.apache.taverna.workbench.loop.comparisons.Comparison;
+import org.apache.taverna.workbench.loop.comparisons.EqualTo;
+import org.apache.taverna.workbench.loop.comparisons.IsGreaterThan;
+import org.apache.taverna.workbench.loop.comparisons.IsLessThan;
+import org.apache.taverna.workbench.loop.comparisons.Matches;
+import org.apache.taverna.workbench.loop.comparisons.NotEqualTo;
+import org.apache.taverna.workbench.loop.comparisons.NotMatches;
+
+import org.apache.log4j.Logger;
+
+import org.apache.taverna.scufl2.api.activity.Activity;
+import org.apache.taverna.scufl2.api.common.Scufl2Tools;
+import org.apache.taverna.scufl2.api.configurations.Configuration;
+import org.apache.taverna.scufl2.api.core.Processor;
+import org.apache.taverna.scufl2.api.port.InputActivityPort;
+import org.apache.taverna.scufl2.api.port.InputProcessorPort;
+import org.apache.taverna.scufl2.api.port.OutputActivityPort;
+import org.apache.taverna.scufl2.api.port.OutputProcessorPort;
+
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
+public class ActivityGenerator {
+
+    private static final String LOOP_PORT = "loop";
+
+    private static final String SCRIPT = "script";
+
+    public static URI BEANSHELL_ACTIVITY = URI
+            .create("http://ns.taverna.org.uk/2010/activity/beanshell";);
+
+    public static URI BEANSHELL_CONFIG = BEANSHELL_ACTIVITY.resolve("#Config");
+
+    
+       public static final double DEFAULT_DELAY_S = 0.2;
+       public static final String COMPARE_PORT = "comparePort";
+       public static final String COMPARISON = "comparison";
+       public static final String CUSTOM_COMPARISON = "custom";
+       public static final String COMPARE_VALUE = "compareValue";
+       public static final String IS_FEED_BACK = "isFeedBack";
+       public static final String DELAY = "delay";
+
+       private static Logger logger = 
Logger.getLogger(ActivityGenerator.class);
+       private final ObjectNode loopProperties;
+       private final Processor processorToCompare;
+       private static Scufl2Tools scufl2Tools = new Scufl2Tools();
+
+       public ActivityGenerator(ObjectNode configuration,
+                       Processor processorToCompare) {
+               this.loopProperties = configuration;
+               this.processorToCompare = processorToCompare;
+       }
+
+       protected Activity generateActivity() {
+               Activity beanshell = new Activity();
+               beanshell.setType(BEANSHELL_ACTIVITY);
+               Configuration config = generateBeanshellConfig(beanshell);
+               // TODO: Where to put the config?
+               return beanshell;
+       }
+
+       private Configuration generateBeanshellConfig(Activity beanshell) {
+           Configuration config = 
scufl2Tools.createConfigurationFor(beanshell, BEANSHELL_CONFIG);
+           generateInputPorts(beanshell);
+           generateOutputPorts(beanshell);
+           config.getJsonAsObjectNode().put(SCRIPT, generateScript());
+               return config;
+       }
+
+       protected static List<Comparison> comparisons = Arrays.asList(
+                       new EqualTo(), new NotEqualTo(), new Matches(), new 
NotMatches(),
+                       new IsGreaterThan(), new IsLessThan());
+
+       protected static Comparison getComparisonById(String id) {
+           if (id == null || id.isEmpty()) {
+               return comparisons.get(0);
+           }
+               for (Comparison potentialComparison : comparisons) {
+                       if (potentialComparison.getId().equals(id)) {
+                               return potentialComparison;
+                       }
+               }
+               return null;
+       }
+
+       @SuppressWarnings("boxing")
+       private String generateScript() {
+               Map<String, String> replacements = new HashMap<String, 
String>();
+               replacements.put("${loopPort}", LOOP_PORT);
+               replacements.put("${port}", 
loopProperties.findValue(COMPARE_PORT).asText());
+               replacements.put("${value}", beanshellString(loopProperties
+                               .findValue(COMPARE_VALUE).asText()));
+
+
+               // as seconds
+               Double delay = 
loopProperties.findPath(DELAY).asDouble(DEFAULT_DELAY_S);
+               // as milliseconds
+               delay = Math.max(0.0, delay) * 1000;
+               // as integer (for Thread.sleep)
+               replacements.put("${delay}", 
Integer.toString(delay.intValue()));
+
+               String template = getComparisonById(
+                               
loopProperties.findValue(COMPARISON).asText()).getScriptTemplate();
+
+               if (delay > 0.0) {
+               template += "\nif (\"true\".matches(${loopPort})) {\n";
+               template += "   Thread.sleep(${delay});\n";
+               template += "}";
+               }
+
+               String script = template;
+               for (Entry<String, String> mapping : replacements.entrySet()) {
+                       script = script.replace(mapping.getKey(), 
mapping.getValue());
+               }
+               return script;
+       }
+
+       private String beanshellString(String value) {
+               value = value.replace("\\", "\\\\");
+               value = value.replace("\n", "\\n");
+               value = value.replace("\"", "\\\"");
+               return '"' + value + '"';
+       }
+
+       private void generateInputPorts(Activity beanshell) {
+               if (processorToCompare == null) {
+                   return;
+               }
+               for (OutputProcessorPort procOut : 
processorToCompare.getOutputPorts()) {
+                   // Any of the outputs are available to the script, giving
+                   // a custom script that compares multiple outputs a better
+                   // starting point.
+                       String portName = procOut.getName();
+                       if 
(portName.equals(loopProperties.findValue(COMPARE_PORT).asText()) ||
+                               
(loopProperties.findValue(IS_FEED_BACK).asBoolean())) {
+                               InputActivityPort input = new 
InputActivityPort(beanshell, portName);
+                               input.setDepth(procOut.getDepth());
+                               input.setParent(beanshell);
+                       }
+               }
+       }
+
+       private void generateOutputPorts(Activity beanshell) {
+              OutputActivityPort loopPort = new OutputActivityPort(beanshell, 
LOOP_PORT);
+               loopPort.setDepth(0);
+               loopPort.setGranularDepth(0);
+           if (processorToCompare == null) {
+            return;
+           }       
+           if (! loopProperties.findValue(IS_FEED_BACK).asBoolean()) {
+           return;
+           }
+           for (InputProcessorPort procIn : 
processorToCompare.getInputPorts()) {
+            String portName = procIn.getName();
+            if (processorToCompare.getOutputPorts().containsName(portName)) {
+                OutputActivityPort actOut = new OutputActivityPort(beanshell, 
portName);
+                actOut.setDepth(procIn.getDepth());
+                actOut.setGranularDepth(procIn.getDepth());
+            }
+           }
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-loop-ui/src/main/java/org/apache/taverna/workbench/loop/AddLoopFactory.java
----------------------------------------------------------------------
diff --git 
a/taverna-loop-ui/src/main/java/org/apache/taverna/workbench/loop/AddLoopFactory.java
 
b/taverna-loop-ui/src/main/java/org/apache/taverna/workbench/loop/AddLoopFactory.java
new file mode 100644
index 0000000..087cba2
--- /dev/null
+++ 
b/taverna-loop-ui/src/main/java/org/apache/taverna/workbench/loop/AddLoopFactory.java
@@ -0,0 +1,125 @@
+/*******************************************************************************
+ * Copyright (C) 2008 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 org.apache.taverna.workbench.loop;
+
+import java.awt.event.ActionEvent;
+import java.net.URI;
+import java.util.List;
+
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+
+import org.apache.taverna.workbench.MainWindow;
+import org.apache.taverna.workbench.edits.EditManager;
+import org.apache.taverna.workbench.file.FileManager;
+import org.apache.taverna.workbench.selection.SelectionManager;
+import 
org.apache.taverna.workbench.ui.views.contextualviews.AddLayerFactorySPI;
+
+import org.apache.log4j.Logger;
+
+import uk.org.taverna.configuration.app.ApplicationConfiguration;
+import org.apache.taverna.scufl2.api.common.Scufl2Tools;
+import org.apache.taverna.scufl2.api.configurations.Configuration;
+import org.apache.taverna.scufl2.api.core.Processor;
+
+import com.fasterxml.jackson.databind.node.JsonNodeFactory;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
+public class AddLoopFactory implements AddLayerFactorySPI {
+
+    private static final URI LOOP_TYPE = 
URI.create("http://ns.taverna.org.uk/2010/scufl2/taverna/dispatchlayer/Loop";);
+
+    
+    private static Logger logger = Logger.getLogger(AddLoopFactory.class);
+    private static final JsonNodeFactory JSON_NODE_FACTORY = 
JsonNodeFactory.instance;
+    private static Scufl2Tools scufl2Tools = new Scufl2Tools();
+    
+       private EditManager editManager;
+       private FileManager fileManager;
+       private SelectionManager selectionManager;
+       private ApplicationConfiguration applicationConfig;
+
+       public boolean canAddLayerFor(Processor processor) {
+          return findLoopLayer(processor) == null;
+       }
+
+
+    public ObjectNode findLoopLayer(Processor processor) {
+        List<Configuration> configs = scufl2Tools.configurationsFor(processor, 
selectionManager.getSelectedProfile());
+        for (Configuration config : configs) {
+            if (config.getJson().has("loop")) {
+                return (ObjectNode) config.getJson().get("loop");
+            }
+        }
+        return null;
+    }
+       
+       @SuppressWarnings("serial")
+       public Action getAddLayerActionFor(final Processor processor) {
+               return new AbstractAction("Add looping") {
+
+            public void actionPerformed(ActionEvent e) {
+                                   ObjectNode loopLayer = 
findLoopLayer(processor);
+                                   if (loopLayer == null) {
+                                       loopLayer = 
JSON_NODE_FACTORY.objectNode();
+                                   }
+                                       // Pop up the configure loop dialog
+                LoopConfigureAction loopConfigureAction = new 
LoopConfigureAction(
+                        MainWindow.getMainWindow(), null, processor, loopLayer,
+                        selectionManager.getSelectedProfile(), editManager,
+                        fileManager, getApplicationConfig());
+                                       loopConfigureAction.actionPerformed(e);
+                       }
+               };
+       }
+
+       @Override
+       public boolean canCreateLayerClass(URI dispatchLayerType) {
+           return dispatchLayerType.equals(LOOP_TYPE);
+       }
+
+       public void setEditManager(EditManager editManager) {
+               this.editManager = editManager;
+       }
+
+       public void setFileManager(FileManager fileManager) {
+               this.fileManager = fileManager;
+       }
+
+    public SelectionManager getSelectionManager() {
+        return selectionManager;
+    }
+
+    public void setSelectionManager(SelectionManager selectionManager) {
+        this.selectionManager = selectionManager;
+    }
+
+
+    public ApplicationConfiguration getApplicationConfig() {
+        return applicationConfig;
+    }
+
+
+    public void setApplicationConfig(ApplicationConfiguration 
applicationConfig) {
+        this.applicationConfig = applicationConfig;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-loop-ui/src/main/java/org/apache/taverna/workbench/loop/LoopAddMenuAction.java
----------------------------------------------------------------------
diff --git 
a/taverna-loop-ui/src/main/java/org/apache/taverna/workbench/loop/LoopAddMenuAction.java
 
b/taverna-loop-ui/src/main/java/org/apache/taverna/workbench/loop/LoopAddMenuAction.java
new file mode 100644
index 0000000..571bc8d
--- /dev/null
+++ 
b/taverna-loop-ui/src/main/java/org/apache/taverna/workbench/loop/LoopAddMenuAction.java
@@ -0,0 +1,73 @@
+/**********************************************************************
+ * 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 org.apache.taverna.workbench.loop;
+
+import java.awt.event.ActionEvent;
+import java.net.URI;
+
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+
+import org.apache.taverna.scufl2.api.core.Processor;
+
+import org.apache.taverna.ui.menu.AbstractContextualMenuAction;
+
+public class LoopAddMenuAction extends AbstractContextualMenuAction {
+
+       public static final URI configureRunningSection = URI
+       .create("http://taverna.sf.net/2009/contextMenu/configureRunning";);
+
+       private static final URI LOOP_ADD_URI = URI
+       .create("http://taverna.sf.net/2008/t2workbench/loopAdd";);
+
+       private static final String LOOP_ADD = "Loop add";
+
+       public LoopAddMenuAction() {
+               super(configureRunningSection, 20, LOOP_ADD_URI);
+       }
+
+       private AddLoopFactory addLoopFactory;
+
+       @SuppressWarnings("serial")
+       @Override
+       protected Action createAction() {
+               return new AbstractAction("Looping...") {
+                       public void actionPerformed(ActionEvent e) {
+                               //Loop loopLayer = null;
+                               Processor p = (Processor) 
getContextualSelection().getSelection();
+                               
addLoopFactory.getAddLayerActionFor(p).actionPerformed(e);
+                               //LoopConfigureMenuAction.configureLoopLayer(p, 
e); // Configuration dialog pop up is now done from getAddLayerActionFor()
+                       }
+               };
+       }
+
+       public boolean isEnabled() {
+               Object selection = getContextualSelection().getSelection();
+               return (super.isEnabled() && (selection instanceof Processor) 
&& (LoopConfigureMenuAction.getLoopLayer((Processor)selection) == null));
+       }
+
+       public void setAddLoopFactory(AddLoopFactory addLoopFactory) {
+               this.addLoopFactory = addLoopFactory;
+       }
+
+
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-loop-ui/src/main/java/org/apache/taverna/workbench/loop/LoopConfigurationPanel.java
----------------------------------------------------------------------
diff --git 
a/taverna-loop-ui/src/main/java/org/apache/taverna/workbench/loop/LoopConfigurationPanel.java
 
b/taverna-loop-ui/src/main/java/org/apache/taverna/workbench/loop/LoopConfigurationPanel.java
new file mode 100644
index 0000000..f9d768a
--- /dev/null
+++ 
b/taverna-loop-ui/src/main/java/org/apache/taverna/workbench/loop/LoopConfigurationPanel.java
@@ -0,0 +1,588 @@
+/*******************************************************************************
+ * Copyright (C) 2008 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 org.apache.taverna.workbench.loop;
+
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.FlowLayout;
+import java.awt.Frame;
+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.List;
+import java.util.Properties;
+
+import javax.swing.AbstractAction;
+import javax.swing.Box;
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JComboBox;
+import javax.swing.JDialog;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JTextField;
+import javax.swing.SwingConstants;
+import javax.swing.border.EmptyBorder;
+
+import 
net.sf.taverna.t2.activities.beanshell.views.BeanshellConfigurationPanel;
+import org.apache.taverna.workbench.helper.HelpEnabledDialog;
+import org.apache.taverna.workbench.loop.comparisons.Comparison;
+import org.apache.taverna.workbench.ui.Utils;
+
+import org.apache.log4j.Logger;
+
+import uk.org.taverna.configuration.app.ApplicationConfiguration;
+import org.apache.taverna.scufl2.api.activity.Activity;
+import org.apache.taverna.scufl2.api.common.Scufl2Tools;
+import org.apache.taverna.scufl2.api.configurations.Configuration;
+import org.apache.taverna.scufl2.api.core.Processor;
+import org.apache.taverna.scufl2.api.profiles.Profile;
+
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
+/**
+ * UI for {@link LoopConfiguration}
+ *
+ * @author Stian Soiland-Reyes
+ *
+ */
+@SuppressWarnings("serial")
+public class LoopConfigurationPanel extends JPanel {
+
+       private static final String CONDITION_ACTIVITY = "conditionActivity";
+    private static final String DEFAULT_DELAY_S = "0.5";
+       protected ObjectNode configuration;
+
+       private static final Scufl2Tools scufl2tools = new Scufl2Tools();
+       private ApplicationConfiguration applicationConfig;
+
+       
+       protected final Processor processor;
+
+       protected JPanel headerPanel = new JPanel();
+       protected JPanel optionsPanel = new JPanel();
+       protected JPanel configPanel = new JPanel();
+       protected JPanel customPanel = new JPanel();
+
+       protected JLabel valueTypeLabel = new JLabel("the string");
+
+       protected JTextField valueField = new JTextField("", 15);
+
+       protected JLabel delayLabel = new JLabel("adding a delay of ");
+       protected JTextField delayField = new JTextField(
+                       Double.toString(ActivityGenerator.DEFAULT_DELAY_S), 4);
+       protected JLabel secondsLabel = new JLabel(" seconds between the 
loops.");
+
+       private JComboBox<String> portCombo;
+       private JComboBox<Comparison> comparisonCombo;
+       private JButton customizeButton;
+
+       protected ObjectNode loopLayer;
+       private Object Comparison;
+       private Activity originalCondition = null;
+    private Profile profile;
+
+    public LoopConfigurationPanel(Processor processor, ObjectNode loopLayer,
+            Profile profile, ApplicationConfiguration applicationConfig) {
+               this.processor = processor;
+               this.loopLayer = loopLayer;
+        this.profile = profile;
+        this.applicationConfig = applicationConfig;
+               this.setBorder(new EmptyBorder(10,10,10,10));
+               initialise();
+               setConfiguration(loopLayer);
+       }
+
+       public ObjectNode getConfiguration() {
+               uiToConfig();
+               return loopLayer.deepCopy();
+       }
+
+       private static Logger logger = Logger
+                       .getLogger(LoopConfigurationPanel.class);
+
+       protected void uiToConfig() {
+           String comparisonStr = 
configuration.path(ActivityGenerator.COMPARISON).asText();
+           if (comparisonStr.isEmpty()) {
+               comparisonStr = ActivityGenerator.CUSTOM_COMPARISON;
+           }
+               if (comparisonStr.equals(ActivityGenerator.CUSTOM_COMPARISON)
+                               && ! 
configuration.path(CONDITION_ACTIVITY).asText().isEmpty()) {
+                       // Ignore values
+               } else {
+                   configuration.put("runFirst", true);
+                       if (portCombo.getSelectedItem() == null) {
+                           // unconfigured port
+                               
configuration.remove(ActivityGenerator.COMPARE_PORT);
+                               configuration.putNull(CONDITION_ACTIVITY);
+                               return;
+                       } else {
+                               
configuration.put(ActivityGenerator.COMPARE_PORT,
+                                               ((String) 
portCombo.getSelectedItem()));
+                       }
+
+                       Comparison comparison = (Comparison) comparisonCombo
+                                       .getSelectedItem();
+                       if (comparison == null) {
+                               
configuration.remove(ActivityGenerator.COMPARISON);
+                               configuration.putNull(CONDITION_ACTIVITY);
+                               return;
+                       } else {
+                               configuration
+                                               
.put(ActivityGenerator.COMPARISON, comparison.getId());
+                       }
+                       configuration.put(ActivityGenerator.COMPARE_VALUE, 
valueField
+                                       .getText());
+                       configuration.put(ActivityGenerator.DELAY, 
Double.parseDouble(delayField.getText()));
+                       configuration.put(ActivityGenerator.IS_FEED_BACK, 
feedBackCheck.isSelected());
+
+                       // Generate activity
+                       ActivityGenerator activityGenerator = new 
ActivityGenerator(
+                                       configuration, processor);
+                       configuration.put(CONDITION_ACTIVITY, 
activityGenerator.generateActivity().getName());
+               }
+       }
+
+       public class ResetAction extends AbstractAction {
+               public ResetAction() {
+                       super("Clear");
+               }
+
+               public void actionPerformed(ActionEvent e) {
+                       configuration.putNull(CONDITION_ACTIVITY);
+                       configToUi();
+               }
+       }
+
+       private final class CustomizeAction implements ActionListener {
+
+
+//             public CustomizeAction() {
+//                     super();
+//                     //putValue(NAME, "Customise loop condition");
+//             }
+
+               public void actionPerformed(ActionEvent e) {
+                       uiToConfig();
+
+                       String conditionName = 
configuration.path(CONDITION_ACTIVITY).asText();
+                       
+                       Activity condition = 
profile.getActivities().getByName(conditionName);
+                       if (condition == null) {
+                           condition = new Activity();
+                           profile.getActivities().add(condition);
+                           configuration.put(CONDITION_ACTIVITY, 
condition.getName());
+                           
condition.setType(ActivityGenerator.BEANSHELL_ACTIVITY);
+                           Configuration config = 
scufl2tools.createConfigurationFor(condition, 
ActivityGenerator.BEANSHELL_CONFIG);
+                       } else if 
(!(condition.getType().equals(ActivityGenerator.BEANSHELL_ACTIVITY))) {
+                               logger.warn("Can't configure unsupported loop 
condition of service type "
+                                               + condition.getType());
+                               return;
+                       }
+
+                       Frame owner = 
Utils.getParentFrame(LoopConfigurationPanel.this);
+                       
+                       
+            final BeanshellConfigurationPanel beanshellConfigView = new 
BeanshellConfigurationPanel(
+                    condition, applicationConfig);
+                       
+                       final JDialog dialog = new HelpEnabledDialog(owner, 
"Customize looping", true);
+                       dialog.setLayout(new BorderLayout());
+                       dialog.add(beanshellConfigView, BorderLayout.NORTH);
+                       dialog.setSize(600, 600);
+                       JPanel buttonPanel = new JPanel();
+
+                       buttonPanel.setLayout(new FlowLayout(FlowLayout.RIGHT));
+
+                       JButton applyButton = new JButton(new AbstractAction() {
+
+                               public void actionPerformed(ActionEvent e) {
+                                       if 
(beanshellConfigView.isConfigurationChanged()) {
+                                               
beanshellConfigView.noteConfiguration();
+//                                                     
beanshellActivity.configure(beanshellConfigView
+//                                                                     
.getConfiguration());
+//                                                     
configuration.setCondition(beanshellActivity);
+                                               Configuration config = 
beanshellConfigView.getConfiguration();
+                                               // TODO: Do we need to store 
this somehow?
+                                               configuration.put(
+                                                               
ActivityGenerator.COMPARISON,
+                                                               
ActivityGenerator.CUSTOM_COMPARISON);
+                                       }
+                                       dialog.setVisible(false);
+                                       configToUi();
+                               }
+
+                       });
+                       applyButton.setText("Apply");
+
+                       buttonPanel.add(applyButton);
+                       JButton closeButton = new JButton(new AbstractAction() {
+
+                               public void actionPerformed(ActionEvent e) {
+                                       dialog.setVisible(false);
+                               }
+                       });
+                       closeButton.setText("Cancel");
+                       buttonPanel.add(closeButton);
+                       dialog.add(buttonPanel, BorderLayout.SOUTH);
+                       dialog.setLocationRelativeTo(customizeButton);
+                       dialog.setVisible(true);
+
+               }
+       }
+
+       public void setConfiguration(ObjectNode configuration) {
+               this.configuration = configuration.deepCopy();
+               configToUi();
+       }
+
+       protected void configToUi() {
+               
+
+               String comparisonId;
+               
+               if (configuration.has(ActivityGenerator.COMPARISON)) {
+            comparisonId = configuration.get(ActivityGenerator.COMPARISON)
+                    .asText();
+               } else {
+            comparisonId = ActivityGenerator.CUSTOM_COMPARISON;
+               }
+
+               if (comparisonId.equals(ActivityGenerator.CUSTOM_COMPARISON)
+                               && configuration.has("conditionalActivity")) {
+                       configPanel.setVisible(false);
+                       customPanel.setVisible(true);
+               } else {
+                       configPanel.setVisible(true);
+                       customPanel.setVisible(false);
+               }
+
+               
portCombo.setSelectedItem(configuration.get(ActivityGenerator.COMPARE_PORT).asText());
+               if (portCombo.getSelectedIndex() == -1
+                               && portCombo.getModel().getSize() > 0) {
+                       portCombo.setSelectedIndex(0);
+               }
+
+               Comparison comparison = ActivityGenerator
+                               .getComparisonById(comparisonId);
+               comparisonCombo.setSelectedItem(comparison);
+               if (comparisonCombo.getSelectedIndex() == -1
+                               && comparisonCombo.getModel().getSize() > 0) {
+                       comparisonCombo.setSelectedIndex(0);
+               }
+
+               
valueField.setText(configuration.get(ActivityGenerator.COMPARE_VALUE).asText());
+
+               if (configuration.has(ActivityGenerator.DELAY)) {
+                   
delayField.setText(configuration.get(ActivityGenerator.DELAY).asText());
+               } else {
+                   delayField.setText(DEFAULT_DELAY_S);
+               }
+
+               
feedBackCheck.setSelected(configuration.get(ActivityGenerator.IS_FEED_BACK).asBoolean());
+               updateFeedbackHelp();
+       }
+
+       private void initialise() {
+               removeAll();
+               setLayout(new GridBagLayout());
+               GridBagConstraints gbc = new GridBagConstraints();
+               gbc.fill = GridBagConstraints.HORIZONTAL;
+               gbc.anchor = GridBagConstraints.FIRST_LINE_START;
+               gbc.gridx = 0;
+               gbc.weightx = 0.1;
+
+               makeHeader();
+               add(headerPanel, gbc);
+
+               makeConfigPanel();
+               gbc.weighty = 0.1;
+               gbc.anchor = GridBagConstraints.CENTER;
+               gbc.fill = GridBagConstraints.BOTH;
+               add(configPanel, gbc);
+
+               makeCustomPanel();
+               add(customPanel, gbc);
+
+               makeOptions();
+               add(optionsPanel, gbc);
+       }
+
+       protected void makeCustomPanel() {
+               customPanel.removeAll();
+               customPanel.setLayout(new GridBagLayout());
+
+               GridBagConstraints gbc = new GridBagConstraints();
+               gbc.anchor = GridBagConstraints.LINE_START;
+               gbc.gridx = 0;
+               gbc.gridy = 0;
+               gbc.gridwidth = 2;
+               gbc.weightx = 0.1;
+               gbc.fill = GridBagConstraints.HORIZONTAL;
+
+               JLabel helpLabel = new JLabel(
+                               "<html><body>"
+                                               + "The service <strong>" + 
processor.getName() +  "</strong> will be "
+                                               + "invoked repeatedly as "
+                                               + "long as the <em>customized 
loop condition service</em> returns a string equal "
+                                               + "to <strong>\"true\"</strong> 
on its output port <code>loop</code>."
+//                                             + "<br><br>"
+//                                             + "Input ports of the condition 
service will be populated with values from "
+//                                             + "the <em>corresponding output 
ports</em> of the main service invocation "
+//                                             + "(as long as they are also "
+//                                             + "<strong>connected</strong> 
in the containing workflow)."
+//                                             + "<br><br> "
+//
+//                                             + "Any <em>matching "
+//                                             + "output ports</em> from the 
condition service will provide the corresponding "
+//                                             + "<em>inputs</em> to the main 
service while looping. You will need to connect "
+//                                             + "the <em>initial inputs</em> 
in the containing workflow."
+                                               + "</body></html>");
+               customPanel.add(helpLabel, gbc);
+
+               gbc.weightx = 0.1;
+               gbc.fill = GridBagConstraints.NONE;
+               gbc.gridx = 0;
+               gbc.gridy++;
+               gbc.gridwidth = 1;
+               gbc.anchor = GridBagConstraints.EAST;
+               JPanel customiseButtonPanel = new JPanel(new FlowLayout());
+               customiseButtonPanel.setBorder(new EmptyBorder(10,0,0,0));
+               customizeButton = new JButton("Customize loop condition");
+               customizeButton.addActionListener(new CustomizeAction());
+               customiseButtonPanel.add(customizeButton);
+               customiseButtonPanel.add(new JButton(new ResetAction()));
+               customPanel.add(customiseButtonPanel, gbc);
+
+       }
+
+       protected void makeConfigPanel() {
+               configPanel.removeAll();
+               configPanel.setLayout(new GridBagLayout());
+
+               GridBagConstraints gbc = new GridBagConstraints();
+               gbc.anchor = GridBagConstraints.LINE_START;
+               gbc.gridx = 0;
+               gbc.gridy = 0;
+               gbc.gridwidth = 4;
+               gbc.weightx = 0.1;
+               gbc.fill = GridBagConstraints.HORIZONTAL;
+               JLabel invokedRepeatedlyLabel = new JLabel(
+
+                               "<html><body>The service <strong>" + 
processor.getName() +  "</strong> " +
+                                               "will be invoked repeatedly 
<em>until</em> its output port</body></html>");
+               invokedRepeatedlyLabel.setBorder(new EmptyBorder(10,0,10,0)); 
// give some top and bottom border to the label
+               configPanel.add(invokedRepeatedlyLabel, gbc);
+               gbc.ipadx = 4;
+               gbc.ipady = 4;
+
+               gbc.weightx = 0.0;
+               gbc.fill = GridBagConstraints.HORIZONTAL;
+               gbc.gridx = 0;
+               gbc.gridy = 1;
+               gbc.gridwidth = 1;
+               List<String> activityOutputPorts = getActivityOutputPorts();
+               portCombo = new JComboBox(activityOutputPorts.toArray());
+               configPanel.add(portCombo, gbc);
+
+               comparisonCombo = new 
JComboBox(ActivityGenerator.comparisons.toArray());
+               comparisonCombo.addActionListener(new ActionListener() {
+                       public void actionPerformed(ActionEvent e) {
+                               Comparison selectedComparison = (Comparison) 
comparisonCombo
+                                               .getSelectedItem();
+                               if (selectedComparison != null) {
+                                       valueTypeLabel.setText("the "
+                                                       + 
selectedComparison.getValueType());
+                               }
+                       }
+               });
+               if (comparisonCombo.getSelectedIndex() == -1) {
+                       comparisonCombo.setSelectedIndex(0);
+               }
+               gbc.gridx = 1;
+               gbc.gridy = 1;
+               configPanel.add(comparisonCombo, gbc);
+
+               gbc.gridx = 2;
+               gbc.gridy = 1;
+               valueTypeLabel.setHorizontalAlignment(SwingConstants.RIGHT);
+               configPanel.add(valueTypeLabel, gbc);
+
+               gbc.gridx = 3;
+               gbc.gridy = 1;
+               gbc.weightx = 0.5; // request all extra space
+               gbc.fill = GridBagConstraints.HORIZONTAL;
+               configPanel.add(valueField, gbc);
+
+               gbc.gridx = 0;
+               gbc.gridy = 2;
+               gbc.weightx = 0.0;
+               configPanel.add(delayLabel, gbc);
+
+               gbc.gridx = 1;
+               gbc.gridx = 1;
+               gbc.gridy = 2;
+               gbc.weightx = 0.0;
+               delayField.setHorizontalAlignment(JTextField.RIGHT);
+               configPanel.add(delayField, gbc);
+
+               gbc.gridx = 2;
+               gbc.gridy = 2;
+               gbc.gridwidth = 2;
+               gbc.weightx = 0.5; // request all extra space
+               gbc.fill = GridBagConstraints.HORIZONTAL;
+               configPanel.add(secondsLabel, gbc);
+
+               if (activityOutputPorts.isEmpty()) {
+                       JLabel warningLabel = new JLabel(
+                                       
"<html><body><strong>Warning:</strong><br>"
+                                                       + "<i>No single value 
output ports detected on the main service, "
+                                                       + "cannot use built-in 
comparisons. You may still add a customized " +
+                                                                       
"looping script</i></body></html>");
+                       gbc.gridx = 0;
+                       gbc.gridy++;
+                       gbc.gridwidth = 4;
+                       gbc.weightx = 0.1;
+                       gbc.fill = GridBagConstraints.BOTH;
+                       gbc.gridy++;
+                       configPanel.add(warningLabel, gbc);
+                       invokedRepeatedlyLabel.setVisible(false);
+                       portCombo.setVisible(false);
+                       comparisonCombo.setVisible(false);
+                       portWarning.setVisible(false);
+                       valueTypeLabel.setVisible(false);
+                       valueField.setVisible(false);
+                       delayField.setVisible(false);
+                       delayLabel.setVisible(false);
+                       secondsLabel.setVisible(false);
+               }
+
+               gbc.gridy++;
+               gbc.gridx = 0;
+               gbc.weightx = 0.1;
+               gbc.gridwidth = 4;
+               gbc.weightx = 0.1;
+               gbc.fill = GridBagConstraints.BOTH;
+               gbc.fill = GridBagConstraints.HORIZONTAL;
+               gbc.insets = new Insets(10, 0, 10, 0);
+               configPanel.add(portWarning, gbc);
+
+               gbc.insets = new Insets(0, 0, 0, 0);
+               gbc.weightx = 0.1;
+               gbc.fill = GridBagConstraints.NONE;
+               gbc.gridx = 0;
+               gbc.gridy++;
+               gbc.gridwidth = 4;
+               gbc.anchor = GridBagConstraints.LAST_LINE_END;
+               JPanel customiseButtonPanel = new JPanel(new FlowLayout());
+               customizeButton = new JButton("Customize loop condition");
+               customizeButton.addActionListener(new CustomizeAction());
+               customiseButtonPanel.add(customizeButton);
+               configPanel.add(customiseButtonPanel, gbc);
+
+               // filler
+               gbc.gridy++;
+               gbc.fill = GridBagConstraints.BOTH;
+               gbc.gridx = 4;
+               gbc.weightx = 0.1;
+               gbc.weighty = 0.1;
+               gbc.gridwidth = 4;
+               configPanel.add(Box.createGlue(), gbc);
+       }
+
+       private List<String> getActivityOutputPorts() {
+           // Should already be sorted
+           return new ArrayList<>(processor.getOutputPorts().getNames());
+    }
+
+    protected JCheckBox feedBackCheck = new JCheckBox(
+                       "Enable output port to input port feedback");
+       private JLabel portWarning = new JLabel(
+                       "<html><body><small>Note that for Taverna to be able to 
execute this loop, "
+                                       + "the output port 
<strong>must</strong> be connected to an input of another service "
+                                       + "or a workflow output 
port.</small></body></html>");
+
+       protected void makeOptions() {
+               optionsPanel.removeAll();
+               optionsPanel.setLayout(new GridBagLayout());
+               GridBagConstraints gbc = new GridBagConstraints();
+               gbc.gridx = 0;
+               gbc.gridy = 0;
+               gbc.weightx = 0.1;
+               gbc.anchor = GridBagConstraints.FIRST_LINE_START;
+               gbc.fill = GridBagConstraints.HORIZONTAL;
+               feedBackCheck.setBorder(new EmptyBorder(0,0,10,0));
+               optionsPanel.add(feedBackCheck, gbc);
+               feedBackCheck.addActionListener(new ActionListener() {
+                       public void actionPerformed(ActionEvent e) {
+                               updateFeedbackHelp();
+                       }
+               });
+               updateFeedbackHelp();
+
+               gbc.gridy = 1;
+               gbc.fill = GridBagConstraints.HORIZONTAL;
+               optionsPanel.add(feedbackHelp, gbc);
+       }
+
+       protected void updateFeedbackHelp() {
+               feedbackHelp.setEnabled(feedBackCheck.isSelected());
+               Color color;
+               if (feedBackCheck.isSelected()) {
+                       color = valueTypeLabel.getForeground();
+               } else {
+                       // Work around
+                       // 
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4303706
+                       // and assume gray is the 'disabled' colour in our Look 
n Feel
+                       color = Color.gray;
+               }
+               feedbackHelp.setForeground(color);
+
+       }
+
+       JLabel feedbackHelp = new JLabel(
+                       "<html><small>"
+                                       + "<p>When feedback is enabled, the 
value of the output port is used as input " +
+                                                       "the next time the loop 
in invoked. The input and output ports used for feedback "
+                                       + "<strong>must</strong> have the same 
<strong>name</strong> and <strong>depth</strong>."
+                                       + "</p><br>"
+
+                                       + "<p>Feedback can be useful for 
looping over a nested workflow, "
+                                       + "where the nested workflow's output 
determines its next input value.</p><br>"
+
+                                       + "<p>In order to use feedback looping, 
you must provide an initial value to the input port by "
+                                       + "connecting it to the output of a 
previous service or workflow input port."
+                                       + "The output port used as feedback 
also has to be connected to a downstream service " +
+                                                       "or a workflow output 
port.</p>"
+
+                                       + "</small></html>");
+
+       protected void makeHeader() {
+               headerPanel.removeAll();
+               headerPanel.setLayout(new BorderLayout());
+               //headerPanel.add(new ShadedLabel("Looping for service"
+               //              + processor.getLocalName(), 
ShadedLabel.ORANGE));
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-loop-ui/src/main/java/org/apache/taverna/workbench/loop/LoopConfigureAction.java
----------------------------------------------------------------------
diff --git 
a/taverna-loop-ui/src/main/java/org/apache/taverna/workbench/loop/LoopConfigureAction.java
 
b/taverna-loop-ui/src/main/java/org/apache/taverna/workbench/loop/LoopConfigureAction.java
new file mode 100644
index 0000000..05b8a43
--- /dev/null
+++ 
b/taverna-loop-ui/src/main/java/org/apache/taverna/workbench/loop/LoopConfigureAction.java
@@ -0,0 +1,262 @@
+/**
+ *
+ */
+package org.apache.taverna.workbench.loop;
+
+import java.awt.BorderLayout;
+import java.awt.FlowLayout;
+import java.awt.Frame;
+import java.awt.event.ActionEvent;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.swing.AbstractAction;
+import javax.swing.JButton;
+import javax.swing.JDialog;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+
+import org.apache.log4j.Logger;
+
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
+import uk.org.taverna.configuration.app.ApplicationConfiguration;
+import org.apache.taverna.scufl2.api.core.Processor;
+import org.apache.taverna.scufl2.api.profiles.Profile;
+
+import org.apache.taverna.workbench.edits.EditManager;
+import org.apache.taverna.workbench.file.FileManager;
+import org.apache.taverna.workbench.helper.HelpEnabledDialog;
+
+/**
+ * @author Alan R Williams
+ * @author Stian Soiland-Reyes
+ *
+ */
+@SuppressWarnings("serial")
+public class LoopConfigureAction extends AbstractAction {
+
+       private static Logger logger = 
Logger.getLogger(LoopConfigureAction.class);
+
+       private final EditManager editManager;
+       private final FileManager fileManager;
+
+       private final Frame owner;
+       private final ObjectNode loopLayer;
+       private final LoopContextualView contextualView;
+       private final Processor processor;
+    private final Profile profile;
+
+    private ApplicationConfiguration applicationConfig;
+
+
+    protected LoopConfigureAction(Frame owner,
+            LoopContextualView contextualView, Processor processor,
+            ObjectNode loopLayer, Profile profile, EditManager editManager,
+            FileManager fileManager, ApplicationConfiguration 
applicationConfig) {
+               super("Configure");
+               this.owner = owner;
+               this.contextualView = contextualView;
+               this.loopLayer = loopLayer;
+        this.profile = profile;
+               this.editManager = editManager;
+               this.fileManager = fileManager;
+               this.processor = processor;
+        this.applicationConfig = applicationConfig;
+       }
+
+       public void actionPerformed(ActionEvent e) {
+               String title = "Looping for service " + processor.getName();
+               final JDialog dialog = new HelpEnabledDialog(owner, title, 
true);
+        LoopConfigurationPanel loopConfigurationPanel = new 
LoopConfigurationPanel(
+                processor, loopLayer, profile, applicationConfig);
+               dialog.add(loopConfigurationPanel, BorderLayout.CENTER);
+
+               JPanel buttonPanel = new JPanel();
+               buttonPanel.setLayout(new FlowLayout());
+
+               JButton okButton = new JButton(new OKAction(dialog, 
loopConfigurationPanel));
+               buttonPanel.add(okButton);
+
+               JButton resetButton = new JButton(new 
ResetAction(loopConfigurationPanel));
+               buttonPanel.add(resetButton);
+
+               JButton cancelButton = new JButton(new CancelAction(dialog));
+               buttonPanel.add(cancelButton);
+
+               dialog.add(buttonPanel, BorderLayout.SOUTH);
+               dialog.pack();
+               dialog.setSize(650, 430);
+               dialog.setLocationRelativeTo(null);
+               dialog.setVisible(true);
+       }
+
+       protected class CancelAction extends AbstractAction {
+               private final JDialog dialog;
+
+               protected CancelAction(JDialog dialog) {
+                       super("Cancel");
+                       this.dialog = dialog;
+               }
+
+               public void actionPerformed(ActionEvent e) {
+                       dialog.setVisible(false);
+                       if (contextualView != null) {
+                               contextualView.refreshView();
+                       }
+               }
+
+       }
+
+       protected class OKAction extends AbstractAction {
+               private final JDialog dialog;
+               private final LoopConfigurationPanel loopConfigurationPanel;
+
+               protected OKAction(JDialog dialog, LoopConfigurationPanel 
loopConfigurationPanel) {
+                       super("OK");
+                       this.dialog = dialog;
+                       this.loopConfigurationPanel = loopConfigurationPanel;
+               }
+
+               public void actionPerformed(ActionEvent e) {
+                       try {
+
+                               List<Edit<?>> compoundEdit = new 
ArrayList<Edit<?>>();
+                               LoopConfiguration configuration = 
loopConfigurationPanel.getConfiguration();
+                               
compoundEdit.add(edits.getConfigureEdit(loopLayer, configuration));
+                               
compoundEdit.addAll(checkPortMappings(configuration.getCondition()));
+
+                               
editManager.doDataflowEdit(fileManager.getCurrentDataflow(), new CompoundEdit(
+                                               compoundEdit));
+                               dialog.setVisible(false);
+                               if (contextualView != null) {
+                                       contextualView.refreshView();
+                               }
+                       } catch (RuntimeException ex) {
+                               logger.warn("Could not configure looping", ex);
+                               JOptionPane.showMessageDialog(owner, "Could not 
configure looping",
+                                               "An error occured when 
configuring looping: " + ex.getMessage(),
+                                               JOptionPane.ERROR_MESSAGE);
+                       } catch (EditException ex) {
+                               logger.warn("Could not configure looping", ex);
+                               JOptionPane.showMessageDialog(owner, "Could not 
configure looping",
+                                               "An error occured when 
configuring looping: " + ex.getMessage(),
+                                               JOptionPane.ERROR_MESSAGE);
+                       }
+               }
+
+               protected List<Edit<?>> checkPortMappings(Activity<?> 
conditionActivity) {
+
+                       List<Edit<?>> compoundEdit = new ArrayList<Edit<?>>();
+                       if (processor.getActivityList().isEmpty()) {
+                               return compoundEdit;
+                       }
+                       Set<String> newInputs = new HashSet<String>();
+                       Set<String> newOutputs = new HashSet<String>();
+
+                       Activity<?> firstProcessorActivity;
+                       firstProcessorActivity = 
processor.getActivityList().get(0);
+                       if (conditionActivity != null) {
+                               for (OutputPort condOutPort : 
conditionActivity.getOutputPorts()) {
+                                       String portName = condOutPort.getName();
+                                       Map<String, String> mapping = 
firstProcessorActivity.getInputPortMapping();
+                                       if (!mapping.containsKey(portName)) {
+                                               if 
(mapping.containsKey(portName)) {
+                                                       logger.warn("Can't 
re-map input for " + "conditional output "
+                                                                       + 
portName);
+                                               }
+                                               for (InputPort inputPort : 
firstProcessorActivity.getInputPorts()) {
+                                                       if 
(inputPort.equals(portName)) {
+                                                               
Edit<Activity<?>> edit = edits.getAddActivityInputPortMappingEdit(
+                                                                               
firstProcessorActivity, portName, portName);
+                                                               
compoundEdit.add(edit);
+                                                               
newInputs.add(portName);
+                                                       }
+                                               }
+                                       }
+                               }
+                               for (InputPort condInPort : 
conditionActivity.getInputPorts()) {
+                                       String portName = condInPort.getName();
+                                       Map<String, String> mapping = 
firstProcessorActivity.getOutputPortMapping();
+                                       if (!mapping.containsValue(portName)) {
+                                               for (OutputPort outputPort : 
firstProcessorActivity.getOutputPorts()) {
+                                                       if 
(outputPort.equals(portName)) {
+                                                               if 
(mapping.containsKey(portName)) {
+                                                                       
logger.warn("Can't re-map output for " + "conditional input "
+                                                                               
        + portName);
+                                                               }
+                                                               
Edit<Activity<?>> edit = edits.getAddActivityOutputPortMappingEdit(
+                                                                               
firstProcessorActivity, portName, portName);
+                                                               
logger.info("Mapping for conditional non-outgoing activity port binding "
+                                                                               
+ portName);
+                                                               
compoundEdit.add(edit);
+                                                               
newOutputs.add(portName);
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+                       // Remove any stale bindings that no longer match 
neither
+                       // conditional activity or the processor output ports
+                       for (String processorIn : 
firstProcessorActivity.getInputPortMapping().keySet()) {
+                               if (newInputs.contains(processorIn)) {
+                                       continue;
+                               }
+                               boolean foundMatch = false;
+                               for (InputPort processorPort : 
processor.getInputPorts()) {
+                                       if 
(processorPort.getName().equals(processorIn)) {
+                                               foundMatch = true;
+                                               break;
+                                       }
+                               }
+                               if (!foundMatch) {
+                                       Edit<Activity<?>> edit = 
edits.getRemoveActivityInputPortMappingEdit(
+                                                       firstProcessorActivity, 
processorIn);
+                                       logger.info("Removing stale input port 
binding " + processorIn);
+                                       compoundEdit.add(edit);
+                               }
+                       }
+                       for (String processorOut : 
firstProcessorActivity.getOutputPortMapping().keySet()) {
+                               if (newInputs.contains(processorOut)) {
+                                       continue;
+                               }
+                               boolean foundMatch = false;
+                               for (OutputPort processorPort : 
processor.getOutputPorts()) {
+                                       if 
(processorPort.getName().equals(processorOut)) {
+                                               foundMatch = true;
+                                               break;
+                                       }
+                               }
+                               if (!foundMatch) {
+                                       Edit<Activity<?>> edit = 
edits.getRemoveActivityOutputPortMappingEdit(
+                                                       firstProcessorActivity, 
processorOut);
+                                       logger.info("Removing stale output port 
binding " + processorOut);
+                                       compoundEdit.add(edit);
+                               }
+                       }
+
+                       return compoundEdit;
+               }
+       }
+
+       protected class ResetAction extends AbstractAction {
+               private LoopConfigurationPanel loopConfigurationPanel;
+
+               protected ResetAction(LoopConfigurationPanel 
loopConfigurationPanel) {
+                       super("Reset");
+                       this.loopConfigurationPanel = loopConfigurationPanel;
+               }
+
+               public void actionPerformed(ActionEvent e) {
+                       if (contextualView != null) {
+                               contextualView.refreshView();
+                       }
+                       
loopConfigurationPanel.setConfiguration(loopLayer.getConfiguration());
+               }
+
+       }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-loop-ui/src/main/java/org/apache/taverna/workbench/loop/LoopConfigureMenuAction.java
----------------------------------------------------------------------
diff --git 
a/taverna-loop-ui/src/main/java/org/apache/taverna/workbench/loop/LoopConfigureMenuAction.java
 
b/taverna-loop-ui/src/main/java/org/apache/taverna/workbench/loop/LoopConfigureMenuAction.java
new file mode 100644
index 0000000..061c225
--- /dev/null
+++ 
b/taverna-loop-ui/src/main/java/org/apache/taverna/workbench/loop/LoopConfigureMenuAction.java
@@ -0,0 +1,97 @@
+/**********************************************************************
+ * 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 org.apache.taverna.workbench.loop;
+
+import java.awt.event.ActionEvent;
+import java.net.URI;
+
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
+import org.apache.taverna.scufl2.api.core.Processor;
+
+import org.apache.taverna.ui.menu.AbstractContextualMenuAction;
+import org.apache.taverna.workbench.edits.EditManager;
+import org.apache.taverna.workbench.file.FileManager;
+
+public class LoopConfigureMenuAction extends AbstractContextualMenuAction {
+
+       public static final URI configureRunningSection = URI
+       .create("http://taverna.sf.net/2009/contextMenu/configureRunning";);
+
+       private static final URI LOOP_CONFIGURE_URI = URI
+       .create("http://taverna.sf.net/2008/t2workbench/loopConfigure";);
+
+       private static final String LOOP_CONFIGURE = "Loop configure";
+
+       private EditManager editManager;
+
+       private FileManager fileManager;
+
+       public LoopConfigureMenuAction() {
+               super(configureRunningSection, 20, LOOP_CONFIGURE_URI);
+       }
+
+       @SuppressWarnings("serial")
+       @Override
+       protected Action createAction() {
+               return new AbstractAction("Looping...") {
+                       public void actionPerformed(ActionEvent e) {
+                               Processor p = (Processor) 
getContextualSelection().getSelection();
+                               configureLoopLayer(p, e);
+                       }
+               };
+       }
+
+       public void configureLoopLayer(Processor p, ActionEvent e) {
+           ObjectNode loopLayer = getLoopLayer(p);
+               if (loopLayer != null) {
+                       LoopConfigureAction loopConfigureAction = new 
LoopConfigureAction(null, null, loopLayer, editManager, fileManager);
+                       loopConfigureAction.actionPerformed(e);
+               }
+       }
+
+       public static ObjectNode getLoopLayer(Processor p) {
+               for (DispatchLayer dl : p.getDispatchStack().getLayers()) {
+                       if (dl instanceof Loop) {
+                               result = (Loop) dl;
+                               break;
+                       }
+               }
+               return result;
+       }
+
+       public boolean isEnabled() {
+               Object selection = getContextualSelection().getSelection();
+               return (super.isEnabled() && (selection instanceof Processor) 
&& (getLoopLayer((Processor)selection) != null));
+       }
+
+       public void setEditManager(EditManager editManager) {
+               this.editManager = editManager;
+       }
+
+       public void setFileManager(FileManager fileManager) {
+               this.fileManager = fileManager;
+       }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/a9a52bd5/taverna-loop-ui/src/main/java/org/apache/taverna/workbench/loop/LoopContextualView.java
----------------------------------------------------------------------
diff --git 
a/taverna-loop-ui/src/main/java/org/apache/taverna/workbench/loop/LoopContextualView.java
 
b/taverna-loop-ui/src/main/java/org/apache/taverna/workbench/loop/LoopContextualView.java
new file mode 100644
index 0000000..fc5e837
--- /dev/null
+++ 
b/taverna-loop-ui/src/main/java/org/apache/taverna/workbench/loop/LoopContextualView.java
@@ -0,0 +1,172 @@
+/*******************************************************************************
+ * Copyright (C) 2008 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 org.apache.taverna.workbench.loop;
+
+import java.awt.Frame;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.util.Properties;
+
+import javax.swing.Action;
+import javax.swing.JComponent;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+
+import org.apache.taverna.workbench.edits.EditManager;
+import org.apache.taverna.workbench.file.FileManager;
+import org.apache.taverna.workbench.loop.comparisons.Comparison;
+import org.apache.taverna.workbench.ui.views.contextualviews.ContextualView;
+
+import org.apache.log4j.Logger;
+
+import org.apache.taverna.scufl2.api.core.Processor;
+
+/**
+ * View of a processor, including it's iteration stack, activities, etc.
+ *
+ * @author Stian Soiland-Reyes
+ *
+ */
+public class LoopContextualView extends ContextualView {
+
+       private static final long serialVersionUID = 1L;
+
+       private static Logger logger = 
Logger.getLogger(LoopContextualView.class);
+
+       private EditManager editManager;
+       private FileManager fileManager;
+
+       private Loop loopLayer;
+
+       private JPanel panel;
+
+       private Processor processor;
+
+       public LoopContextualView(Processor processor, EditManager editManager, 
FileManager fileManager) {
+               super();
+               this.loopLayer = loopLayer;
+               this.editManager = editManager;
+               this.fileManager = fileManager;
+               this.processor = processor;
+               initialise();
+               initView();
+       }
+
+       @Override
+       public Action getConfigureAction(Frame owner) {
+               return new LoopConfigureAction(owner, this, processor, 
editManager, fileManager);
+       }
+
+       @Override
+       public void refreshView() {
+               initialise();
+       }
+
+       private void initialise() {
+               if (panel == null) {
+                       panel = new JPanel();
+               } else {
+                       panel.removeAll();
+               }
+               panel.setLayout(new GridBagLayout());
+               updateUIByConfig();
+       }
+
+       @Override
+       public JComponent getMainFrame() {
+               return panel;
+       }
+
+       @Override
+       public String getViewTitle() {
+               return "Loop of " + processor.getLocalName();
+       }
+
+       protected void updateUIByConfig() {
+               GridBagConstraints gbc = new GridBagConstraints();
+               gbc.gridx = 0;
+               gbc.gridy = 1;
+               gbc.weightx = 0.1;
+               gbc.fill = GridBagConstraints.HORIZONTAL;
+
+               StringBuilder description = new StringBuilder("<html><body>");
+               Properties properties = 
loopLayer.getConfiguration().getProperties();
+               if (properties.getProperty(ActivityGenerator.COMPARISON,
+                               ActivityGenerator.CUSTOM_COMPARISON).equals(
+                               ActivityGenerator.CUSTOM_COMPARISON)) {
+                       Activity<?> condition = 
loopLayer.getConfiguration().getCondition();
+                       if (condition != null) {
+                               description.append("Looping using custom 
conditional ");
+                               if (condition instanceof BeanshellActivity) {
+                                       String script = 
((BeanshellActivity)condition).getConfiguration().getScript();
+                                       if (script != null) {
+                                               if (script.length() <= 100) {
+                                                       
description.append("<pre>\n");
+                                                       
description.append(script);
+                                                       
description.append("</pre>\n");
+                                               }
+                                       }
+                               }
+                       } else {
+                               description.append("<i>Unconfigured, will not 
loop</i>");
+                       }
+               } else {
+                       description.append("The service will be invoked 
repeatedly ");
+                       description.append("until<br> its output <strong>");
+                       description.append(properties
+                                       
.getProperty(ActivityGenerator.COMPARE_PORT));
+                       description.append("</strong> ");
+
+                       Comparison comparison = ActivityGenerator
+                                       .getComparisonById(properties
+                                                       
.getProperty(ActivityGenerator.COMPARISON));
+                       description.append(comparison.getName());
+
+                       description.append(" the " + comparison.getValueType() 
+ ": <pre>");
+                       description.append(properties
+                                       
.getProperty(ActivityGenerator.COMPARE_VALUE));
+                       description.append("</pre>");
+
+                       String delay = 
properties.getProperty(ActivityGenerator.DELAY, "");
+                       try {
+                               if (Double.parseDouble(delay) > 0) {
+                                       description.append("adding a delay of " 
+ delay
+                                                       + " seconds between 
loops.");
+                               }
+                       } catch (NumberFormatException ex) {
+                       }
+               }
+               description.append("</body></html>");
+
+               panel.add(new JLabel(description.toString()), gbc);
+               gbc.gridy++;
+
+               revalidate();
+       }
+
+
+
+       @Override
+       public int getPreferredPosition() {
+               return 400;
+       }
+
+}

Reply via email to