You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@taverna.apache.org by st...@apache.org on 2015/02/17 12:45:29 UTC
[05/52] [abbrv] incubator-taverna-workbench git commit:
taverna-ui-impl/
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/72850d5a/taverna-workbench-renderers-impl/src/main/java/net/sf/taverna/t2/renderers/impl/XMLTree.java
----------------------------------------------------------------------
diff --git a/taverna-workbench-renderers-impl/src/main/java/net/sf/taverna/t2/renderers/impl/XMLTree.java b/taverna-workbench-renderers-impl/src/main/java/net/sf/taverna/t2/renderers/impl/XMLTree.java
new file mode 100644
index 0000000..2d53218
--- /dev/null
+++ b/taverna-workbench-renderers-impl/src/main/java/net/sf/taverna/t2/renderers/impl/XMLTree.java
@@ -0,0 +1,329 @@
+/*******************************************************************************
+ * Copyright (C) 2007 The University of Manchester
+ *
+ * Modifications to the initial code base are copyright of their
+ * respective authors, or their employers as appropriate.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+package net.sf.taverna.t2.renderers.impl;
+
+import static java.util.prefs.Preferences.userNodeForPackage;
+import static javax.swing.JFileChooser.APPROVE_OPTION;
+import static javax.swing.JOptionPane.ERROR_MESSAGE;
+import static javax.swing.JOptionPane.showMessageDialog;
+import static javax.swing.tree.TreeSelectionModel.SINGLE_TREE_SELECTION;
+import static org.jdom.output.Format.getPrettyFormat;
+
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringReader;
+import java.util.Enumeration;
+import java.util.prefs.Preferences;
+
+import javax.swing.JFileChooser;
+import javax.swing.JMenuItem;
+import javax.swing.JPopupMenu;
+import javax.swing.JTree;
+import javax.swing.tree.DefaultMutableTreeNode;
+import javax.swing.tree.DefaultTreeCellRenderer;
+import javax.swing.tree.DefaultTreeModel;
+import javax.swing.tree.TreeNode;
+import javax.swing.tree.TreePath;
+
+import org.jdom.Attribute;
+import org.jdom.Content;
+import org.jdom.Document;
+import org.jdom.Element;
+import org.jdom.JDOMException;
+import org.jdom.Parent;
+import org.jdom.Text;
+import org.jdom.input.SAXBuilder;
+import org.jdom.output.XMLOutputter;
+
+/**
+ * An extension of the {@link JTree} class, constructed with a String of XML and
+ * used to display the XML structure as an interactive tree. Derived from <a
+ * href="http://www.devx.com/gethelpon/10MinuteSolution/16694/0/page/1">original
+ * code by Kyle Gabhart</a> and then subsequently heavily rewritten to move to
+ * JDOM, and moved lots of the setup code to the renderer to cut down
+ * initialisation time. Added text node size limit as well. Displaying large
+ * gene sequences as base64 encoded text in a single node really, <i>really</i>
+ * hurts performance.
+ *
+ * @author Kyle Gabhart
+ * @author Tom Oinn
+ * @author Kevin Glover
+ * @author Ian Dunlop
+ */
+@SuppressWarnings("serial")
+class XMLTree extends JTree {
+ private class XMLNode extends DefaultMutableTreeNode {
+ public XMLNode(Content userObject) {
+ super(userObject);
+ }
+ }
+
+ int textSizeLimit = 1000;
+ final JFileChooser fc = new JFileChooser();
+ Element rootElement = null;
+
+ /**
+ * Build a new XMLTree from the supplied String containing XML.
+ *
+ * @param text
+ * @throws IOException
+ * @throws JDOMException
+ */
+ public XMLTree(String text) throws IOException, JDOMException {
+ super();
+ Document document = new SAXBuilder(false).build(new StringReader(text));
+ init(document.getRootElement());
+ revalidate();
+ }
+
+ public String getText() {
+ if (rootElement == null)
+ return "";
+ XMLOutputter xo = new XMLOutputter(getPrettyFormat());
+ return xo.outputString(rootElement);
+ }
+
+ public XMLTree(String text, boolean limit) throws IOException,
+ JDOMException {
+ if (!limit)
+ textSizeLimit = -1;
+ Document document = new SAXBuilder(false).build(new StringReader(text));
+ init(document.getRootElement());
+ revalidate();
+ }
+
+ public XMLTree(Document document) {
+ this(document.getRootElement());
+ }
+
+ public XMLTree(Element element) {
+ super();
+ init(element);
+ revalidate();
+ }
+
+ private void init(Content content) {
+ rootElement = (Element) content;
+ /*
+ * Fix for platforms other than metal which can't otherwise cope with
+ * arbitrary size rows
+ */
+ setRowHeight(0);
+ getSelectionModel().setSelectionMode(SINGLE_TREE_SELECTION);
+ setShowsRootHandles(true);
+ setEditable(false);
+ setModel(new DefaultTreeModel(createTreeNode(content)));
+ setCellRenderer(new DefaultTreeCellRenderer() {
+ @Override
+ public Color getBackgroundNonSelectionColor() {
+ return null;
+ }
+
+ @Override
+ public Color getBackground() {
+ return null;
+ }
+
+ @Override
+ public Component getTreeCellRendererComponent(JTree tree,
+ Object value, boolean sel, boolean expanded, boolean leaf,
+ int row, boolean hasFocus) {
+ super.getTreeCellRendererComponent(tree, value, sel, expanded,
+ leaf, row, hasFocus);
+ setOpaque(false);
+ if (value instanceof XMLNode) {
+ XMLNode node = (XMLNode) value;
+ if (node.getUserObject() instanceof Element)
+ renderElementNode((Element) node.getUserObject());
+ else if (node.getUserObject() instanceof Text)
+ renderTextNode((Text) node.getUserObject());
+ // TODO what about other node types?
+ }
+ setBackground(new Color(0, 0, 0, 0));
+ return this;
+ }
+
+ private void renderElementNode(Element element) {
+ // setIcon(TavernaIcons.xmlNodeIcon);
+ StringBuilder nameBuffer = new StringBuilder("<html>")
+ .append(element.getQualifiedName());
+ /*
+ * Bit of a quick and dirty hack here to try to ensure that the
+ * element namespace is shown. There appears no way to get the
+ * actual xmlns declarations that are part of an element through
+ * jdom. Also, please note, there's no namespace handling at all
+ * for attributes...
+ */
+ if (element.getParent() instanceof Element) {
+ Element parent = (Element) element.getParent();
+ if (parent.getNamespace(element.getNamespacePrefix()) == null)
+ nameBuffer
+ .append(" <font color=\"purple\">xmlns:")
+ .append(element.getNamespacePrefix())
+ .append("</font>=\"<font color=\"green\">")
+ .append(element.getNamespaceURI() + "</font>\"");
+ } else
+ nameBuffer.append(" <font color=\"purple\">xmlns:")
+ .append(element.getNamespacePrefix())
+ .append("</font>=\"<font color=\"green\">")
+ .append(element.getNamespaceURI() + "</font>\"");
+
+ String sep = "";
+ for (Object a : element.getAttributes()) {
+ Attribute attribute = (Attribute) a;
+ String name = attribute.getName().trim();
+ String value = attribute.getValue().trim();
+ if (value != null && value.length() > 0) {
+ // TODO xml-quote name and value
+ nameBuffer.append(sep)
+ .append(" <font color=\"purple\">")
+ .append(name)
+ .append("</font>=\"<font color=\"green\">")
+ .append(value).append("</font>\"");
+ sep = ",";
+ }
+ }
+
+ nameBuffer.append("</html>");
+ setText(nameBuffer.toString());
+ }
+
+ private void renderTextNode(Text text) {
+ // setIcon(TavernaIcons.leafIcon);
+ String name = text.getText();
+ if (textSizeLimit > -1 && name.length() > textSizeLimit)
+ name = name.substring(0, textSizeLimit) + "...";
+ setText("<html><pre><font color=\"blue\">"
+ + name.replaceAll("<br>", "\n").replaceAll("<", "<")
+ + "</font></pre></html>");
+ }
+ });
+ setAllNodesExpanded();
+
+ // Add a listener to present the 'save as text' option
+ addMouseListener(new MouseAdapter() {
+ @Override
+ public void mousePressed(MouseEvent e) {
+ if (e.isPopupTrigger())
+ doEvent(e);
+ }
+
+ @Override
+ public void mouseReleased(MouseEvent e) {
+ if (e.isPopupTrigger())
+ doEvent(e);
+ }
+
+ public void doEvent(MouseEvent e) {
+ JPopupMenu menu = new JPopupMenu();
+ JMenuItem item = new JMenuItem("Save as XML text");
+ menu.add(item);
+ item.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent ae) {
+ saveTreeXML();
+ }
+ });
+ menu.show(XMLTree.this, e.getX(), e.getY());
+ }
+ });
+ }
+
+ private void saveTreeXML() {
+ try {
+ Preferences prefs = userNodeForPackage(XMLTree.class);
+ String curDir = prefs.get("currentDir",
+ System.getProperty("user.home"));
+ fc.resetChoosableFileFilters();
+ fc.setFileFilter(new ExtensionFileFilter(new String[] { "xml" }));
+ fc.setCurrentDirectory(new File(curDir));
+ if (fc.showSaveDialog(this) == APPROVE_OPTION) {
+ prefs.put("currentDir", fc.getCurrentDirectory().toString());
+ saveTreeXML(fc.getSelectedFile());
+ }
+ } catch (Exception ex) {
+ showMessageDialog(this, "Problem saving XML:\n" + ex.getMessage(),
+ "Error!", ERROR_MESSAGE);
+ }
+ }
+
+ private void saveTreeXML(File file) throws IOException {
+ try (PrintWriter out = new PrintWriter(new FileWriter(file))) {
+ out.print(this.getText());
+ }
+ }
+
+ public void setAllNodesExpanded() {
+ synchronized (this.getModel()) {
+ expandAll(this, new TreePath(this.getModel().getRoot()), true);
+ }
+ }
+
+ private void expandAll(JTree tree, TreePath parent, boolean expand) {
+ synchronized (this.getModel()) {
+ /*
+ * Traverse children
+ *
+ * Ignores nodes who's userObject is a Processor type to avoid
+ * overloading the UI with nodes at startup.
+ */
+ TreeNode node = (TreeNode) parent.getLastPathComponent();
+ for (Enumeration<?> e = node.children(); e.hasMoreElements(); ) {
+ TreeNode n = (TreeNode) e.nextElement();
+ expandAll(tree, parent.pathByAddingChild(n), expand);
+ }
+ // Expansion or collapse must be done bottom-up
+ if (expand)
+ tree.expandPath(parent);
+ else
+ tree.collapsePath(parent);
+ }
+ }
+
+ public void setTextNodeSizeLimit(int sizeLimit) {
+ textSizeLimit = sizeLimit;
+ }
+
+ private XMLNode createTreeNode(Content content) {
+ XMLNode node = new XMLNode(content);
+ if (content instanceof Parent) {
+ Parent parent = (Parent) content;
+ for (Object child : parent.getContent()) {
+ if (child instanceof Element)
+ node.add(createTreeNode((Content) child));
+ else if (textSizeLimit != 0 && child instanceof Text) {
+ Text text = (Text) child;
+ if (!text.getTextNormalize().isEmpty())
+ node.add(createTreeNode(text));
+ }
+ }
+ }
+ return node;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/72850d5a/taverna-workbench-renderers-impl/src/main/resources/META-INF/services/net.sf.taverna.t2.renderers.Renderer
----------------------------------------------------------------------
diff --git a/taverna-workbench-renderers-impl/src/main/resources/META-INF/services/net.sf.taverna.t2.renderers.Renderer b/taverna-workbench-renderers-impl/src/main/resources/META-INF/services/net.sf.taverna.t2.renderers.Renderer
new file mode 100644
index 0000000..044a396
--- /dev/null
+++ b/taverna-workbench-renderers-impl/src/main/resources/META-INF/services/net.sf.taverna.t2.renderers.Renderer
@@ -0,0 +1,7 @@
+net.sf.taverna.t2.renderers.impl.AdvancedImageRenderer
+net.sf.taverna.t2.renderers.impl.HexBinaryRenderer
+net.sf.taverna.t2.renderers.impl.TextRenderer
+net.sf.taverna.t2.renderers.impl.TextRtfRenderer
+net.sf.taverna.t2.renderers.impl.TextXMLRenderer
+
+
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/72850d5a/taverna-workbench-renderers-impl/src/main/resources/META-INF/spring/renderers-impl-context-osgi.xml
----------------------------------------------------------------------
diff --git a/taverna-workbench-renderers-impl/src/main/resources/META-INF/spring/renderers-impl-context-osgi.xml b/taverna-workbench-renderers-impl/src/main/resources/META-INF/spring/renderers-impl-context-osgi.xml
new file mode 100644
index 0000000..436426a
--- /dev/null
+++ b/taverna-workbench-renderers-impl/src/main/resources/META-INF/spring/renderers-impl-context-osgi.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans:beans xmlns="http://www.springframework.org/schema/osgi" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:beans="http://www.springframework.org/schema/beans"
+ xsi:schemaLocation="http://www.springframework.org/schema/beans
+ http://www.springframework.org/schema/beans/spring-beans.xsd
+ http://www.springframework.org/schema/osgi
+ http://www.springframework.org/schema/osgi/spring-osgi.xsd">
+
+ <service ref="AdvancedImageRenderer" interface="net.sf.taverna.t2.renderers.Renderer" />
+ <service ref="HexBinaryRenderer" interface="net.sf.taverna.t2.renderers.Renderer" />
+ <service ref="TextRenderer" interface="net.sf.taverna.t2.renderers.Renderer" />
+ <service ref="TextRtfRenderer" interface="net.sf.taverna.t2.renderers.Renderer" />
+ <service ref="TextXMLRenderer" interface="net.sf.taverna.t2.renderers.Renderer" />
+
+ <service ref="RendererRegistry" interface="net.sf.taverna.t2.renderers.RendererRegistry" />
+
+ <list id="renderers" interface="net.sf.taverna.t2.renderers.Renderer" cardinality="0..N" />
+
+</beans:beans>
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/72850d5a/taverna-workbench-renderers-impl/src/main/resources/META-INF/spring/renderers-impl-context.xml
----------------------------------------------------------------------
diff --git a/taverna-workbench-renderers-impl/src/main/resources/META-INF/spring/renderers-impl-context.xml b/taverna-workbench-renderers-impl/src/main/resources/META-INF/spring/renderers-impl-context.xml
new file mode 100644
index 0000000..a041c98
--- /dev/null
+++ b/taverna-workbench-renderers-impl/src/main/resources/META-INF/spring/renderers-impl-context.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.springframework.org/schema/beans
+ http://www.springframework.org/schema/beans/spring-beans.xsd">
+
+ <bean id="AdvancedImageRenderer" class="net.sf.taverna.t2.renderers.impl.AdvancedImageRenderer" />
+ <bean id="HexBinaryRenderer" class="net.sf.taverna.t2.renderers.impl.HexBinaryRenderer" />
+ <bean id="TextRenderer" class="net.sf.taverna.t2.renderers.impl.TextRenderer" />
+ <bean id="TextRtfRenderer" class="net.sf.taverna.t2.renderers.impl.TextRtfRenderer" />
+ <bean id="TextXMLRenderer" class="net.sf.taverna.t2.renderers.impl.TextXMLRenderer" />
+
+ <bean id="RendererRegistry" class="net.sf.taverna.t2.renderers.impl.RendererRegistryImpl">
+ <property name="renderers" ref="renderers" />
+ </bean>
+
+
+</beans>
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/72850d5a/taverna-workbench-renderers-impl/src/test/java/net/sf/taverna/t2/renderers/TestRendererSPI.java
----------------------------------------------------------------------
diff --git a/taverna-workbench-renderers-impl/src/test/java/net/sf/taverna/t2/renderers/TestRendererSPI.java b/taverna-workbench-renderers-impl/src/test/java/net/sf/taverna/t2/renderers/TestRendererSPI.java
new file mode 100644
index 0000000..ece7cf5
--- /dev/null
+++ b/taverna-workbench-renderers-impl/src/test/java/net/sf/taverna/t2/renderers/TestRendererSPI.java
@@ -0,0 +1,154 @@
+/*******************************************************************************
+ * Copyright (C) 2007 The University of Manchester
+ *
+ * Modifications to the initial code base are copyright of their
+ * respective authors, or their employers as appropriate.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+package net.sf.taverna.t2.renderers;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.util.HashSet;
+import java.util.List;
+
+import org.junit.Before;
+import org.junit.Test;
+
+
+@SuppressWarnings("unused")
+public class TestRendererSPI {
+
+ private static final String TEST_NS = "testNS";
+
+ @Test
+ public void doNothing() {
+ //do nothing for the moment
+ }
+
+// @Test
+// public void getAllRenderers() {
+// RendererRegistry rendererRegistry = new RendererRegistry();
+// assertEquals(rendererRegistry.getInstances().size(), 10);
+// }
+//
+// @Test
+// public void checkTextHtmlMimeType() throws EmptyListException, MalformedListException, UnsupportedObjectTypeException {
+// String mimeType = "text/html";
+// String html = "<HTML><HEAD></HEAD><BODY>hello</BODY></HTML>";
+// EntityIdentifier entityIdentifier = facade.register(html, "utf-8");
+// RendererRegistry rendererRegistry = new RendererRegistry();
+// List<Renderer> renderersForMimeType = rendererRegistry.getRenderersForMimeType(facade, entityIdentifier, mimeType);
+// assertEquals(renderersForMimeType.size(),2);
+// assertEquals(renderersForMimeType.get(0).getClass().getSimpleName(), "TextRenderer");
+// assertEquals(renderersForMimeType.get(1).getClass().getSimpleName(), "TextHtmlRenderer");
+// assertTrue(renderersForMimeType.get(0).canHandle("text/html"));
+// }
+//
+// @Test
+// public void checkURLMimeType() throws EmptyListException, MalformedListException, UnsupportedObjectTypeException {
+// String mimeType = "text/x-taverna-web-url.text";
+// String url = "http://google.com";
+// EntityIdentifier entityIdentifier = facade.register(url);
+// RendererRegistry rendererRegistry = new RendererRegistry();
+// List<Renderer> renderersForMimeType = rendererRegistry.getRenderersForMimeType(facade, entityIdentifier, mimeType);
+// assertEquals(renderersForMimeType.size(),2);
+// assertEquals(renderersForMimeType.get(0).getClass().getSimpleName(), "TextRenderer");
+// assertEquals(renderersForMimeType.get(1).getClass().getSimpleName(), "TextTavernaWebUrlRenderer");
+// assertTrue(renderersForMimeType.get(1).canHandle("text/x-taverna-web-url.text"));
+// }
+//
+// @Test
+// public void checkJMolMimeType() throws EmptyListException, MalformedListException, UnsupportedObjectTypeException {
+// String mimeType ="chemical/x-pdb";
+// String jmol = "jmol";
+// EntityIdentifier entityIdentifier = facade.register(jmol);
+// RendererRegistry rendererRegistry = new RendererRegistry();
+// List<Renderer> renderersForMimeType = rendererRegistry.getRenderersForMimeType(facade, entityIdentifier, mimeType);
+// assertEquals(renderersForMimeType.size(), 1);
+// assertEquals(renderersForMimeType.get(0).getClass().getSimpleName(), "JMolRenderer");
+// assertTrue(renderersForMimeType.get(0).canHandle("chemical/x-mdl-molfile"));
+// assertTrue(renderersForMimeType.get(0).canHandle("chemical/x-cml"));
+// }
+//
+// @Test
+// public void checkSeqVistaMimeType() throws EmptyListException, MalformedListException, UnsupportedObjectTypeException {
+// String mimeType ="chemical/x-swissprot";
+// String type = "seqvista";
+// EntityIdentifier entityIdentifier = facade.register(type);
+// RendererRegistry rendererRegistry = new RendererRegistry();
+// List<Renderer> renderersForMimeType = rendererRegistry.getRenderersForMimeType(facade, entityIdentifier, mimeType);
+// assertEquals(renderersForMimeType.size(), 1);
+// assertEquals(renderersForMimeType.get(0).getClass().getSimpleName(), "SeqVistaRenderer");
+// assertTrue(renderersForMimeType.get(0).canHandle("chemical/x-embl-dl-nucleotide"));
+// assertTrue(renderersForMimeType.get(0).canHandle("chemical/x-fasta"));
+// }
+//
+// @Test
+// public void checkSVGMimeType() throws EmptyListException, MalformedListException, UnsupportedObjectTypeException {
+// String mimeType ="image/svg+xml";
+// String type = "SVG";
+// EntityIdentifier entityIdentifier = facade.register(type);
+// RendererRegistry rendererRegistry = new RendererRegistry();
+// List<Renderer> renderersForMimeType = rendererRegistry.getRenderersForMimeType(facade, entityIdentifier, mimeType);
+// assertEquals(renderersForMimeType.size(), 2);
+// assertEquals(renderersForMimeType.get(1).getClass().getSimpleName(), "SVGRenderer");
+// }
+//
+// @Test
+// public void checkTextMimeType() throws EmptyListException, MalformedListException, UnsupportedObjectTypeException {
+// String mimeType ="text/text";
+// String type = "text";
+// EntityIdentifier entityIdentifier = facade.register(type);
+// RendererRegistry rendererRegistry = new RendererRegistry();
+// List<Renderer> renderersForMimeType = rendererRegistry.getRenderersForMimeType(facade, entityIdentifier, mimeType);
+// assertEquals(renderersForMimeType.size(), 1);
+// assertEquals(renderersForMimeType.get(0).getClass().getSimpleName(), "TextRenderer");
+// }
+//
+// @Test
+// public void checkTextRtfMimeType() throws EmptyListException, MalformedListException, UnsupportedObjectTypeException {
+// String mimeType ="text/rtf";
+// String type = "textRTF";
+// EntityIdentifier entityIdentifier = facade.register(type);
+// RendererRegistry rendererRegistry = new RendererRegistry();
+// List<Renderer> renderersForMimeType = rendererRegistry.getRenderersForMimeType(facade, entityIdentifier, mimeType);
+// assertEquals(renderersForMimeType.size(), 2);
+// assertEquals(renderersForMimeType.get(1).getClass().getSimpleName(), "TextRtfRenderer");
+// }
+//
+// @Test
+// public void checkTextXMLMimeType() throws EmptyListException, MalformedListException, UnsupportedObjectTypeException {
+// String mimeType ="text/xml";
+// String type = "textXML";
+// EntityIdentifier entityIdentifier = facade.register(type);
+// RendererRegistry rendererRegistry = new RendererRegistry();
+// List<Renderer> renderersForMimeType = rendererRegistry.getRenderersForMimeType(facade, entityIdentifier, mimeType);
+// assertEquals(renderersForMimeType.size(), 2);
+// assertEquals(renderersForMimeType.get(1).getClass().getSimpleName(), "TextXMLRenderer");
+// }
+//
+// @Before
+// public void setDataManager() {
+// // dManager = new FileDataManager("testNS",
+// // new HashSet<LocationalContext>(), new File("/tmp/fish"));
+// dManager = new InMemoryDataManager(TEST_NS,
+// new HashSet<LocationalContext>());
+// facade = new DataFacade(dManager);
+// }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/72850d5a/taverna-workbench-report-impl/pom.xml
----------------------------------------------------------------------
diff --git a/taverna-workbench-report-impl/pom.xml b/taverna-workbench-report-impl/pom.xml
new file mode 100644
index 0000000..c0e72bb
--- /dev/null
+++ b/taverna-workbench-report-impl/pom.xml
@@ -0,0 +1,40 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <artifactId>ui-impl</artifactId>
+ <groupId>net.sf.taverna.t2</groupId>
+ <version>2.0-SNAPSHOT</version>
+ </parent>
+ <groupId>net.sf.taverna.t2.ui-impl</groupId>
+ <artifactId>report-impl</artifactId>
+ <packaging>bundle</packaging>
+ <name>Reporting Implementation</name>
+ <dependencies>
+ <dependency>
+ <groupId>net.sf.taverna.t2.core</groupId>
+ <artifactId>workflowmodel-api</artifactId>
+ <version>${t2.core.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>net.sf.taverna.t2.ui-api</groupId>
+ <artifactId>report-api</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>net.sf.taverna.t2.ui-api</groupId>
+ <artifactId>file-api</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>net.sf.taverna.t2.ui-api</groupId>
+ <artifactId>edits-api</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>uk.org.taverna.configuration</groupId>
+ <artifactId>taverna-configuration-api</artifactId>
+ <version>${taverna.configuration.version}</version>
+ </dependency>
+ </dependencies>
+</project>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/72850d5a/taverna-workbench-report-impl/src/main/java/net/sf/taverna/t2/workbench/report/config/impl/ReportManagerConfigurationImpl.java
----------------------------------------------------------------------
diff --git a/taverna-workbench-report-impl/src/main/java/net/sf/taverna/t2/workbench/report/config/impl/ReportManagerConfigurationImpl.java b/taverna-workbench-report-impl/src/main/java/net/sf/taverna/t2/workbench/report/config/impl/ReportManagerConfigurationImpl.java
new file mode 100644
index 0000000..b5986b5
--- /dev/null
+++ b/taverna-workbench-report-impl/src/main/java/net/sf/taverna/t2/workbench/report/config/impl/ReportManagerConfigurationImpl.java
@@ -0,0 +1,71 @@
+/**
+ *
+ */
+package net.sf.taverna.t2.workbench.report.config.impl;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import uk.org.taverna.configuration.AbstractConfigurable;
+import uk.org.taverna.configuration.ConfigurationManager;
+
+import net.sf.taverna.t2.workbench.report.config.ReportManagerConfiguration;
+import net.sf.taverna.t2.workflowmodel.health.RemoteHealthChecker;
+
+/**
+ * @author alanrw
+ *
+ */
+public final class ReportManagerConfigurationImpl extends AbstractConfigurable implements ReportManagerConfiguration {
+
+ private static final int DEFAULT_TIMEOUT = 10;
+
+ private Map<String, String> defaultPropertyMap;
+
+ public ReportManagerConfigurationImpl(ConfigurationManager configurationManager) {
+ super(configurationManager);
+ }
+
+ public String getCategory() {
+ return "general";
+ }
+
+ public Map<String, String> getDefaultPropertyMap() {
+
+ if (defaultPropertyMap == null) {
+ defaultPropertyMap = new HashMap<String, String>();
+ defaultPropertyMap.put(TIMEOUT, Integer.toString(DEFAULT_TIMEOUT));
+ defaultPropertyMap.put(ON_EDIT, QUICK_CHECK);
+ defaultPropertyMap.put(ON_OPEN, QUICK_CHECK);
+ defaultPropertyMap.put(BEFORE_RUN, FULL_CHECK);
+ defaultPropertyMap.put(QUERY_BEFORE_RUN, ERRORS_OR_WARNINGS);
+ defaultPropertyMap.put(REPORT_EXPIRATION, Integer.toString(DEFAULT_REPORT_EXPIRATION));
+ }
+ return defaultPropertyMap;
+ }
+
+ public String getDisplayName() {
+ return "Validation report";
+ }
+
+ public String getFilePrefix() {
+ return "ReportManager";
+ }
+
+ public String getUUID() {
+ return "F86378E5-0EC4-4DE9-8A55-6098595413DC";
+ }
+
+ @Override
+ public void applySettings() {
+ RemoteHealthChecker.setTimeoutInSeconds(Integer.parseInt(this.getProperty(TIMEOUT)));
+ }
+
+ public void setProperty(String key, String value) {
+ super.setProperty(key, value);
+ if (key.equals(TIMEOUT)) {
+ applySettings();
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/72850d5a/taverna-workbench-report-impl/src/main/java/net/sf/taverna/t2/workbench/report/impl/ReportManagerImpl.java
----------------------------------------------------------------------
diff --git a/taverna-workbench-report-impl/src/main/java/net/sf/taverna/t2/workbench/report/impl/ReportManagerImpl.java b/taverna-workbench-report-impl/src/main/java/net/sf/taverna/t2/workbench/report/impl/ReportManagerImpl.java
new file mode 100644
index 0000000..825efee
--- /dev/null
+++ b/taverna-workbench-report-impl/src/main/java/net/sf/taverna/t2/workbench/report/impl/ReportManagerImpl.java
@@ -0,0 +1,564 @@
+/**
+ *
+ */
+package net.sf.taverna.t2.workbench.report.impl;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.WeakHashMap;
+
+import net.sf.taverna.t2.lang.observer.MultiCaster;
+import net.sf.taverna.t2.lang.observer.Observable;
+import net.sf.taverna.t2.lang.observer.Observer;
+import net.sf.taverna.t2.visit.HierarchyTraverser;
+import net.sf.taverna.t2.visit.VisitKind;
+import net.sf.taverna.t2.visit.VisitReport;
+import net.sf.taverna.t2.visit.VisitReport.Status;
+import net.sf.taverna.t2.visit.Visitor;
+import net.sf.taverna.t2.workbench.edits.EditManager;
+import net.sf.taverna.t2.workbench.edits.EditManager.AbstractDataflowEditEvent;
+import net.sf.taverna.t2.workbench.edits.EditManager.EditManagerEvent;
+import net.sf.taverna.t2.workbench.file.FileManager;
+import net.sf.taverna.t2.workbench.file.events.ClosedDataflowEvent;
+import net.sf.taverna.t2.workbench.file.events.FileManagerEvent;
+import net.sf.taverna.t2.workbench.file.events.SetCurrentDataflowEvent;
+import net.sf.taverna.t2.workbench.report.DataflowReportEvent;
+import net.sf.taverna.t2.workbench.report.FailedEntityKind;
+import net.sf.taverna.t2.workbench.report.IncompleteDataflowKind;
+import net.sf.taverna.t2.workbench.report.InvalidDataflowKind;
+import net.sf.taverna.t2.workbench.report.ReportManager;
+import net.sf.taverna.t2.workbench.report.ReportManagerEvent;
+import net.sf.taverna.t2.workbench.report.UnresolvedOutputKind;
+import net.sf.taverna.t2.workbench.report.UnsatisfiedEntityKind;
+import net.sf.taverna.t2.workbench.report.config.ReportManagerConfiguration;
+import net.sf.taverna.t2.workflowmodel.Dataflow;
+import net.sf.taverna.t2.workflowmodel.DataflowValidationReport;
+import net.sf.taverna.t2.workflowmodel.Processor;
+
+import org.apache.log4j.Logger;
+
+/**
+ * @author Alan R Williams
+ *
+ */
+public class ReportManagerImpl implements Observable<ReportManagerEvent>, ReportManager {
+
+ private static final long MAX_AGE_OUTDATED_MILLIS = 1 * 60 * 60 * 1000; // 1 hour
+ private static Logger logger = Logger.getLogger(ReportManagerImpl.class);
+
+ private ReportManagerConfiguration reportManagerConfiguration;
+ private HierarchyTraverser traverser = null;
+ private Map<Dataflow, Map<Object, Set<VisitReport>>> reportMap = Collections
+ .synchronizedMap(new WeakHashMap<Dataflow, Map<Object, Set<VisitReport>>>());;
+ private Map<Dataflow, Map<Object, Status>> statusMap = Collections
+ .synchronizedMap(new WeakHashMap<Dataflow, Map<Object, Status>>());
+ private Map<Dataflow, Map<Object, String>> summaryMap = Collections
+ .synchronizedMap(new WeakHashMap<Dataflow, Map<Object, String>>());
+ private Map<Dataflow, Long> lastCheckedMap = Collections
+ .synchronizedMap(new WeakHashMap<Dataflow, Long>());
+ private Map<Dataflow, Long> lastFullCheckedMap = Collections
+ .synchronizedMap(new WeakHashMap<Dataflow, Long>());
+ private Map<Dataflow, String> lastFullCheckedDataflowIdMap = Collections
+ .synchronizedMap(new WeakHashMap<Dataflow, String>());
+
+ private EditManager editManager;
+ private FileManager fileManager;
+
+ // private Set<Visitor<?>> visitors;
+
+ protected ReportManagerImpl(EditManager editManager, FileManager fileManager,
+ Set<Visitor<?>> visitors, ReportManagerConfiguration reportManagerConfiguration)
+ throws IllegalStateException {
+ this.editManager = editManager;
+ this.fileManager = fileManager;
+ this.reportManagerConfiguration = reportManagerConfiguration;
+ // this.visitors = visitors;
+ traverser = new HierarchyTraverser(visitors);
+ ReportManagerFileObserver fileObserver = new ReportManagerFileObserver();
+ fileManager.addObserver(fileObserver);
+ addEditObserver();
+ reportManagerConfiguration.applySettings();
+ }
+
+ private void addEditObserver() {
+ synchronized (editManager) {
+ List<Observer<EditManagerEvent>> currentObservers = editManager.getObservers();
+ for (Observer<EditManagerEvent> o : currentObservers) {
+ editManager.removeObserver(o);
+ }
+ editManager.addObserver(new ReportManagerEditObserver());
+ for (Observer<EditManagerEvent> o : currentObservers) {
+ editManager.addObserver(o);
+ }
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * net.sf.taverna.t2.workbench.report.ReportManagerI#updateReport(net.sf.taverna.t2.workflowmodel
+ * .Dataflow, boolean, boolean)
+ */
+ @Override
+ public void updateReport(Dataflow d, boolean includeTimeConsuming, boolean remember) {
+ Set<VisitReport> oldTimeConsumingReports = null;
+ long time = System.currentTimeMillis();
+ long expiration = Integer.parseInt(reportManagerConfiguration
+ .getProperty(ReportManagerConfiguration.REPORT_EXPIRATION)) * 60 * 1000;
+ if (remember && !includeTimeConsuming
+ && ((expiration == 0) || ((time - getLastFullCheckedTime(d)) < expiration))) {
+ oldTimeConsumingReports = getTimeConsumingReports(d);
+ }
+ Map<Object, Set<VisitReport>> reportsEntry = new HashMap<Object, Set<VisitReport>>();
+ Map<Object, Status> statusEntry = new HashMap<Object, Status>();
+ Map<Object, String> summaryEntry = new HashMap<Object, String>();
+ reportMap.put(d, reportsEntry);
+ statusMap.put(d, statusEntry);
+ summaryMap.put(d, summaryEntry);
+ validateDataflow(d, reportsEntry, statusEntry, summaryEntry);
+
+ Set<VisitReport> newReports = new HashSet<VisitReport>();
+ traverser.traverse(d, new ArrayList<Object>(), newReports, includeTimeConsuming);
+ for (VisitReport vr : newReports) {
+ addReport(reportsEntry, statusEntry, summaryEntry, vr);
+ }
+ if (oldTimeConsumingReports != null) {
+ for (VisitReport vr : oldTimeConsumingReports) {
+ addReport(reportsEntry, statusEntry, summaryEntry, vr);
+ }
+ }
+ time = System.currentTimeMillis();
+ lastCheckedMap.put(d, time);
+ if (includeTimeConsuming) {
+ lastFullCheckedMap.put(d, time);
+ lastFullCheckedDataflowIdMap.put(d, d.getIdentifier());
+ }
+ multiCaster.notify(new DataflowReportEvent(d));
+ }
+
+ private void updateObjectReportInternal(Dataflow d, Object o) {
+ Map<Object, Set<VisitReport>> reportsEntry = reportMap.get(d);
+ Map<Object, Status> statusEntry = statusMap.get(d);
+ Map<Object, String> summaryEntry = summaryMap.get(d);
+ if (reportsEntry == null) {
+ logger.error("Attempt to update reports on an object in a dataflow that has not been checked");
+ reportsEntry = new HashMap<Object, Set<VisitReport>>();
+ statusEntry = new HashMap<Object, Status>();
+ summaryEntry = new HashMap<Object, String>();
+ reportMap.put(d, reportsEntry);
+ statusMap.put(d, statusEntry);
+ summaryMap.put(d, summaryEntry);
+ } else {
+ reportsEntry.remove(o);
+ statusEntry.remove(o);
+ summaryEntry.remove(o);
+ }
+ // Assume o is directly inside d
+ List<Object> ancestry = new ArrayList<Object>();
+ ancestry.add(d);
+ Set<VisitReport> newReports = new HashSet<VisitReport>();
+ traverser.traverse(o, ancestry, newReports, true);
+ for (VisitReport vr : newReports) {
+ addReport(reportsEntry, statusEntry, summaryEntry, vr);
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * net.sf.taverna.t2.workbench.report.ReportManagerI#updateObjectSetReport(net.sf.taverna.t2
+ * .workflowmodel.Dataflow, java.util.Set)
+ */
+ @Override
+ public void updateObjectSetReport(Dataflow d, Set<Object> objects) {
+ for (Object o : objects) {
+ updateObjectReportInternal(d, o);
+ }
+ multiCaster.notify(new DataflowReportEvent(d));
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see net.sf.taverna.t2.workbench.report.ReportManagerI#updateObjectReport(net.sf.taverna.t2.
+ * workflowmodel.Dataflow, java.lang.Object)
+ */
+ @Override
+ public void updateObjectReport(Dataflow d, Object o) {
+ updateObjectReportInternal(d, o);
+ multiCaster.notify(new DataflowReportEvent(d));
+ }
+
+ private Set<VisitReport> getTimeConsumingReports(Dataflow d) {
+ Set<VisitReport> result = new HashSet<VisitReport>();
+ Map<Object, Set<VisitReport>> currentReports = getReports(d);
+ if (currentReports != null) {
+ for (Object o : currentReports.keySet()) {
+ for (VisitReport vr : currentReports.get(o)) {
+ if (vr.wasTimeConsuming()) {
+ result.add(vr);
+ }
+ }
+ }
+ }
+ return result;
+ }
+
+ private void removeReport(Dataflow d) {
+ reportMap.remove(d);
+ statusMap.remove(d);
+ summaryMap.remove(d);
+ }
+
+ private void addReport(Map<Object, Set<VisitReport>> reports, Map<Object, Status> statusEntry,
+ Map<Object, String> summaryEntry, VisitReport newReport) {
+ if (newReport.getCheckTime() == 0) {
+ newReport.setCheckTime(System.currentTimeMillis());
+ }
+ Object subject = newReport.getSubject();
+ Set<VisitReport> currentReports = reports.get(subject);
+ Status newReportStatus = newReport.getStatus();
+ if (currentReports == null) {
+ currentReports = new HashSet<VisitReport>();
+ reports.put(subject, currentReports);
+ statusEntry.put(subject, newReportStatus);
+ summaryEntry.put(subject, newReport.getMessage());
+ } else {
+ Status currentStatus = statusEntry.get(subject);
+ if (currentStatus.compareTo(newReportStatus) < 0) {
+ statusEntry.put(subject, newReportStatus);
+ summaryEntry.put(subject, newReport.getMessage());
+ } else if (currentStatus.compareTo(newReportStatus) == 0) {
+ if (currentStatus.equals(Status.WARNING)) {
+ summaryEntry.put(subject, "Multiple warnings");
+ } else if (currentStatus.equals(Status.SEVERE)) {
+ summaryEntry.put(subject, "Multiple errors");
+ }
+ }
+ }
+ currentReports.add(newReport);
+ }
+
+ private void validateDataflow(Dataflow d, Map<Object, Set<VisitReport>> reportsEntry,
+ Map<Object, Status> statusEntry, Map<Object, String> summaryEntry) {
+ DataflowValidationReport validationReport = d.checkValidity();
+ if (validationReport.isWorkflowIncomplete()) {
+ addReport(reportsEntry, statusEntry, summaryEntry, new VisitReport(
+ IncompleteDataflowKind.getInstance(), d, "Incomplete workflow",
+ IncompleteDataflowKind.INCOMPLETE_DATAFLOW, VisitReport.Status.SEVERE));
+ } else if (!validationReport.isValid()) {
+ addReport(reportsEntry, statusEntry, summaryEntry,
+ new VisitReport(InvalidDataflowKind.getInstance(), d, "Invalid workflow",
+ InvalidDataflowKind.INVALID_DATAFLOW, VisitReport.Status.SEVERE));
+ }
+ fillInReport(reportsEntry, statusEntry, summaryEntry, validationReport);
+ }
+
+ private void fillInReport(Map<Object, Set<VisitReport>> reportsEntry,
+ Map<Object, Status> statusEntry, Map<Object, String> summaryEntry,
+ DataflowValidationReport report) {
+ for (Object o : report.getUnresolvedOutputs()) {
+ addReport(reportsEntry, statusEntry, summaryEntry,
+ new VisitReport(UnresolvedOutputKind.getInstance(), o,
+ "Invalid workflow output", UnresolvedOutputKind.OUTPUT,
+ VisitReport.Status.SEVERE));
+ }
+ for (Object o : report.getFailedEntities()) {
+ addReport(reportsEntry, statusEntry, summaryEntry,
+ new VisitReport(FailedEntityKind.getInstance(), o,
+ "Mismatch of input list depths", FailedEntityKind.FAILED_ENTITY,
+ VisitReport.Status.SEVERE));
+ }
+ for (Object o : report.getUnsatisfiedEntities()) {
+ addReport(reportsEntry, statusEntry, summaryEntry, new VisitReport(
+ UnsatisfiedEntityKind.getInstance(), o, "Unknown prior list depth",
+ UnsatisfiedEntityKind.UNSATISFIED_ENTITY, VisitReport.Status.SEVERE));
+ }
+ // for (DataflowValidationReport subReport : report.getInvalidDataflows().values()) {
+ // fillInReport(descriptionMap, subReport);
+ // }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * net.sf.taverna.t2.workbench.report.ReportManagerI#getReports(net.sf.taverna.t2.workflowmodel
+ * .Dataflow, java.lang.Object)
+ */
+ @Override
+ public Set<VisitReport> getReports(Dataflow d, Object object) {
+ Set<VisitReport> result = new HashSet<VisitReport>();
+ Map<Object, Set<VisitReport>> objectReports = reportMap.get(d);
+ if (objectReports != null) {
+ Set<Object> objects = new HashSet<Object>();
+ objects.add(object);
+ if (object instanceof Processor) {
+ objects.addAll(((Processor) object).getActivityList());
+ }
+ for (Object o : objects) {
+ if (objectReports.containsKey(o)) {
+ result.addAll(objectReports.get(o));
+ }
+ }
+ }
+ return result;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * net.sf.taverna.t2.workbench.report.ReportManagerI#getReports(net.sf.taverna.t2.workflowmodel
+ * .Dataflow)
+ */
+ @Override
+ public Map<Object, Set<VisitReport>> getReports(Dataflow d) {
+ return reportMap.get(d);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see net.sf.taverna.t2.workbench.report.ReportManagerI#isStructurallySound(net.sf.taverna.t2.
+ * workflowmodel.Dataflow)
+ */
+ @Override
+ public boolean isStructurallySound(Dataflow d) {
+ Map<Object, Set<VisitReport>> objectReports = reportMap.get(d);
+ if (objectReports == null) {
+ return false;
+ }
+ for (Set<VisitReport> visitReportSet : objectReports.values()) {
+ for (VisitReport vr : visitReportSet) {
+ if (vr.getStatus().equals(Status.SEVERE)) {
+ VisitKind vk = vr.getKind();
+ if ((vk instanceof IncompleteDataflowKind)
+ || (vk instanceof InvalidDataflowKind)
+ || (vk instanceof UnresolvedOutputKind)
+ || (vk instanceof FailedEntityKind)
+ || (vk instanceof UnsatisfiedEntityKind)) {
+ return false;
+ }
+ }
+ }
+ }
+ return true;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * net.sf.taverna.t2.workbench.report.ReportManagerI#getStatus(net.sf.taverna.t2.workflowmodel
+ * .Dataflow)
+ */
+ @Override
+ public Status getStatus(Dataflow d) {
+ Map<Object, Set<VisitReport>> objectReports = reportMap.get(d);
+ if (objectReports == null) {
+ return Status.OK;
+ }
+ Status currentStatus = Status.OK;
+ for (Set<VisitReport> visitReportSet : objectReports.values()) {
+ for (VisitReport vr : visitReportSet) {
+ Status status = vr.getStatus();
+ if (status.compareTo(currentStatus) > 0) {
+ currentStatus = status;
+ }
+ if (currentStatus.equals(Status.SEVERE)) {
+ return currentStatus;
+ }
+ }
+ }
+ return currentStatus;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * net.sf.taverna.t2.workbench.report.ReportManagerI#getStatus(net.sf.taverna.t2.workflowmodel
+ * .Dataflow, java.lang.Object)
+ */
+ @Override
+ public Status getStatus(Dataflow d, Object object) {
+ Status result = Status.OK;
+ Map<Object, Status> statusEntry = statusMap.get(d);
+ if (statusEntry != null) {
+ Status value = statusEntry.get(object);
+ if (value != null) {
+ result = value;
+ }
+ }
+ return result;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see net.sf.taverna.t2.workbench.report.ReportManagerI#getSummaryMessage(net.sf.taverna.t2.
+ * workflowmodel.Dataflow, java.lang.Object)
+ */
+ @Override
+ public String getSummaryMessage(Dataflow d, Object object) {
+ String result = null;
+ if (!getStatus(d, object).equals(Status.OK)) {
+ Map<Object, String> summaryEntry = summaryMap.get(d);
+ if (summaryEntry != null) {
+ result = summaryEntry.get(object);
+ }
+ }
+ return result;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see net.sf.taverna.t2.workbench.report.ReportManagerI#getLastCheckedTime(net.sf.taverna.t2.
+ * workflowmodel.Dataflow)
+ */
+ @Override
+ public long getLastCheckedTime(Dataflow d) {
+ Long l = lastCheckedMap.get(d);
+ if (l == null) {
+ return 0;
+ } else {
+ return l.longValue();
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * net.sf.taverna.t2.workbench.report.ReportManagerI#getLastFullCheckedTime(net.sf.taverna.t2
+ * .workflowmodel.Dataflow)
+ */
+ @Override
+ public long getLastFullCheckedTime(Dataflow d) {
+ Long l = lastFullCheckedMap.get(d);
+ if (l == null) {
+ return 0;
+ } else {
+ return l.longValue();
+ }
+ }
+
+ /**
+ * @author alanrw
+ *
+ */
+ public class ReportManagerFileObserver implements Observer<FileManagerEvent> {
+
+ public void notify(Observable<FileManagerEvent> sender, FileManagerEvent message)
+ throws Exception {
+ String onOpen = reportManagerConfiguration.getProperty(
+ ReportManagerConfiguration.ON_OPEN);
+ if (message instanceof ClosedDataflowEvent) {
+ ReportManagerImpl.this.removeReport(((ClosedDataflowEvent) message).getDataflow());
+ } else if (message instanceof SetCurrentDataflowEvent) {
+ Dataflow dataflow = ((SetCurrentDataflowEvent) message).getDataflow();
+ if (!reportMap.containsKey(dataflow)) {
+ if (!onOpen.equals(ReportManagerConfiguration.NO_CHECK)) {
+ updateReport(dataflow,
+ onOpen.equals(ReportManagerConfiguration.FULL_CHECK), true);
+ } else {
+ ReportManagerImpl.this.multiCaster
+ .notify(new DataflowReportEvent(dataflow));
+ }
+ } else {
+ ReportManagerImpl.this.multiCaster.notify(new DataflowReportEvent(dataflow));
+ }
+ }
+ }
+
+ }
+
+ private MultiCaster<ReportManagerEvent> multiCaster = new MultiCaster<ReportManagerEvent>(this);
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * net.sf.taverna.t2.workbench.report.ReportManagerI#addObserver(net.sf.taverna.t2.lang.observer
+ * .Observer)
+ */
+ @Override
+ public void addObserver(Observer<ReportManagerEvent> observer) {
+ multiCaster.addObserver(observer);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see net.sf.taverna.t2.workbench.report.ReportManagerI#getObservers()
+ */
+ @Override
+ public List<Observer<ReportManagerEvent>> getObservers() {
+ return multiCaster.getObservers();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * net.sf.taverna.t2.workbench.report.ReportManagerI#removeObserver(net.sf.taverna.t2.lang.observer
+ * .Observer)
+ */
+ @Override
+ public void removeObserver(Observer<ReportManagerEvent> observer) {
+ multiCaster.removeObserver(observer);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see net.sf.taverna.t2.workbench.report.ReportManagerI#isReportOutdated(net.sf.taverna.t2.
+ * workflowmodel.Dataflow)
+ */
+ @Override
+ public boolean isReportOutdated(Dataflow dataflow) {
+ String lastCheckedId = lastFullCheckedDataflowIdMap.get(dataflow);
+ Long lastCheck = lastFullCheckedMap.get(dataflow);
+ if (lastCheckedId == null || lastCheck == null) {
+ // Unknown, so outdated
+ return true;
+ }
+ if (!lastCheckedId.equals(dataflow.getIdentifier())) {
+ // Workflow changed, so outdaeted
+ return true;
+ }
+ long now = System.currentTimeMillis();
+ long age = now - lastCheck;
+ // Outdated if it is older than the maximum
+ return age > MAX_AGE_OUTDATED_MILLIS;
+ }
+
+ public class ReportManagerEditObserver implements Observer<EditManagerEvent> {
+ public void notify(Observable<EditManagerEvent> sender, EditManagerEvent message)
+ throws Exception {
+ String onEdit = reportManagerConfiguration
+ .getProperty(ReportManagerConfiguration.ON_EDIT);
+ Dataflow dataflow = fileManager.getCurrentDataflow();
+ if (message instanceof AbstractDataflowEditEvent) {
+ AbstractDataflowEditEvent adee = (AbstractDataflowEditEvent) message;
+ if (adee.getDataFlow().equals(dataflow)) {
+ if (onEdit.equals(ReportManagerConfiguration.QUICK_CHECK)) {
+ updateReport(dataflow, false, true);
+ } else if (onEdit.equals(ReportManagerConfiguration.FULL_CHECK)) {
+ updateReport(dataflow, true, true);
+ }
+ }
+ }
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/72850d5a/taverna-workbench-report-impl/src/main/resources/META-INF/spring/report-impl-context-osgi.xml
----------------------------------------------------------------------
diff --git a/taverna-workbench-report-impl/src/main/resources/META-INF/spring/report-impl-context-osgi.xml b/taverna-workbench-report-impl/src/main/resources/META-INF/spring/report-impl-context-osgi.xml
new file mode 100644
index 0000000..31c7432
--- /dev/null
+++ b/taverna-workbench-report-impl/src/main/resources/META-INF/spring/report-impl-context-osgi.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans:beans xmlns="http://www.springframework.org/schema/osgi" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:beans="http://www.springframework.org/schema/beans"
+ xsi:schemaLocation="http://www.springframework.org/schema/beans
+ http://www.springframework.org/schema/beans/spring-beans.xsd
+ http://www.springframework.org/schema/osgi
+ http://www.springframework.org/schema/osgi/spring-osgi.xsd">
+
+ <!-- <service ref="ProcessorFragilityChecker" interface="net.sf.taverna.t2.visit.fragility.FragilityChecker" /> -->
+
+ <!-- <service ref="FragilityCheck" interface="net.sf.taverna.t2.visit.VisitKind" /> -->
+
+ <service ref="ReportManagerImpl" interface="net.sf.taverna.t2.workbench.report.ReportManager" />
+
+ <service ref="ReportManagerConfiguration" interface="net.sf.taverna.t2.workbench.report.config.ReportManagerConfiguration" />
+
+ <reference id="editManager" interface="net.sf.taverna.t2.workbench.edits.EditManager" />
+ <reference id="fileManager" interface="net.sf.taverna.t2.workbench.file.FileManager" />
+ <reference id="configurationManager" interface="uk.org.taverna.configuration.ConfigurationManager" />
+
+ <set id="visitors" interface="net.sf.taverna.t2.visit.Visitor" cardinality="0..N" />
+
+</beans:beans>
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/72850d5a/taverna-workbench-report-impl/src/main/resources/META-INF/spring/report-impl-context.xml
----------------------------------------------------------------------
diff --git a/taverna-workbench-report-impl/src/main/resources/META-INF/spring/report-impl-context.xml b/taverna-workbench-report-impl/src/main/resources/META-INF/spring/report-impl-context.xml
new file mode 100644
index 0000000..966d50d
--- /dev/null
+++ b/taverna-workbench-report-impl/src/main/resources/META-INF/spring/report-impl-context.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.springframework.org/schema/beans
+ http://www.springframework.org/schema/beans/spring-beans.xsd">
+
+ <!-- <bean id="ProcessorFragilityChecker" class="net.sf.taverna.t2.visit.fragility.impl.ProcessorFragilityChecker" /> -->
+
+ <!-- <bean id="FragilityCheck" class="net.sf.taverna.t2.visit.fragility.impl.FragilityCheck" /> -->
+
+ <bean id="ReportManagerImpl" class="net.sf.taverna.t2.workbench.report.impl.ReportManagerImpl">
+ <constructor-arg ref="editManager" />
+ <constructor-arg ref="fileManager" />
+ <constructor-arg ref="visitors" />
+ <constructor-arg ref="ReportManagerConfiguration"/>
+ </bean>
+
+ <bean id="ReportManagerConfiguration" class="net.sf.taverna.t2.workbench.report.config.impl.ReportManagerConfigurationImpl">
+ <constructor-arg ref="configurationManager"/>
+ </bean>
+
+</beans>
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/72850d5a/taverna-workbench-selection-impl/pom.xml
----------------------------------------------------------------------
diff --git a/taverna-workbench-selection-impl/pom.xml b/taverna-workbench-selection-impl/pom.xml
new file mode 100644
index 0000000..cb6cbcb
--- /dev/null
+++ b/taverna-workbench-selection-impl/pom.xml
@@ -0,0 +1,35 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>net.sf.taverna.t2</groupId>
+ <artifactId>ui-impl</artifactId>
+ <version>2.0-SNAPSHOT</version>
+ </parent>
+ <groupId>net.sf.taverna.t2.ui-impl</groupId>
+ <artifactId>selection-impl</artifactId>
+ <packaging>bundle</packaging>
+ <name>Selection Implementation</name>
+ <dependencies>
+ <dependency>
+ <groupId>net.sf.taverna.t2.ui-api</groupId>
+ <artifactId>edits-api</artifactId>
+ <version>${t2.ui.api.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>net.sf.taverna.t2.ui-api</groupId>
+ <artifactId>file-api</artifactId>
+ <version>${t2.ui.api.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>net.sf.taverna.t2.ui-api</groupId>
+ <artifactId>selection-api</artifactId>
+ <version>${t2.ui.api.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.compendium</artifactId>
+ <version>${osgi.core.version}</version>
+ </dependency>
+ </dependencies>
+</project>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/72850d5a/taverna-workbench-selection-impl/src/main/java/net/sf/taverna/t2/workbench/selection/impl/DataflowSelectionModelImpl.java
----------------------------------------------------------------------
diff --git a/taverna-workbench-selection-impl/src/main/java/net/sf/taverna/t2/workbench/selection/impl/DataflowSelectionModelImpl.java b/taverna-workbench-selection-impl/src/main/java/net/sf/taverna/t2/workbench/selection/impl/DataflowSelectionModelImpl.java
new file mode 100644
index 0000000..09d6f71
--- /dev/null
+++ b/taverna-workbench-selection-impl/src/main/java/net/sf/taverna/t2/workbench/selection/impl/DataflowSelectionModelImpl.java
@@ -0,0 +1,116 @@
+/*******************************************************************************
+ * Copyright (C) 2007 The University of Manchester
+ *
+ * Modifications to the initial code base are copyright of their
+ * respective authors, or their employers as appropriate.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+package net.sf.taverna.t2.workbench.selection.impl;
+
+import static net.sf.taverna.t2.workbench.selection.events.DataflowSelectionMessage.Type.ADDED;
+import static net.sf.taverna.t2.workbench.selection.events.DataflowSelectionMessage.Type.REMOVED;
+
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.TreeSet;
+
+import net.sf.taverna.t2.lang.observer.MultiCaster;
+import net.sf.taverna.t2.lang.observer.Observer;
+import net.sf.taverna.t2.workbench.selection.DataflowSelectionModel;
+import net.sf.taverna.t2.workbench.selection.events.DataflowSelectionMessage;
+
+/**
+ * Default implementation of a <code>DataflowSelectionModel</code>.
+ *
+ * @author David Withers
+ */
+public class DataflowSelectionModelImpl implements DataflowSelectionModel {
+ private MultiCaster<DataflowSelectionMessage> multiCaster;
+ private Set<Object> selection = new TreeSet<>(new Comparator<Object>() {
+ @Override
+ public int compare(Object o1, Object o2) {
+ if (o1 == o2)
+ return 0;
+ return o1.hashCode() - o2.hashCode();
+ }
+ });
+
+ /**
+ * Constructs a new instance of DataflowSelectionModelImpl.
+ */
+ public DataflowSelectionModelImpl() {
+ multiCaster = new MultiCaster<>(this);
+ }
+
+ @Override
+ public void addSelection(Object element) {
+ if (element != null) {
+ if (!selection.contains(element)) {
+ clearSelection();
+ selection.add(element);
+ multiCaster.notify(new DataflowSelectionMessage(ADDED, element));
+ }
+ }
+ }
+
+ @Override
+ public void clearSelection() {
+ for (Object element : new HashSet<>(selection))
+ removeSelection(element);
+ }
+
+ @Override
+ public Set<Object> getSelection() {
+ return new HashSet<>(selection);
+ }
+
+ @Override
+ public void removeSelection(Object element) {
+ if (element != null && selection.remove(element))
+ multiCaster.notify(new DataflowSelectionMessage(REMOVED, element));
+ }
+
+ @Override
+ public void setSelection(Set<Object> elements) {
+ if (elements == null) {
+ clearSelection();
+ return;
+ }
+ Set<Object> newSelection = new HashSet<>(elements);
+ for (Object element : new HashSet<>(selection))
+ if (!newSelection.remove(element))
+ removeSelection(element);
+ for (Object element : newSelection)
+ addSelection(element);
+ }
+
+ @Override
+ public void addObserver(Observer<DataflowSelectionMessage> observer) {
+ multiCaster.addObserver(observer);
+ }
+
+ @Override
+ public List<Observer<DataflowSelectionMessage>> getObservers() {
+ return multiCaster.getObservers();
+ }
+
+ @Override
+ public void removeObserver(Observer<DataflowSelectionMessage> observer) {
+ multiCaster.removeObserver(observer);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/72850d5a/taverna-workbench-selection-impl/src/main/java/net/sf/taverna/t2/workbench/selection/impl/SelectionManagerImpl.java
----------------------------------------------------------------------
diff --git a/taverna-workbench-selection-impl/src/main/java/net/sf/taverna/t2/workbench/selection/impl/SelectionManagerImpl.java b/taverna-workbench-selection-impl/src/main/java/net/sf/taverna/t2/workbench/selection/impl/SelectionManagerImpl.java
new file mode 100644
index 0000000..2e86f1a
--- /dev/null
+++ b/taverna-workbench-selection-impl/src/main/java/net/sf/taverna/t2/workbench/selection/impl/SelectionManagerImpl.java
@@ -0,0 +1,367 @@
+/*******************************************************************************
+ * Copyright (C) 2007 The University of Manchester
+ *
+ * Modifications to the initial code base are copyright of their
+ * respective authors, or their employers as appropriate.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+package net.sf.taverna.t2.workbench.selection.impl;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.IdentityHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import net.sf.taverna.t2.lang.observer.MultiCaster;
+import net.sf.taverna.t2.lang.observer.Observable;
+import net.sf.taverna.t2.lang.observer.Observer;
+import net.sf.taverna.t2.workbench.edits.CompoundEdit;
+import net.sf.taverna.t2.workbench.edits.Edit;
+import net.sf.taverna.t2.workbench.edits.EditManager;
+import net.sf.taverna.t2.workbench.edits.EditManager.DataFlowUndoEvent;
+import net.sf.taverna.t2.workbench.edits.EditManager.EditManagerEvent;
+import net.sf.taverna.t2.workbench.file.FileManager;
+import net.sf.taverna.t2.workbench.file.events.ClosedDataflowEvent;
+import net.sf.taverna.t2.workbench.file.events.FileManagerEvent;
+import net.sf.taverna.t2.workbench.file.events.OpenedDataflowEvent;
+import net.sf.taverna.t2.workbench.file.events.SetCurrentDataflowEvent;
+import net.sf.taverna.t2.workbench.selection.DataflowSelectionModel;
+import net.sf.taverna.t2.workbench.selection.SelectionManager;
+import net.sf.taverna.t2.workbench.selection.events.DataflowSelectionMessage;
+import net.sf.taverna.t2.workbench.selection.events.PerspectiveSelectionEvent;
+import net.sf.taverna.t2.workbench.selection.events.ProfileSelectionEvent;
+import net.sf.taverna.t2.workbench.selection.events.SelectionManagerEvent;
+import net.sf.taverna.t2.workbench.selection.events.WorkflowBundleSelectionEvent;
+import net.sf.taverna.t2.workbench.selection.events.WorkflowRunSelectionEvent;
+import net.sf.taverna.t2.workbench.selection.events.WorkflowSelectionEvent;
+import net.sf.taverna.t2.workbench.ui.zaria.PerspectiveSPI;
+import net.sf.taverna.t2.workflow.edits.AddChildEdit;
+
+import org.apache.log4j.Logger;
+
+import uk.org.taverna.scufl2.api.container.WorkflowBundle;
+import uk.org.taverna.scufl2.api.core.Processor;
+import uk.org.taverna.scufl2.api.core.Workflow;
+import uk.org.taverna.scufl2.api.port.InputWorkflowPort;
+import uk.org.taverna.scufl2.api.port.OutputWorkflowPort;
+import uk.org.taverna.scufl2.api.profiles.Profile;
+
+/**
+ * Implementation of the {@link SelectionManager}.
+ *
+ * @author David Withers
+ */
+public class SelectionManagerImpl implements SelectionManager {
+ private static final String RESULTS_PERSPECTIVE_ID = "net.sf.taverna.t2.ui.perspectives.results.ResultsPerspective";
+
+ private static final String DESIGN_PERSPECTIVE_ID = "net.sf.taverna.t2.ui.perspectives.design.DesignPerspective";
+
+ private static final Logger logger = Logger.getLogger(SelectionManagerImpl.class);
+
+ private WorkflowBundle selectedWorkflowBundle;
+ private Map<WorkflowBundle, DataflowSelectionModel> workflowSelectionModels = new IdentityHashMap<>();
+ private Map<WorkflowBundle, Workflow> selectedWorkflows = new IdentityHashMap<>();
+ private Map<WorkflowBundle, Profile> selectedProfiles = new IdentityHashMap<>();
+ private String selectedWorkflowRun;
+ private Map<String, DataflowSelectionModel> workflowRunSelectionModels = new HashMap<>();
+ private PerspectiveSPI selectedPerspective;
+ private MultiCaster<SelectionManagerEvent> observers = new MultiCaster<>(this);
+ private FileManager fileManager;
+ private List<PerspectiveSPI> perspectives;
+
+ @Override
+ public DataflowSelectionModel getDataflowSelectionModel(WorkflowBundle dataflow) {
+ DataflowSelectionModel selectionModel;
+ synchronized (workflowSelectionModels) {
+ selectionModel = workflowSelectionModels.get(dataflow);
+ if (selectionModel == null) {
+ selectionModel = new DataflowSelectionModelImpl();
+ workflowSelectionModels.put(dataflow, selectionModel);
+ }
+ }
+ return selectionModel;
+ }
+
+ @Override
+ public WorkflowBundle getSelectedWorkflowBundle() {
+ return selectedWorkflowBundle;
+ }
+
+ @Override
+ public void setSelectedWorkflowBundle(WorkflowBundle workflowBundle) {
+ setSelectedWorkflowBundle(workflowBundle, true);
+ }
+
+ private void setSelectedWorkflowBundle(WorkflowBundle workflowBundle, boolean notifyFileManager) {
+ if (workflowBundle == null || workflowBundle == selectedWorkflowBundle)
+ return;
+ if (notifyFileManager) {
+ fileManager.setCurrentDataflow(workflowBundle);
+ return;
+ }
+ if (selectedWorkflows.get(workflowBundle) == null)
+ selectedWorkflows.put(workflowBundle,
+ workflowBundle.getMainWorkflow());
+ if (selectedProfiles.get(workflowBundle) == null)
+ selectedProfiles.put(workflowBundle,
+ workflowBundle.getMainProfile());
+ SelectionManagerEvent selectionManagerEvent = new WorkflowBundleSelectionEvent(
+ selectedWorkflowBundle, workflowBundle);
+ selectedWorkflowBundle = workflowBundle;
+ notify(selectionManagerEvent);
+ selectDesignPerspective();
+ }
+
+ private void removeWorkflowBundle(WorkflowBundle dataflow) {
+ synchronized (workflowSelectionModels) {
+ DataflowSelectionModel selectionModel = workflowSelectionModels.remove(dataflow);
+ if (selectionModel != null)
+ for (Observer<DataflowSelectionMessage> observer : selectionModel.getObservers())
+ selectionModel.removeObserver(observer);
+ }
+ synchronized (selectedWorkflows) {
+ selectedWorkflows.remove(dataflow);
+ }
+ synchronized (selectedProfiles) {
+ selectedProfiles.remove(dataflow);
+ }
+ }
+
+ @Override
+ public Workflow getSelectedWorkflow() {
+ return selectedWorkflows.get(selectedWorkflowBundle);
+ }
+
+ @Override
+ public void setSelectedWorkflow(Workflow workflow) {
+ if (workflow != null) {
+ Workflow selectedWorkflow = selectedWorkflows.get(workflow
+ .getParent());
+ if (selectedWorkflow != workflow) {
+ SelectionManagerEvent selectionManagerEvent = new WorkflowSelectionEvent(
+ selectedWorkflow, workflow);
+ selectedWorkflows.put(workflow.getParent(), workflow);
+ notify(selectionManagerEvent);
+ }
+ }
+ }
+
+ @Override
+ public Profile getSelectedProfile() {
+ return selectedProfiles.get(selectedWorkflowBundle);
+ }
+
+ @Override
+ public void setSelectedProfile(Profile profile) {
+ if (profile != null) {
+ Profile selectedProfile = selectedProfiles.get(profile.getParent());
+ if (selectedProfile != profile) {
+ SelectionManagerEvent selectionManagerEvent = new ProfileSelectionEvent(
+ selectedProfile, profile);
+ selectedProfiles.put(profile.getParent(), profile);
+ notify(selectionManagerEvent);
+ }
+ }
+ }
+
+ @Override
+ public String getSelectedWorkflowRun() {
+ return selectedWorkflowRun;
+ }
+
+ @Override
+ public void setSelectedWorkflowRun(String workflowRun) {
+ if ((selectedWorkflowRun == null && workflowRun != null)
+ || !selectedWorkflowRun.equals(workflowRun)) {
+ SelectionManagerEvent selectionManagerEvent = new WorkflowRunSelectionEvent(
+ selectedWorkflowRun, workflowRun);
+ selectedWorkflowRun = workflowRun;
+ notify(selectionManagerEvent);
+ selectResultsPerspective();
+ }
+ }
+
+ @Override
+ public DataflowSelectionModel getWorkflowRunSelectionModel(String workflowRun) {
+ DataflowSelectionModel selectionModel;
+ synchronized (workflowRunSelectionModels) {
+ selectionModel = workflowRunSelectionModels.get(workflowRun);
+ if (selectionModel == null) {
+ selectionModel = new DataflowSelectionModelImpl();
+ workflowRunSelectionModels.put(workflowRun, selectionModel);
+ }
+ }
+ return selectionModel;
+ }
+
+ @SuppressWarnings("unused")
+ private void removeWorkflowRun(String workflowRun) {
+ synchronized (workflowRunSelectionModels) {
+ DataflowSelectionModel selectionModel = workflowRunSelectionModels
+ .remove(workflowRun);
+ if (selectionModel != null)
+ for (Observer<DataflowSelectionMessage> observer : selectionModel
+ .getObservers())
+ selectionModel.removeObserver(observer);
+ }
+ }
+
+ @Override
+ public PerspectiveSPI getSelectedPerspective() {
+ return selectedPerspective;
+ }
+
+ @Override
+ public void setSelectedPerspective(PerspectiveSPI perspective) {
+ if (selectedPerspective != perspective) {
+ SelectionManagerEvent selectionManagerEvent = new PerspectiveSelectionEvent(
+ selectedPerspective, perspective);
+ selectedPerspective = perspective;
+ notify(selectionManagerEvent);
+ }
+ }
+
+ private void selectDesignPerspective() {
+ for (PerspectiveSPI perspective : perspectives)
+ if (DESIGN_PERSPECTIVE_ID.equals(perspective.getID())) {
+ setSelectedPerspective(perspective);
+ break;
+ }
+ }
+
+ private void selectResultsPerspective() {
+ for (PerspectiveSPI perspective : perspectives)
+ if (RESULTS_PERSPECTIVE_ID.equals(perspective.getID())) {
+ setSelectedPerspective(perspective);
+ break;
+ }
+ }
+
+ @Override
+ public void addObserver(Observer<SelectionManagerEvent> observer) {
+ synchronized (observers) {
+ WorkflowBundle selectedWorkflowBundle = getSelectedWorkflowBundle();
+ Workflow selectedWorkflow = getSelectedWorkflow();
+ Profile selectedProfile = getSelectedProfile();
+ String selectedWorkflowRun = getSelectedWorkflowRun();
+ PerspectiveSPI selectedPerspective = getSelectedPerspective();
+ try {
+ if (selectedWorkflowBundle != null)
+ observer.notify(this, new WorkflowBundleSelectionEvent(
+ null, selectedWorkflowBundle));
+ if (selectedWorkflow != null)
+ observer.notify(this, new WorkflowSelectionEvent(null,
+ selectedWorkflow));
+ if (selectedProfile != null)
+ observer.notify(this, new ProfileSelectionEvent(null,
+ selectedProfile));
+ if (selectedWorkflowRun != null)
+ observer.notify(this, new WorkflowRunSelectionEvent(null,
+ selectedWorkflowRun));
+ if (selectedPerspective != null)
+ observer.notify(this, new PerspectiveSelectionEvent(null,
+ selectedPerspective));
+ } catch (Exception e) {
+ logger.warn("Could not notify " + observer, e);
+ }
+ observers.addObserver(observer);
+ }
+ }
+
+ @Override
+ public void removeObserver(Observer<SelectionManagerEvent> observer) {
+ observers.removeObserver(observer);
+ }
+
+ @Override
+ public List<Observer<SelectionManagerEvent>> getObservers() {
+ return observers.getObservers();
+ }
+
+ public void setFileManager(FileManager fileManager) {
+ this.fileManager = fileManager;
+ setSelectedWorkflowBundle(fileManager.getCurrentDataflow());
+ fileManager.addObserver(new FileManagerObserver());
+ }
+
+ public void setEditManager(EditManager editManager) {
+ editManager.addObserver(new EditManagerObserver());
+ }
+
+ public void setPerspectives(List<PerspectiveSPI> perspectives) {
+ this.perspectives = perspectives;
+ }
+
+ public class FileManagerObserver implements Observer<FileManagerEvent> {
+ @Override
+ public void notify(Observable<FileManagerEvent> sender,
+ FileManagerEvent message) throws Exception {
+ if (message instanceof ClosedDataflowEvent) {
+ WorkflowBundle workflowBundle = ((ClosedDataflowEvent) message).getDataflow();
+ removeWorkflowBundle(workflowBundle);
+ } else if (message instanceof OpenedDataflowEvent) {
+ WorkflowBundle workflowBundle = ((OpenedDataflowEvent) message).getDataflow();
+ setSelectedWorkflowBundle(workflowBundle, false);
+ } else if (message instanceof SetCurrentDataflowEvent) {
+ WorkflowBundle workflowBundle = ((SetCurrentDataflowEvent) message).getDataflow();
+ setSelectedWorkflowBundle(workflowBundle, false);
+ }
+ }
+ }
+
+ private class EditManagerObserver implements Observer<EditManagerEvent> {
+ @Override
+ public void notify(Observable<EditManagerEvent> sender, EditManagerEvent message)
+ throws Exception {
+ Edit<?> edit = message.getEdit();
+ considerEdit(edit, message instanceof DataFlowUndoEvent);
+ }
+
+ private void considerEdit(Edit<?> edit, boolean undoing) {
+ if (edit instanceof CompoundEdit) {
+ CompoundEdit compound = (CompoundEdit) edit;
+ for (Edit<?> e : compound.getChildEdits())
+ considerEdit(e, undoing);
+ } else if (edit instanceof AddChildEdit
+ && edit.getSubject() instanceof Workflow) {
+ Workflow subject = (Workflow) edit.getSubject();
+ DataflowSelectionModel selectionModel = getDataflowSelectionModel(subject
+ .getParent());
+ Object child = ((AddChildEdit<?>) edit).getChild();
+ if (child instanceof Processor
+ || child instanceof InputWorkflowPort
+ || child instanceof OutputWorkflowPort) {
+ if (undoing
+ && selectionModel.getSelection().contains(child))
+ selectionModel.clearSelection();
+ else {
+ Set<Object> selection = new HashSet<>();
+ selection.add(child);
+ selectionModel.setSelection(selection);
+ }
+ }
+ }
+ }
+ }
+
+ private void notify(SelectionManagerEvent event) {
+ synchronized (observers) {
+ observers.notify(event);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/72850d5a/taverna-workbench-selection-impl/src/main/resources/META-INF/spring/selection-impl-context-osgi.xml
----------------------------------------------------------------------
diff --git a/taverna-workbench-selection-impl/src/main/resources/META-INF/spring/selection-impl-context-osgi.xml b/taverna-workbench-selection-impl/src/main/resources/META-INF/spring/selection-impl-context-osgi.xml
new file mode 100644
index 0000000..19faa00
--- /dev/null
+++ b/taverna-workbench-selection-impl/src/main/resources/META-INF/spring/selection-impl-context-osgi.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans:beans xmlns="http://www.springframework.org/schema/osgi" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:beans="http://www.springframework.org/schema/beans"
+ xsi:schemaLocation="http://www.springframework.org/schema/beans
+ http://www.springframework.org/schema/beans/spring-beans.xsd
+ http://www.springframework.org/schema/osgi
+ http://www.springframework.org/schema/osgi/spring-osgi.xsd">
+
+ <service ref="selectionManager" interface="net.sf.taverna.t2.workbench.selection.SelectionManager" />
+
+ <reference id="editManager" interface="net.sf.taverna.t2.workbench.edits.EditManager" />
+ <reference id="fileManager" interface="net.sf.taverna.t2.workbench.file.FileManager" />
+ <!-- <reference id="menuManager" interface="net.sf.taverna.t2.ui.menu.MenuManager" /> -->
+
+ <list id="perspectives" interface="net.sf.taverna.t2.workbench.ui.zaria.PerspectiveSPI" cardinality="0..N" />
+
+</beans:beans>
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/72850d5a/taverna-workbench-selection-impl/src/main/resources/META-INF/spring/selection-impl-context.xml
----------------------------------------------------------------------
diff --git a/taverna-workbench-selection-impl/src/main/resources/META-INF/spring/selection-impl-context.xml b/taverna-workbench-selection-impl/src/main/resources/META-INF/spring/selection-impl-context.xml
new file mode 100644
index 0000000..84bbff1
--- /dev/null
+++ b/taverna-workbench-selection-impl/src/main/resources/META-INF/spring/selection-impl-context.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.springframework.org/schema/beans
+ http://www.springframework.org/schema/beans/spring-beans.xsd">
+
+ <bean id="selectionManager" class="net.sf.taverna.t2.workbench.selection.impl.SelectionManagerImpl" >
+ <property name="fileManager" ref="fileManager"/>
+ <property name="editManager" ref="editManager"/>
+ <property name="perspectives" ref="perspectives"/>
+ </bean>
+
+</beans>
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/72850d5a/taverna-workbench-update-manager/pom.xml
----------------------------------------------------------------------
diff --git a/taverna-workbench-update-manager/pom.xml b/taverna-workbench-update-manager/pom.xml
new file mode 100644
index 0000000..c2f2003
--- /dev/null
+++ b/taverna-workbench-update-manager/pom.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>net.sf.taverna.t2</groupId>
+ <artifactId>ui-impl</artifactId>
+ <version>2.0-SNAPSHOT</version>
+ </parent>
+ <groupId>net.sf.taverna.t2.ui-impl</groupId>
+ <artifactId>update-manager</artifactId>
+ <version>2.0.1-SNAPSHOT</version>
+ <packaging>bundle</packaging>
+ <name>Taverna Workbench Update Manager</name>
+ <dependencies>
+ <dependency>
+ <groupId>net.sf.taverna.t2.ui-api</groupId>
+ <artifactId>menu-api</artifactId>
+ <version>${t2.ui.api.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>uk.org.taverna.commons</groupId>
+ <artifactId>taverna-update-api</artifactId>
+ <version>${taverna.commons.version}</version>
+ </dependency>
+ </dependencies>
+</project>
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/72850d5a/taverna-workbench-update-manager/src/main/java/net/sf/taverna/t2/workbench/update/impl/UpdateManagerView.java
----------------------------------------------------------------------
diff --git a/taverna-workbench-update-manager/src/main/java/net/sf/taverna/t2/workbench/update/impl/UpdateManagerView.java b/taverna-workbench-update-manager/src/main/java/net/sf/taverna/t2/workbench/update/impl/UpdateManagerView.java
new file mode 100644
index 0000000..6b70101
--- /dev/null
+++ b/taverna-workbench-update-manager/src/main/java/net/sf/taverna/t2/workbench/update/impl/UpdateManagerView.java
@@ -0,0 +1,45 @@
+/*******************************************************************************
+ * Copyright (C) 2013 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.update.impl;
+
+import java.awt.GridBagLayout;
+
+import javax.swing.JPanel;
+
+import uk.org.taverna.commons.update.UpdateManager;
+
+/**
+ * @author David Withers
+ */
+@SuppressWarnings({ "serial", "unused" })
+public class UpdateManagerView extends JPanel {
+
+ private UpdateManager updateManager;
+
+ public UpdateManagerView(UpdateManager updateManager) {
+ this.updateManager = updateManager;
+ initialize();
+ }
+
+ private void initialize() {
+ setLayout(new GridBagLayout());
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/72850d5a/taverna-workbench-update-manager/src/main/java/net/sf/taverna/t2/workbench/update/impl/menu/UpdateMenuAction.java
----------------------------------------------------------------------
diff --git a/taverna-workbench-update-manager/src/main/java/net/sf/taverna/t2/workbench/update/impl/menu/UpdateMenuAction.java b/taverna-workbench-update-manager/src/main/java/net/sf/taverna/t2/workbench/update/impl/menu/UpdateMenuAction.java
new file mode 100644
index 0000000..2c1459b
--- /dev/null
+++ b/taverna-workbench-update-manager/src/main/java/net/sf/taverna/t2/workbench/update/impl/menu/UpdateMenuAction.java
@@ -0,0 +1,92 @@
+/*******************************************************************************
+ * Copyright (C) 2013 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.update.impl.menu;
+
+import static javax.swing.JOptionPane.YES_OPTION;
+import static javax.swing.JOptionPane.showConfirmDialog;
+import static javax.swing.JOptionPane.showMessageDialog;
+
+import java.awt.Component;
+import java.awt.event.ActionEvent;
+import java.net.URI;
+
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+
+import net.sf.taverna.t2.ui.menu.AbstractMenuAction;
+
+import org.apache.log4j.Logger;
+
+import uk.org.taverna.commons.update.UpdateException;
+import uk.org.taverna.commons.update.UpdateManager;
+
+public class UpdateMenuAction extends AbstractMenuAction {
+ private static final Logger logger = Logger.getLogger(UpdateMenuAction.class);
+ private static final URI ADVANCED_MENU_URI = URI
+ .create("http://taverna.sf.net/2008/t2workbench/menu#advanced");
+
+ private UpdateManager updateManager;
+
+ public UpdateMenuAction() {
+ super(ADVANCED_MENU_URI, 1000);
+ }
+
+ @SuppressWarnings("serial")
+ @Override
+ protected Action createAction() {
+ return new AbstractAction("Check for updates") {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ findUpdates();
+ }
+ };
+ }
+
+ public void setUpdateManager(UpdateManager updateManager) {
+ this.updateManager = updateManager;
+ }
+
+ private void findUpdates() {
+ Component parent = null;
+ try {
+ if (!areUpdatesAvailable()) {
+ showMessageDialog(null, "No update available");
+ return;
+ }
+ if (showConfirmDialog(parent, "Update available. Update Now?") != YES_OPTION)
+ return;
+ applyUpdates();
+ showMessageDialog(parent,
+ "Update complete. Restart Taverna to apply update.");
+ } catch (UpdateException ex) {
+ showMessageDialog(parent, "Update failed: " + ex.getMessage());
+ logger.warn("Update failed", ex);
+ }
+ }
+
+ protected boolean areUpdatesAvailable() throws UpdateException {
+ return updateManager.checkForUpdates();
+ }
+
+ protected void applyUpdates() throws UpdateException {
+ updateManager.update();
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/72850d5a/taverna-workbench-update-manager/src/main/java/net/sf/taverna/t2/workbench/updatemanager/PluginMenuAction.java
----------------------------------------------------------------------
diff --git a/taverna-workbench-update-manager/src/main/java/net/sf/taverna/t2/workbench/updatemanager/PluginMenuAction.java b/taverna-workbench-update-manager/src/main/java/net/sf/taverna/t2/workbench/updatemanager/PluginMenuAction.java
new file mode 100644
index 0000000..e6b4695
--- /dev/null
+++ b/taverna-workbench-update-manager/src/main/java/net/sf/taverna/t2/workbench/updatemanager/PluginMenuAction.java
@@ -0,0 +1,52 @@
+package net.sf.taverna.t2.workbench.updatemanager;
+
+import static java.awt.event.KeyEvent.VK_F12;
+import static javax.swing.KeyStroke.getKeyStroke;
+
+import java.awt.Component;
+import java.awt.event.ActionEvent;
+import java.net.URI;
+
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+
+import net.sf.taverna.t2.ui.menu.AbstractMenuAction;
+
+public class PluginMenuAction extends AbstractMenuAction {
+ private static final String UPDATES_AND_PLUGINS = "Updates and plugins";
+
+ @SuppressWarnings("serial")
+ protected class SoftwareUpdates extends AbstractAction {
+ public SoftwareUpdates() {
+ super(UPDATES_AND_PLUGINS, null/*UpdatesAvailableIcon.updateRecommendedIcon*/);
+ putValue(ACCELERATOR_KEY, getKeyStroke(VK_F12, 0));
+ }
+
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ @SuppressWarnings("unused")
+ Component parent = null;
+ if (e.getSource() instanceof Component) {
+ parent = (Component) e.getSource();
+ }
+ //FIXME this does nothing!
+ //final PluginManagerFrame pluginManagerUI = new PluginManagerFrame(
+ // PluginManager.getInstance());
+ //if (parent != null) {
+ // pluginManagerUI.setLocationRelativeTo(parent);
+ //}
+ //pluginManagerUI.setVisible(true);
+ }
+ }
+
+ public PluginMenuAction() {
+ super(URI.create("http://taverna.sf.net/2008/t2workbench/menu#advanced"),
+ 100);
+ }
+
+ @Override
+ protected Action createAction() {
+ //return new SoftwareUpdates();
+ return null;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/72850d5a/taverna-workbench-update-manager/src/main/java/net/sf/taverna/t2/workbench/updatemanager/UpdatesAvailableMenuAction.java
----------------------------------------------------------------------
diff --git a/taverna-workbench-update-manager/src/main/java/net/sf/taverna/t2/workbench/updatemanager/UpdatesAvailableMenuAction.java b/taverna-workbench-update-manager/src/main/java/net/sf/taverna/t2/workbench/updatemanager/UpdatesAvailableMenuAction.java
new file mode 100644
index 0000000..e2611be
--- /dev/null
+++ b/taverna-workbench-update-manager/src/main/java/net/sf/taverna/t2/workbench/updatemanager/UpdatesAvailableMenuAction.java
@@ -0,0 +1,19 @@
+package net.sf.taverna.t2.workbench.updatemanager;
+
+import static net.sf.taverna.t2.workbench.updatemanager.UpdatesToolbarSection.UPDATES_SECTION;
+
+import java.awt.Component;
+
+import net.sf.taverna.t2.ui.menu.AbstractMenuCustom;
+
+public class UpdatesAvailableMenuAction extends AbstractMenuCustom {
+ public UpdatesAvailableMenuAction() {
+ super(UPDATES_SECTION, 10);
+ }
+
+ @Override
+ protected Component createCustomComponent() {
+ //return new UpdatesAvailableIcon();
+ return null;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/72850d5a/taverna-workbench-update-manager/src/main/java/net/sf/taverna/t2/workbench/updatemanager/UpdatesToolbarSection.java
----------------------------------------------------------------------
diff --git a/taverna-workbench-update-manager/src/main/java/net/sf/taverna/t2/workbench/updatemanager/UpdatesToolbarSection.java b/taverna-workbench-update-manager/src/main/java/net/sf/taverna/t2/workbench/updatemanager/UpdatesToolbarSection.java
new file mode 100644
index 0000000..b16d614
--- /dev/null
+++ b/taverna-workbench-update-manager/src/main/java/net/sf/taverna/t2/workbench/updatemanager/UpdatesToolbarSection.java
@@ -0,0 +1,16 @@
+package net.sf.taverna.t2.workbench.updatemanager;
+
+import static net.sf.taverna.t2.ui.menu.DefaultToolBar.DEFAULT_TOOL_BAR;
+
+import java.net.URI;
+
+import net.sf.taverna.t2.ui.menu.AbstractMenuSection;
+
+public class UpdatesToolbarSection extends AbstractMenuSection {
+ public static final URI UPDATES_SECTION = URI
+ .create("http://taverna.sf.net/2008/t2workbench/toolbar#updatesSection");
+
+ public UpdatesToolbarSection() {
+ super(DEFAULT_TOOL_BAR, 10000, UPDATES_SECTION);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/72850d5a/taverna-workbench-update-manager/src/main/resources/META-INF/spring/update-manager-context-osgi.xml
----------------------------------------------------------------------
diff --git a/taverna-workbench-update-manager/src/main/resources/META-INF/spring/update-manager-context-osgi.xml b/taverna-workbench-update-manager/src/main/resources/META-INF/spring/update-manager-context-osgi.xml
new file mode 100644
index 0000000..ea637dd
--- /dev/null
+++ b/taverna-workbench-update-manager/src/main/resources/META-INF/spring/update-manager-context-osgi.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans:beans xmlns="http://www.springframework.org/schema/osgi"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:beans="http://www.springframework.org/schema/beans"
+ xsi:schemaLocation="http://www.springframework.org/schema/beans
+ http://www.springframework.org/schema/beans/spring-beans.xsd
+ http://www.springframework.org/schema/osgi
+ http://www.springframework.org/schema/osgi/spring-osgi.xsd">
+
+ <service ref="UpdateMenuAction" auto-export="interfaces" />
+
+ <reference id="updateManager" interface="uk.org.taverna.commons.update.UpdateManager" />
+
+</beans:beans>