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:15 UTC

[30/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/main/java/org/apache/taverna/scufl2/api/profiles/ProcessorPortBinding.java
----------------------------------------------------------------------
diff --git a/taverna-scufl2-api/src/main/java/org/apache/taverna/scufl2/api/profiles/ProcessorPortBinding.java b/taverna-scufl2-api/src/main/java/org/apache/taverna/scufl2/api/profiles/ProcessorPortBinding.java
new file mode 100644
index 0000000..658296d
--- /dev/null
+++ b/taverna-scufl2-api/src/main/java/org/apache/taverna/scufl2/api/profiles/ProcessorPortBinding.java
@@ -0,0 +1,156 @@
+package org.apache.taverna.scufl2.api.profiles;
+
+/*
+ * 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.net.URI;
+import java.util.Collection;
+
+import org.apache.taverna.scufl2.api.annotation.Annotation;
+import org.apache.taverna.scufl2.api.common.AbstractCloneable;
+import org.apache.taverna.scufl2.api.common.Child;
+import org.apache.taverna.scufl2.api.common.Scufl2Tools;
+import org.apache.taverna.scufl2.api.common.URITools;
+import org.apache.taverna.scufl2.api.common.Visitor;
+import org.apache.taverna.scufl2.api.common.WorkflowBean;
+import org.apache.taverna.scufl2.api.port.ActivityPort;
+import org.apache.taverna.scufl2.api.port.InputActivityPort;
+import org.apache.taverna.scufl2.api.port.InputProcessorPort;
+import org.apache.taverna.scufl2.api.port.OutputActivityPort;
+import org.apache.taverna.scufl2.api.port.OutputProcessorPort;
+import org.apache.taverna.scufl2.api.port.ProcessorPort;
+
+
+/**
+ * The binding between an <code>ActivityPort</code> and a
+ * <code>ProcessorPort</code>.
+ * <p>
+ * This abstract class is realized as either an
+ * {@link ProcessorInputPortBinding} or {@link ProcessorOutputPortBinding}. For
+ * an input port binding, the binding goes from an {@link InputProcessorPort} to
+ * an {@link InputActivityPort}, while for an output port binding the binding
+ * goes from an {@link OutputActivityPort} to an {@link OutputProcessorPort}.
+ * 
+ * @author Alan R Williams
+ * @author Stian Soiland-Reyes
+ * @param <A>
+ *            the <code>ActivityPort</code>
+ * @param <P>
+ *            the <code>ProcessorPort</code>
+ *            
+ */
+public abstract class ProcessorPortBinding<A extends ActivityPort, P extends ProcessorPort>
+		extends AbstractCloneable implements Child<ProcessorBinding> {
+	private P boundProcessorPort;
+	private A boundActivityPort;
+
+	@Override
+	public boolean accept(Visitor visitor) {
+		return visitor.visit(this);
+	}
+
+	/**
+	 * Return the {@link ActivityPort} which is passing data from/to the
+	 * {@link #getBoundProcessorPort()}.
+	 * 
+	 * @return the <code>ActivityPort</code> to which data is passing from/to
+	 *         the bound <code>ProcessorPort</code>
+	 */
+	public A getBoundActivityPort() {
+		return boundActivityPort;
+	}
+
+	/**
+	 * Return the {@link ProcessorPort} which is passing data to/from the
+	 * {@link #getBoundActivityPort()}.
+	 * 
+	 * @return the <code>ProcessorPort</code> to which data is passing to/from
+	 *         the bound <code>ActivityPort</code>
+	 */
+	public P getBoundProcessorPort() {
+		return boundProcessorPort;
+	}
+
+	/**
+	 * Sets the {@link ActivityPort} which is passing data from/to the
+	 * {@link #getBoundProcessorPort()}.
+	 * 
+	 * @param boundActivityPort
+	 *            the <code>ActivityPort</code> to which data is passing from/to
+	 *            the bound <code>ProcessorPort</code>
+	 */
+	public void setBoundActivityPort(A boundActivityPort) {
+		this.boundActivityPort = boundActivityPort;
+	}
+
+	/**
+	 * Sets the {@link ProcessorPort} which is passing data to/from the
+	 * {@link #getBoundActivityPort()}.
+	 * 
+	 * @param boundProcessorPort
+	 *            the <code>ProcessorPort</code> to which data is passing
+	 *            to/from the bound <code>ActivityPort</code>
+	 */
+	public void setBoundProcessorPort(P boundProcessorPort) {
+		this.boundProcessorPort = boundProcessorPort;
+	}
+
+	@Override
+	protected void cloneInto(WorkflowBean clone, Cloning cloning) {
+		@SuppressWarnings("unchecked")
+		ProcessorPortBinding<A, P> cloneBinding = (ProcessorPortBinding<A, P>) clone;
+		cloneBinding.setBoundActivityPort(cloning
+				.cloneOrOriginal(getBoundActivityPort()));
+		cloneBinding.setBoundProcessorPort(cloning
+				.cloneOrOriginal(getBoundProcessorPort()));
+	}
+
+	// Derived operations
+
+	/**
+	 * Get all the annotations that pertain to this port binding.
+	 * 
+	 * @return The collection of annotations.
+	 * @see Scufl2Tools#annotationsFor(Child)
+	 */
+	public Collection<Annotation> getAnnotations() {
+		return getTools().annotationsFor(this);
+	}
+
+	/**
+	 * Get the URI of this port binding.
+	 * 
+	 * @return The absolute URI.
+	 * @see URITools#uriForBean(WorkflowBean)
+	 */
+	public URI getURI() {
+		return getUriTools().uriForBean(this);
+	}
+
+	/**
+	 * Get the URI of this port binding relative to another workflow element.
+	 * 
+	 * @return The relative URI.
+	 * @see URITools#relativeUriForBean(WorkflowBean,WorflowBean)
+	 */
+	public URI getRelativeURI(WorkflowBean relativeTo) {
+		return getUriTools().relativeUriForBean(this, relativeTo);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-language/blob/c08405cb/taverna-scufl2-api/src/main/java/org/apache/taverna/scufl2/api/profiles/Profile.java
----------------------------------------------------------------------
diff --git a/taverna-scufl2-api/src/main/java/org/apache/taverna/scufl2/api/profiles/Profile.java b/taverna-scufl2-api/src/main/java/org/apache/taverna/scufl2/api/profiles/Profile.java
new file mode 100644
index 0000000..a6e3498
--- /dev/null
+++ b/taverna-scufl2-api/src/main/java/org/apache/taverna/scufl2/api/profiles/Profile.java
@@ -0,0 +1,220 @@
+package org.apache.taverna.scufl2.api.profiles;
+
+/*
+ * 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.net.URI;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.taverna.scufl2.api.activity.Activity;
+import org.apache.taverna.scufl2.api.annotation.Revisioned;
+import org.apache.taverna.scufl2.api.common.AbstractRevisioned;
+import org.apache.taverna.scufl2.api.common.Child;
+import org.apache.taverna.scufl2.api.common.NamedSet;
+import org.apache.taverna.scufl2.api.common.Visitor;
+import org.apache.taverna.scufl2.api.common.WorkflowBean;
+import org.apache.taverna.scufl2.api.configurations.Configuration;
+import org.apache.taverna.scufl2.api.container.WorkflowBundle;
+
+
+/**
+ * A <code>Profile</code> specifies a set of compatible {@link ProcessorBinding}
+ * s.
+ * <p>
+ * For example, one <code>Profile</code> could contain ways of enacting a set of
+ * {@link org.apache.taverna.scufl2.api.core.Processor Processor}s on a grid whilst
+ * another contained ways of enacting the <code>Processor</code>s on a laptop.
+ * 
+ * @author Alan R Williams
+ */
+public class Profile extends AbstractRevisioned implements
+		Child<WorkflowBundle>, Revisioned {
+	private final NamedSet<ProcessorBinding> processorBindings = new NamedSet<>();
+	private final NamedSet<Configuration> configurations = new NamedSet<>();
+	private Integer profilePosition;
+	private final NamedSet<Activity> activities = new NamedSet<>();
+	private WorkflowBundle parent;
+
+	/**
+	 * Constructs a <code>Profile</code> with a random UUID as the name.
+	 */
+	public Profile() {
+		super();
+	}
+
+	/**
+	 * Constructs a <code>Profile</code> with the specified name.
+	 * 
+	 * @param name
+	 *            the name of the <code>Profile</code>. <strong>Must
+	 *            not</strong> be <code>null</code> or an empty String.
+	 */
+	public Profile(String name) {
+		super(name);
+	}
+
+	@Override
+	public boolean accept(Visitor visitor) {
+		if (visitor.visitEnter(this)) {
+			List<Iterable<? extends WorkflowBean>> children = new ArrayList<>();
+			children.add(getActivities());
+			children.add(getProcessorBindings());
+			children.add(getConfigurations());
+			outer: for (Iterable<? extends WorkflowBean> it : children)
+				for (WorkflowBean bean : it)
+					if (!bean.accept(visitor))
+						break outer;
+		}
+		return visitor.visitLeave(this);
+	}
+
+	/**
+	 * Returns the <code>Activity</code>s that this <code>Profile</code>
+	 * contains.
+	 * <p>
+	 * The <code>Activity</code>s may be bound to <code>Processor</code>s in the
+	 * <code>ProcessorBinding</code>s.
+	 * 
+	 * @return the <code>Activity</code>s that this <code>Profile</code>
+	 *         contains
+	 */
+	public NamedSet<Activity> getActivities() {
+		return activities;
+	}
+
+	/**
+	 * Returns the <code>Configuration</code>s that this <code>Profile</code>
+	 * contains.
+	 * 
+	 * @return the <code>Configuration</code>s that this <code>Profile</code>
+	 *         contains
+	 */
+	public NamedSet<Configuration> getConfigurations() {
+		return configurations;
+	}
+
+	@Override
+	public WorkflowBundle getParent() {
+		return parent;
+	}
+
+	/**
+	 * Return the set of bindings for individual <code>Processor</code>s.
+	 * 
+	 * @return the set of bindings for individual <code>Processor</code>s
+	 */
+	public NamedSet<ProcessorBinding> getProcessorBindings() {
+		return processorBindings;
+	}
+
+	/**
+	 * Return the suggested position of this profile within the
+	 * {@link WorkflowBundle}.
+	 * <p>
+	 * If ordering profiles (for instance for displaying them to the user), they
+	 * might be sorted by increasing profilePosition. If two profiles have the
+	 * same position, their internal order is undetermined. Profiles with
+	 * profile position <code>null</code> should be sorted last in such a list.
+	 * 
+	 * @return the position of this profile within the
+	 *         <code>WorkflowBundle</code>
+	 */
+	public final Integer getProfilePosition() {
+		return profilePosition;
+	}
+
+	/**
+	 * Sets the <code>Activity</code>s that this <code>Profile</code> contains.
+	 * 
+	 * @param activities
+	 *            the <code>Activity</code>s that this <code>Profile</code>
+	 *            contains
+	 */
+	public void setActivities(Set<Activity> activities) {
+		this.activities.clear();
+		this.activities.addAll(activities);
+	}
+
+	/**
+	 * Sets the <code>Configuration</code>s that this <code>Profile</code>
+	 * contains.
+	 * 
+	 * @param configurations
+	 *            the <code>Configuration</code>s that this <code>Profile</code>
+	 *            contains
+	 */
+	public void setConfigurations(Set<Configuration> configurations) {
+		this.configurations.clear();
+		this.configurations.addAll(configurations);
+	}
+
+	@Override
+	public void setParent(WorkflowBundle parent) {
+		if (this.parent != null && this.parent != parent)
+			this.parent.getProfiles().remove(this);
+		this.parent = parent;
+		if (parent != null)
+			parent.getProfiles().add(this);
+	}
+
+	/**
+	 * Sets the bindings for individual <code>Processor</code>s.
+	 * 
+	 * @param processorBindings
+	 *            the bindings for individual <code>Processor</code>s
+	 */
+	public void setProcessorBindings(Set<ProcessorBinding> processorBindings) {
+		this.processorBindings.clear();
+		this.processorBindings.addAll(processorBindings);
+	}
+
+	/**
+	 * Sets the position of this profile within the {@link WorkflowBundle}.
+	 * <p>
+	 * When ordering profiles, they can be sorted by decreasing profilePosition.
+	 * If two profiles have the same position, their internal order is
+	 * undetermined.
+	 * 
+	 * 
+	 * @param profilePosition
+	 *            the position of this profile within the
+	 *            <code>WorkflowBundle</code>
+	 */
+	public final void setProfilePosition(Integer profilePosition) {
+		this.profilePosition = profilePosition;
+	}
+
+	public static final URI PROFILE_ROOT = URI
+			.create("http://ns.taverna.org.uk/2012/scufl2-profile/");
+
+	@Override
+	protected URI getIdentifierRoot() {
+		return PROFILE_ROOT;
+	}
+
+	@Override
+	protected void cloneInto(WorkflowBean clone, Cloning cloning) {
+		super.cloneInto(clone, cloning);
+		Profile cloneProfile = (Profile) clone;
+		cloneProfile.setProfilePosition(getProfilePosition());
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-language/blob/c08405cb/taverna-scufl2-api/src/main/java/org/apache/taverna/scufl2/api/profiles/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-scufl2-api/src/main/java/org/apache/taverna/scufl2/api/profiles/package-info.java b/taverna-scufl2-api/src/main/java/org/apache/taverna/scufl2/api/profiles/package-info.java
new file mode 100644
index 0000000..7b49066
--- /dev/null
+++ b/taverna-scufl2-api/src/main/java/org/apache/taverna/scufl2/api/profiles/package-info.java
@@ -0,0 +1,22 @@
+package org.apache.taverna.scufl2.api.profiles;
+
+/*
+ * 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.
+ */
+
+

http://git-wip-us.apache.org/repos/asf/incubator-taverna-language/blob/c08405cb/taverna-scufl2-api/src/main/java/org/apache/taverna/scufl2/api/reference/package-info.java
----------------------------------------------------------------------
diff --git a/taverna-scufl2-api/src/main/java/org/apache/taverna/scufl2/api/reference/package-info.java b/taverna-scufl2-api/src/main/java/org/apache/taverna/scufl2/api/reference/package-info.java
new file mode 100644
index 0000000..7981ecd
--- /dev/null
+++ b/taverna-scufl2-api/src/main/java/org/apache/taverna/scufl2/api/reference/package-info.java
@@ -0,0 +1,23 @@
+package org.apache.taverna.scufl2.api.reference;
+
+/*
+ * 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.
+ */
+
+
+

http://git-wip-us.apache.org/repos/asf/incubator-taverna-language/blob/c08405cb/taverna-scufl2-api/src/main/resources/META-INF/services/org.apache.taverna.scufl2.api.io.WorkflowBundleReader
----------------------------------------------------------------------
diff --git a/taverna-scufl2-api/src/main/resources/META-INF/services/org.apache.taverna.scufl2.api.io.WorkflowBundleReader b/taverna-scufl2-api/src/main/resources/META-INF/services/org.apache.taverna.scufl2.api.io.WorkflowBundleReader
new file mode 100644
index 0000000..f26e617
--- /dev/null
+++ b/taverna-scufl2-api/src/main/resources/META-INF/services/org.apache.taverna.scufl2.api.io.WorkflowBundleReader
@@ -0,0 +1 @@
+#   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.
org.apache.taverna.scufl2.api.io.structure.StructureReader
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-language/blob/c08405cb/taverna-scufl2-api/src/main/resources/META-INF/services/org.apache.taverna.scufl2.api.io.WorkflowBundleWriter
----------------------------------------------------------------------
diff --git a/taverna-scufl2-api/src/main/resources/META-INF/services/org.apache.taverna.scufl2.api.io.WorkflowBundleWriter b/taverna-scufl2-api/src/main/resources/META-INF/services/org.apache.taverna.scufl2.api.io.WorkflowBundleWriter
new file mode 100644
index 0000000..7f5d611
--- /dev/null
+++ b/taverna-scufl2-api/src/main/resources/META-INF/services/org.apache.taverna.scufl2.api.io.WorkflowBundleWriter
@@ -0,0 +1 @@
+#   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.
org.apache.taverna.scufl2.api.io.structure.StructureWriter
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-language/blob/c08405cb/taverna-scufl2-api/src/main/resources/META-INF/spring/scufl2-api-context-osgi.xml
----------------------------------------------------------------------
diff --git a/taverna-scufl2-api/src/main/resources/META-INF/spring/scufl2-api-context-osgi.xml b/taverna-scufl2-api/src/main/resources/META-INF/spring/scufl2-api-context-osgi.xml
new file mode 100644
index 0000000..c5845d4
--- /dev/null
+++ b/taverna-scufl2-api/src/main/resources/META-INF/spring/scufl2-api-context-osgi.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+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.
+-->
+
+<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/osgi http://www.springframework.org/schema/osgi/spring-osgi.xsd
+		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
+
+	<list id="readers" interface="org.apache.taverna.scufl2.api.io.WorkflowBundleReader" cardinality="0..N" />
+	<list id="writers" interface="org.apache.taverna.scufl2.api.io.WorkflowBundleWriter" cardinality="0..N" />
+
+	<reference id="transformerFactory" interface="javax.xml.transform.TransformerFactory" cardinality="0..1"/>
+
+	<reference id="documentBuilderFactory" interface="javax.xml.parsers.DocumentBuilderFactory"  cardinality="0..1" filter="(parser.namespaceAware=true)"/>
+
+	<service ref="workflowBundleIO" interface="org.apache.taverna.scufl2.api.io.WorkflowBundleIO" />
+
+	<service ref="structureReader" interface="org.apache.taverna.scufl2.api.io.WorkflowBundleReader" />
+
+	<service ref="structureWriter" interface="org.apache.taverna.scufl2.api.io.WorkflowBundleWriter" />
+
+</beans:beans>

http://git-wip-us.apache.org/repos/asf/incubator-taverna-language/blob/c08405cb/taverna-scufl2-api/src/main/resources/META-INF/spring/scufl2-api-context.xml
----------------------------------------------------------------------
diff --git a/taverna-scufl2-api/src/main/resources/META-INF/spring/scufl2-api-context.xml b/taverna-scufl2-api/src/main/resources/META-INF/spring/scufl2-api-context.xml
new file mode 100644
index 0000000..7ef270b
--- /dev/null
+++ b/taverna-scufl2-api/src/main/resources/META-INF/spring/scufl2-api-context.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+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.
+-->
+
+<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="structureReader" class="org.apache.taverna.scufl2.api.io.structure.StructureReader" />
+
+	<bean id="structureWriter" class="org.apache.taverna.scufl2.api.io.structure.StructureWriter" />
+
+	<bean id="workflowBundleIO" class="org.apache.taverna.scufl2.api.io.WorkflowBundleIO">
+		<property name="readers" ref="readers" />
+		<property name="writers" ref="writers" />
+	</bean>
+
+</beans>

http://git-wip-us.apache.org/repos/asf/incubator-taverna-language/blob/c08405cb/taverna-scufl2-api/src/test/java/org/apache/taverna/scufl2/api/EqualsOnArrayListsTest.java
----------------------------------------------------------------------
diff --git a/taverna-scufl2-api/src/test/java/org/apache/taverna/scufl2/api/EqualsOnArrayListsTest.java b/taverna-scufl2-api/src/test/java/org/apache/taverna/scufl2/api/EqualsOnArrayListsTest.java
new file mode 100644
index 0000000..2aec94b
--- /dev/null
+++ b/taverna-scufl2-api/src/test/java/org/apache/taverna/scufl2/api/EqualsOnArrayListsTest.java
@@ -0,0 +1,95 @@
+package org.apache.taverna.scufl2.api;
+
+/*
+ * 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.assertNotEquals;
+
+import org.apache.taverna.scufl2.api.iterationstrategy.CrossProduct;
+import org.apache.taverna.scufl2.api.iterationstrategy.DotProduct;
+import org.apache.taverna.scufl2.api.iterationstrategy.IterationStrategyStack;
+import org.apache.taverna.scufl2.api.iterationstrategy.PortNode;
+import org.junit.Test;
+
+
+public class EqualsOnArrayListsTest {
+    
+    @Test
+    public void crossProductEqualIfEmpty() throws Exception {
+        CrossProduct crossProd1 = new CrossProduct();
+        CrossProduct crossProd2 = new CrossProduct();
+        assertEquals(crossProd1, crossProd2);                
+    }
+        
+    @Test
+    public void crossProductNotEqual() throws Exception {
+        CrossProduct crossProd1 = new CrossProduct();
+        CrossProduct crossProd2 = new CrossProduct();
+        crossProd2.add(new PortNode());
+        assertNotEquals(crossProd1, crossProd2);                
+    }
+    
+    
+    @Test
+    public void crossProductNotEqualToDotProduct() throws Exception {
+        DotProduct dotProd = new DotProduct();
+        CrossProduct crossProd = new CrossProduct();
+        assertNotEquals(crossProd, dotProd);
+        assertNotEquals(dotProd, crossProd);
+    }
+
+    @Test
+    public void dotProductEqualIfEmpty() throws Exception {
+        DotProduct dotProd1 = new DotProduct();
+        DotProduct dotProd2 = new DotProduct();
+        assertEquals(dotProd1, dotProd2);                
+    }
+
+    @Test
+    public void dotProductNotEqual() throws Exception {
+        DotProduct dotProd1 = new DotProduct();
+        DotProduct dotProd2 = new DotProduct();
+        dotProd2.add(new PortNode());
+        assertNotEquals(dotProd1, dotProd2);                
+    }
+    
+    @Test
+    public void iterationStackEqualIfEmpty() throws Exception {
+        IterationStrategyStack itStack1 = new IterationStrategyStack();
+        IterationStrategyStack itStack2 = new IterationStrategyStack();        
+        assertEquals(itStack1, itStack2);                
+    }
+
+    @Test
+    public void iterationStackNotEqualToCrossProduct() throws Exception {
+        IterationStrategyStack itStack = new IterationStrategyStack();
+        CrossProduct crossProd = new CrossProduct();
+        assertNotEquals(itStack, crossProd);                
+    }    
+
+    @Test
+    public void iterationStackNotEqualToDotProduct() throws Exception {
+        IterationStrategyStack itStack = new IterationStrategyStack();
+        DotProduct dotProd = new DotProduct();
+        assertNotEquals(itStack, dotProd);                
+    }
+}
+

http://git-wip-us.apache.org/repos/asf/incubator-taverna-language/blob/c08405cb/taverna-scufl2-api/src/test/java/org/apache/taverna/scufl2/api/ExampleWorkflow.java
----------------------------------------------------------------------
diff --git a/taverna-scufl2-api/src/test/java/org/apache/taverna/scufl2/api/ExampleWorkflow.java b/taverna-scufl2-api/src/test/java/org/apache/taverna/scufl2/api/ExampleWorkflow.java
new file mode 100644
index 0000000..c8a047a
--- /dev/null
+++ b/taverna-scufl2-api/src/test/java/org/apache/taverna/scufl2/api/ExampleWorkflow.java
@@ -0,0 +1,238 @@
+package org.apache.taverna.scufl2.api;
+
+/*
+ * 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.net.URI;
+
+import org.apache.taverna.scufl2.api.activity.Activity;
+import org.apache.taverna.scufl2.api.common.Scufl2Tools;
+import org.apache.taverna.scufl2.api.configurations.Configuration;
+import org.apache.taverna.scufl2.api.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.core.Workflow;
+import org.apache.taverna.scufl2.api.iterationstrategy.CrossProduct;
+import org.apache.taverna.scufl2.api.iterationstrategy.IterationStrategyStack;
+import org.apache.taverna.scufl2.api.iterationstrategy.PortNode;
+import org.apache.taverna.scufl2.api.port.InputActivityPort;
+import org.apache.taverna.scufl2.api.port.InputProcessorPort;
+import org.apache.taverna.scufl2.api.port.InputWorkflowPort;
+import org.apache.taverna.scufl2.api.port.OutputActivityPort;
+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.apache.taverna.scufl2.api.profiles.Profile;
+
+
+import com.fasterxml.jackson.databind.node.JsonNodeFactory;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
+public class ExampleWorkflow {
+
+	protected Workflow workflow;
+	protected Processor processor;
+	protected WorkflowBundle workflowBundle;
+	protected InputProcessorPort processorName;
+	protected OutputProcessorPort processorGreeting;
+	protected InputActivityPort personName;
+	protected OutputActivityPort hello;
+	protected Activity activity;
+	protected BlockingControlLink condition;
+	protected Processor wait4me;
+    @SuppressWarnings("unused")
+    private DataLink nameLink;
+
+	protected static URI TAVERNA_2_2 = URI.create("http://ns.taverna.org.uk/2010/taverna/2.2/");
+
+	public Activity makeActivity() {
+		activity = new Activity();
+		activity.setName("HelloScript");
+		activity.setType(URI
+				.create("http://ns.taverna.org.uk/2010/activity/beanshell"));
+
+		personName = new InputActivityPort(activity, "personName");
+		personName.setDepth(0);
+		hello = new OutputActivityPort(activity, "hello");
+		hello.setDepth(0);
+		hello.setGranularDepth(0);
+		return activity;
+
+	}
+
+	public Configuration makeConfiguration() {
+		Configuration configuration = new Configuration("Hello");
+		configuration.setConfigures(activity);
+
+		configuration
+				.setType(
+						URI.create("http://ns.taverna.org.uk/2010/activity/beanshell#Config"));
+		ObjectNode json = (ObjectNode) configuration.getJson();
+		json.put("script",
+				"hello = \"Hello, \" + personName;\n"
+								+ "JOptionPane.showMessageDialog(null, hello);");
+		return configuration;
+	}
+
+	public IterationStrategyStack makeIterationStrategyStack(
+			InputProcessorPort... inputs) {
+		IterationStrategyStack stack = new IterationStrategyStack();
+		CrossProduct crossProduct = new CrossProduct();
+		crossProduct.setParent(stack);
+		for (InputProcessorPort inp : inputs) {
+			PortNode n = new PortNode(crossProduct, inp);
+			n.setDesiredDepth(0);
+		}
+		return stack;
+	}
+
+	public Profile makeMainProfile() {
+		Profile profile = new Profile();
+		profile.setName("tavernaWorkbench");
+
+		// FIXME: Can't set dc:creator/date/description
+
+		// FIXME: Can't create recommendsEnvironment/requiresEnvironment
+
+		makeActivity().setParent(profile);
+
+		makeConfiguration().setParent(profile);
+		makeProcessorBinding().setParent(profile);
+
+		// profile.setProfilePosition(0);
+
+		return profile;
+	}
+
+	public Workflow makeMainWorkflow() {
+		workflow = new Workflow();
+		workflow.setName("HelloWorld");
+
+		// NOTE: setWorkflowIdentifier should only be called when loading a
+		// workflow
+		// which already has an ID
+		workflow.setIdentifier(URI
+				.create("http://ns.taverna.org.uk/2010/workflow/00626652-55ae-4a9e-80d4-c8e9ac84e2ca/"));
+
+		InputWorkflowPort yourName = new InputWorkflowPort(workflow, "yourName");
+		yourName.setDepth(0);
+		OutputWorkflowPort results = new OutputWorkflowPort(workflow, "results");
+		// Not needed:
+		// workflow.getInputPorts().add(yourName);
+		// workflow.getOutputPorts().add(results);
+
+		workflow.getProcessors().add(makeProcessor());
+		workflow.getProcessors().add(makeProcessor2());
+
+		// Make links
+		DataLink directLink = new DataLink(workflow, yourName, results);
+		directLink.setMergePosition(1);
+
+		DataLink greetingLink = new DataLink(workflow, processorGreeting,
+				results);
+		greetingLink.setMergePosition(0);
+
+		nameLink = new DataLink(workflow, yourName, processorName);
+
+		condition = new BlockingControlLink(processor, wait4me);
+
+		return workflow;
+	}
+
+	public Processor makeProcessor() {
+		processor = new Processor(workflow, "Hello");
+		processorName = new InputProcessorPort(processor, "name");
+		processorName.setDepth(0);
+		processorGreeting = new OutputProcessorPort(processor, "greeting");
+		processorGreeting.setDepth(0);
+		processorGreeting.setGranularDepth(0);
+
+		// FIXME: Should not need to make default iteration stack
+		makeIterationStrategyStack(processorName).setParent(processor);
+
+		return processor;
+	}
+
+	public Processor makeProcessor2() {
+		wait4me = new Processor(workflow, "wait4me");
+
+		// FIXME: Should not need to make default iteration stack
+		makeIterationStrategyStack().setParent(wait4me);
+
+		return processor;
+	}
+
+	public ProcessorBinding makeProcessorBinding() {
+		ProcessorBinding processorBinding = new ProcessorBinding();
+		processorBinding.setName("Hello");
+		processorBinding.setBoundProcessor(processor);
+		processorBinding.setBoundActivity(activity);
+
+		new ProcessorInputPortBinding(processorBinding, processorName,
+				personName);
+		new ProcessorOutputPortBinding(processorBinding, hello,
+				processorGreeting);
+
+		return processorBinding;
+	}
+
+	public Profile makeSecondaryProfile() {
+		Profile profile = makeMainProfile();
+		profile.setName("tavernaServer");
+		Configuration config = profile.getConfigurations().getByName("Hello");
+		ObjectNode json = JsonNodeFactory.instance.objectNode();
+	    json.put("script",
+						"hello = \"Hello, \" + personName;\n"
+								+ "System.out.println(\"Server says: \" + hello);");
+	    config.setJson(json);
+		return profile;
+	}
+
+	public WorkflowBundle makeWorkflowBundle() {
+		// Based on
+		// uk.org.taverna.scufl2.scufl2-usecases/src/main/resources/workflows/example/workflowBundle.rdf
+
+		workflowBundle = new WorkflowBundle();
+		workflowBundle.setName("HelloWorld");
+		// NOTE: setSameBaseAs should only be called when loading a workflow
+		// bundle
+		// which already has an ID
+		workflowBundle
+				.setGlobalBaseURI(URI
+						.create("http://ns.taverna.org.uk/2010/workflowBundle/28f7c554-4f35-401f-b34b-516e9a0ef731/"));
+		Workflow workflow = makeMainWorkflow();
+		workflow.setParent(workflowBundle);
+		workflowBundle.setMainWorkflow(workflow);
+		Profile profile = makeMainProfile();
+		profile.setParent(workflowBundle);
+		workflowBundle.setMainProfile(profile);
+		Profile secondaryProfile = makeSecondaryProfile();
+		secondaryProfile.setParent(workflowBundle);
+		
+		Scufl2Tools scufl2Tools = new Scufl2Tools();
+		scufl2Tools.setParents(workflowBundle);
+		
+		return workflowBundle;
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-language/blob/c08405cb/taverna-scufl2-api/src/test/java/org/apache/taverna/scufl2/api/TestAPICreation.java
----------------------------------------------------------------------
diff --git a/taverna-scufl2-api/src/test/java/org/apache/taverna/scufl2/api/TestAPICreation.java b/taverna-scufl2-api/src/test/java/org/apache/taverna/scufl2/api/TestAPICreation.java
new file mode 100644
index 0000000..6f1f7be
--- /dev/null
+++ b/taverna-scufl2-api/src/test/java/org/apache/taverna/scufl2/api/TestAPICreation.java
@@ -0,0 +1,122 @@
+package org.apache.taverna.scufl2.api;
+
+/*
+ * 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.io.FileOutputStream;
+import java.net.URI;
+import java.util.Collections;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.Marshaller;
+
+import org.apache.taverna.scufl2.api.activity.Activity;
+import org.apache.taverna.scufl2.api.container.WorkflowBundle;
+import org.apache.taverna.scufl2.api.core.DataLink;
+import org.apache.taverna.scufl2.api.core.Processor;
+import org.apache.taverna.scufl2.api.core.Workflow;
+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.Profile;
+import org.junit.Ignore;
+import org.junit.Test;
+
+
+public class TestAPICreation {
+
+	private WorkflowBundle ro;
+
+	@Test
+	public void makeExampleWorkflow() throws Exception {
+
+		ro = new WorkflowBundle();
+		Workflow wf1 = new Workflow();
+		ro.setWorkflows(Collections.singleton(wf1));
+		ro.setMainWorkflow(wf1);
+
+		assertEquals("Non-empty input ports", Collections.EMPTY_SET, wf1.getInputPorts());
+
+		InputWorkflowPort i = new InputWorkflowPort(wf1, "I");
+		assertEquals("Did not add input port 'I'", Collections.singleton(i), wf1
+				.getInputPorts());
+
+		OutputWorkflowPort wf1_out1 = new OutputWorkflowPort(wf1, "out1");
+		assertTrue("Did not add 'out1' to list of output ports", wf1
+				.getOutputPorts().contains(wf1_out1));
+
+		new OutputWorkflowPort(wf1, "out1");
+
+		assertTrue("Unexpected processors", wf1.getProcessors().isEmpty());
+		Processor p1 = new Processor(wf1, "p1");
+		assertTrue("Did not add processor", wf1.getProcessors().contains(p1));
+
+		InputProcessorPort p1_y1 = new InputProcessorPort(p1, "Y1");
+		OutputProcessorPort p1_y2 = new OutputProcessorPort(p1, "Y2");
+		p1.getOutputPorts().add(p1_y2);
+
+		Processor p4 = new Processor(wf1, "p4");
+		wf1.getProcessors().add(p4);
+		InputProcessorPort p4_x2 = new InputProcessorPort(p4, "X2");
+		p4.getInputPorts().add(p4_x2);
+		p4.getInputPorts().add(new InputProcessorPort(p4, "Y1"));
+		OutputProcessorPort p4_y = new OutputProcessorPort(p4, "Y");
+		p4.getOutputPorts().add(p4_y);
+
+		Processor pNested = new Processor(wf1, "PNested");
+		wf1.getProcessors().add(pNested);
+
+		InputProcessorPort pNested_i = new InputProcessorPort(pNested, "I");
+		pNested.getInputPorts().add(pNested_i);
+		OutputProcessorPort pNested_o = new OutputProcessorPort(pNested, "O");
+		pNested.getOutputPorts().add(pNested_o);
+
+		wf1.getDataLinks().add(new DataLink(wf1, p1_y2, pNested_i));
+
+		wf1.getDataLinks().add(new DataLink(wf1, p1_y2, p4_x2));
+
+		wf1.getDataLinks().add(new DataLink(wf1, pNested_o, p1_y1));
+
+		wf1.getDataLinks().add(new DataLink(wf1, p4_y, wf1_out1));
+
+		Activity activity = new Activity("act0");
+		Profile p = new Profile();
+		ro.getProfiles().add(p);
+		p.getActivities().add(activity);
+
+		activity.setType(URI
+				.create("http://taverna.sf.net/2009/2.1/activity/beanshell#wrongURI"));
+	}
+
+	@Ignore("Not doing XML here anymore")
+	@Test
+	public void marshal() throws Exception {
+		makeExampleWorkflow();
+		JAXBContext jc = JAXBContext.newInstance(WorkflowBundle.class );
+		Marshaller marshaller = jc.createMarshaller();
+		marshaller.setProperty( Marshaller.JAXB_FORMATTED_OUTPUT,
+				Boolean.TRUE );
+		marshaller.marshal( ro, new FileOutputStream("target/foo.xml") );
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-language/blob/c08405cb/taverna-scufl2-api/src/test/java/org/apache/taverna/scufl2/api/TestAbstractRevisioned.java
----------------------------------------------------------------------
diff --git a/taverna-scufl2-api/src/test/java/org/apache/taverna/scufl2/api/TestAbstractRevisioned.java b/taverna-scufl2-api/src/test/java/org/apache/taverna/scufl2/api/TestAbstractRevisioned.java
new file mode 100644
index 0000000..2dd8adf
--- /dev/null
+++ b/taverna-scufl2-api/src/test/java/org/apache/taverna/scufl2/api/TestAbstractRevisioned.java
@@ -0,0 +1,55 @@
+package org.apache.taverna.scufl2.api;
+
+/*
+ * 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.UUID;
+
+import org.apache.taverna.scufl2.api.container.WorkflowBundle;
+import org.apache.taverna.scufl2.api.core.Workflow;
+import org.apache.taverna.scufl2.api.profiles.Profile;
+import org.junit.Test;
+
+
+public class TestAbstractRevisioned {
+    @Test
+    public void profileName() throws Exception {
+        Profile p = new Profile();
+        UUID uuid = UUID.fromString(p.getName());
+        assertEquals(4, uuid.version());
+        
+    }
+    
+    @Test
+    public void workflow() throws Exception {
+        Workflow wf = new Workflow();
+        UUID uuid = UUID.fromString(wf.getName());
+        assertEquals(4, uuid.version());
+    }
+    
+    @Test
+    public void workflowBundle() throws Exception {
+        WorkflowBundle wfBundle = new WorkflowBundle();
+        UUID uuid = UUID.fromString(wfBundle.getName());
+        assertEquals(4, uuid.version());
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-language/blob/c08405cb/taverna-scufl2-api/src/test/java/org/apache/taverna/scufl2/api/TestExampleWorkflow.java
----------------------------------------------------------------------
diff --git a/taverna-scufl2-api/src/test/java/org/apache/taverna/scufl2/api/TestExampleWorkflow.java b/taverna-scufl2-api/src/test/java/org/apache/taverna/scufl2/api/TestExampleWorkflow.java
new file mode 100644
index 0000000..9744a32
--- /dev/null
+++ b/taverna-scufl2-api/src/test/java/org/apache/taverna/scufl2/api/TestExampleWorkflow.java
@@ -0,0 +1,33 @@
+package org.apache.taverna.scufl2.api;
+
+/*
+ * 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 org.junit.Test;
+
+public class TestExampleWorkflow extends ExampleWorkflow {
+
+	@Test
+	public void makeflowBundle() throws Exception {
+		makeWorkflowBundle();
+		// TODO: Check fields
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-language/blob/c08405cb/taverna-scufl2-api/src/test/java/org/apache/taverna/scufl2/api/VisitorTest.java
----------------------------------------------------------------------
diff --git a/taverna-scufl2-api/src/test/java/org/apache/taverna/scufl2/api/VisitorTest.java b/taverna-scufl2-api/src/test/java/org/apache/taverna/scufl2/api/VisitorTest.java
new file mode 100644
index 0000000..c6b877b
--- /dev/null
+++ b/taverna-scufl2-api/src/test/java/org/apache/taverna/scufl2/api/VisitorTest.java
@@ -0,0 +1,100 @@
+package org.apache.taverna.scufl2.api;
+
+/*
+ * 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 static org.junit.Assert.fail;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Stack;
+
+import org.apache.taverna.scufl2.api.common.Child;
+import org.apache.taverna.scufl2.api.common.Visitor;
+import org.apache.taverna.scufl2.api.common.WorkflowBean;
+import org.apache.taverna.scufl2.api.container.WorkflowBundle;
+import org.junit.Test;
+
+
+public class VisitorTest {
+	@SuppressWarnings({ "rawtypes", "unchecked" })
+	@Test
+	public void visitAll() throws Exception {
+
+		final List<WorkflowBean> enters = new ArrayList<WorkflowBean>();
+		final List<WorkflowBean> leaves = new ArrayList<WorkflowBean>();
+		final List<WorkflowBean> visits = new ArrayList<WorkflowBean>();
+		final Stack<WorkflowBean> stack = new Stack<WorkflowBean>();
+
+		WorkflowBundle example = new ExampleWorkflow().makeWorkflowBundle();
+
+		example.accept(new Visitor() {
+
+			@Override
+			public boolean visit(WorkflowBean node) {
+				visits.add(node);
+				return true;
+			}
+
+			@Override
+			public boolean visitEnter(WorkflowBean node) {
+				if (enters.contains(node)) {
+					fail("Duplicate enter on " + node);
+				}
+				if (leaves.contains(node)) {
+					fail("Leave before enter on " + node);
+				}
+				stack.add(node);
+
+				enters.add(node);
+				return true;
+			}
+
+			@Override
+			public boolean visitLeave(WorkflowBean node) {
+				leaves.add(node);
+				assertEquals(stack.pop(), node);
+				assertTrue(enters.contains(node));
+				return true;
+			}
+		});
+		assertTrue(stack.isEmpty());
+		assertEquals(enters.size(), leaves.size());
+
+		HashSet entersSet = new HashSet(enters);
+		HashSet leavesSet = new HashSet(leaves);
+		assertEquals(entersSet, leavesSet);
+		assertEquals(enters.size(), entersSet.size());
+
+		for (WorkflowBean b : visits) {
+			if (b instanceof Child) {
+				Child child = (Child) b;
+				WorkflowBean parent = child.getParent();
+				assertTrue(enters.contains(parent));
+			} else {
+				fail("Bean is not a Child");
+			}
+		}
+
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-language/blob/c08405cb/taverna-scufl2-api/src/test/java/org/apache/taverna/scufl2/api/annotation/TestAnnotations.java
----------------------------------------------------------------------
diff --git a/taverna-scufl2-api/src/test/java/org/apache/taverna/scufl2/api/annotation/TestAnnotations.java b/taverna-scufl2-api/src/test/java/org/apache/taverna/scufl2/api/annotation/TestAnnotations.java
new file mode 100644
index 0000000..1f8468b
--- /dev/null
+++ b/taverna-scufl2-api/src/test/java/org/apache/taverna/scufl2/api/annotation/TestAnnotations.java
@@ -0,0 +1,36 @@
+package org.apache.taverna.scufl2.api.annotation;
+
+/*
+ * 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 org.apache.taverna.scufl2.api.annotation.Annotation;
+import org.apache.taverna.scufl2.api.container.WorkflowBundle;
+
+public class TestAnnotations {
+	
+	
+	public void addAnnotation() {
+		WorkflowBundle wfBundle = new WorkflowBundle();
+		Annotation ann = new Annotation();
+		wfBundle.getAnnotations().add(ann);
+		
+	}
+	
+}

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/AllBeansVisitor.java
----------------------------------------------------------------------
diff --git a/taverna-scufl2-api/src/test/java/org/apache/taverna/scufl2/api/common/AllBeansVisitor.java b/taverna-scufl2-api/src/test/java/org/apache/taverna/scufl2/api/common/AllBeansVisitor.java
new file mode 100644
index 0000000..f148f83
--- /dev/null
+++ b/taverna-scufl2-api/src/test/java/org/apache/taverna/scufl2/api/common/AllBeansVisitor.java
@@ -0,0 +1,53 @@
+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 java.util.ArrayList;
+import java.util.List;
+
+import org.apache.taverna.scufl2.api.common.Visitor;
+import org.apache.taverna.scufl2.api.common.WorkflowBean;
+import org.apache.taverna.scufl2.api.common.Visitor.VisitorWithPath;
+
+
+public class AllBeansVisitor extends VisitorWithPath implements Visitor {
+
+	private final List<WorkflowBean> allBeans = new ArrayList<WorkflowBean>();
+	
+	@Override
+	public boolean visit() {
+		getAllBeans().add(getCurrentNode());
+		return true;
+	}
+
+	public List<WorkflowBean> getAllBeans() {
+		return allBeans;
+	}
+	
+	public static List<WorkflowBean> allBeansFrom(WorkflowBean bean) {
+		AllBeansVisitor visitor = new AllBeansVisitor();
+		bean.accept(visitor);
+		return visitor.getAllBeans();
+	}
+
+	
+
+}

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/TestAbstractCloneable.java
----------------------------------------------------------------------
diff --git a/taverna-scufl2-api/src/test/java/org/apache/taverna/scufl2/api/common/TestAbstractCloneable.java b/taverna-scufl2-api/src/test/java/org/apache/taverna/scufl2/api/common/TestAbstractCloneable.java
new file mode 100644
index 0000000..7acea9d
--- /dev/null
+++ b/taverna-scufl2-api/src/test/java/org/apache/taverna/scufl2/api/common/TestAbstractCloneable.java
@@ -0,0 +1,183 @@
+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.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.taverna.scufl2.api.common.AbstractCloneable;
+import org.apache.taverna.scufl2.api.common.Child;
+import org.apache.taverna.scufl2.api.common.WorkflowBean;
+import org.apache.taverna.scufl2.api.container.WorkflowBundle;
+import org.apache.taverna.scufl2.api.core.Processor;
+import org.apache.taverna.scufl2.api.core.Workflow;
+import org.apache.taverna.scufl2.api.io.TestWorkflowBundleIO;
+import org.apache.taverna.scufl2.api.profiles.ProcessorBinding;
+import org.apache.taverna.scufl2.api.profiles.Profile;
+import org.junit.Before;
+import org.junit.Test;
+
+
+public class TestAbstractCloneable {
+	private WorkflowBundle originalWfBundle;
+	private List<WorkflowBean> originalBeans;
+
+	@Before
+	public void makeExampleWorkflow() {
+		originalWfBundle = new TestWorkflowBundleIO().makeWorkflowBundle();
+		originalBeans = AllBeansVisitor.allBeansFrom(originalWfBundle);
+	}
+
+	@Test
+	public void cloneBundle() throws Exception {
+		AbstractCloneable clone = originalWfBundle.clone();
+		// AbstractCloneable clone = originalWfBundle;
+
+		List<WorkflowBean> stillOriginalBeans = AllBeansVisitor
+				.allBeansFrom(originalWfBundle);
+		System.out.println(stillOriginalBeans);
+		assertEquals(originalBeans.size(), stillOriginalBeans.size());
+		// All original beans should be identical
+		assertEquals(originalBeans.size(),
+				findCommonById(originalBeans, stillOriginalBeans).size());
+
+		List<WorkflowBean> clonedBeans = AllBeansVisitor.allBeansFrom(clone);
+		List<WorkflowBean> common = findCommonById(originalBeans, clonedBeans);
+		assertTrue("Found some common beans: " + common, common.isEmpty());
+		//
+		// Check parents are present
+		checkParents(originalBeans);
+		checkParents(stillOriginalBeans);
+		checkParents(clonedBeans);
+	}
+
+	@Test
+	public void cloneWorkflow() throws Exception {
+		Workflow original = originalWfBundle.getMainWorkflow();
+		assertEquals(originalWfBundle, original.getParent());
+		Workflow clone = (Workflow) original.clone();
+		assertNull(clone.getParent());
+		assertEquals(original.getName(), clone.getName());
+		assertNotSame(original.getProcessors().getByName("Hello"), clone
+				.getProcessors().getByName("Hello"));
+		assertNotSame(original.getCurrentRevision(), clone.getCurrentRevision());
+		assertEquals(original.getCurrentRevision(), clone.getCurrentRevision());
+
+	}
+
+	@Test
+	public void cloneProfile() throws Exception {
+		Profile original = originalWfBundle.getMainProfile();
+		assertEquals(originalWfBundle, original.getParent());
+		Profile clone = (Profile) original.clone();
+		assertNull(clone.getParent());
+		assertEquals(original.getName(), clone.getName());
+
+		ProcessorBinding originalBinding = original.getProcessorBindings()
+				.getByName("Hello");
+		ProcessorBinding cloneBinding = clone.getProcessorBindings().getByName(
+				"Hello");
+		assertNotSame(originalBinding, cloneBinding);
+		assertNotSame(originalBinding.getBoundActivity(),
+				cloneBinding.getBoundActivity());
+		// but processor is the same, as we did not clone the workflow
+		assertSame(originalBinding.getBoundProcessor(),
+				cloneBinding.getBoundProcessor());
+	}
+
+	@Test
+	public void cloneProcessor() throws Exception {
+		Workflow wf = originalWfBundle.getMainWorkflow();
+		Processor original = wf.getProcessors().getByName("Hello");
+		Processor clone = (Processor) original.clone();
+		assertEquals(clone.getName(), original.getName());
+		assertNotNull(original.getParent());
+		assertNull(clone.getParent());
+		
+		wf.getProcessors().addWithUniqueName(clone);
+		assertTrue(!clone.getName().equals(original.getName()));
+		// Now it is safe to set the parent without loosing original
+		clone.setParent(wf);
+		
+		assertSame(original, wf.getProcessors().getByName("Hello"));
+		assertSame(clone, wf.getProcessors().getByName(clone.getName()));
+	}
+
+	@Test
+	public void nullParentNotCopied() throws Exception {
+		Workflow wf = new Workflow();
+		Processor orphan = new Processor();
+		orphan.setName("orphan");
+		// NOTE: NOT calling
+		// orphan.setParent(wf)
+		wf.getProcessors().add(orphan);
+
+		assertNull(orphan.getParent());
+
+		Workflow clone = (Workflow) wf.clone();
+		assertTrue(clone.getProcessors().isEmpty());
+
+		orphan.setParent(wf);
+
+		Workflow clone2 = (Workflow) wf.clone();
+		assertEquals(Collections.singleton("orphan"), clone2.getProcessors()
+				.getNames());
+
+	}
+
+	public static void checkParents(List<WorkflowBean> beans) {
+		for (WorkflowBean b : beans) {
+			if (b instanceof Child) {
+				@SuppressWarnings("rawtypes")
+				Child child = (Child) b;
+				if (child.getParent() == null) {
+					System.err.println("No parent? " + child);
+					continue;
+				}
+				if (!beans.contains(child.getParent())) {
+					fail("Unknown parent for " + child + " "
+							+ child.getParent());
+				}
+			}
+		}
+	}
+
+	public static <T> List<T> findCommonById(List<T> listA, List<T> listB) {
+		List<T> common = new ArrayList<T>();
+		for (T a : listA) {
+			int bIndex = listB.indexOf(a);
+			if (bIndex < 0) {
+				// System.err.println("Missing " + a);
+				continue;
+			}
+			T b = listB.get(bIndex);
+			if (a == b) {
+				common.add(a);
+			} else {
+				// System.err.println("Non-identical equals " + a + " " + b);
+			}
+		}
+		return common;
+	}
+}

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/TestAbstractNamed.java
----------------------------------------------------------------------
diff --git a/taverna-scufl2-api/src/test/java/org/apache/taverna/scufl2/api/common/TestAbstractNamed.java b/taverna-scufl2-api/src/test/java/org/apache/taverna/scufl2/api/common/TestAbstractNamed.java
new file mode 100644
index 0000000..58b338e
--- /dev/null
+++ b/taverna-scufl2-api/src/test/java/org/apache/taverna/scufl2/api/common/TestAbstractNamed.java
@@ -0,0 +1,127 @@
+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.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+import java.util.HashSet;
+
+import org.apache.taverna.scufl2.api.core.Processor;
+import org.apache.taverna.scufl2.api.core.Workflow;
+import org.junit.Test;
+
+
+@SuppressWarnings({ "rawtypes", "unchecked" })
+public class TestAbstractNamed {
+
+	@Test
+	public void replaceOnRename() throws Exception {
+		Workflow wf = new Workflow();
+		Processor fish = new Processor(wf, "fish");
+		@SuppressWarnings("unused")
+		Processor soup = new Processor(wf, "soup");
+		assertEquals(2, wf.getProcessors().size());
+
+		assertEquals(new HashSet(Arrays.asList("fish", "soup")), wf
+				.getProcessors().getNames());
+		fish.setName("soup");
+		assertEquals(new HashSet(Arrays.asList("soup")), wf
+				.getProcessors().getNames());
+		assertEquals(1, wf.getProcessors().size());
+
+		assertEquals(fish, wf.getProcessors().iterator().next());
+		assertEquals(fish, wf.getProcessors().getByName("soup"));
+		assertNull(wf.getProcessors().getByName("fish"));
+	}
+	
+	
+	@Test(expected=NullPointerException.class)
+    public void nameNull() throws Exception {
+        Processor p = new Processor();
+        p.setName(null);
+    }
+	
+    @Test(expected=IllegalArgumentException.class)
+    public void nameEmpty() throws Exception {
+        Processor p = new Processor();
+        p.setName("");
+    }
+	
+    @Test(expected=IllegalArgumentException.class)
+    public void nameWithNewline() throws Exception {
+        Processor p = new Processor();
+        p.setName("new\nline");
+    }
+    
+
+    @Test(expected=IllegalArgumentException.class)
+    public void nameWithControlChar() throws Exception {
+        Processor p = new Processor();
+        p.setName("no\bell");
+    }
+
+    @Test(expected=IllegalArgumentException.class)
+    public void nameWithColon() throws Exception {
+        Processor p = new Processor();
+        p.setName("not:url");
+    }
+    
+    @Test(expected=IllegalArgumentException.class)
+    public void nameWithSlash() throws Exception {
+        Processor p = new Processor();
+        p.setName("no/slash");
+    }
+    
+    @Test
+    public void nameWithSpace() throws Exception {
+        Processor p = new Processor();
+        p.setName("space allowed");
+    }
+
+    
+	@Test
+	public void setName() throws Exception {
+		Workflow wf = new Workflow();
+		Processor p = new Processor();
+		p.setName("fish");
+		p.setName("soup");
+		p.setParent(wf);
+	}
+
+	@Test
+	public void setNameWithParent() throws Exception {
+		Workflow wf = new Workflow();
+		Processor p = new Processor();
+		p.setName("fish");
+		p.setParent(wf);
+		assertTrue(wf.getProcessors().contains(p));
+		assertTrue(wf.getProcessors().containsName("fish"));
+		assertFalse(wf.getProcessors().containsName("soup"));
+		p.setName("soup");
+		assertFalse(wf.getProcessors().containsName("fish"));
+		assertTrue(wf.getProcessors().containsName("soup"));
+	}
+
+}

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/TestScufl2Tools.java
----------------------------------------------------------------------
diff --git a/taverna-scufl2-api/src/test/java/org/apache/taverna/scufl2/api/common/TestScufl2Tools.java b/taverna-scufl2-api/src/test/java/org/apache/taverna/scufl2/api/common/TestScufl2Tools.java
new file mode 100644
index 0000000..5880253
--- /dev/null
+++ b/taverna-scufl2-api/src/test/java/org/apache/taverna/scufl2/api/common/TestScufl2Tools.java
@@ -0,0 +1,481 @@
+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.assertNotNull;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.taverna.scufl2.api.ExampleWorkflow;
+import org.apache.taverna.scufl2.api.activity.Activity;
+import org.apache.taverna.scufl2.api.common.Child;
+import org.apache.taverna.scufl2.api.common.Scufl2Tools;
+import org.apache.taverna.scufl2.api.common.WorkflowBean;
+import org.apache.taverna.scufl2.api.common.Visitor.VisitorWithPath;
+import org.apache.taverna.scufl2.api.container.WorkflowBundle;
+import org.apache.taverna.scufl2.api.core.ControlLink;
+import org.apache.taverna.scufl2.api.core.Processor;
+import org.apache.taverna.scufl2.api.port.InputActivityPort;
+import org.apache.taverna.scufl2.api.port.InputProcessorPort;
+import org.apache.taverna.scufl2.api.port.OutputActivityPort;
+import org.apache.taverna.scufl2.api.port.OutputProcessorPort;
+import 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.apache.taverna.scufl2.api.profiles.ProcessorPortBinding;
+import org.apache.taverna.scufl2.api.profiles.Profile;
+import org.junit.Before;
+import org.junit.Test;
+
+
+public class TestScufl2Tools extends ExampleWorkflow {
+
+	private Scufl2Tools scufl2Tools = new Scufl2Tools();
+
+	@Before
+	public void makeBundle() {
+		makeWorkflowBundle();
+		assertNotNull(workflowBundle);
+	}
+	
+	@Test
+	public void controlLinksBlocking() {
+		Processor hello = workflowBundle.getMainWorkflow().getProcessors()
+				.getByName("Hello");
+		Processor wait4me = workflowBundle.getMainWorkflow().getProcessors()
+				.getByName("wait4me");
+		ControlLink controlLink = workflowBundle.getMainWorkflow().getControlLinks()
+				.iterator().next();
+
+		assertEquals(Collections.singletonList(controlLink),
+				scufl2Tools.controlLinksBlocking(hello));
+		assertTrue(scufl2Tools.controlLinksBlocking(wait4me).isEmpty());
+	}
+
+	@Test
+	public void controlLinksWaitingFor() {
+		Processor hello = workflowBundle.getMainWorkflow().getProcessors()
+				.getByName("Hello");
+		Processor wait4me = workflowBundle.getMainWorkflow().getProcessors()
+				.getByName("wait4me");
+		ControlLink controlLink = workflowBundle.getMainWorkflow().getControlLinks()
+				.iterator().next();
+
+		assertEquals(Collections.singletonList(controlLink),
+				scufl2Tools.controlLinksWaitingFor(wait4me));
+		assertTrue(scufl2Tools.controlLinksWaitingFor(hello).isEmpty());
+	}
+
+	@Test
+	public void processorPortBindingForInputActivityPort() throws Exception {
+		Profile profile = workflowBundle.getMainProfile();
+		Activity helloScript = profile.getActivities().getByName("HelloScript");
+		InputActivityPort port = helloScript.getInputPorts().getByName(
+				"personName");
+		ProcessorBinding processorBinding = profile.getProcessorBindings()
+				.getByName("Hello");
+		ProcessorInputPortBinding inputPortBinding = processorBinding
+				.getInputPortBindings().iterator().next();
+		assertSame(inputPortBinding,
+				scufl2Tools.processorPortBindingForPort(port, profile));
+	}
+
+	@Test
+	public void processorPortBindingForInputProcessorPort() throws Exception {
+		Profile profile = workflowBundle.getMainProfile();
+		Processor hello = workflowBundle.getMainWorkflow().getProcessors()
+				.getByName("Hello");
+		InputProcessorPort port = hello.getInputPorts().getByName("name");
+		ProcessorBinding processorBinding = profile.getProcessorBindings()
+				.getByName("Hello");
+		ProcessorInputPortBinding inputPortBinding = processorBinding
+				.getInputPortBindings().iterator().next();
+		assertSame(inputPortBinding,
+				scufl2Tools.processorPortBindingForPort(port, profile));
+	}
+
+	@Test
+	public void processorPortBindingForOutputActivityPort() throws Exception {
+		Profile profile = workflowBundle.getMainProfile();
+		Activity helloScript = profile.getActivities().getByName("HelloScript");
+		OutputActivityPort port = helloScript.getOutputPorts().getByName(
+				"hello");
+		ProcessorBinding processorBinding = profile.getProcessorBindings()
+				.getByName("Hello");
+		ProcessorOutputPortBinding outputPortBinding = processorBinding
+				.getOutputPortBindings().iterator().next();
+		assertSame(outputPortBinding,
+				scufl2Tools.processorPortBindingForPort(port, profile));
+	}
+
+	@Test
+	public void processorPortBindingForOutputProcessorPort() throws Exception {
+		Profile profile = workflowBundle.getMainProfile();
+		Processor hello = workflowBundle.getMainWorkflow().getProcessors()
+				.getByName("Hello");
+		OutputProcessorPort port = hello.getOutputPorts().getByName("greeting");
+		ProcessorBinding processorBinding = profile.getProcessorBindings()
+				.getByName("Hello");
+		ProcessorOutputPortBinding outputPortBinding = processorBinding
+				.getOutputPortBindings().iterator().next();
+		assertSame(outputPortBinding,
+				scufl2Tools.processorPortBindingForPort(port, profile));
+	}
+
+	@Test
+	public void createProcessorFromActivity() throws Exception {
+		Profile profile = new Profile();
+		Activity a = new Activity();
+		a.setParent(profile);
+		new InputActivityPort(a, "in1");
+		new InputActivityPort(a, "in2").setDepth(1);		
+		new OutputActivityPort(a, "out1");
+		new OutputActivityPort(a, "out2").setDepth(0);		
+		OutputActivityPort aOut3 = new OutputActivityPort(a, "out3");
+		aOut3.setDepth(2);
+		aOut3.setGranularDepth(1);
+		
+		ProcessorBinding binding = scufl2Tools.createProcessorAndBindingFromActivity(a);
+		Processor p = binding.getBoundProcessor();
+		assertEquals(profile, binding.getParent());
+		
+		assertEquals(2, p.getInputPorts().size());
+		assertEquals(3, p.getOutputPorts().size());
+		assertEquals(2, binding.getInputPortBindings().size());
+		assertEquals(3, binding.getOutputPortBindings().size());
+		assertEquals(a, binding.getBoundActivity());
+		assertEquals(p, binding.getBoundProcessor());
+
+	}
+	
+
+	@Test
+	public void createActivityFromProcessor() throws Exception {
+		Processor p = new Processor();
+		new InputProcessorPort(p, "in1");
+		new InputProcessorPort(p, "in2").setDepth(1);
+		
+		new OutputProcessorPort(p, "out1");
+		new OutputProcessorPort(p, "out2").setDepth(0);
+		
+		OutputProcessorPort pOut3 = new OutputProcessorPort(p, "out3");
+		pOut3.setDepth(2);
+		pOut3.setGranularDepth(1);	
+
+		Profile profile = new Profile();
+		Activity a = scufl2Tools.createActivityFromProcessor(p, profile);
+		
+		assertEquals(profile, a.getParent());
+		ProcessorBinding binding = scufl2Tools.processorBindingForProcessor(p, profile);
+		
+		assertEquals(2, a.getInputPorts().size());
+		assertEquals(3, a.getOutputPorts().size());
+		assertEquals(2, binding.getInputPortBindings().size());
+		assertEquals(3, binding.getOutputPortBindings().size());
+		assertEquals(a, binding.getBoundActivity());
+		assertEquals(p, binding.getBoundProcessor());	
+	}
+	
+	@SuppressWarnings({ "unchecked", "rawtypes" })
+	@Test
+	public void updatePortBindingByMatchingPorts() throws Exception {
+		Processor p = new Processor();
+		new InputProcessorPort(p, "in1");
+		new InputProcessorPort(p, "in2");
+		new OutputProcessorPort(p, "out1");		
+		new OutputProcessorPort(p, "out2");
+		Profile profile = new Profile();
+		Activity a = scufl2Tools.createActivityFromProcessor(p, profile);
+		ProcessorBinding binding = scufl2Tools.processorBindingsToActivity(a).get(0);
+		
+		// Add some
+		new InputProcessorPort(p, "new1");
+		new InputProcessorPort(p, "new2");
+		new InputActivityPort(a, "new1");
+		new InputActivityPort(a, "new2");
+		new OutputProcessorPort(p, "new3");
+		new OutputProcessorPort(p, "new4");
+		new OutputActivityPort(a, "new4");
+		new OutputActivityPort(a, "new5");
+		// And remove some
+		p.getInputPorts().removeByName("in2");
+		a.getOutputPorts().removeByName("out1");
+		
+		scufl2Tools.updateBindingByMatchingPorts(binding);
+		
+//		assertEquals(3, binding.getInputPortBindings().size());
+//		assertEquals(2, binding.getOutputPortBindings().size());
+
+		Set<String> namesIn = procPortNames(binding.getInputPortBindings());
+		Set<String> namesOut = procPortNames(binding.getOutputPortBindings());
+		assertEquals(new HashSet(Arrays.asList("in1", "new1", "new2")), namesIn);
+		assertEquals(new HashSet(Arrays.asList("out2", "new4")), namesOut);		
+	}
+	
+	
+	@SuppressWarnings("rawtypes")
+	private Set<String> procPortNames(
+			Set<? extends ProcessorPortBinding> portBindings) {
+		Set<String> names = new HashSet<String>();
+		for (ProcessorPortBinding portBinding : portBindings) {
+			names.add(portBinding.getBoundProcessorPort().getName());
+		}
+		return names;
+	}
+
+	@Test
+	public void setParents() throws Exception {
+		// Deliberately orphan a profile and a processor
+		Profile profile = workflowBundle.getProfiles().getByName("tavernaWorkbench");
+		profile.setParent(null);		
+		workflowBundle.getProfiles().add(profile);		
+		processor.setParent(null);
+		workflow.getProcessors().add(processor);
+		
+		assertNull(processor.getParent());
+		assertNull(profile.getParent());		
+		scufl2Tools.setParents(workflowBundle);
+		assertNotNull(processor.getParent());
+		assertNotNull(profile.getParent());				
+
+	}
+
+	@Test
+	public void setParentsAllBeans() throws Exception {
+		AllBeansVisitor visitBefore = new AllBeansVisitor();
+		workflowBundle.accept(visitBefore);
+		scufl2Tools.setParents(workflowBundle);		
+		AllBeansVisitor visitAfter = new AllBeansVisitor();
+		workflowBundle.accept(visitAfter);
+		// Ensure we did not loose or double-add anyone
+		assertEquals(visitBefore.getAllBeans(), visitAfter.getAllBeans());		
+	}
+		
+
+	@Test
+	public void setParentsAllBeansAgain() throws Exception {
+		AllBeansVisitor visitBefore = new AllBeansVisitor();
+		workflowBundle.accept(visitBefore);
+		setParentsAgain(workflowBundle);		
+		AllBeansVisitor visitAfter = new AllBeansVisitor();
+		workflowBundle.accept(visitAfter);
+		// Ensure we did not loose or double-add anyone
+		assertEquals(visitBefore.getAllBeans().toString(), visitAfter.getAllBeans().toString());	
+	}
+
+	/**
+	 * A slight variation of {@link Scufl2Tools#setParents(org.apache.taverna.scufl2.api.container.WorkflowBundle)}
+	 * that always set a new parent
+	 * @param wfBundle 
+	 * @throws Exception
+	 */
+	public void setParentsAgain(WorkflowBundle wfBundle) throws Exception {
+		wfBundle.accept(new VisitorWithPath() {			
+			@SuppressWarnings({ "unchecked", "rawtypes" })
+			@Override
+			public boolean visit() {
+				WorkflowBean node = getCurrentNode();
+				if (node instanceof Child) {
+					Child child = (Child) node;
+					WorkflowBean parent = getCurrentPath().peek();
+					child.setParent(parent);
+				}
+				return true;
+			}
+		});
+	}
+
+	@Test
+	public void createActivityPortsFromProcessor() throws Exception {
+		Processor p = new Processor();
+		new InputProcessorPort(p, "in1");
+		new InputProcessorPort(p, "in2").setDepth(1);
+		
+		new OutputProcessorPort(p, "out1");
+		new OutputProcessorPort(p, "out2").setDepth(0);
+		
+		OutputProcessorPort pOut3 = new OutputProcessorPort(p, "out3");
+		pOut3.setDepth(2);
+		pOut3.setGranularDepth(1);
+		
+		
+		Activity a = new Activity();
+		scufl2Tools.createActivityPortsFromProcessor(a, p);
+		
+		
+		assertEquals(2, a.getInputPorts().size());
+		InputActivityPort aIn1 = a.getInputPorts().getByName("in1");
+		assertNull(aIn1.getDepth());
+		InputActivityPort aIn2 = a.getInputPorts().getByName("in2");
+		assertEquals(1, aIn2.getDepth().intValue());
+		
+		assertEquals(3, a.getOutputPorts().size());
+		OutputActivityPort aOut1 = a.getOutputPorts().getByName("out1");
+		assertEquals(null, aOut1.getDepth());
+		assertEquals(null, aOut1.getGranularDepth());
+		
+		OutputActivityPort aOut2 = a.getOutputPorts().getByName("out2");
+		assertEquals(0, aOut2.getDepth().intValue());
+		assertEquals(null, aOut2.getGranularDepth());
+		
+		OutputActivityPort aOut3 = a.getOutputPorts().getByName("out3");
+		assertEquals(2, aOut3.getDepth().intValue());
+		assertEquals(1, aOut3.getGranularDepth().intValue());		
+	}
+
+	@Test
+	public void createActivityPortsFromProcessorWithOverwrite() throws Exception {
+		Processor p = new Processor();
+		new InputProcessorPort(p, "in1");
+		new OutputProcessorPort(p, "out1");
+		new OutputProcessorPort(p, "out2").setDepth(1);
+
+		
+		Activity a = new Activity();
+		new InputActivityPort(a, "other");
+		OutputActivityPort toBeOverWritten = new OutputActivityPort(a, "out1");
+		toBeOverWritten.setDepth(1);
+		assertEquals(a, toBeOverWritten.getParent());
+		
+		
+		scufl2Tools.createActivityPortsFromProcessor(a, p);
+		// Still there
+		assertNotNull(a.getInputPorts().getByName("other"));
+		
+		// but out1 has been overwritten
+ 		OutputActivityPort aOut1 = a.getOutputPorts().getByName("out1");
+		assertNull(aOut1.getDepth());
+		assertNotSame(toBeOverWritten, aOut1);		
+	}
+
+	
+	
+	@Test
+	public void createProcessorPortsFromActivity() throws Exception {
+		Activity a = new Activity();
+		new InputActivityPort(a, "in1");
+		new InputActivityPort(a, "in2").setDepth(1);
+		
+		new OutputActivityPort(a, "out1");
+		new OutputActivityPort(a, "out2").setDepth(0);
+		
+		OutputActivityPort aOut3 = new OutputActivityPort(a, "out3");
+		aOut3.setDepth(2);
+		aOut3.setGranularDepth(1);
+		
+		
+		Processor p = new Processor();
+		scufl2Tools.createProcessorPortsFromActivity(p, a);
+		
+		
+		assertEquals(2, p.getInputPorts().size());
+		InputProcessorPort pIn1 = p.getInputPorts().getByName("in1");
+		assertNull(pIn1.getDepth());
+		InputProcessorPort pIn2 = p.getInputPorts().getByName("in2");
+		assertEquals(1, pIn2.getDepth().intValue());
+		
+		assertEquals(3, p.getOutputPorts().size());
+		OutputProcessorPort pOut1 = p.getOutputPorts().getByName("out1");
+		assertEquals(null, pOut1.getDepth());
+		assertEquals(null, pOut1.getGranularDepth());
+		
+		OutputProcessorPort pOut2 = p.getOutputPorts().getByName("out2");
+		assertEquals(0, pOut2.getDepth().intValue());
+		assertEquals(null, pOut2.getGranularDepth());
+		
+		OutputProcessorPort pOut3 = p.getOutputPorts().getByName("out3");
+		assertEquals(2, pOut3.getDepth().intValue());
+		assertEquals(1, pOut3.getGranularDepth().intValue());		
+	}
+
+	@Test
+	public void createProcessorPortsFromActivityWithOverwrite() throws Exception {
+		Activity a = new Activity();
+
+		new InputActivityPort(a, "in1");
+		
+		new OutputActivityPort(a, "out1");
+		new OutputActivityPort(a, "out2").setDepth(1);
+
+		Processor p = new Processor();
+		new InputProcessorPort(p, "other");
+		OutputProcessorPort toBeOverWritten = new OutputProcessorPort(p, "out1");
+		toBeOverWritten.setDepth(1);
+		assertEquals(p, toBeOverWritten.getParent());
+		
+		
+		scufl2Tools.createProcessorPortsFromActivity(p, a);
+		// Still there
+		assertNotNull(p.getInputPorts().getByName("other"));
+		
+		// but out1 has been overwritten
+ 		OutputProcessorPort pOut1 = p.getOutputPorts().getByName("out1");
+		assertNull(pOut1.getDepth());
+		assertNotSame(toBeOverWritten, pOut1);
+	}
+	
+	
+	@Test
+	public void bindActivityToProcessorByMatchingPorts() throws Exception {
+		Processor p = new Processor();
+		new InputProcessorPort(p, "in1");
+		new InputProcessorPort(p, "in2");
+		new OutputProcessorPort(p, "out1");
+		new OutputProcessorPort(p, "out2");
+		new OutputProcessorPort(p, "out3");
+		
+		Activity a = new Activity();
+		new InputActivityPort(a, "in1");
+		// in2 missing
+		new InputActivityPort(a, "in3"); // additional in3
+		new OutputActivityPort(a, "out1");
+		// out2 missing
+		new OutputActivityPort(a, "out3");
+		new OutputActivityPort(a, "out4"); // additional out4
+
+		ProcessorBinding binding = scufl2Tools.bindActivityToProcessorByMatchingPorts(a, p);
+		assertEquals(a, binding.getBoundActivity());
+		assertEquals(p, binding.getBoundProcessor());
+		assertEquals(1, binding.getInputPortBindings().size());
+		ProcessorInputPortBinding inBinding = binding.getInputPortBindings().iterator().next();
+		assertEquals(p.getInputPorts().getByName("in1"), inBinding.getBoundProcessorPort());
+		assertEquals(a.getInputPorts().getByName("in1"), inBinding.getBoundActivityPort());
+		
+		assertEquals(2, binding.getOutputPortBindings().size());
+		// should be out1 and out3
+		for (ProcessorOutputPortBinding outBinding : binding.getOutputPortBindings()) {
+			assertEquals(outBinding.getBoundActivityPort().getName(),
+						outBinding.getBoundProcessorPort().getName());
+			assertEquals(a, outBinding.getBoundActivityPort().getParent());
+			assertEquals(p, outBinding.getBoundProcessorPort().getParent());
+		}
+		
+	}
+}
+

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/TestSetParent.java
----------------------------------------------------------------------
diff --git a/taverna-scufl2-api/src/test/java/org/apache/taverna/scufl2/api/common/TestSetParent.java b/taverna-scufl2-api/src/test/java/org/apache/taverna/scufl2/api/common/TestSetParent.java
new file mode 100644
index 0000000..e026614
--- /dev/null
+++ b/taverna-scufl2-api/src/test/java/org/apache/taverna/scufl2/api/common/TestSetParent.java
@@ -0,0 +1,60 @@
+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 org.apache.taverna.scufl2.api.ExampleWorkflow;
+import org.apache.taverna.scufl2.api.common.Child;
+import org.apache.taverna.scufl2.api.common.Scufl2Tools;
+import org.apache.taverna.scufl2.api.common.WorkflowBean;
+import org.apache.taverna.scufl2.api.common.Visitor.VisitorWithPath;
+import org.apache.taverna.scufl2.api.container.WorkflowBundle;
+import org.junit.Test;
+
+
+public class TestSetParent {
+	WorkflowBundle example = new ExampleWorkflow().makeWorkflowBundle();
+
+	Scufl2Tools tools = new Scufl2Tools();
+
+	@Test
+	public void checkParents() throws Exception {
+		example.accept(new VisitorWithPath() {
+			@SuppressWarnings("rawtypes")
+			@Override
+			public boolean visit() {
+				WorkflowBean node = getCurrentNode();
+				if (node instanceof Child) {
+					Child child = (Child) node;
+					WorkflowBean parent = child.getParent();
+					WorkflowBean expectedParent = getCurrentPath().peek();
+					if (!(parent == expectedParent)) {
+						throw new IllegalStateException("Wrong parent for "
+								+ node + ": " + parent + ", expected: "
+								+ expectedParent);
+					}
+				}
+				return true;
+			}
+
+		});
+	}
+
+}