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/23 11:05:14 UTC

[29/79] [partial] incubator-taverna-language git commit: Revert "temporarily empty repository"

http://git-wip-us.apache.org/repos/asf/incubator-taverna-language/blob/c08405cb/taverna-scufl2-api/src/test/java/org/apache/taverna/scufl2/api/common/TestURITools.java
----------------------------------------------------------------------
diff --git a/taverna-scufl2-api/src/test/java/org/apache/taverna/scufl2/api/common/TestURITools.java b/taverna-scufl2-api/src/test/java/org/apache/taverna/scufl2/api/common/TestURITools.java
new file mode 100644
index 0000000..76e4a85
--- /dev/null
+++ b/taverna-scufl2-api/src/test/java/org/apache/taverna/scufl2/api/common/TestURITools.java
@@ -0,0 +1,196 @@
+package org.apache.taverna.scufl2.api.common;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.net.URI;
+import java.util.UUID;
+
+import org.apache.taverna.scufl2.api.common.URITools;
+import org.apache.taverna.scufl2.api.container.WorkflowBundle;
+import org.apache.taverna.scufl2.api.core.Workflow;
+import org.apache.taverna.scufl2.api.io.TestWorkflowBundleIO;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+
+
+public class TestURITools {
+
+	private URITools uriTools = new URITools();
+	private WorkflowBundle wfBundle;
+
+	@Before
+	public void makeExampleWorkflow() {
+		wfBundle = new TestWorkflowBundleIO().makeWorkflowBundle();
+	}
+
+	@Test
+	public void relativizeNotSameFolder() {
+		URI base = URI.create("workflow/Workflow.rdf");
+		URI uri = URI.create("profile/Profile/");
+		assertEquals("../profile/Profile/", uriTools.relativePath(base, uri).toASCIIString());
+	}
+
+	@Test
+	public void relativizeNotSameFolderAbsolute() {
+		URI base = URI.create("/workflow/Workflow.rdf");
+		URI uri = URI.create("/profile/Profile/");
+		assertEquals("../profile/Profile/", uriTools.relativePath(base, uri).toASCIIString());
+	}
+
+	@Test
+	public void relativizeNotSameFolderComplete() {
+		URI base = URI.create("http://example.com/workflow/Workflow.rdf");
+		URI uri = URI.create("http://example.com/profile/Profile/");
+		assertEquals("../profile/Profile/", uriTools.relativePath(base, uri)
+				.toASCIIString());
+	}
+
+	@Test
+	public void relativizeSameFolder() {
+		URI base = URI.create("workflow/Workflow.rdf");
+		URI uri = URI.create("workflow/Folder/");
+		assertEquals("Folder/", uriTools.relativePath(base, uri)
+				.toASCIIString());
+	}
+
+	@Test
+	public void relativizeSameFolderAbsoulute() {
+		URI base = URI.create("/workflow/Workflow.rdf");
+		URI uri = URI.create("/workflow/Folder/");
+		assertEquals("Folder/", uriTools.relativePath(base, uri)
+				.toASCIIString());
+	}
+
+	@Test
+	public void relativizeSameFolderComplete() {
+		URI base = URI.create("http://example.com/workflow/Workflow.rdf");
+		URI uri = URI.create("http://example.com/workflow/Folder/");
+		assertEquals("Folder/", uriTools.relativePath(base, uri)
+				.toASCIIString());
+	}
+
+	@Test
+	public void relativizeSamePath() {
+		URI base = URI.create("workflow/../workflow//Workflow.rdf#");
+		URI uri = URI.create("workflow/Workflow.rdf#fish");
+		assertEquals("#fish", uriTools.relativePath(base, uri).toASCIIString());
+	}
+
+	@Test
+	public void relativizeSamePathAbsolute() {
+		URI base = URI.create("/workflow/../workflow//Workflow.rdf#");
+		URI uri = URI.create("/workflow/Workflow.rdf#fish");
+		assertEquals("#fish", uriTools.relativePath(base, uri).toASCIIString());
+	}
+
+	@Test
+	public void relativizeSamePathComplete() {
+		URI base = URI
+				.create("http://example.com/workflow/../workflow//Workflow.rdf#");
+		URI uri = URI
+.create("http://example.com/workflow/Workflow.rdf#fish");
+		assertEquals("#fish", uriTools.relativePath(base, uri).toASCIIString());
+	}
+
+	@Test
+	public void relatizeSame() throws Exception {
+		URI base = URI.create("workflow/HelloWorld.rdf");
+		URI uri = URI.create("workflow/HelloWorld/");
+		assertEquals("HelloWorld/", uriTools.relativePath(base, uri).toASCIIString());
+	}
+
+	@Test
+	public void relatizeToFragment() throws Exception {
+		URI base = URI.create("filename.txt");
+		URI fragment = URI.create("./#sd");
+		assertEquals(".#sd", uriTools.relativePath(base, fragment)
+				.toASCIIString());
+	}
+
+	@Ignore("Not so critical to fix for now..")
+	@Test
+	public void relatizeToSlash() throws Exception {
+		URI base = URI.create("filename.txt");
+		URI fragment = URI.create("./");
+		assertEquals("./", uriTools.relativePath(base, fragment)
+				.toASCIIString());
+	}
+
+	@Test
+	public void validFileName() {
+		assertEquals(
+				"f%2fsd%5Csdf'asd%20fa%3as&%3F%3dd%20%C6%92%C3%AB%E2%88%9A%C3%A6%E2%80%9A%C3%84%C3%B9%C2%AC%C2%AA%E2%88%9A%C2%B6",
+				uriTools.validFilename("f/sd\\sdf'asd fa:s&?=d \u0192\u00eb\u221a\u00e6\u201a\u00c4\u00f9\u00ac\u00aa\u221a\u00b6")); 
+		// f/sd\sdf'asd fa:s&?=d  đþ”»æ  -- double check your Maven/Eclipse is using utf-8
+	}
+
+
+	@Test(expected=NullPointerException.class)
+	public void validFileNameNull() {		
+		uriTools.validFilename(null);
+	}
+	
+	@Test
+	public void wfBundle() {
+		assertEquals(
+				"http://ns.taverna.org.uk/2010/workflowBundle/28f7c554-4f35-401f-b34b-516e9a0ef731/",
+				wfBundle.getGlobalBaseURI().toASCIIString());
+		assertEquals(wfBundle.getGlobalBaseURI(), uriTools.uriForBean(wfBundle));
+		String uuidPath = uriTools.relativePath(
+				WorkflowBundle.WORKFLOW_BUNDLE_ROOT, wfBundle.getGlobalBaseURI())
+				.getPath();
+		assertTrue(uuidPath.endsWith("/"));
+		// Should be a valid uuid
+		UUID.fromString(uuidPath.substring(0, uuidPath.length() - 1));
+	}
+
+	@Test
+	public void wfBundleSelfRelative() {
+		assertEquals(URI.create(""),
+				uriTools.relativeUriForBean(wfBundle, wfBundle));
+	}
+
+	@Test
+	public void workflow() {
+		Workflow wf = wfBundle.getMainWorkflow();
+		URI wfUri = uriTools.uriForBean(wf);
+		assertEquals(
+				"http://ns.taverna.org.uk/2010/workflowBundle/28f7c554-4f35-401f-b34b-516e9a0ef731/workflow/HelloWorld/",
+				wfUri.toASCIIString());
+		URI namePath = uriTools.relativeUriForBean(wf, wfBundle);
+		assertEquals("workflow/HelloWorld/", namePath.toASCIIString()); // wf.getName();
+	}
+
+	@Test
+	public void workflowIdentifier() {
+		Workflow wf = wfBundle.getMainWorkflow();
+		String uuidPath = uriTools.relativePath(Workflow.WORKFLOW_ROOT,
+				wf.getIdentifier()).getPath();
+		assertTrue(uuidPath.endsWith("/"));
+		// Should be a valid uuid
+		UUID.fromString(uuidPath.substring(0, uuidPath.length() - 1));
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-language/blob/c08405cb/taverna-scufl2-api/src/test/java/org/apache/taverna/scufl2/api/common/TestURIToolsBeans.java
----------------------------------------------------------------------
diff --git a/taverna-scufl2-api/src/test/java/org/apache/taverna/scufl2/api/common/TestURIToolsBeans.java b/taverna-scufl2-api/src/test/java/org/apache/taverna/scufl2/api/common/TestURIToolsBeans.java
new file mode 100644
index 0000000..6f1d90f
--- /dev/null
+++ b/taverna-scufl2-api/src/test/java/org/apache/taverna/scufl2/api/common/TestURIToolsBeans.java
@@ -0,0 +1,328 @@
+package org.apache.taverna.scufl2.api.common;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+
+import static org.junit.Assert.*;
+
+import java.net.URI;
+import java.util.List;
+
+import org.apache.taverna.scufl2.api.ExampleWorkflow;
+import org.apache.taverna.scufl2.api.activity.Activity;
+import org.apache.taverna.scufl2.api.common.Scufl2Tools;
+import org.apache.taverna.scufl2.api.common.URITools;
+import org.apache.taverna.scufl2.api.common.WorkflowBean;
+import org.apache.taverna.scufl2.api.common.Visitor.VisitorWithPath;
+import org.apache.taverna.scufl2.api.configurations.Configuration;
+import org.apache.taverna.scufl2.api.container.WorkflowBundle;
+import org.apache.taverna.scufl2.api.core.BlockingControlLink;
+import org.apache.taverna.scufl2.api.core.ControlLink;
+import org.apache.taverna.scufl2.api.core.DataLink;
+import org.apache.taverna.scufl2.api.core.Processor;
+import org.apache.taverna.scufl2.api.iterationstrategy.CrossProduct;
+import org.apache.taverna.scufl2.api.profiles.ProcessorBinding;
+import org.apache.taverna.scufl2.api.profiles.ProcessorInputPortBinding;
+import org.apache.taverna.scufl2.api.profiles.ProcessorOutputPortBinding;
+import org.junit.Before;
+import org.junit.Test;
+
+
+public class TestURIToolsBeans {
+
+	private static final String BUNDLE_URI = "http://ns.taverna.org.uk/2010/workflowBundle/28f7c554-4f35-401f-b34b-516e9a0ef731/";
+	private static final String HELLOWORLD_URI = BUNDLE_URI
+			+ "workflow/HelloWorld/";
+	private static final String HELLO_URI = HELLOWORLD_URI + "processor/Hello/";
+	private URITools uriTools = new URITools();
+	private Scufl2Tools scufl2Tools = new Scufl2Tools();
+	private WorkflowBundle wfBundle;
+
+	@Before
+	public void makeExampleWorkflow() {
+		wfBundle = new ExampleWorkflow().makeWorkflowBundle();
+	}
+
+	@Test
+	public void uriForActivity() throws Exception {
+		Activity activity = wfBundle.getMainProfile().getActivities()
+				.getByName("HelloScript");
+		URI uri = uriTools.uriForBean(activity);
+		assertEquals(BUNDLE_URI + "profile/tavernaWorkbench/"
+				+ "activity/HelloScript/", uri.toASCIIString());
+	}
+
+	@Test
+	public void uriForActivityInput() throws Exception {
+		Activity activity = wfBundle.getMainProfile().getActivities()
+				.getByName("HelloScript");
+		URI uri = uriTools.uriForBean(activity.getInputPorts().getByName(
+				"personName"));
+		assertEquals(BUNDLE_URI + "profile/tavernaWorkbench/"
+				+ "activity/HelloScript/in/personName", uri.toASCIIString());
+	}
+
+	@Test
+	public void uriForActivityOutput() throws Exception {
+		Activity activity = wfBundle.getMainProfile().getActivities()
+				.getByName("HelloScript");
+		URI uri = uriTools.uriForBean(activity.getOutputPorts().getByName(
+				"hello"));
+		assertEquals(BUNDLE_URI + "profile/tavernaWorkbench/"
+				+ "activity/HelloScript/out/hello", uri.toASCIIString());
+	}
+
+	@Test
+	public void uriForConfig() throws Exception {
+		Configuration config = wfBundle.getMainProfile().getConfigurations()
+				.getByName("Hello");
+		URI uri = uriTools.uriForBean(config);
+		assertEquals(BUNDLE_URI + "profile/tavernaWorkbench/"
+				+ "configuration/Hello/", uri.toASCIIString());
+	}
+
+	@Test
+	public void uriForControlLink() throws Exception {
+        Processor hello = wfBundle.getMainWorkflow().getProcessors()
+				.getByName("Hello");
+		assertNotNull(hello);
+		ControlLink condition = wfBundle.getMainWorkflow().getControlLinks()
+				.iterator().next();
+		assertTrue(condition instanceof BlockingControlLink);
+		URI uri = uriTools.uriForBean(condition);
+
+		assertEquals(
+				HELLOWORLD_URI
+						+ "control?block=processor/Hello/&untilFinished=processor/wait4me/",
+				uri.toASCIIString());
+	}
+
+	@Test
+	public void uriForDatalink() throws Exception {
+		Processor hello = wfBundle.getMainWorkflow().getProcessors()
+				.getByName("Hello");
+		List<DataLink> nameLinks = scufl2Tools.datalinksTo(hello
+				.getInputPorts().getByName("name"));
+		URI uri = uriTools.uriForBean(nameLinks.get(0));
+		assertEquals(HELLOWORLD_URI
+				+ "datalink?from=in/yourName&to=processor/Hello/in/name",
+				uri.toASCIIString());
+	}
+
+	@Test
+	public void uriForDatalinkWithMerge() throws Exception {
+		Processor hello = wfBundle.getMainWorkflow().getProcessors()
+				.getByName("Hello");
+		List<DataLink> greetingLinks = scufl2Tools.datalinksFrom(hello
+				.getOutputPorts().getByName("greeting"));
+		URI uri = uriTools.uriForBean(greetingLinks.get(0));
+		assertEquals(
+				HELLOWORLD_URI
+						+ "datalink?from=processor/Hello/out/greeting&to=out/results&mergePosition=0",
+				uri.toASCIIString());
+	}
+
+	@Test
+	public void uriForIterationStrategyCross() throws Exception {
+		Processor hello = wfBundle.getMainWorkflow().getProcessors()
+				.getByName("Hello");
+		CrossProduct crossProduct = (CrossProduct) hello
+				.getIterationStrategyStack().get(0);
+		URI uri = uriTools.uriForBean(crossProduct.get(0));
+		assertEquals(HELLO_URI + "iterationstrategy/0/0/",
+				uri.toASCIIString());
+	}
+
+	@Test
+	public void uriForIterationStrategyRoot() throws Exception {
+		Processor hello = wfBundle.getMainWorkflow().getProcessors()
+				.getByName("Hello");
+		URI uri = uriTools.uriForBean(hello.getIterationStrategyStack().get(0));
+
+		assertEquals(HELLO_URI + "iterationstrategy/0/",
+				uri.toASCIIString());
+	}
+
+	@Test
+	public void uriForIterationStrategyStack() throws Exception {
+		URI uri = uriTools
+				.uriForBean(wfBundle.getMainWorkflow().getProcessors()
+						.getByName("Hello").getIterationStrategyStack());
+		assertEquals(HELLO_URI +
+
+		"iterationstrategy/", uri.toASCIIString());
+	}
+
+	@Test
+	public void uriForProcessor() throws Exception {
+		URI uri = uriTools.uriForBean(wfBundle.getMainWorkflow()
+				.getProcessors().getByName("Hello"));
+		assertEquals(HELLO_URI, uri.toASCIIString());
+	}
+
+	@Test
+	public void uriForProcessorBinding() throws Exception {
+		ProcessorBinding processorBinding = wfBundle.getMainProfile()
+				.getProcessorBindings().getByName("Hello");
+		URI uri = uriTools.uriForBean(processorBinding);
+		assertEquals(BUNDLE_URI + "profile/tavernaWorkbench/"
+				+ "processorbinding/Hello/", uri.toASCIIString());
+	}
+
+	@Test
+	public void uriForProcessorBindingIn() throws Exception {
+		ProcessorBinding processorBinding = wfBundle.getMainProfile()
+				.getProcessorBindings().getByName("Hello");
+		ProcessorInputPortBinding inputPortBinding = processorBinding
+				.getInputPortBindings().iterator().next();
+		URI uri = uriTools.uriForBean(inputPortBinding);
+		assertEquals(BUNDLE_URI + "profile/tavernaWorkbench/"
+				+ "processorbinding/Hello/in/name" + "", uri.toASCIIString());
+	}
+
+	@Test
+	public void uriForProcessorBindingOut() throws Exception {
+		ProcessorBinding processorBinding = wfBundle.getMainProfile()
+				.getProcessorBindings().getByName("Hello");
+		ProcessorOutputPortBinding outputPortBinding = processorBinding
+				.getOutputPortBindings().iterator().next();
+		URI uri = uriTools.uriForBean(outputPortBinding);
+		assertEquals(BUNDLE_URI + "profile/tavernaWorkbench/"
+				+ "processorbinding/Hello/out/greeting" + "",
+				uri.toASCIIString());
+	}
+
+	@Test
+	public void uriForProcessorInPort() throws Exception {
+		Processor hello = wfBundle.getMainWorkflow().getProcessors()
+				.getByName("Hello");
+		URI uri = uriTools.uriForBean(hello.getInputPorts().getByName("name"));
+		assertEquals(HELLO_URI + "in/name", uri.toASCIIString());
+	}
+
+	@Test
+	public void uriForProcessorOutPort() throws Exception {
+
+		Processor hello = wfBundle.getMainWorkflow().getProcessors()
+				.getByName("Hello");
+		URI uri = uriTools.uriForBean(hello.getOutputPorts().getByName(
+				"greeting"));
+		assertEquals(HELLO_URI + "out/greeting", uri.toASCIIString());
+	}
+
+	@Test
+	public void uriForProfile() throws Exception {
+		URI uri = uriTools.uriForBean(wfBundle.getMainProfile());
+		assertEquals(BUNDLE_URI + "profile/tavernaWorkbench/" + "",
+				uri.toASCIIString());
+	}
+
+	@Test
+	public void uriForWfBundle() throws Exception {
+		URI uri = uriTools.uriForBean(wfBundle);
+		assertEquals(BUNDLE_URI, uri.toASCIIString());
+	}
+
+	@Test
+	public void uriForWorkflow() throws Exception {
+		URI uri = uriTools.uriForBean(wfBundle.getMainWorkflow());
+		assertEquals(HELLOWORLD_URI, uri.toASCIIString());
+	}
+
+	@Test
+	public void uriForWorkflowInPort() throws Exception {
+		URI uri = uriTools.uriForBean(wfBundle.getMainWorkflow()
+				.getInputPorts().getByName("yourName"));
+		assertEquals(HELLOWORLD_URI + "in/yourName", uri.toASCIIString());
+	}
+
+	@Test
+	public void uriForWorkflowOutPort() throws Exception {
+		URI uri = uriTools.uriForBean(wfBundle.getMainWorkflow()
+				.getOutputPorts().getByName("results"));
+		assertEquals(HELLOWORLD_URI + "out/results", uri.toASCIIString());
+	}
+
+	@Test
+	public void uriVisitor() {
+		final StringBuffer paths = new StringBuffer();
+		wfBundle.accept(new VisitorWithPath() {
+			@Override
+			public boolean visit() {
+				WorkflowBean node = getCurrentNode();
+				URI uri;
+				if (getCurrentPath().isEmpty()) {
+					uri = uriTools.uriForBean(node);
+				} else {
+					uri = uriTools.relativeUriForBean(node, getCurrentPath()
+							.peek());
+				}
+				String indent = "";
+				for (int i = 0; i < getCurrentPath().size(); i++) {
+					indent += "  ";
+				}
+				paths.append(indent);
+				paths.append(uri);
+				paths.append("\n");
+				// we won't recurse into Configuration as PropertyResource's
+				// don't have URIs
+				return !(node instanceof Configuration);
+			}
+		});
+		// System.out.println(paths);
+		assertEquals(
+				"http://ns.taverna.org.uk/2010/workflowBundle/28f7c554-4f35-401f-b34b-516e9a0ef731/\n"
+						+ "  workflow/HelloWorld/\n"
+						+ "    in/yourName\n"
+						+ "    out/results\n"
+						+ "    processor/Hello/\n"
+						+ "      in/name\n"
+						+ "      out/greeting\n"
+						+ "      iterationstrategy/\n"
+						+ "        0/\n"
+						+ "          0/\n"
+						+ "    processor/wait4me/\n"
+						+ "      iterationstrategy/\n"
+						+ "        0/\n"
+					    + "    datalink?from=processor/Hello/out/greeting&to=out/results&mergePosition=0\n"
+						+ "    datalink?from=in/yourName&to=processor/Hello/in/name\n"
+						+ "    datalink?from=in/yourName&to=out/results&mergePosition=1\n"
+						+ "    control?block=processor/Hello/&untilFinished=processor/wait4me/\n"
+					    + "    ../../../../workflow/00626652-55ae-4a9e-80d4-c8e9ac84e2ca/\n"
+						+ "  profile/tavernaServer/\n"
+						+ "    activity/HelloScript/\n"
+						+ "      in/personName\n"
+						+ "      out/hello\n"
+						+ "    processorbinding/Hello/\n"
+						+ "      in/name\n"
+						+ "      out/greeting\n"
+						+ "    configuration/Hello/\n"
+						+ "  profile/tavernaWorkbench/\n"
+						+ "    activity/HelloScript/\n"
+						+ "      in/personName\n"
+						+ "      out/hello\n"
+						+ "    processorbinding/Hello/\n"
+						+ "      in/name\n"
+						+ "      out/greeting\n"
+						+ "    configuration/Hello/\n",
+				paths.toString());
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-language/blob/c08405cb/taverna-scufl2-api/src/test/java/org/apache/taverna/scufl2/api/common/TestURIToolsResolve.java
----------------------------------------------------------------------
diff --git a/taverna-scufl2-api/src/test/java/org/apache/taverna/scufl2/api/common/TestURIToolsResolve.java b/taverna-scufl2-api/src/test/java/org/apache/taverna/scufl2/api/common/TestURIToolsResolve.java
new file mode 100644
index 0000000..200ff80
--- /dev/null
+++ b/taverna-scufl2-api/src/test/java/org/apache/taverna/scufl2/api/common/TestURIToolsResolve.java
@@ -0,0 +1,321 @@
+package org.apache.taverna.scufl2.api.common;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertSame;
+
+import java.net.URI;
+import java.util.List;
+
+import org.apache.taverna.scufl2.api.ExampleWorkflow;
+import org.apache.taverna.scufl2.api.activity.Activity;
+import org.apache.taverna.scufl2.api.annotation.Revision;
+import org.apache.taverna.scufl2.api.common.Scufl2Tools;
+import org.apache.taverna.scufl2.api.common.URITools;
+import org.apache.taverna.scufl2.api.configurations.Configuration;
+import org.apache.taverna.scufl2.api.container.WorkflowBundle;
+import org.apache.taverna.scufl2.api.core.BlockingControlLink;
+import org.apache.taverna.scufl2.api.core.DataLink;
+import org.apache.taverna.scufl2.api.core.Processor;
+import org.apache.taverna.scufl2.api.iterationstrategy.CrossProduct;
+import org.apache.taverna.scufl2.api.port.InputProcessorPort;
+import org.apache.taverna.scufl2.api.port.InputWorkflowPort;
+import org.apache.taverna.scufl2.api.port.OutputProcessorPort;
+import org.apache.taverna.scufl2.api.port.OutputWorkflowPort;
+import org.apache.taverna.scufl2.api.profiles.ProcessorBinding;
+import org.apache.taverna.scufl2.api.profiles.ProcessorInputPortBinding;
+import org.apache.taverna.scufl2.api.profiles.ProcessorOutputPortBinding;
+import org.junit.Ignore;
+import org.junit.Test;
+
+
+public class TestURIToolsResolve {
+	private static final URI BUNDLE_URI = URI
+			.create("http://ns.taverna.org.uk/2010/workflowBundle/28f7c554-4f35-401f-b34b-516e9a0ef731/");
+	private static final URI HELLOWORLD_URI = BUNDLE_URI
+			.resolve("workflow/HelloWorld/");
+	private static final URI HELLO_URI = HELLOWORLD_URI
+			.resolve("processor/Hello/");
+	private static final URI PROFILE_URI = BUNDLE_URI
+			.resolve("profile/tavernaWorkbench/");
+	private URITools uriTools = new URITools();
+	private Scufl2Tools scufl2Tools = new Scufl2Tools();
+	private WorkflowBundle wfBundle = new ExampleWorkflow()
+			.makeWorkflowBundle();
+
+	@Test
+	public void resolveActivity() throws Exception {
+		Activity helloScript = wfBundle.getMainProfile().getActivities().getByName("HelloScript");
+		assertSame(helloScript, uriTools.resolveUri(PROFILE_URI.resolve("activity/HelloScript/"), wfBundle));
+	}
+
+	@Test
+	public void resolveActivityInput() throws Exception {
+		Activity helloScript = wfBundle.getMainProfile().getActivities()
+				.getByName("HelloScript");
+
+		assertSame(helloScript.getInputPorts().getByName("personName"),
+				uriTools.resolveUri(PROFILE_URI
+						.resolve("activity/HelloScript/in/personName"),
+						wfBundle));
+	}
+
+	@Test
+	public void resolveActivityOutput() throws Exception {
+		Activity helloScript = wfBundle.getMainProfile().getActivities()
+				.getByName("HelloScript");
+		assertSame(helloScript.getOutputPorts().getByName("hello"),
+				uriTools.resolveUri(
+						PROFILE_URI.resolve("activity/HelloScript/out/hello"),
+						wfBundle));
+	}
+
+	@Test
+	public void resolveBundle() throws Exception {
+		assertSame(wfBundle, uriTools.resolveUri(BUNDLE_URI, wfBundle));
+	}
+
+
+	@Test
+	public void resolveConfiguration() throws Exception {
+		Configuration config = wfBundle.getMainProfile().getConfigurations().getByName("Hello");
+
+		assertSame(config,
+				uriTools.resolveUri(
+						PROFILE_URI.resolve("configuration/Hello/"),
+						wfBundle));
+	}
+
+	@Test
+	public void resolveControlLink() throws Exception {
+		Processor hello = wfBundle.getMainWorkflow().getProcessors()
+				.getByName("Hello");
+		List<BlockingControlLink> blocks = scufl2Tools
+				.controlLinksBlocking(hello);
+		assertSame(
+				blocks.get(0),
+				uriTools.resolveUri(
+						HELLOWORLD_URI
+								.resolve("control?block=processor/Hello/&untilFinished=processor/wait4me/"),
+						wfBundle));
+	}
+
+	@Test
+	public void resolveDataLink() throws Exception {
+		Processor hello = wfBundle.getMainWorkflow().getProcessors()
+				.getByName("Hello");
+		List<DataLink> datalinks = scufl2Tools.datalinksTo(hello
+				.getInputPorts().getByName("name"));
+		assertSame(
+				datalinks.get(0),
+				uriTools.resolveUri(
+						HELLOWORLD_URI
+								.resolve("datalink?from=in/yourName&to=processor/Hello/in/name"),
+						wfBundle));
+	}
+
+	@Test
+	public void resolveDataLinkWithMerge() throws Exception {
+		Processor hello = wfBundle.getMainWorkflow().getProcessors()
+				.getByName("Hello");
+		OutputProcessorPort greeting = hello.getOutputPorts().getByName(
+				"greeting");
+		List<DataLink> datalinks = scufl2Tools.datalinksFrom(greeting);
+		assertSame(
+				datalinks.get(0),
+				uriTools.resolveUri(
+						HELLOWORLD_URI
+								.resolve("datalink?from=processor/Hello/out/greeting&to=out/results&mergePosition=0"),
+						wfBundle));
+	}
+
+	@Test
+	public void resolveNonAbsolute() throws Exception {
+		InputWorkflowPort yourName = wfBundle.getMainWorkflow().getInputPorts()
+				.getByName("yourName");
+		assertSame(yourName, uriTools.resolveUri(
+				URI.create("/workflow/HelloWorld/in/yourName"), wfBundle));
+	}
+
+	@Test
+	public void resolveProcessor() throws Exception {
+		Processor hello = wfBundle.getMainWorkflow().getProcessors()
+				.getByName("Hello");
+		assertSame(hello, uriTools.resolveUri(HELLO_URI, wfBundle));
+	}
+
+	@Test
+	public void resolveProcessorBinding() throws Exception {
+		ProcessorBinding procBind = wfBundle.getMainProfile().getProcessorBindings()
+				.getByName("Hello");
+		assertSame(procBind,
+				uriTools.resolveUri(
+						PROFILE_URI.resolve("processorbinding/Hello/"),
+						wfBundle));
+	}
+
+	@Test
+	public void resolveProcessorBindingIn() throws Exception {
+		Processor hello = wfBundle.getMainWorkflow().getProcessors()
+				.getByName("Hello");
+		ProcessorInputPortBinding binding = scufl2Tools
+				.processorPortBindingForPort(
+						hello.getInputPorts().getByName("name"),
+						wfBundle.getMainProfile());
+		assertSame(binding,
+				uriTools.resolveUri(
+						PROFILE_URI.resolve("processorbinding/Hello/in/name"),
+						wfBundle));
+	}
+
+	@Test
+	public void resolveProcessorBindingOut() throws Exception {
+		Processor hello = wfBundle.getMainWorkflow().getProcessors()
+		.getByName("Hello");
+		ProcessorOutputPortBinding binding = scufl2Tools
+				.processorPortBindingForPort(
+						hello.getOutputPorts().getByName("greeting"),
+						wfBundle.getMainProfile());
+		assertSame(binding,
+				uriTools.resolveUri(
+						PROFILE_URI.resolve("processorbinding/Hello/out/greeting"),
+						wfBundle));
+	}
+
+	@Test
+	public void resolveProcessorInput() throws Exception {
+		Processor hello = wfBundle.getMainWorkflow().getProcessors()
+				.getByName("Hello");
+		InputProcessorPort helloName = hello.getInputPorts().getByName("name");
+		assertSame(helloName,
+				uriTools.resolveUri(HELLO_URI.resolve("in/name"), wfBundle));
+	}
+
+	@Test
+	public void resolveProcessorIterationStrategy() throws Exception {
+		Processor hello = wfBundle.getMainWorkflow().getProcessors()
+				.getByName("Hello");
+		assertSame(hello.getIterationStrategyStack().get(0),
+				uriTools.resolveUri(
+HELLO_URI.resolve("iterationstrategy/0/"),
+						wfBundle));
+	}
+
+	@Test
+	public void resolveProcessorIterationStrategyNode() throws Exception {
+		Processor hello = wfBundle.getMainWorkflow().getProcessors()
+				.getByName("Hello");
+		CrossProduct rootStrategyNode = (CrossProduct) hello
+				.getIterationStrategyStack().get(0);
+		assertSame(rootStrategyNode.get(0),
+				uriTools.resolveUri(
+				HELLO_URI.resolve("iterationstrategy/0/0/"),
+						wfBundle));
+	}
+
+	@Test
+	public void resolveProcessorIterationStrategyRoot() throws Exception {
+		Processor hello = wfBundle.getMainWorkflow().getProcessors()
+				.getByName("Hello");
+		assertSame(hello.getIterationStrategyStack().get(0),
+				uriTools.resolveUri(HELLO_URI.resolve("iterationstrategy/0/"),
+						wfBundle));
+	}
+
+	@Test
+	public void resolveProcessorIterationStrategyStack() throws Exception {
+		Processor hello = wfBundle.getMainWorkflow().getProcessors()
+				.getByName("Hello");
+		assertSame(
+				hello.getIterationStrategyStack(),
+				uriTools.resolveUri(
+				HELLO_URI.resolve("iterationstrategy/"), wfBundle));
+	}
+
+	@Test
+	public void resolveProcessorOutput() throws Exception {
+		Processor hello = wfBundle.getMainWorkflow().getProcessors()
+				.getByName("Hello");
+		OutputProcessorPort greeting = hello.getOutputPorts().getByName(
+				"greeting");
+		assertSame(greeting, uriTools.resolveUri(
+				HELLO_URI.resolve("out/greeting"), wfBundle));
+	}
+
+	@Test
+	public void resolveProfile() throws Exception {
+		assertSame(wfBundle.getMainProfile(), uriTools.resolveUri(PROFILE_URI, wfBundle));
+	}
+
+	@Test
+	public void resolveRelative() throws Exception {
+		InputWorkflowPort yourName = wfBundle.getMainWorkflow().getInputPorts()
+				.getByName("yourName");
+		assertSame(yourName, uriTools.resolveUri(
+				URI.create("workflow/HelloWorld/in/yourName"), wfBundle));
+	}
+
+	@Test
+	public void resolveWorkflow() throws Exception {
+		assertSame(wfBundle.getMainWorkflow(),
+				uriTools.resolveUri(HELLOWORLD_URI, wfBundle));
+	}
+
+	@Test
+	public void resolveWorkflowInput() throws Exception {
+		InputWorkflowPort yourName = wfBundle.getMainWorkflow().getInputPorts()
+				.getByName("yourName");
+		assertSame(yourName, uriTools.resolveUri(
+				HELLOWORLD_URI.resolve("in/yourName"), wfBundle));
+	}
+
+	@Test
+	public void resolveWorkflowOutput() throws Exception {
+		OutputWorkflowPort results = wfBundle.getMainWorkflow()
+				.getOutputPorts().getByName("results");
+		assertSame(results, uriTools.resolveUri(
+				HELLOWORLD_URI.resolve("out/results"), wfBundle));
+	}
+	
+	@Test
+	public void revisionURIs() {
+		Revision r1 = wfBundle.newRevision();
+		assertEquals(r1.getIdentifier(), uriTools.uriForBean(r1));
+		
+//		assertEquals(r1, uriTools.resolveUri(r3.getIdentifier(), wfBundle));
+			
+	}
+
+	@Ignore
+	@Test
+	public void resolveRevisions() {
+		Revision r1 = wfBundle.newRevision();
+		Revision r2 = wfBundle.newRevision();
+		Revision r3 = wfBundle.newRevision();
+		assertEquals(wfBundle, uriTools.resolveUri(r3.getIdentifier(), wfBundle));
+		assertEquals(r2, uriTools.resolveUri(r2.getIdentifier(), wfBundle));
+		assertEquals(r1, uriTools.resolveUri(r1.getIdentifier(), wfBundle));	
+	}
+
+	
+}
+

http://git-wip-us.apache.org/repos/asf/incubator-taverna-language/blob/c08405cb/taverna-scufl2-api/src/test/java/org/apache/taverna/scufl2/api/configurations/ConfigurationTest.java
----------------------------------------------------------------------
diff --git a/taverna-scufl2-api/src/test/java/org/apache/taverna/scufl2/api/configurations/ConfigurationTest.java b/taverna-scufl2-api/src/test/java/org/apache/taverna/scufl2/api/configurations/ConfigurationTest.java
new file mode 100644
index 0000000..c3668f0
--- /dev/null
+++ b/taverna-scufl2-api/src/test/java/org/apache/taverna/scufl2/api/configurations/ConfigurationTest.java
@@ -0,0 +1,78 @@
+package org.apache.taverna.scufl2.api.configurations;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+
+import static org.junit.Assert.*;
+
+import org.apache.taverna.scufl2.api.ExampleWorkflow;
+import org.apache.taverna.scufl2.api.common.Scufl2Tools;
+import org.apache.taverna.scufl2.api.configurations.Configuration;
+import org.apache.taverna.scufl2.api.container.WorkflowBundle;
+import org.apache.taverna.scufl2.api.core.DataLinkCompareTest;
+import org.apache.taverna.scufl2.api.profiles.Profile;
+import org.junit.Before;
+import org.junit.Test;
+
+
+public class ConfigurationTest extends ExampleWorkflow {
+	
+	@Before
+	public void makeBundle() {
+		makeWorkflowBundle();
+	}
+	
+	/**
+	 * Similar bug to {@link DataLinkCompareTest#dataLinkNotAddedTwice()}
+	 */
+	@Test
+	public void configurationNotAddedTwice() throws Exception {
+		Configuration c1a = new Configuration("c1");
+		Profile p1 = new Profile("p1");
+		p1.getConfigurations().add(c1a);		
+		c1a.setParent(p1);
+		p1.getConfigurations().add(c1a);
+		
+		
+		Configuration c1b = new Configuration("c1");
+		Profile p2 = new Profile("p2");
+		p2.getConfigurations().add(c1b);		
+		c1b.setParent(p2);
+		p2.getConfigurations().add(c1b);
+		
+		
+		WorkflowBundle bundle = new WorkflowBundle();
+		p1.setParent(bundle);
+		p2.setParent(bundle);
+		new Scufl2Tools().setParents(bundle);
+		assertEquals(1, p1.getConfigurations().size());
+		assertEquals(1, p2.getConfigurations().size());
+		
+	}
+	
+	@Test
+	public void configurationNotAddedTwiceExample() throws Exception {
+		Profile p = workflowBundle.getMainProfile();
+		assertEquals(1, p.getConfigurations().size());
+		new Scufl2Tools().setParents(workflowBundle);
+		assertEquals(1, p.getConfigurations().size());
+	}
+	
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-language/blob/c08405cb/taverna-scufl2-api/src/test/java/org/apache/taverna/scufl2/api/container/TestWorkflowBundleEquals.java
----------------------------------------------------------------------
diff --git a/taverna-scufl2-api/src/test/java/org/apache/taverna/scufl2/api/container/TestWorkflowBundleEquals.java b/taverna-scufl2-api/src/test/java/org/apache/taverna/scufl2/api/container/TestWorkflowBundleEquals.java
new file mode 100644
index 0000000..3ba16fc
--- /dev/null
+++ b/taverna-scufl2-api/src/test/java/org/apache/taverna/scufl2/api/container/TestWorkflowBundleEquals.java
@@ -0,0 +1,82 @@
+package org.apache.taverna.scufl2.api.container;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+
+import static org.junit.Assert.*;
+
+import java.net.URI;
+
+import org.apache.taverna.scufl2.api.container.WorkflowBundle;
+import org.apache.taverna.scufl2.api.core.Workflow;
+import org.junit.Test;
+
+
+public class TestWorkflowBundleEquals {
+	
+	@Test
+	public void notEquals() throws Exception {
+		WorkflowBundle wb1 = new WorkflowBundle();
+		
+		WorkflowBundle wb2 = new WorkflowBundle();
+		// Make them look "equal"
+		wb1.setName("bob");
+		wb2.setName("bob");
+		wb1.setGlobalBaseURI(URI.create("http://example.com/bob"));
+		wb2.setGlobalBaseURI(URI.create("http://example.com/bob"));		
+		assertFalse(wb1.equals(wb2));
+	}
+	
+	@Test
+	public void equals() throws Exception {
+		WorkflowBundle wb1 = new WorkflowBundle();	
+		assertTrue(wb1.equals(wb1));		
+	}
+	
+	@Test 
+	public void workflowsNotEqualsUnlessOrphans() {
+		Workflow wf1 = new Workflow();
+		Workflow wf2 = new Workflow();
+		wf1.setName("fred");
+		wf2.setName("fred");
+		// No parents, so they are equal
+		assertEquals(wf1, wf2);
+		
+		
+		WorkflowBundle wb1 = new WorkflowBundle();
+		
+		WorkflowBundle wb2 = new WorkflowBundle();
+		// Make them look "equal"
+		wb2.setName(wb1.getName());
+		wb2.setGlobalBaseURI(wb1.getGlobalBaseURI());
+		assertFalse(wb1.equals(wb2));
+		
+		wf1.setParent(wb1);
+		wf2.setParent(wb2);		
+		assertFalse(wf1.equals(wf2));
+		
+		wf1.setParent(null);
+		assertFalse(wf1.equals(wf2));
+		assertFalse(wf2.equals(wf1));
+		wf2.setParent(null);
+		assertTrue(wf1.equals(wf2));	
+	}
+	
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-language/blob/c08405cb/taverna-scufl2-api/src/test/java/org/apache/taverna/scufl2/api/core/ControlLinkCompareTest.java
----------------------------------------------------------------------
diff --git a/taverna-scufl2-api/src/test/java/org/apache/taverna/scufl2/api/core/ControlLinkCompareTest.java b/taverna-scufl2-api/src/test/java/org/apache/taverna/scufl2/api/core/ControlLinkCompareTest.java
new file mode 100644
index 0000000..f38f251
--- /dev/null
+++ b/taverna-scufl2-api/src/test/java/org/apache/taverna/scufl2/api/core/ControlLinkCompareTest.java
@@ -0,0 +1,104 @@
+package org.apache.taverna.scufl2.api.core;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+
+import static org.junit.Assert.*;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+
+import org.apache.taverna.scufl2.api.core.BlockingControlLink;
+import org.apache.taverna.scufl2.api.core.ControlLink;
+import org.apache.taverna.scufl2.api.core.Processor;
+import org.apache.taverna.scufl2.api.core.Workflow;
+import org.junit.Test;
+
+public class ControlLinkCompareTest {
+	@SuppressWarnings("unchecked")
+	@Test
+	public void expectedOrder() throws Exception {
+
+		Workflow wf = new Workflow();		
+		wf.setName("wf");
+		
+		Processor a = new Processor(wf, "a");
+		Processor b = new Processor(wf, "b");
+		Processor c = new Processor(wf, "c");
+		Processor d = new Processor(wf, "d");
+
+		BlockingControlLink b_blocks_c = new BlockingControlLink(c, b);
+		BlockingControlLink a_blocks_c = new BlockingControlLink(c, a);
+		BlockingControlLink a_blocks_b = new BlockingControlLink(b, a);
+		BlockingControlLink b_blocks_d = new BlockingControlLink(d, b);
+		BlockingControlLink a_blocks_d = new BlockingControlLink(d, a);
+		
+		ArrayList<ControlLink> links = new ArrayList<ControlLink>(wf.getControlLinks());
+		assertEquals(Arrays.asList(a_blocks_b, a_blocks_c, a_blocks_d, b_blocks_c, b_blocks_d), links);
+		Collections.shuffle(links);
+		Collections.sort(links);
+		assertEquals(Arrays.asList(a_blocks_b, a_blocks_c, a_blocks_d, b_blocks_c, b_blocks_d), links);
+	}
+
+	@SuppressWarnings("unchecked")
+	@Test
+	public void nullSupport() throws Exception {
+		Workflow wf = new Workflow();		
+		wf.setName("wf");
+		
+		
+		
+		Processor a = new Processor(wf, "a");
+		Processor b = new Processor(wf, "b");
+		Processor c = new Processor(wf, "c");
+		Processor d = new Processor(wf, "d");
+
+		BlockingControlLink b_blocks_c = new BlockingControlLink(c, b);
+		BlockingControlLink null_blocks_c = new BlockingControlLink();
+		null_blocks_c.setBlock(c);
+		null_blocks_c.setParent(wf);
+		BlockingControlLink a_blocks_b = new BlockingControlLink(b, a);
+		BlockingControlLink b_blocks_null = new BlockingControlLink();
+		b_blocks_null.setUntilFinished(b);
+		b_blocks_null.setParent(wf);
+		
+		BlockingControlLink null_blocks_null = new BlockingControlLink();		
+		null_blocks_null.setParent(wf);
+		
+		
+		ArrayList<ControlLink> links = new ArrayList<ControlLink>(wf.getControlLinks());
+		assertEquals(Arrays.asList(null_blocks_null, null_blocks_c, a_blocks_b, b_blocks_null, b_blocks_c), links);				
+
+		Collections.shuffle(links);		
+		Collections.sort(links);
+		
+		BlockingControlLink a_blocks_d_no_parent = new BlockingControlLink();
+		a_blocks_d_no_parent.setBlock(d);
+		a_blocks_d_no_parent.setUntilFinished(a);
+		// no setParent
+		links.add(a_blocks_d_no_parent);
+		Collections.shuffle(links);		
+		Collections.sort(links);
+		
+		assertEquals(Arrays.asList(null_blocks_null, null_blocks_c, a_blocks_b, a_blocks_d_no_parent, b_blocks_null, b_blocks_c), links);		
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-language/blob/c08405cb/taverna-scufl2-api/src/test/java/org/apache/taverna/scufl2/api/core/DataLinkCompareTest.java
----------------------------------------------------------------------
diff --git a/taverna-scufl2-api/src/test/java/org/apache/taverna/scufl2/api/core/DataLinkCompareTest.java b/taverna-scufl2-api/src/test/java/org/apache/taverna/scufl2/api/core/DataLinkCompareTest.java
new file mode 100644
index 0000000..79a68bf
--- /dev/null
+++ b/taverna-scufl2-api/src/test/java/org/apache/taverna/scufl2/api/core/DataLinkCompareTest.java
@@ -0,0 +1,128 @@
+package org.apache.taverna.scufl2.api.core;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+
+import org.apache.taverna.scufl2.api.ExampleWorkflow;
+import org.apache.taverna.scufl2.api.core.DataLink;
+import org.apache.taverna.scufl2.api.core.Workflow;
+import org.apache.taverna.scufl2.api.port.InputWorkflowPort;
+import org.apache.taverna.scufl2.api.port.OutputWorkflowPort;
+import org.junit.Before;
+import org.junit.Test;
+
+
+public class DataLinkCompareTest extends ExampleWorkflow {
+	
+	@Before
+	public void makeBundle() throws Exception {
+		makeWorkflowBundle();
+	}
+
+	
+	@SuppressWarnings({ "unchecked", "unused" })
+	@Test
+	public void expectedOrder() throws Exception {
+
+		Workflow wf = new Workflow();
+		wf.setName("wf");
+		InputWorkflowPort a = new InputWorkflowPort(wf, "a");
+		InputWorkflowPort b = new InputWorkflowPort(wf, "b");
+		InputWorkflowPort c = new InputWorkflowPort(wf, "c");
+
+		OutputWorkflowPort x = new OutputWorkflowPort(wf, "x");
+		OutputWorkflowPort y = new OutputWorkflowPort(wf, "y");
+		OutputWorkflowPort z = new OutputWorkflowPort(wf, "z");
+
+		DataLink c_x = new DataLink(wf, c, x);
+		DataLink b_x = new DataLink(wf, b, x);
+		DataLink b_z = new DataLink(wf, b, z);
+		DataLink a_z = new DataLink(wf, a, z);
+		DataLink a_x = new DataLink(wf, a, x);
+
+		ArrayList<DataLink> links = new ArrayList<DataLink>(wf.getDataLinks());
+		assertEquals(Arrays.asList(a_x, a_z, b_x, b_z, c_x), links);
+		Collections.shuffle(links);
+		Collections.sort(links);
+		assertEquals(Arrays.asList(a_x, a_z, b_x, b_z, c_x), links);
+	}
+
+	@SuppressWarnings({ "unchecked", "unused" })
+	@Test
+	public void nullSupport() throws Exception {
+
+		Workflow wf = new Workflow();
+		wf.setName("wf");
+		InputWorkflowPort a = new InputWorkflowPort(wf, "a");
+		InputWorkflowPort b = new InputWorkflowPort(wf, "b");
+		InputWorkflowPort c = new InputWorkflowPort(wf, "c");
+
+		OutputWorkflowPort x = new OutputWorkflowPort(wf, "x");
+		OutputWorkflowPort y = new OutputWorkflowPort(wf, "y");
+		OutputWorkflowPort z = new OutputWorkflowPort(wf, "z");
+
+		DataLink null_null = new DataLink();
+		null_null.setParent(wf);
+		// neither receivesFrom nor sendsTo
+
+		DataLink null_z = new DataLink();
+		// no receivesFrom
+		null_z.setSendsTo(z);
+		null_z.setParent(wf);
+		DataLink a_z = new DataLink(wf, a, z);
+		DataLink a_null = new DataLink();
+		// no sendsTo
+		a_null.setReceivesFrom(a);
+		a_null.setParent(wf);
+
+		ArrayList<DataLink> links = new ArrayList<DataLink>(wf.getDataLinks());
+		assertEquals(Arrays.asList(null_null, null_z, a_null, a_z), links);
+
+		DataLink allNull = new DataLink();
+		links.add(allNull);
+
+		Collections.shuffle(links);
+		Collections.sort(links);
+		assertEquals(Arrays.asList(allNull, null_null, null_z, a_null, a_z),
+				links);
+	}
+
+	@Test
+	public void dataLinkNotAddedTwice() throws Exception {
+		assertEquals(3, workflow.getDataLinks().size());
+		DataLink dl1 = workflow.getDataLinks().iterator().next();
+		assertTrue(workflow.getDataLinks().contains(dl1));
+		workflow.getDataLinks().add(dl1);
+		dl1.setParent(workflow);
+		// This could happen because dataLink.compareTo() calls
+		// .compareTo() on the sender/receiver link, and if 
+		// their parents was null at insertion and non-null
+		// later, the TreeSet order got messed up.
+		assertEquals(3, workflow.getDataLinks().size());
+	}
+	
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-language/blob/c08405cb/taverna-scufl2-api/src/test/java/org/apache/taverna/scufl2/api/core/PortOrderTest.java
----------------------------------------------------------------------
diff --git a/taverna-scufl2-api/src/test/java/org/apache/taverna/scufl2/api/core/PortOrderTest.java b/taverna-scufl2-api/src/test/java/org/apache/taverna/scufl2/api/core/PortOrderTest.java
new file mode 100644
index 0000000..0211b42
--- /dev/null
+++ b/taverna-scufl2-api/src/test/java/org/apache/taverna/scufl2/api/core/PortOrderTest.java
@@ -0,0 +1,84 @@
+package org.apache.taverna.scufl2.api.core;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.taverna.scufl2.api.common.Named;
+import org.apache.taverna.scufl2.api.core.Workflow;
+import org.apache.taverna.scufl2.api.port.InputWorkflowPort;
+import org.apache.taverna.scufl2.api.port.OutputWorkflowPort;
+import org.apache.taverna.scufl2.api.port.Port;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+@SuppressWarnings("unchecked")
+public class PortOrderTest {
+	List<Port> ports = new ArrayList<Port>();
+	
+	Workflow wf = new Workflow();
+
+	@Test
+	public void orderedByName() throws Exception {
+		ports.add(new InputWorkflowPort(wf, "p3"));
+		ports.add(new InputWorkflowPort(wf, "p1"));
+		ports.add(new InputWorkflowPort(wf, "p2"));
+		Collections.sort(ports);
+		assertNamesEqual(ports, "p1", "p2", "p3");
+	}
+	
+	@Test
+	public void ignoringNull() throws Exception {
+		ports.add(new InputWorkflowPort(null, "p3"));
+		ports.add(new InputWorkflowPort(null, "p1"));
+		ports.add(new InputWorkflowPort(wf, "p2"));
+		Collections.sort(ports);
+		assertNamesEqual(ports, "p1", "p2", "p3");
+	}
+	
+	@Test
+	public void orderedByClassName() throws Exception {
+		ports.add(new InputWorkflowPort(wf, "p3"));
+		ports.add(new OutputWorkflowPort(wf, "p1"));
+		ports.add(new InputWorkflowPort(wf, "p2"));
+		Collections.sort(ports);
+		assertNamesEqual(ports, "p2", "p3", "p1");
+	}
+
+
+	public static void assertNamesEqual(List<? extends Named> named, String... expectedNames) {
+		List<String> names = namesOf(named);	
+		assertEquals(Arrays.asList(expectedNames), names);		
+	}
+
+	public static List<String> namesOf(List<? extends Named> named) {
+		List<String> names = new ArrayList<String>();
+		for (Named n : named) {
+			names.add(n.getName());
+		}
+		return names;
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-language/blob/c08405cb/taverna-scufl2-api/src/test/java/org/apache/taverna/scufl2/api/impl/TestIterableComparator.java
----------------------------------------------------------------------
diff --git a/taverna-scufl2-api/src/test/java/org/apache/taverna/scufl2/api/impl/TestIterableComparator.java b/taverna-scufl2-api/src/test/java/org/apache/taverna/scufl2/api/impl/TestIterableComparator.java
new file mode 100644
index 0000000..bbb8528
--- /dev/null
+++ b/taverna-scufl2-api/src/test/java/org/apache/taverna/scufl2/api/impl/TestIterableComparator.java
@@ -0,0 +1,95 @@
+package org.apache.taverna.scufl2.api.impl;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+
+import static org.junit.Assert.*;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.taverna.scufl2.api.impl.IterableComparator;
+import org.junit.Test;
+
+public class TestIterableComparator {
+	@SuppressWarnings("serial")
+	public class ReverseComparableList extends ArrayList<String> implements Comparable<ReverseComparableList> {
+		public boolean called = false;
+		public ReverseComparableList(String... items) {
+			addAll(Arrays.asList(items));
+		}
+
+		@Override
+		public int compareTo(ReverseComparableList o) {
+			called = true;
+			// Reverse string order
+			return o.toString().compareTo(this.toString());
+		}
+	}
+
+	@Test
+	public void listCompare() throws Exception {
+		List<List<String>> values = Arrays.asList(Arrays.asList("x", "y"),
+				Arrays.asList("a", "b", "c", "d", "e"),
+				Arrays.asList("a", "b", "c", "d"),
+				Arrays.asList("a", "b", null, "d"));
+
+		List<List<String>> sortedValues = Arrays.asList(
+				Arrays.asList("a", "b", null, "d"), // null < c
+				Arrays.asList("a", "b", "c", "d"), // shorter list (but matching
+													// prefix)
+				Arrays.asList("a", "b", "c", "d", "e"), Arrays.asList("x", "y") // "x"
+																				// >
+																				// "a"
+				);
+
+		Collections.sort(values, new IterableComparator());
+		assertEquals(sortedValues, values);
+	}
+
+	@Test
+	public void nestedListCompare() throws Exception {
+		List<List<List<String>>> values = Arrays.asList(
+				Arrays.asList(Arrays.asList("x", "y", "z"),
+						Arrays.asList("1", "2", "3"), Arrays.asList("extra")),
+				Arrays.asList(Arrays.asList("x", "y", "z"),
+						Arrays.asList("1", "2", "3")));
+
+		List<List<List<String>>> sortedValues = Arrays.asList(
+				Arrays.asList(Arrays.asList("x", "y", "z"),
+						Arrays.asList("1", "2", "3")),
+				Arrays.asList(Arrays.asList("x", "y", "z"),
+						Arrays.asList("1", "2", "3"), Arrays.asList("extra")));
+
+		Collections.sort(values, new IterableComparator());
+		assertEquals(sortedValues, values);
+	}
+
+	@SuppressWarnings({ "rawtypes", "unchecked" })
+	@Test(expected = ClassCastException.class)
+	public void intsAndStrings() throws Exception {
+		List<Integer> intList = Arrays.asList(1, 2, 3);
+		List<String> strList = Arrays.asList("x", "y");
+		List values = Arrays.asList(intList, strList);
+		Collections.sort(values, new IterableComparator());
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-language/blob/c08405cb/taverna-scufl2-api/src/test/java/org/apache/taverna/scufl2/api/impl/TestNullCompare.java
----------------------------------------------------------------------
diff --git a/taverna-scufl2-api/src/test/java/org/apache/taverna/scufl2/api/impl/TestNullCompare.java b/taverna-scufl2-api/src/test/java/org/apache/taverna/scufl2/api/impl/TestNullCompare.java
new file mode 100644
index 0000000..e25b559
--- /dev/null
+++ b/taverna-scufl2-api/src/test/java/org/apache/taverna/scufl2/api/impl/TestNullCompare.java
@@ -0,0 +1,39 @@
+package org.apache.taverna.scufl2.api.impl;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.taverna.scufl2.api.impl.NullSafeComparator;
+import org.junit.Test;
+
+public class TestNullCompare {
+	@Test
+	public void testNullCompare() throws Exception {
+		List<String> values = Arrays.asList("c", null, "b", null, "a", "c");
+		Collections.sort(values, new NullSafeComparator<String>());
+		assertEquals(Arrays.asList(null, null, "a", "b", "c", "c"), values);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-language/blob/c08405cb/taverna-scufl2-api/src/test/java/org/apache/taverna/scufl2/api/io/TestResources.java
----------------------------------------------------------------------
diff --git a/taverna-scufl2-api/src/test/java/org/apache/taverna/scufl2/api/io/TestResources.java b/taverna-scufl2-api/src/test/java/org/apache/taverna/scufl2/api/io/TestResources.java
new file mode 100644
index 0000000..2073430
--- /dev/null
+++ b/taverna-scufl2-api/src/test/java/org/apache/taverna/scufl2/api/io/TestResources.java
@@ -0,0 +1,54 @@
+package org.apache.taverna.scufl2.api.io;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+
+import static org.junit.Assert.assertTrue;
+
+import org.apache.taverna.scufl2.api.ExampleWorkflow;
+import org.apache.taverna.scufl2.api.container.WorkflowBundle;
+import org.apache.taverna.scufl2.ucfpackage.UCFPackage;
+import org.junit.Before;
+import org.junit.Test;
+
+
+public class TestResources {
+
+	private WorkflowBundle wb;
+	ExampleWorkflow exampleWorkflow = new ExampleWorkflow();
+
+	@Test
+	public void emptyResources() throws Exception {
+		UCFPackage resources = wb.getResources();
+		assertTrue(resources.listResources().isEmpty());
+	}
+
+	@Before
+	public void makeBundle() {
+		wb = exampleWorkflow.makeWorkflowBundle();
+	}
+
+	@Test
+	public void singleFile() throws Exception {
+		UCFPackage resources = wb.getResources();
+		resources.addResource("Hello there", "hello.txt", "text/plain");
+		assertTrue(resources.listResources().containsKey("hello.txt"));
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-language/blob/c08405cb/taverna-scufl2-api/src/test/java/org/apache/taverna/scufl2/api/io/TestStructureReader.java
----------------------------------------------------------------------
diff --git a/taverna-scufl2-api/src/test/java/org/apache/taverna/scufl2/api/io/TestStructureReader.java b/taverna-scufl2-api/src/test/java/org/apache/taverna/scufl2/api/io/TestStructureReader.java
new file mode 100644
index 0000000..ae0c91f
--- /dev/null
+++ b/taverna-scufl2-api/src/test/java/org/apache/taverna/scufl2/api/io/TestStructureReader.java
@@ -0,0 +1,99 @@
+package org.apache.taverna.scufl2.api.io;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+
+import static org.apache.taverna.scufl2.api.io.structure.StructureReader.TEXT_VND_TAVERNA_SCUFL2_STRUCTURE;
+import static org.junit.Assert.assertEquals;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.io.output.ByteArrayOutputStream;
+import org.apache.taverna.scufl2.api.common.Scufl2Tools;
+import org.apache.taverna.scufl2.api.configurations.Configuration;
+import org.apache.taverna.scufl2.api.container.WorkflowBundle;
+import org.apache.taverna.scufl2.api.io.WorkflowBundleIO;
+import org.junit.Test;
+
+
+public class TestStructureReader {
+
+	private static final String UTF_8 = "utf-8";
+	protected WorkflowBundleIO bundleIO = new WorkflowBundleIO();
+	
+	public String getStructureFormatWorkflowBundle() throws IOException {
+		InputStream helloWorldStream = getClass().getResourceAsStream(
+				"HelloWorld.txt");
+		return IOUtils.toString(helloWorldStream);
+	}
+	
+	@Test
+	public void configurationReadTwice() throws Exception {
+		InputStream inputStream = new ByteArrayInputStream(
+				getStructureFormatWorkflowBundle().getBytes("utf-8"));
+		WorkflowBundle readBundle = bundleIO.readBundle(inputStream,
+				TEXT_VND_TAVERNA_SCUFL2_STRUCTURE);
+		assertEquals(1, readBundle.getMainProfile().getConfigurations().size());
+		new Scufl2Tools().setParents(readBundle);
+		assertEquals(1, readBundle.getMainProfile().getConfigurations().size());
+		ByteArrayOutputStream output = new ByteArrayOutputStream();
+		bundleIO.writeBundle(readBundle, output, TEXT_VND_TAVERNA_SCUFL2_STRUCTURE);
+		assertEquals(1, readBundle.getMainProfile().getConfigurations().size());
+		String bundleTxt = new String(output.toByteArray(), UTF_8);
+                String getStructureFormatWorkflowBundle = getStructureFormatWorkflowBundle();
+                bundleTxt = bundleTxt.replaceAll("\r", "").replaceAll("\n", "");
+                getStructureFormatWorkflowBundle = getStructureFormatWorkflowBundle.replaceAll("\r", "").replaceAll("\n", "");
+		assertEquals(getStructureFormatWorkflowBundle, bundleTxt);
+		
+	}
+	
+	@Test
+    public void multiLineJson() throws Exception {
+	    String struct = getStructureFormatWorkflowBundle();
+	    // Make JSON multi-line by adding some whitespace
+	    struct = struct.replace("{", "{\n         ");
+	    struct = struct.replace("\":\"", "\":\n             \"");
+	    struct = struct.replace("}", "\n        }\n");
+	    // EG: 
+//       {
+//        "script":
+//            "hello = \"Hello, \" + personName;\nJOptionPane.showMessageDialog(null, hello);"
+//       }
+	    
+//	    System.out.println(struct);
+	    
+	    InputStream inputStream = new ByteArrayInputStream(
+	            struct.getBytes("utf-8"));
+        WorkflowBundle readBundle = bundleIO.readBundle(inputStream,
+                TEXT_VND_TAVERNA_SCUFL2_STRUCTURE);
+        assertEquals(1, readBundle.getMainProfile().getConfigurations().size());
+        
+        Configuration config = readBundle.getMainProfile().getConfigurations().getByName("Hello");
+        String script = config.getJson().get("script").asText();
+        String expected = "hello = \"Hello, \" + personName;\n"
+                + "JOptionPane.showMessageDialog(null, hello);";
+        assertEquals(expected, script);        
+    }
+
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-language/blob/c08405cb/taverna-scufl2-api/src/test/java/org/apache/taverna/scufl2/api/io/TestWorkflowBundleIO.java
----------------------------------------------------------------------
diff --git a/taverna-scufl2-api/src/test/java/org/apache/taverna/scufl2/api/io/TestWorkflowBundleIO.java b/taverna-scufl2-api/src/test/java/org/apache/taverna/scufl2/api/io/TestWorkflowBundleIO.java
new file mode 100644
index 0000000..e1d25d6
--- /dev/null
+++ b/taverna-scufl2-api/src/test/java/org/apache/taverna/scufl2/api/io/TestWorkflowBundleIO.java
@@ -0,0 +1,383 @@
+package org.apache.taverna.scufl2.api.io;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+
+import static org.apache.taverna.scufl2.api.io.structure.StructureReader.TEXT_VND_TAVERNA_SCUFL2_STRUCTURE;
+import static org.junit.Assert.*;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Set;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.io.output.ByteArrayOutputStream;
+import org.apache.taverna.scufl2.api.ExampleWorkflow;
+import org.apache.taverna.scufl2.api.container.WorkflowBundle;
+import org.apache.taverna.scufl2.api.io.WorkflowBundleIO;
+import org.apache.taverna.scufl2.api.io.WorkflowBundleReader;
+import org.apache.taverna.scufl2.api.io.WorkflowBundleWriter;
+import org.apache.taverna.scufl2.api.io.structure.StructureReader;
+import org.apache.taverna.scufl2.api.io.structure.StructureWriter;
+import org.apache.taverna.scufl2.api.profiles.Profile;
+import org.junit.Ignore;
+import org.junit.Test;
+
+
+public class TestWorkflowBundleIO extends ExampleWorkflow {
+
+	private static final String UTF_8 = "utf-8";
+	protected WorkflowBundleIO bundleIO = new WorkflowBundleIO();
+	protected WorkflowBundle wfBundle = makeWorkflowBundle();
+
+	@Test
+	public void createBundle() throws Exception {
+		WorkflowBundle wb = bundleIO.createBundle();
+		assertEquals(wb, wb.getMainWorkflow().getParent());
+		assertEquals(wb, wb.getMainProfile().getParent());
+		assertEquals("bundle1", wb.getName());
+		assertEquals("workflow1", wb.getMainWorkflow().getName());
+		assertEquals("profile1", wb.getMainProfile().getName());
+		assertNotNull(wb.getCurrentRevision());
+		assertNotNull(wb.getMainWorkflow().getCurrentRevision());
+		assertNotNull(wb.getMainProfile().getCurrentRevision());
+	}
+	
+	@Test
+	public void getReaderForMediaType() throws Exception {
+		WorkflowBundleReader Reader = bundleIO
+		.getReaderForMediaType(TEXT_VND_TAVERNA_SCUFL2_STRUCTURE);
+		assertTrue(Reader instanceof StructureReader);
+	}
+
+	@Test
+	public void getReaderForUnknownMediaType() throws Exception {
+		assertNull(bundleIO
+				.getReaderForMediaType("application/vnd.example.unknownStuff"));
+	}
+
+	public String getStructureFormatWorkflowBundle() throws IOException {
+		InputStream helloWorldStream = getClass().getResourceAsStream(
+				"HelloWorld.txt");
+		return IOUtils.toString(helloWorldStream);
+	}
+
+	@Test
+	public void getWorkflowBundleReaders() throws Exception {
+		assertEquals(1, bundleIO.getReaders().size());
+		WorkflowBundleReader Reader = bundleIO.getReaders().get(0);
+		assertTrue(Reader instanceof StructureReader);
+	}
+
+	@Test
+	public void getWorkflowBundleWriters() throws Exception {
+		assertEquals(1, bundleIO.getWriters().size());
+		WorkflowBundleWriter writer = bundleIO.getWriters().get(0);
+		assertTrue(writer instanceof StructureWriter);
+	}
+
+	
+	@Test
+	public void getWriterForMediaType() throws Exception {
+		WorkflowBundleWriter writer = bundleIO
+		.getWriterForMediaType(TEXT_VND_TAVERNA_SCUFL2_STRUCTURE);
+		assertTrue(writer instanceof StructureWriter);
+	}
+
+	@Test
+	public void getWriterForUnknownMediaType() throws Exception {
+		assertNull(bundleIO
+				.getWriterForMediaType("application/vnd.example.unknownStuff"));
+	}
+	
+	@Test
+	public void guessMediaType() {
+		WorkflowBundleReader myReader = new WorkflowBundleReader() {
+			@Override
+			public Set<String> getMediaTypes() {
+				return null;
+			}
+			@Override
+			public WorkflowBundle readBundle(File bundleFile, String mediaType) {
+				return null;
+			}
+			@Override
+			public WorkflowBundle readBundle(InputStream inputStream,
+					String mediaType) {
+				return null;
+			}
+			@Override
+			public String guessMediaTypeForSignature(byte[] firstBytes) {
+				if (firstBytes.length == 4) {
+					return "test/test";
+				}
+				return null;
+			}
+		};
+
+		WorkflowBundleReader otherReader = new WorkflowBundleReader() {
+			@Override
+			public Set<String> getMediaTypes() {
+				return null;
+			}
+			@Override
+			public WorkflowBundle readBundle(File bundleFile, String mediaType) {
+				return null;
+			}
+			@Override
+			public WorkflowBundle readBundle(InputStream inputStream,
+					String mediaType) {
+				return null;
+			}
+			@Override
+			public String guessMediaTypeForSignature(byte[] firstBytes) {
+				if (firstBytes.length == 4) {
+					return "test/other";
+				}
+				return null;
+			}
+		};
+
+		
+		bundleIO.setReaders(Arrays.asList(myReader));
+		assertEquals(null, bundleIO.guessMediaTypeForSignature(new byte[16]));
+		assertEquals("test/test", bundleIO.guessMediaTypeForSignature(new byte[4]));
+
+
+		bundleIO.setReaders(Arrays.asList(myReader, myReader));
+		// 4 bytes should not be ambiguous, they all agree
+		assertEquals("test/test", bundleIO.guessMediaTypeForSignature(new byte[4]));		
+		
+		bundleIO.setReaders(Arrays.asList(myReader, myReader, otherReader));
+		// 4 bytes should now be ambiguous
+		assertEquals(null, bundleIO.guessMediaTypeForSignature(new byte[4]));		
+	}
+
+
+	@Test
+	public void readBundleFile() throws Exception {
+		File bundleFile = tempFile();
+		FileUtils.writeStringToFile(bundleFile,
+				getStructureFormatWorkflowBundle(),
+				UTF_8);
+		WorkflowBundle wfBundle = bundleIO.readBundle(bundleFile,
+				TEXT_VND_TAVERNA_SCUFL2_STRUCTURE);
+		assertEquals("HelloWorld", wfBundle.getName());
+		assertEquals("HelloWorld", wfBundle.getMainWorkflow().getName());
+		assertTrue(wfBundle.getMainWorkflow().getProcessors()
+				.containsName("Hello"));
+	}
+
+	
+
+	@Test
+	public void readBundleFileNoMediaType() throws Exception {
+		File bundleFile = tempFile();
+		FileUtils.writeStringToFile(bundleFile,
+				getStructureFormatWorkflowBundle(),
+				UTF_8);
+		WorkflowBundle wfBundle = bundleIO.readBundle(bundleFile,null);
+		assertNotNull(wfBundle);
+
+		File emptyFile = File.createTempFile("test", "txt");
+		try {
+			@SuppressWarnings("unused")
+			WorkflowBundle none = bundleIO.readBundle(emptyFile,null);
+			fail("Should throw IllegalArgumentException for unrecognized file");
+		} catch (IllegalArgumentException ex) {
+		}
+	}
+
+	@Test
+	public void readBundleStream() throws Exception {
+		InputStream inputStream = new ByteArrayInputStream(
+				getStructureFormatWorkflowBundle().getBytes("utf-8"));
+		WorkflowBundle wfBundle = bundleIO.readBundle(inputStream,
+				TEXT_VND_TAVERNA_SCUFL2_STRUCTURE);
+		assertEquals("HelloWorld", wfBundle.getName());
+		assertEquals("HelloWorld", wfBundle.getMainWorkflow().getName());
+		assertTrue(wfBundle.getMainWorkflow().getProcessors()
+				.containsName("Hello"));
+	}
+	
+	@Test
+	public void readBundleStreamNoMediaType() throws Exception {
+		InputStream inputStream = new ByteArrayInputStream(
+				getStructureFormatWorkflowBundle().getBytes("utf-8"));
+		WorkflowBundle wfBundle = bundleIO.readBundle(inputStream, null);
+		assertNotNull(wfBundle);
+		assertEquals("HelloWorld", wfBundle.getName());
+
+	}
+
+
+	@Test
+	public void readToWriteRoundTrip() throws Exception {
+		InputStream inputStream = new ByteArrayInputStream(
+				getStructureFormatWorkflowBundle().getBytes("utf-8"));
+		WorkflowBundle readBundle = bundleIO.readBundle(inputStream,
+				TEXT_VND_TAVERNA_SCUFL2_STRUCTURE);
+		ByteArrayOutputStream output = new ByteArrayOutputStream();
+		bundleIO.writeBundle(readBundle, output, TEXT_VND_TAVERNA_SCUFL2_STRUCTURE);
+		String bundleTxt = new String(output.toByteArray(), UTF_8);
+                String getStructureFormatWorkflowBundle = getStructureFormatWorkflowBundle();
+                bundleTxt = bundleTxt.replaceAll("\r", "").replaceAll("\n", "");
+                getStructureFormatWorkflowBundle = getStructureFormatWorkflowBundle.replaceAll("\r", "").replaceAll("\n", "");
+		assertEquals(getStructureFormatWorkflowBundle, bundleTxt);
+	}
+
+	@Test
+	public void setReaders() {
+		WorkflowBundleReader myReader = new WorkflowBundleReader() {
+			@Override
+			public Set<String> getMediaTypes() {
+				return Collections.singleton("application/vnd.example.myOwn");
+			}
+			@Override
+			public WorkflowBundle readBundle(File bundleFile, String mediaType) {
+				return null;
+			}
+			@Override
+			public WorkflowBundle readBundle(InputStream inputStream,
+					String mediaType) {
+				return null;
+			}
+			@Override
+			public String guessMediaTypeForSignature(byte[] firstBytes) {
+				return "test/test";
+			}
+		};
+
+		bundleIO.setReaders(Collections.singletonList(myReader));
+		assertEquals(1, bundleIO.getReaders().size());
+		assertSame(myReader, bundleIO.getReaders().get(0));
+		assertSame(myReader,
+				bundleIO.getReaderForMediaType("application/vnd.example.myOwn"));
+
+		// Should now be null
+		assertNull(bundleIO
+				.getReaderForMediaType(TEXT_VND_TAVERNA_SCUFL2_STRUCTURE));		
+		assertEquals("test/test", bundleIO.guessMediaTypeForSignature(new byte[4]));
+	}
+	
+	
+
+	@Test
+	public void setWriters() {
+		WorkflowBundleWriter myWriter = new WorkflowBundleWriter() {
+			@Override
+			public Set<String> getMediaTypes() {
+				return Collections.singleton("application/vnd.example.myOwn");
+			}
+			@Override
+			public void writeBundle(WorkflowBundle wfBundle, File destination,
+					String mediaType) {
+			}
+			@Override
+			public void writeBundle(WorkflowBundle wfBundle,
+					OutputStream output, String mediaType) {
+			}
+		};
+
+		bundleIO.setWriters(Collections.singletonList(myWriter));
+		assertEquals(1, bundleIO.getWriters().size());
+		assertSame(myWriter, bundleIO.getWriters().get(0));
+		assertSame(myWriter,
+				bundleIO.getWriterForMediaType("application/vnd.example.myOwn"));
+
+		// Should now be null
+		assertNull(bundleIO
+				.getWriterForMediaType(TEXT_VND_TAVERNA_SCUFL2_STRUCTURE));
+	}
+
+	public File tempFile() throws IOException {
+		File bundleFile = File.createTempFile("scufl2", "txt");
+		bundleFile.deleteOnExit();
+		return bundleFile;
+	}
+
+	@Test
+	public void writeBundleFile() throws Exception {
+		File bundleFile = tempFile();
+		bundleIO.writeBundle(wfBundle, bundleFile,
+				TEXT_VND_TAVERNA_SCUFL2_STRUCTURE);
+		String bundleTxt = FileUtils.readFileToString(bundleFile, UTF_8);
+                String getStructureFormatWorkflowBundle = getStructureFormatWorkflowBundle();
+                bundleTxt = bundleTxt.replaceAll("\r", "").replaceAll("\n", "");
+                getStructureFormatWorkflowBundle = getStructureFormatWorkflowBundle.replaceAll("\r", "").replaceAll("\n", "");
+		assertEquals(getStructureFormatWorkflowBundle, bundleTxt);
+	}
+
+	@Ignore
+	@Test
+	public void writeBundleFileSetParents() throws Exception {
+		File bundleFile = tempFile();
+		// Deliberately orphan a profile and a processor
+		Profile profile = wfBundle.getProfiles().getByName("tavernaWorkbench");
+		profile.setParent(null);		
+		wfBundle.getProfiles().add(profile);		
+		processor.setParent(null);
+		workflow.getProcessors().add(processor);		
+		
+		assertNull(processor.getParent());
+		assertNull(profile.getParent());		
+		bundleIO.writeBundle(wfBundle, bundleFile,
+				TEXT_VND_TAVERNA_SCUFL2_STRUCTURE);
+		assertNotNull(processor.getParent());
+		assertNotNull(profile.getParent());				
+		String bundleTxt = FileUtils.readFileToString(bundleFile, UTF_8);
+		assertTrue(bundleTxt.contains("Processor 'Hello'"));
+		assertTrue(bundleTxt.contains("Profile 'tavernaWorkbench'"));		
+	}
+	
+	@Test
+	public void writeBundleStream() throws Exception {
+		ByteArrayOutputStream output = new ByteArrayOutputStream();
+		bundleIO.writeBundle(wfBundle, output, TEXT_VND_TAVERNA_SCUFL2_STRUCTURE);
+		String bundleTxt = new String(output.toByteArray(), UTF_8);
+                String getStructureFormatWorkflowBundle = getStructureFormatWorkflowBundle();
+                bundleTxt = bundleTxt.replaceAll("\r", "").replaceAll("\n", "");
+                getStructureFormatWorkflowBundle = getStructureFormatWorkflowBundle.replaceAll("\r", "").replaceAll("\n", "");
+		assertEquals(getStructureFormatWorkflowBundle, bundleTxt);
+	}
+
+	@Test(expected = IllegalArgumentException.class)
+	public void writeBundleUnknownMediaType() throws Exception {
+		File bundleFile = tempFile();
+		bundleIO.writeBundle(wfBundle, bundleFile,
+		"application/vnd.example.unknownStuff");
+	}
+
+	@Test(expected = IOException.class)
+	public void writeBundleWrongLocation() throws Exception {
+		File bundleDir = tempFile();
+		bundleDir.delete();
+		File bundleFile = new File(bundleDir, "nonExistingDir");
+		bundleIO.writeBundle(wfBundle, bundleFile,
+				TEXT_VND_TAVERNA_SCUFL2_STRUCTURE);
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-language/blob/c08405cb/taverna-scufl2-api/src/test/resources/org/apache/taverna/scufl2/api/io/HelloWorld.txt
----------------------------------------------------------------------
diff --git a/taverna-scufl2-api/src/test/resources/org/apache/taverna/scufl2/api/io/HelloWorld.txt b/taverna-scufl2-api/src/test/resources/org/apache/taverna/scufl2/api/io/HelloWorld.txt
new file mode 100644
index 0000000..55a7d0e
--- /dev/null
+++ b/taverna-scufl2-api/src/test/resources/org/apache/taverna/scufl2/api/io/HelloWorld.txt
@@ -0,0 +1,48 @@
+WorkflowBundle 'HelloWorld'
+  MainWorkflow 'HelloWorld'
+  Workflow 'HelloWorld'
+    In 'yourName'
+    Out 'results'
+    Processor 'Hello'
+      In 'name'
+      Out 'greeting'
+    Processor 'wait4me'
+    Links
+      'Hello:greeting' -> 'results'
+      'yourName' -> 'Hello:name'
+      'yourName' -> 'results'
+    Controls
+      block 'Hello' until 'wait4me' finish
+  MainProfile 'tavernaWorkbench'
+  Profile 'tavernaServer'
+    Activity 'HelloScript'
+      Type <http://ns.taverna.org.uk/2010/activity/beanshell>
+      In 'personName'
+      Out 'hello'
+    ProcessorBinding 'Hello'
+      Activity 'HelloScript'
+      Processor 'HelloWorld:Hello'
+      InputPortBindings
+        'name' -> 'personName'
+      OutputPortBindings
+        'hello' -> 'greeting'
+    Configuration 'Hello'
+      Type <http://ns.taverna.org.uk/2010/activity/beanshell#Config>
+      Configures 'activity/HelloScript'
+        {"script":"hello = \"Hello, \" + personName;\nSystem.out.println(\"Server says: \" + hello);"}
+  Profile 'tavernaWorkbench'
+    Activity 'HelloScript'
+      Type <http://ns.taverna.org.uk/2010/activity/beanshell>
+      In 'personName'
+      Out 'hello'
+    ProcessorBinding 'Hello'
+      Activity 'HelloScript'
+      Processor 'HelloWorld:Hello'
+      InputPortBindings
+        'name' -> 'personName'
+      OutputPortBindings
+        'hello' -> 'greeting'
+    Configuration 'Hello'
+      Type <http://ns.taverna.org.uk/2010/activity/beanshell#Config>
+      Configures 'activity/HelloScript'
+        {"script":"hello = \"Hello, \" + personName;\nJOptionPane.showMessageDialog(null, hello);"}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-language/blob/c08405cb/taverna-scufl2-api/src/test/resources/roevo-test.ttl
----------------------------------------------------------------------
diff --git a/taverna-scufl2-api/src/test/resources/roevo-test.ttl b/taverna-scufl2-api/src/test/resources/roevo-test.ttl
new file mode 100644
index 0000000..6e0c5aa
--- /dev/null
+++ b/taverna-scufl2-api/src/test/resources/roevo-test.ttl
@@ -0,0 +1,96 @@
+#   Licensed to the Apache Software Foundation (ASF) under one or more
+#   contributor license agreements.  See the NOTICE file distributed with
+#   this work for additional information regarding copyright ownership.
+#   The ASF licenses this file to You under the Apache License, Version 2.0
+#   (the "License"); you may not use this file except in compliance with
+#   the License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#   Unless required by applicable law or agreed to in writing, software
+#   distributed under the License is distributed on an "AS IS" BASIS,
+#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#   See the License for the specific language governing permissions and
+#   limitations under the License.
+@prefix roevo: <http://purl.org/wf4ever/roevo#> .
+@prefix ro: <http://purl.org/wf4ever/ro#> .
+@prefix wfdesc: <http://purl.org/wf4ever/wfdesc#> .
+@prefix prov: <http://www.w3.org/ns/prov#> .
+@prefix terms: <http://purl.org/dc/terms/> .
+@prefix scufl2: <http://ns.taverna.org.uk/2010/scufl2#> .
+@prefix : <#> .
+
+<wf-v3> a wfdesc:Workflow, scufl2:Workflow, roevo:VersionableResource, prov:Entity ;
+    terms:identifier "23481928391283" ;
+    prov:wasGeneratedBy <wf-v3-change> ;
+    roevo:wasChangedBy <wf-v3-change> .
+    
+<wf-v3-change-spec> a roevo:ChangeSpecification, prov:Activity ;
+    prov:endedAtTime "2012-12-24T18:00:00+01" ;
+    roevo:fromVersion <wf-v2> ;
+    roevo:toVersion <wf-v3> ;
+    roevo:hasChange <wf-v3-change> .
+
+<wf-v3-change> a roevo:Change, roevo:Addition, prov:Activity ;
+    prov:wasGeneratedBy <wf-v3-change> ;
+    prov:used <nested-workflow1> ;
+    roevo:relatedResource <nested-workflow1> .
+
+# Short-hand form without any related resource
+<wf-v2> a roevo:VersionableResource ;
+     roevo:wasChangedBy [ a roevo:ChangeSpecification ;
+         roevo:fromVersion <wf-v1> ;
+         roevo:hasChange [ a roevo:Addition
+		roevo:relatedResource <nested-workflow1>.
+	]	
+     ] .
+
+# Simple
+<simple-v3> a prov:Entity ;
+    prov:generatedAtTime  "2012-12-24T18:00:00+01" ;
+    prov:wasRevisionOf <simple-v2> .
+
+
+# Joined
+<joint-v3> a prov:Entity ;
+    prov:generatedAtTime  "2012-12-24T18:00:00+01" ;
+    prov:wasRevisionOf <joint-v2> ;
+    roevo:wasChangedBy [ a roevo:ChangeSpecification, prov:Activity;
+        roevo:fromVersion <joint-v2> ;
+        roevo:hasChange [ a roevo:Addition;
+            roevo:relatedResource <nested-workflow1> 
+        ] 
+    ] .
+
+
+<VersionableResource rdf:about="joint-v3">
+  <wasChangedBy>
+    <ChangeSpecification>
+      <fromVersion rdf:resource="joint-v2"/>
+      <hasChange>
+        <Addition>
+          <relatedResource rdf:resource="nested-workflow1"/>
+        </Addition>
+      </hasChange>
+    </ChangeSpecification>
+  </wasChangedBy>
+  <prov:generatedAtTime>2012-12-24T18:00:00+01</prov:generatedAtTime>
+  <prov:wasRevisionOf rdf:resource="joint-v2"/>
+</VersionableResource>
+
+<VersionableResource rdf:about="joint-v2">
+  <wasChangedBy>
+    <ChangeSpecification>
+      <fromVersion rdf:resource="joint-v1"/>
+      <hasChange>
+        <Addition>
+          <relatedResource rdf:resource="nested-workflow1"/>
+        </Addition>
+      </hasChange>
+    </ChangeSpecification>
+  </wasChangedBy>
+  <prov:generatedAtTime>2012-12-24T18:00:00+01</prov:generatedAtTime>
+  <prov:wasRevisionOf rdf:resource="joint-v1"/>
+</VersionableResource>
+
+