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

[28/51] [partial] incubator-taverna-engine git commit:

http://git-wip-us.apache.org/repos/asf/incubator-taverna-engine/blob/5f1ddb71/taverna-run-api/src/main/java/uk/org/taverna/platform/run/api/RunProfile.java
----------------------------------------------------------------------
diff --git a/taverna-run-api/src/main/java/uk/org/taverna/platform/run/api/RunProfile.java b/taverna-run-api/src/main/java/uk/org/taverna/platform/run/api/RunProfile.java
deleted file mode 100644
index deecf8e..0000000
--- a/taverna-run-api/src/main/java/uk/org/taverna/platform/run/api/RunProfile.java
+++ /dev/null
@@ -1,196 +0,0 @@
-package uk.org.taverna.platform.run.api;
-
-import org.apache.taverna.robundle.Bundle;
-
-import uk.org.taverna.platform.execution.api.ExecutionEnvironment;
-import org.apache.taverna.scufl2.api.container.WorkflowBundle;
-
-/**
- * A <code>RunProfile</code> specifies the parameters required to run a
- * {@link org.apache.taverna.scufl2.api.core.Workflow}.
- * 
- * @author David Withers
- */
-public class RunProfile {
-	private ExecutionEnvironment executionEnvironment;
-	private WorkflowBundle workflowBundle;
-	private Bundle dataBundle;
-	private String workflowName;
-	private String profileName;
-
-	/**
-	 * Constructs a <code>RunProfile</code> that specifies the parameters
-	 * required to run a {@link org.apache.taverna.scufl2.api.core.Workflow}. The
-	 * main <code>Workflow</code> and <code>Profile</code> from the
-	 * <code>WorkflowBundle</code> are used.
-	 * 
-	 * @param executionEnvironment
-	 *            the {@link ExecutionEnvironment} used to execute the
-	 *            <code>Workflow</code>
-	 * @param workflowBundle
-	 *            the <code>WorkflowBundle</code> containing the
-	 *            <code>Workflow</code> to run
-	 * @param dataBundle
-	 *            the <code>Bundle</code> containing the data values for the
-	 *            <code>Workflow</code>
-	 */
-	public RunProfile(ExecutionEnvironment executionEnvironment,
-			WorkflowBundle workflowBundle, Bundle dataBundle) {
-		this(executionEnvironment, workflowBundle, null, null, dataBundle);
-	}
-
-	/**
-	 * Constructs a <code>RunProfile</code> that specifies the parameters
-	 * required to run a {@link org.apache.taverna.scufl2.api.core.Workflow}.
-	 * 
-	 * @param executionEnvironment
-	 *            the {@link ExecutionEnvironment} used to execute the
-	 *            <code>Workflow</code>
-	 * @param workflowBundle
-	 *            the <code>WorkflowBundle</code> containing the
-	 *            <code>Workflow</code> to run
-	 * @param workflow
-	 *            the <code>Workflow</code> to run. If <code>null</code> uses
-	 *            the main <code>Workflow</code> from the
-	 *            <code>WorkflowBundle</code>
-	 * @param profile
-	 *            the {@link org.apache.taverna.scufl2.api.profiles.Profile} to use
-	 *            when running the <code>Workflow</code>. If null uses the main
-	 *            <code>Profile</code> from the <code>WorkflowBundle</code>
-	 * @param dataBundle
-	 *            the <code>Bundle</code> containing the data values for the
-	 *            <code>Workflow</code>
-	 */
-	public RunProfile(ExecutionEnvironment executionEnvironment,
-			WorkflowBundle workflowBundle, String workflowName,
-			String profileName, Bundle dataBundle) {
-		this.executionEnvironment = executionEnvironment;
-		this.workflowBundle = workflowBundle;
-		this.workflowName = workflowName;
-		this.profileName = profileName;
-		this.dataBundle = dataBundle;
-	}
-
-	/**
-	 * Returns the <code>WorkflowBundle</code>.
-	 * 
-	 * @return the <code>WorkflowBundle</code>
-	 */
-	public WorkflowBundle getWorkflowBundle() {
-		return workflowBundle;
-	}
-
-	/**
-	 * Sets the <code>WorkflowBundle</code> containing the <code>Workflow</code>
-	 * to run.
-	 * 
-	 * @param workflowBundle
-	 *            the <code>WorkflowBundle</code> containing the
-	 *            <code>Workflow</code> to run
-	 */
-	public void setWorkflowBundle(WorkflowBundle workflowBundle) {
-		this.workflowBundle = workflowBundle;
-	}
-
-	/**
-	 * Returns the name of the <code>Workflow</code> to run. If no
-	 * <code>Workflow</code> name is set the main <code>Workflow</code> from the
-	 * <code>WorkflowBundle</code> will be run.
-	 * 
-	 * @return the <code>Workflow</code> to run
-	 */
-	public String getWorkflowName() {
-		if (workflowName == null && workflowBundle.getMainWorkflow() != null)
-			return workflowBundle.getMainWorkflow().getName();
-		return workflowName;
-	}
-
-	/**
-	 * Sets the name of the <code>Workflow</code> to run. If no
-	 * <code>Workflow</code> name is set the main <code>Workflow</code> from the
-	 * <code>WorkflowBundle</code> will be run.
-	 * 
-	 * @param workflowName
-	 *            the name of the <code>Workflow</code> to run
-	 */
-	public void setWorkflowName(String workflowName) {
-		this.workflowName = workflowName;
-	}
-
-	/**
-	 * Returns the name of the <code>Profile</code> to use when running the
-	 * <code>Workflow</code>. If no <code>Profile</code> name is set the main
-	 * <code>Profile</code> from the <code>WorkflowBundle</code> will be used.
-	 * 
-	 * @return the <code>Profile</code> to use when running the
-	 *         <code>Workflow</code>
-	 */
-	public String getProfileName() {
-		if (profileName == null && workflowBundle.getMainProfile() != null) {
-			return workflowBundle.getMainProfile().getName();
-		}
-		return profileName;
-	}
-
-	/**
-	 * Sets the name of the <code>Profile</code> to use when running the
-	 * <code>Workflow</code>.
-	 * <p>
-	 * If no <code>Profile</code> name is set the main <code>Profile</code> from
-	 * the <code>WorkflowBundle</code> will be used.
-	 * 
-	 * @param profileName
-	 *            the name of the <code>Profile</code> to use when running the
-	 *            <code>Workflow</code>
-	 */
-	public void setProfileName(String profileName) {
-		this.profileName = profileName;
-	}
-
-	/**
-	 * Returns the <code>Bundle</code> containing the data values for the
-	 * <code>Workflow</code>.
-	 * 
-	 * @return the <code>Bundle</code> containing the data values for the
-	 *         <code>Workflow</code>
-	 */
-	public Bundle getDataBundle() {
-		return dataBundle;
-	}
-
-	/**
-	 * Sets the <code>Bundle</code> containing the data values for the
-	 * <code>Workflow</code>.
-	 * 
-	 * @param dataBundle
-	 *            the <code>Bundle</code> containing the data values for the
-	 *            <code>Workflow</code>
-	 */
-	public void setDataBundle(Bundle dataBundle) {
-		this.dataBundle = dataBundle;
-	}
-
-	/**
-	 * Returns the <code>ExecutionEnvironment</code> used to execute the
-	 * <code>Workflow</code>.
-	 * 
-	 * @return the <code>ExecutionEnvironment</code> used to execute the
-	 *         <code>Workflow</code>
-	 */
-	public ExecutionEnvironment getExecutionEnvironment() {
-		return executionEnvironment;
-	}
-
-	/**
-	 * Sets the <code>ExecutionEnvironment</code> used to execute the
-	 * <code>Workflow</code>.
-	 * 
-	 * @param executionEnvironment
-	 *            the <code>ExecutionEnvironment</code> used to execute the
-	 *            <code>Workflow</code>
-	 */
-	public void setExecutionEnvironment(
-			ExecutionEnvironment executionEnvironment) {
-		this.executionEnvironment = executionEnvironment;
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-engine/blob/5f1ddb71/taverna-run-api/src/main/java/uk/org/taverna/platform/run/api/RunProfileException.java
----------------------------------------------------------------------
diff --git a/taverna-run-api/src/main/java/uk/org/taverna/platform/run/api/RunProfileException.java b/taverna-run-api/src/main/java/uk/org/taverna/platform/run/api/RunProfileException.java
deleted file mode 100644
index c6477d3..0000000
--- a/taverna-run-api/src/main/java/uk/org/taverna/platform/run/api/RunProfileException.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*******************************************************************************
- * Copyright (C) 2010 The University of Manchester   
- * 
- *  Modifications to the initial code base are copyright of their
- *  respective authors, or their employers as appropriate.
- * 
- *  This program is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public License
- *  as published by the Free Software Foundation; either version 2.1 of
- *  the License, or (at your option) any later version.
- *    
- *  This program is distributed in the hope that it will be useful, but
- *  WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  Lesser General Public License for more details.
- *    
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- ******************************************************************************/
-package uk.org.taverna.platform.run.api;
-
-/**
- * Thrown when a <code>RunProfile</code> doesn't contain the correct components
- * to run a workflow.
- * 
- * @author David Withers
- */
-public class RunProfileException extends Exception {
-	private static final long serialVersionUID = 4717267498382223527L;
-
-	public RunProfileException() {
-		super();
-	}
-
-	public RunProfileException(String message, Throwable cause) {
-		super(message, cause);
-	}
-
-	public RunProfileException(String message) {
-		super(message);
-	}
-
-	public RunProfileException(Throwable cause) {
-		super(cause);
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-engine/blob/5f1ddb71/taverna-run-api/src/main/java/uk/org/taverna/platform/run/api/RunService.java
----------------------------------------------------------------------
diff --git a/taverna-run-api/src/main/java/uk/org/taverna/platform/run/api/RunService.java b/taverna-run-api/src/main/java/uk/org/taverna/platform/run/api/RunService.java
deleted file mode 100644
index 03705d7..0000000
--- a/taverna-run-api/src/main/java/uk/org/taverna/platform/run/api/RunService.java
+++ /dev/null
@@ -1,235 +0,0 @@
-package uk.org.taverna.platform.run.api;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.List;
-import java.util.Set;
-
-import org.apache.taverna.robundle.Bundle;
-
-import uk.org.taverna.platform.execution.api.ExecutionEnvironment;
-import uk.org.taverna.platform.execution.api.InvalidExecutionIdException;
-import uk.org.taverna.platform.execution.api.InvalidWorkflowException;
-import uk.org.taverna.platform.report.State;
-import uk.org.taverna.platform.report.WorkflowReport;
-import org.apache.taverna.scufl2.api.container.WorkflowBundle;
-import org.apache.taverna.scufl2.api.core.Workflow;
-import org.apache.taverna.scufl2.api.profiles.Profile;
-
-/**
- * Service for managing runs of Taverna workflows.
- * 
- * @author David Withers
- */
-public interface RunService {
-	String EVENT_TOPIC_ROOT = "uk/org/taverna/platform/run/RunService/";
-	String RUN_CREATED = EVENT_TOPIC_ROOT + "RUN_CREATED";
-	String RUN_DELETED = EVENT_TOPIC_ROOT + "RUN_DELETED";
-	String RUN_STARTED = EVENT_TOPIC_ROOT + "RUN_STARTED";
-	String RUN_STOPPED = EVENT_TOPIC_ROOT + "RUN_STOPPED";
-	String RUN_PAUSED = EVENT_TOPIC_ROOT + "RUN_PAUSED";
-	String RUN_RESUMED = EVENT_TOPIC_ROOT + "RUN_RESUMED";
-	String RUN_OPENED = EVENT_TOPIC_ROOT + "RUN_OPENED";
-	String RUN_CLOSED = EVENT_TOPIC_ROOT + "RUN_CLOSED";
-
-	/**
-	 * Returns the available <code>ExecutionEnvironment</code>s.
-	 * 
-	 * @return the available <code>ExecutionEnvironment</code>s
-	 */
-	Set<ExecutionEnvironment> getExecutionEnvironments();
-
-	/**
-	 * Returns the <code>ExecutionEnvironment</code>s that can execute the
-	 * specified <code>WorkflowBundle</code> using its default
-	 * <code>Profile</code>.
-	 * 
-	 * @param workflowBundle
-	 *            the <code>WorkflowBundle</code> to find
-	 *            <code>ExecutionEnvironment</code>s for
-	 * @return the <code>ExecutionEnvironment</code>s that can execute the
-	 *         specified <code>WorkflowBundle</code>
-	 */
-	Set<ExecutionEnvironment> getExecutionEnvironments(
-			WorkflowBundle workflowBundle);
-
-	/**
-	 * Returns the <code>ExecutionEnvironment</code>s that can execute the
-	 * specified <code>Profile</code>.
-	 * 
-	 * @param profile
-	 *            the <code>Profile</code> to find
-	 *            <code>ExecutionEnvironment</code>s for
-	 * @return the <code>ExecutionEnvironment</code>s that can execute the
-	 *         specified <code>Profile</code>
-	 */
-	Set<ExecutionEnvironment> getExecutionEnvironments(Profile profile);
-
-	/**
-	 * Creates a new run and returns the ID for the run.
-	 * 
-	 * To start the run use the {@link #start(String)} method.
-	 * 
-	 * @param runProfile
-	 *            the workflow to run
-	 * @return the run ID
-	 * @throws InvalidWorkflowException
-	 * @throws RunProfileException
-	 */
-	String createRun(RunProfile runProfile) throws InvalidWorkflowException,
-			RunProfileException;
-
-	/**
-	 * Returns the list of runs that this service is managing.
-	 * <p>
-	 * If there are no runs this method returns an empty list.
-	 * 
-	 * @return the list of runs that this service is managing
-	 */
-	List<String> getRuns();
-
-	/**
-	 * Opens a run and returns the ID for the run.
-	 * 
-	 * @param runFile
-	 *            the workflow run to open
-	 * @return the run ID
-	 * @throws InvalidWorkflowException
-	 * @throws RunProfileException
-	 */
-	String open(File runFile) throws IOException;
-
-	/**
-	 * Closes a run.
-	 * 
-	 * @param runID
-	 *            the ID of the run
-	 * @throws InvalidRunIdException
-	 *             if the run ID is not valid
-	 * @throws InvalidExecutionIdException
-	 */
-	void close(String runID) throws InvalidRunIdException,
-			InvalidExecutionIdException;
-
-	/**
-	 * Saves a run.
-	 * 
-	 * @param runID
-	 *            the ID of the run
-	 * @throws InvalidRunIdException
-	 *             if the run ID is not valid
-	 * @throws InvalidExecutionIdException
-	 */
-	void save(String runID, File runFile) throws InvalidRunIdException,
-			IOException;
-
-	/**
-	 * Deletes a run.
-	 * 
-	 * @param runID
-	 *            the ID of the run
-	 * @throws InvalidRunIdException
-	 *             if the run ID is not valid
-	 * @throws InvalidExecutionIdException
-	 */
-	void delete(String runID) throws InvalidRunIdException,
-			InvalidExecutionIdException;
-
-	/**
-	 * Starts a run.
-	 * 
-	 * @param runID
-	 *            the ID of the run
-	 * @throws InvalidRunIdException
-	 *             if the run ID is not valid
-	 * @throws RunStateException
-	 *             if the run state is not CREATED
-	 * @throws InvalidExecutionIdException
-	 */
-	void start(String runID) throws InvalidRunIdException, RunStateException,
-			InvalidExecutionIdException;
-
-	/**
-	 * Pauses a running run.
-	 * 
-	 * @param runID
-	 *            the ID of the run
-	 * @throws InvalidRunIdException
-	 *             if the run ID is not valid
-	 * @throws RunStateException
-	 *             if the run state is not RUNNING
-	 * @throws InvalidExecutionIdException
-	 */
-	void pause(String runID) throws InvalidRunIdException, RunStateException,
-			InvalidExecutionIdException;
-
-	/**
-	 * Resumes a paused run.
-	 * 
-	 * @param runID
-	 *            the ID of the run
-	 * @throws InvalidRunIdException
-	 *             if the run ID is not valid
-	 * @throws RunStateException
-	 *             if the run state is not PAUSED
-	 * @throws InvalidExecutionIdException
-	 */
-	void resume(String runID) throws InvalidRunIdException, RunStateException,
-			InvalidExecutionIdException;
-
-	/**
-	 * Cancels a running or paused run.
-	 * 
-	 * @param runID
-	 *            the ID of the run
-	 * @throws InvalidRunIdException
-	 *             if the run ID is not valid
-	 * @throws RunStateException
-	 *             if the run state is not RUNNING or PAUSED
-	 * @throws InvalidExecutionIdException
-	 */
-	void cancel(String runID) throws InvalidRunIdException, RunStateException,
-			InvalidExecutionIdException;
-
-	/**
-	 * Returns the current state of the run.
-	 * 
-	 * A run's state can be CREATED, RUNNING, COMPLETED, PAUSED, CANCELLED or
-	 * FAILED.
-	 * 
-	 * @param runID
-	 *            the ID of the run
-	 * @return the current state of the run
-	 * @throws InvalidRunIdException
-	 *             if the run ID is not valid
-	 */
-	State getState(String runID) throws InvalidRunIdException;
-
-	/**
-	 * Returns the <code>Bundle</code> containing the data values of the run.
-	 * 
-	 * @param runID
-	 *            the ID of the run
-	 * @return the <code>Databundle</code> containing the data values of the run
-	 * @throws InvalidRunIdException
-	 *             if the run ID is not valid
-	 */
-	Bundle getDataBundle(String runID) throws InvalidRunIdException;
-
-	/**
-	 * Returns the status report for the run.
-	 * 
-	 * @param runID
-	 *            the ID of the run
-	 * @return the status report for the run
-	 * @throws InvalidRunIdException
-	 *             if the run ID is not valid
-	 */
-	WorkflowReport getWorkflowReport(String runID) throws InvalidRunIdException;
-
-	Workflow getWorkflow(String runID) throws InvalidRunIdException;
-
-	Profile getProfile(String runID) throws InvalidRunIdException;
-
-	String getRunName(String runID) throws InvalidRunIdException;
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-taverna-engine/blob/5f1ddb71/taverna-run-api/src/main/java/uk/org/taverna/platform/run/api/RunStateException.java
----------------------------------------------------------------------
diff --git a/taverna-run-api/src/main/java/uk/org/taverna/platform/run/api/RunStateException.java b/taverna-run-api/src/main/java/uk/org/taverna/platform/run/api/RunStateException.java
deleted file mode 100644
index 56cd032..0000000
--- a/taverna-run-api/src/main/java/uk/org/taverna/platform/run/api/RunStateException.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*******************************************************************************
- * Copyright (C) 2010 The University of Manchester   
- * 
- *  Modifications to the initial code base are copyright of their
- *  respective authors, or their employers as appropriate.
- * 
- *  This program is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public License
- *  as published by the Free Software Foundation; either version 2.1 of
- *  the License, or (at your option) any later version.
- *    
- *  This program is distributed in the hope that it will be useful, but
- *  WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  Lesser General Public License for more details.
- *    
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- ******************************************************************************/
-package uk.org.taverna.platform.run.api;
-
-/**
- * Thrown when an operation is attempted when a workflow is in the wrong state,
- * e.g., resuming a workflow that is not paused.
- * 
- * @author David Withers
- */
-public class RunStateException extends Exception {
-	private static final long serialVersionUID = 6759341273715906131L;
-
-	public RunStateException() {
-		super();
-	}
-
-	public RunStateException(String message, Throwable cause) {
-		super(message, cause);
-	}
-
-	public RunStateException(String message) {
-		super(message);
-	}
-
-	public RunStateException(Throwable cause) {
-		super(cause);
-	}
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-engine/blob/5f1ddb71/taverna-run-api/src/test/java/org/apache/taverna/platform/run/api/RunProfileTest.java
----------------------------------------------------------------------
diff --git a/taverna-run-api/src/test/java/org/apache/taverna/platform/run/api/RunProfileTest.java b/taverna-run-api/src/test/java/org/apache/taverna/platform/run/api/RunProfileTest.java
new file mode 100644
index 0000000..4144eb6
--- /dev/null
+++ b/taverna-run-api/src/test/java/org/apache/taverna/platform/run/api/RunProfileTest.java
@@ -0,0 +1,232 @@
+/*
+* 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.
+*/
+
+package org.apache.taverna.platform.run.api;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.apache.taverna.robundle.Bundle;
+
+import org.apache.taverna.databundle.DataBundles;
+import org.apache.taverna.platform.execution.api.ExecutionEnvironment;
+import org.apache.taverna.platform.execution.impl.local.LocalExecutionEnvironment;
+import org.apache.taverna.platform.execution.impl.local.LocalExecutionService;
+import org.apache.taverna.scufl2.api.container.WorkflowBundle;
+import org.apache.taverna.scufl2.api.core.Workflow;
+import org.apache.taverna.scufl2.api.profiles.Profile;
+
+/**
+ *
+ *
+ * @author David Withers
+ */
+@Ignore
+public class RunProfileTest {
+
+	private RunProfile runProfile;
+	private ExecutionEnvironment executionEnvironment;
+	private WorkflowBundle workflowBundle;
+	private LocalExecutionService executionService;
+	private Workflow workflow, mainWorkflow;
+	private Profile profile, mainProfile;
+	private Bundle dataBundle;
+
+	/**
+	 * @throws java.lang.Exception
+	 */
+	@Before
+	public void setUp() throws Exception {
+		workflow = new Workflow();
+		mainWorkflow = new Workflow();
+		profile = new Profile();
+		mainProfile = new Profile();
+		workflowBundle = new WorkflowBundle();
+		workflowBundle.setMainProfile(mainProfile);
+		workflowBundle.setMainWorkflow(mainWorkflow);
+		executionService = new LocalExecutionService();
+		executionEnvironment = new LocalExecutionEnvironment(executionService, null, null);
+
+		dataBundle = DataBundles.createBundle();
+		runProfile = new RunProfile(executionEnvironment, workflowBundle, workflow.getName(), profile.getName(), dataBundle);
+	}
+
+	/**
+	 * Test method for
+	 * {@link uk.org.taverna.platform.run.api.RunProfile#RunProfile(org.apache.taverna.scufl2.api.container.WorkflowBundle, java.util.Map, org.apache.taverna.reference.ReferenceService, org.apache.taverna.platform.execution.api.ExecutionService)}
+	 * .
+	 */
+	@Test
+	public void testRunProfileWorkflowBundleMapOfStringT2ReferenceReferenceServiceExecutionService() {
+		runProfile = new RunProfile(executionEnvironment, workflowBundle, dataBundle);
+	}
+
+	/**
+	 * Test method for
+	 * {@link org.apache.taverna.platform.run.api.RunProfile#RunProfile(org.apache.taverna.scufl2.api.container.WorkflowBundle, org.apache.taverna.scufl2.api.core.Workflow, org.apache.taverna.scufl2.api.profiles.Profile, java.util.Map, org.apache.taverna.reference.ReferenceService, org.apache.taverna.platform.execution.api.ExecutionService)}
+	 * .
+	 */
+	@Test
+	public void testRunProfileWorkflowBundleWorkflowProfileMapOfStringT2ReferenceReferenceServiceExecutionService() {
+		runProfile = new RunProfile(executionEnvironment, workflowBundle, workflow.getName(), profile.getName(), dataBundle);
+	}
+
+	/**
+	 * Test method for
+	 * {@link org.apache.taverna.platform.run.api.RunProfile#getWorkflowBundle()}.
+	 */
+	@Test
+	public void testGetWorkflowBundle() {
+		assertNotNull(runProfile.getWorkflowBundle());
+		assertEquals(workflowBundle, runProfile.getWorkflowBundle());
+		assertEquals(runProfile.getWorkflowBundle(), runProfile.getWorkflowBundle());
+	}
+
+	/**
+	 * Test method for
+	 * {@link org.apache.taverna.platform.run.api.RunProfile#setWorkflowBundle(org.apache.taverna.scufl2.api.container.WorkflowBundle)}
+	 * .
+	 */
+	@Test
+	public void testSetWorkflowBundle() {
+		runProfile.setWorkflowBundle(null);
+		assertNull(runProfile.getWorkflowBundle());
+		runProfile.setWorkflowBundle(workflowBundle);
+		assertEquals(workflowBundle, runProfile.getWorkflowBundle());
+	}
+
+	/**
+	 * Test method for
+	 * {@link uk.org.taverna.platform.run.api.RunProfile#getWorkflow()}.
+	 */
+	@Test
+	public void testGetWorkflow() {
+		assertNotNull(runProfile.getWorkflowName());
+		assertEquals(workflow.getName(), runProfile.getWorkflowName());
+		assertEquals(runProfile.getWorkflowName(), runProfile.getWorkflowName());
+		runProfile.setWorkflowName(null);
+		assertNotNull(runProfile.getWorkflowName());
+		assertEquals(mainWorkflow.getName(), runProfile.getWorkflowName());
+	}
+
+	/**
+	 * Test method for
+	 * {@link uk.org.taverna.platform.run.api.RunProfile#setWorkflow(org.apache.taverna.scufl2.api.core.Workflow)}
+	 * .
+	 */
+	@Test
+	public void testSetWorkflow() {
+		runProfile.setWorkflowName(null);
+		assertNotNull(runProfile.getWorkflowName());
+		assertEquals(mainWorkflow.getName(), runProfile.getWorkflowName());
+		runProfile.setWorkflowBundle(new WorkflowBundle());
+		runProfile.setWorkflowName(null);
+		assertNull(runProfile.getWorkflowName());
+		runProfile.setWorkflowName(workflow.getName());
+		assertEquals(workflow.getName(), runProfile.getWorkflowName());
+		runProfile.setWorkflowName(mainWorkflow.getName());
+		assertEquals(mainWorkflow.getName(), runProfile.getWorkflowName());
+	}
+
+	/**
+	 * Test method for
+	 * {@link uk.org.taverna.platform.run.api.RunProfile#getProfile()}.
+	 */
+	@Test
+	public void testGetProfile() {
+		assertNotNull(runProfile.getProfileName());
+		assertEquals(profile.getName(), runProfile.getProfileName());
+		assertEquals(runProfile.getProfileName(), runProfile.getProfileName());
+		runProfile.setProfileName(null);
+		assertNotNull(runProfile.getProfileName());
+		assertEquals(mainProfile.getName(), runProfile.getProfileName());
+	}
+
+	/**
+	 * Test method for
+	 * {@link uk.org.taverna.platform.run.api.RunProfile#setProfile(org.apache.taverna.scufl2.api.profiles.Profile)}
+	 * .
+	 */
+	@Test
+	public void testSetProfile() {
+		runProfile.setProfileName(null);
+		assertNotNull(runProfile.getProfileName());
+		assertEquals(mainProfile.getName(), runProfile.getProfileName());
+		runProfile.setWorkflowBundle(new WorkflowBundle());
+		runProfile.setProfileName(null);
+		assertNull(runProfile.getProfileName());
+		runProfile.setProfileName(profile.getName());
+		assertEquals(profile.getName(), runProfile.getProfileName());
+		runProfile.setProfileName(mainProfile.getName());
+		assertEquals(mainProfile.getName(), runProfile.getProfileName());
+	}
+
+	/**
+	 * Test method for
+	 * {@link uk.org.taverna.platform.run.api.RunProfile#getDataBundle()}.
+	 */
+	@Test
+	public void testGetDataBundle() {
+		assertNotNull(runProfile.getDataBundle());
+		assertEquals(dataBundle, runProfile.getDataBundle());
+		assertEquals(runProfile.getDataBundle(), runProfile.getDataBundle());
+	}
+
+	/**
+	 * Test method for
+	 * {@link uk.org.taverna.platform.run.api.RunProfile#setDataBundle(org.apache.taverna.robundle.Bundle)}
+	 * .
+	 */
+	@Test
+	public void testSetDataBundle() {
+		runProfile.setDataBundle(null);
+		assertNull(runProfile.getDataBundle());
+		runProfile.setDataBundle(dataBundle);
+		assertEquals(dataBundle, runProfile.getDataBundle());
+	}
+
+	/**
+	 * Test method for
+	 * {@link uk.org.taverna.platform.run.api.RunProfile#getExecutionEnvironment()}.
+	 */
+	@Test
+	public void testGetExecutionEnvironment() {
+		assertNotNull(runProfile.getExecutionEnvironment());
+		assertEquals(executionEnvironment, runProfile.getExecutionEnvironment());
+		assertEquals(runProfile.getExecutionEnvironment(), runProfile.getExecutionEnvironment());
+	}
+
+	/**
+	 * Test method for
+	 * {@link uk.org.taverna.platform.run.api.RunProfile#setExecutionEnvironment(uk.org.taverna.platform.execution.api.ExecutionEnvironment)}
+	 * .
+	 */
+	@Test
+	public void testSetExecutionEnvironment() {
+		runProfile.setExecutionEnvironment(null);
+		assertNull(runProfile.getExecutionEnvironment());
+		runProfile.setExecutionEnvironment(executionEnvironment);
+		assertEquals(executionEnvironment, runProfile.getExecutionEnvironment());
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-engine/blob/5f1ddb71/taverna-run-api/src/test/java/uk/org/taverna/platform/run/api/RunProfileTest.java
----------------------------------------------------------------------
diff --git a/taverna-run-api/src/test/java/uk/org/taverna/platform/run/api/RunProfileTest.java b/taverna-run-api/src/test/java/uk/org/taverna/platform/run/api/RunProfileTest.java
deleted file mode 100644
index ec3830a..0000000
--- a/taverna-run-api/src/test/java/uk/org/taverna/platform/run/api/RunProfileTest.java
+++ /dev/null
@@ -1,233 +0,0 @@
-/*******************************************************************************
- * Copyright (C) 2011 The University of Manchester
- *
- *  Modifications to the initial code base are copyright of their
- *  respective authors, or their employers as appropriate.
- *
- *  This program is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public License
- *  as published by the Free Software Foundation; either version 2.1 of
- *  the License, or (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful, but
- *  WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- ******************************************************************************/
-package uk.org.taverna.platform.run.api;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-
-import org.junit.Before;
-import org.junit.Ignore;
-import org.junit.Test;
-import org.apache.taverna.robundle.Bundle;
-
-import org.apache.taverna.databundle.DataBundles;
-import uk.org.taverna.platform.execution.api.ExecutionEnvironment;
-import uk.org.taverna.platform.execution.impl.local.LocalExecutionEnvironment;
-import uk.org.taverna.platform.execution.impl.local.LocalExecutionService;
-import org.apache.taverna.scufl2.api.container.WorkflowBundle;
-import org.apache.taverna.scufl2.api.core.Workflow;
-import org.apache.taverna.scufl2.api.profiles.Profile;
-
-/**
- *
- *
- * @author David Withers
- */
-@Ignore
-public class RunProfileTest {
-
-	private RunProfile runProfile;
-	private ExecutionEnvironment executionEnvironment;
-	private WorkflowBundle workflowBundle;
-	private LocalExecutionService executionService;
-	private Workflow workflow, mainWorkflow;
-	private Profile profile, mainProfile;
-	private Bundle dataBundle;
-
-	/**
-	 * @throws java.lang.Exception
-	 */
-	@Before
-	public void setUp() throws Exception {
-		workflow = new Workflow();
-		mainWorkflow = new Workflow();
-		profile = new Profile();
-		mainProfile = new Profile();
-		workflowBundle = new WorkflowBundle();
-		workflowBundle.setMainProfile(mainProfile);
-		workflowBundle.setMainWorkflow(mainWorkflow);
-		executionService = new LocalExecutionService();
-		executionEnvironment = new LocalExecutionEnvironment(executionService, null, null);
-
-		dataBundle = DataBundles.createBundle();
-		runProfile = new RunProfile(executionEnvironment, workflowBundle, workflow.getName(), profile.getName(), dataBundle);
-	}
-
-	/**
-	 * Test method for
-	 * {@link uk.org.taverna.platform.run.api.RunProfile#RunProfile(org.apache.taverna.scufl2.api.container.WorkflowBundle, java.util.Map, net.sf.taverna.t2.reference.ReferenceService, uk.org.taverna.platform.execution.api.ExecutionService)}
-	 * .
-	 */
-	@Test
-	public void testRunProfileWorkflowBundleMapOfStringT2ReferenceReferenceServiceExecutionService() {
-		runProfile = new RunProfile(executionEnvironment, workflowBundle, dataBundle);
-	}
-
-	/**
-	 * Test method for
-	 * {@link uk.org.taverna.platform.run.api.RunProfile#RunProfile(org.apache.taverna.scufl2.api.container.WorkflowBundle, org.apache.taverna.scufl2.api.core.Workflow, org.apache.taverna.scufl2.api.profiles.Profile, java.util.Map, net.sf.taverna.t2.reference.ReferenceService, uk.org.taverna.platform.execution.api.ExecutionService)}
-	 * .
-	 */
-	@Test
-	public void testRunProfileWorkflowBundleWorkflowProfileMapOfStringT2ReferenceReferenceServiceExecutionService() {
-		runProfile = new RunProfile(executionEnvironment, workflowBundle, workflow.getName(), profile.getName(), dataBundle);
-	}
-
-	/**
-	 * Test method for
-	 * {@link uk.org.taverna.platform.run.api.RunProfile#getWorkflowBundle()}.
-	 */
-	@Test
-	public void testGetWorkflowBundle() {
-		assertNotNull(runProfile.getWorkflowBundle());
-		assertEquals(workflowBundle, runProfile.getWorkflowBundle());
-		assertEquals(runProfile.getWorkflowBundle(), runProfile.getWorkflowBundle());
-	}
-
-	/**
-	 * Test method for
-	 * {@link uk.org.taverna.platform.run.api.RunProfile#setWorkflowBundle(org.apache.taverna.scufl2.api.container.WorkflowBundle)}
-	 * .
-	 */
-	@Test
-	public void testSetWorkflowBundle() {
-		runProfile.setWorkflowBundle(null);
-		assertNull(runProfile.getWorkflowBundle());
-		runProfile.setWorkflowBundle(workflowBundle);
-		assertEquals(workflowBundle, runProfile.getWorkflowBundle());
-	}
-
-	/**
-	 * Test method for
-	 * {@link uk.org.taverna.platform.run.api.RunProfile#getWorkflow()}.
-	 */
-	@Test
-	public void testGetWorkflow() {
-		assertNotNull(runProfile.getWorkflowName());
-		assertEquals(workflow.getName(), runProfile.getWorkflowName());
-		assertEquals(runProfile.getWorkflowName(), runProfile.getWorkflowName());
-		runProfile.setWorkflowName(null);
-		assertNotNull(runProfile.getWorkflowName());
-		assertEquals(mainWorkflow.getName(), runProfile.getWorkflowName());
-	}
-
-	/**
-	 * Test method for
-	 * {@link uk.org.taverna.platform.run.api.RunProfile#setWorkflow(org.apache.taverna.scufl2.api.core.Workflow)}
-	 * .
-	 */
-	@Test
-	public void testSetWorkflow() {
-		runProfile.setWorkflowName(null);
-		assertNotNull(runProfile.getWorkflowName());
-		assertEquals(mainWorkflow.getName(), runProfile.getWorkflowName());
-		runProfile.setWorkflowBundle(new WorkflowBundle());
-		runProfile.setWorkflowName(null);
-		assertNull(runProfile.getWorkflowName());
-		runProfile.setWorkflowName(workflow.getName());
-		assertEquals(workflow.getName(), runProfile.getWorkflowName());
-		runProfile.setWorkflowName(mainWorkflow.getName());
-		assertEquals(mainWorkflow.getName(), runProfile.getWorkflowName());
-	}
-
-	/**
-	 * Test method for
-	 * {@link uk.org.taverna.platform.run.api.RunProfile#getProfile()}.
-	 */
-	@Test
-	public void testGetProfile() {
-		assertNotNull(runProfile.getProfileName());
-		assertEquals(profile.getName(), runProfile.getProfileName());
-		assertEquals(runProfile.getProfileName(), runProfile.getProfileName());
-		runProfile.setProfileName(null);
-		assertNotNull(runProfile.getProfileName());
-		assertEquals(mainProfile.getName(), runProfile.getProfileName());
-	}
-
-	/**
-	 * Test method for
-	 * {@link uk.org.taverna.platform.run.api.RunProfile#setProfile(org.apache.taverna.scufl2.api.profiles.Profile)}
-	 * .
-	 */
-	@Test
-	public void testSetProfile() {
-		runProfile.setProfileName(null);
-		assertNotNull(runProfile.getProfileName());
-		assertEquals(mainProfile.getName(), runProfile.getProfileName());
-		runProfile.setWorkflowBundle(new WorkflowBundle());
-		runProfile.setProfileName(null);
-		assertNull(runProfile.getProfileName());
-		runProfile.setProfileName(profile.getName());
-		assertEquals(profile.getName(), runProfile.getProfileName());
-		runProfile.setProfileName(mainProfile.getName());
-		assertEquals(mainProfile.getName(), runProfile.getProfileName());
-	}
-
-	/**
-	 * Test method for
-	 * {@link uk.org.taverna.platform.run.api.RunProfile#getDataBundle()}.
-	 */
-	@Test
-	public void testGetDataBundle() {
-		assertNotNull(runProfile.getDataBundle());
-		assertEquals(dataBundle, runProfile.getDataBundle());
-		assertEquals(runProfile.getDataBundle(), runProfile.getDataBundle());
-	}
-
-	/**
-	 * Test method for
-	 * {@link uk.org.taverna.platform.run.api.RunProfile#setDataBundle(org.apache.taverna.robundle.Bundle)}
-	 * .
-	 */
-	@Test
-	public void testSetDataBundle() {
-		runProfile.setDataBundle(null);
-		assertNull(runProfile.getDataBundle());
-		runProfile.setDataBundle(dataBundle);
-		assertEquals(dataBundle, runProfile.getDataBundle());
-	}
-
-	/**
-	 * Test method for
-	 * {@link uk.org.taverna.platform.run.api.RunProfile#getExecutionEnvironment()}.
-	 */
-	@Test
-	public void testGetExecutionEnvironment() {
-		assertNotNull(runProfile.getExecutionEnvironment());
-		assertEquals(executionEnvironment, runProfile.getExecutionEnvironment());
-		assertEquals(runProfile.getExecutionEnvironment(), runProfile.getExecutionEnvironment());
-	}
-
-	/**
-	 * Test method for
-	 * {@link uk.org.taverna.platform.run.api.RunProfile#setExecutionEnvironment(uk.org.taverna.platform.execution.api.ExecutionEnvironment)}
-	 * .
-	 */
-	@Test
-	public void testSetExecutionEnvironment() {
-		runProfile.setExecutionEnvironment(null);
-		assertNull(runProfile.getExecutionEnvironment());
-		runProfile.setExecutionEnvironment(executionEnvironment);
-		assertEquals(executionEnvironment, runProfile.getExecutionEnvironment());
-	}
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-engine/blob/5f1ddb71/taverna-run-impl/src/main/java/org/apache/taverna/platform/run/impl/Run.java
----------------------------------------------------------------------
diff --git a/taverna-run-impl/src/main/java/org/apache/taverna/platform/run/impl/Run.java b/taverna-run-impl/src/main/java/org/apache/taverna/platform/run/impl/Run.java
new file mode 100755
index 0000000..894bc58
--- /dev/null
+++ b/taverna-run-impl/src/main/java/org/apache/taverna/platform/run/impl/Run.java
@@ -0,0 +1,278 @@
+/*
+* 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.
+*/
+
+package org.apache.taverna.platform.run.impl;
+
+import static java.util.logging.Level.WARNING;
+import static org.apache.taverna.platform.report.State.CANCELLED;
+import static org.apache.taverna.platform.report.State.COMPLETED;
+import static org.apache.taverna.platform.report.State.CREATED;
+import static org.apache.taverna.platform.report.State.FAILED;
+import static org.apache.taverna.platform.report.State.PAUSED;
+import static org.apache.taverna.platform.report.State.RUNNING;
+
+import java.io.IOException;
+import java.text.ParseException;
+import java.util.Date;
+import java.util.UUID;
+import java.util.logging.Logger;
+
+import org.apache.taverna.robundle.Bundle;
+import org.apache.taverna.robundle.manifest.Manifest;
+
+import org.apache.taverna.databundle.DataBundles;
+import org.apache.taverna.platform.execution.api.ExecutionEnvironment;
+import org.apache.taverna.platform.execution.api.InvalidExecutionIdException;
+import org.apache.taverna.platform.execution.api.InvalidWorkflowException;
+import org.apache.taverna.platform.report.State;
+import org.apache.taverna.platform.report.WorkflowReport;
+import org.apache.taverna.platform.run.api.RunProfile;
+import org.apache.taverna.platform.run.api.RunProfileException;
+import org.apache.taverna.platform.run.api.RunStateException;
+import org.apache.taverna.scufl2.api.container.WorkflowBundle;
+import org.apache.taverna.scufl2.api.core.Workflow;
+import org.apache.taverna.scufl2.api.io.ReaderException;
+import org.apache.taverna.scufl2.api.profiles.Profile;
+
+/**
+ * A single run of a {@link Workflow}.
+ * 
+ * @author David Withers
+ */
+public class Run {
+	private static final WorkflowReportJSON workflowReportJson = new WorkflowReportJSON();
+	private static final Logger logger = Logger.getLogger(Run.class.getName());
+
+	private final String ID, executionID;
+	private final ExecutionEnvironment executionEnvironment;
+	private final WorkflowReport workflowReport;
+	private final WorkflowBundle workflowBundle;
+	private final Bundle dataBundle;
+	private final Workflow workflow;
+	private final Profile profile;
+
+	/**
+	 * Constructs a <code>Run</code> from the specified <code>RunProfile</code>.
+	 * 
+	 * @param runProfile
+	 *            the profile to create a <code>Run</code> from
+	 * @throws InvalidWorkflowException
+	 *             if the <code>Workflow</code> specified by the
+	 *             <code>RunProfile</code> is not valid
+	 * @throws RunProfileException
+	 *             if the <code>RunProfile</code> does not contain the correct
+	 *             information to run a <code>Workflow</code>
+	 */
+	public Run(RunProfile runProfile) throws InvalidWorkflowException,
+			RunProfileException {
+		if (runProfile.getWorkflowBundle() == null) {
+			String message = "No WorkflowBundle specified in the RunProfile";
+			logger.warning(message);
+			throw new RunProfileException(message);
+		}
+		workflowBundle = runProfile.getWorkflowBundle();
+		if (runProfile.getWorkflowName() == null) {
+			if (workflowBundle.getMainWorkflow() == null) {
+				String message = "No Workflow specified in either the RunProfile or the WorkflowBundle";
+				logger.warning(message);
+				throw new RunProfileException(message);
+			}
+			logger.info("No Workflow specified - using the main Workflow from the WorkflowBundle");
+			workflow = workflowBundle.getMainWorkflow();
+		} else {
+			workflow = workflowBundle.getWorkflows().getByName(
+					runProfile.getWorkflowName());
+		}
+		if (runProfile.getProfileName() == null) {
+			if (workflowBundle.getMainProfile() == null) {
+				String message = "No Profile specified in either the RunProfile or the WorkflowBundle";
+				logger.warning(message);
+				throw new RunProfileException(message);
+			}
+			logger.info("No Profile specified - using the main Profile from the WorkflowBundle");
+			profile = workflowBundle.getMainProfile();
+		} else {
+			profile = workflowBundle.getProfiles().getByName(
+					runProfile.getProfileName());
+		}
+		if (runProfile.getDataBundle() == null) {
+			String message = "No DataBundle specified in the RunProfile";
+			logger.warning(message);
+			throw new RunProfileException(message);
+		}
+		dataBundle = runProfile.getDataBundle();
+		try {
+			DataBundles.setWorkflowBundle(dataBundle, workflowBundle);
+		} catch (IOException e) {
+			String message = "Could not save workflow bundle to data bundle";
+			logger.log(WARNING, message, e);
+			throw new InvalidWorkflowException(message, e);
+		}
+		if (runProfile.getExecutionEnvironment() == null) {
+			String message = "No ExecutionEnvironment specified in the RunProfile";
+			logger.warning(message);
+			throw new RunProfileException(message);
+		}
+		executionEnvironment = runProfile.getExecutionEnvironment();
+
+		ID = UUID.randomUUID().toString();
+		executionID = executionEnvironment.getExecutionService()
+				.createExecution(executionEnvironment, workflowBundle,
+						workflow, profile, dataBundle);
+		try {
+			workflowReport = executionEnvironment.getExecutionService()
+					.getWorkflowReport(executionID);
+		} catch (InvalidExecutionIdException e) {
+			String message = "Error while creating a execution on the "
+					+ executionEnvironment.getName();
+			logger.severe(message);
+			throw new RuntimeException(message, e);
+		}
+	}
+
+	public Run(String id, Bundle bundle) throws IOException, ReaderException,
+			ParseException {
+		this.ID = id;
+		executionID = null;
+		executionEnvironment = null;
+		workflowReport = workflowReportJson.load(bundle);
+		workflowBundle = DataBundles.getWorkflowBundle(bundle);
+		dataBundle = bundle;
+		workflow = workflowBundle.getMainWorkflow();
+		profile = workflowBundle.getMainProfile();
+	}
+
+	/**
+	 * Returns the identifier for this <code>Run</code>.
+	 * 
+	 * @return the identifier for this <code>Run</code>
+	 */
+	public String getID() {
+		return ID;
+	}
+
+	/**
+	 * Returns the current {@link State} of the <code>Run</code>.
+	 * 
+	 * A <code>Run</code>'s state can be CREATED, RUNNING, COMPLETED, PAUSED,
+	 * CANCELLED or FAILED.
+	 * 
+	 * @return the current <code>State</code> of the <code>Run</code>
+	 */
+	public State getState() {
+		return workflowReport.getState();
+	}
+
+	/**
+	 * Returns the <code>Bundle</code> containing the data values of the run.
+	 * <p>
+	 * 
+	 * @return the <code>Bundle</code> containing the data values for the
+	 *         <code>Workflow</code>
+	 */
+	public Bundle getDataBundle() {
+		if (getWorkflowReport() != null)
+			// Save the workflow report
+			try {
+				workflowReportJson.save(getWorkflowReport(), dataBundle);
+			} catch (IOException e) {
+				logger.log(WARNING,
+						"Can't save workflow report to data bundle", e);
+			}
+		// Update manifest
+		try {
+			Manifest manifest = new Manifest(dataBundle);
+			manifest.populateFromBundle();
+			manifest.writeAsJsonLD();
+		} catch (IOException e) {
+			logger.log(WARNING, "Can't add manifest to data bundle", e);
+		}
+		return dataBundle;
+	}
+
+	/**
+	 * Returns the status report for the run.
+	 * 
+	 * @return the status report for the run
+	 */
+	public WorkflowReport getWorkflowReport() {
+		return workflowReport;
+	}
+
+	public Workflow getWorkflow() {
+		return workflow;
+	}
+
+	public Profile getProfile() {
+		return profile;
+	}
+
+	/**
+	 * Deletes a run.
+	 * 
+	 * @throws InvalidExecutionIdException
+	 */
+	public void delete() throws InvalidExecutionIdException {
+		synchronized (workflowReport) {
+			executionEnvironment.getExecutionService().delete(executionID);
+		}
+	}
+
+	public void start() throws RunStateException, InvalidExecutionIdException {
+		synchronized (workflowReport) {
+			State state = workflowReport.getState();
+			if (!state.equals(CREATED))
+				throw new RunStateException("Cannot start a " + state + " run.");
+			executionEnvironment.getExecutionService().start(executionID);
+		}
+	}
+
+	public void pause() throws RunStateException, InvalidExecutionIdException {
+		synchronized (workflowReport) {
+			State state = workflowReport.getState();
+			if (!state.equals(RUNNING))
+				throw new RunStateException("Cannot pause a " + state + " run.");
+			executionEnvironment.getExecutionService().pause(executionID);
+			workflowReport.setPausedDate(new Date());
+		}
+	}
+
+	public void resume() throws RunStateException, InvalidExecutionIdException {
+		synchronized (workflowReport) {
+			State state = workflowReport.getState();
+			if (!state.equals(PAUSED))
+				throw new RunStateException("Cannot resume a " + state
+						+ " run.");
+			executionEnvironment.getExecutionService().resume(executionID);
+			workflowReport.setResumedDate(new Date());
+		}
+	}
+
+	public void cancel() throws RunStateException, InvalidExecutionIdException {
+		synchronized (workflowReport) {
+			State state = workflowReport.getState();
+			if (state.equals(CANCELLED) || state.equals(COMPLETED)
+					|| state.equals(FAILED))
+				throw new RunStateException("Cannot cancel a " + state
+						+ " run.");
+			executionEnvironment.getExecutionService().cancel(executionID);
+			workflowReport.setCancelledDate(new Date());
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-engine/blob/5f1ddb71/taverna-run-impl/src/main/java/org/apache/taverna/platform/run/impl/RunServiceImpl.java
----------------------------------------------------------------------
diff --git a/taverna-run-impl/src/main/java/org/apache/taverna/platform/run/impl/RunServiceImpl.java b/taverna-run-impl/src/main/java/org/apache/taverna/platform/run/impl/RunServiceImpl.java
new file mode 100755
index 0000000..f7afba3
--- /dev/null
+++ b/taverna-run-impl/src/main/java/org/apache/taverna/platform/run/impl/RunServiceImpl.java
@@ -0,0 +1,267 @@
+/*
+* 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.
+*/
+
+package org.apache.taverna.platform.run.impl;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.ClosedFileSystemException;
+import java.nio.file.InvalidPathException;
+import java.nio.file.Path;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.osgi.service.event.Event;
+import org.osgi.service.event.EventAdmin;
+import org.apache.taverna.robundle.Bundle;
+
+import org.apache.taverna.databundle.DataBundles;
+import org.apache.taverna.platform.execution.api.ExecutionEnvironment;
+import org.apache.taverna.platform.execution.api.ExecutionEnvironmentService;
+import org.apache.taverna.platform.execution.api.InvalidExecutionIdException;
+import org.apache.taverna.platform.execution.api.InvalidWorkflowException;
+import org.apache.taverna.platform.report.ReportListener;
+import org.apache.taverna.platform.report.State;
+import org.apache.taverna.platform.report.WorkflowReport;
+import org.apache.taverna.platform.run.api.InvalidRunIdException;
+import org.apache.taverna.platform.run.api.RunProfile;
+import org.apache.taverna.platform.run.api.RunProfileException;
+import org.apache.taverna.platform.run.api.RunService;
+import org.apache.taverna.platform.run.api.RunStateException;
+import org.apache.taverna.scufl2.api.container.WorkflowBundle;
+import org.apache.taverna.scufl2.api.core.Workflow;
+import org.apache.taverna.scufl2.api.io.ReaderException;
+import org.apache.taverna.scufl2.api.io.WorkflowBundleIO;
+import org.apache.taverna.scufl2.api.profiles.Profile;
+
+/**
+ * Implementation of the <code>RunService</code>.
+ *
+ * @author David Withers
+ */
+public class RunServiceImpl implements RunService {
+	private static final Logger logger = Logger.getLogger(RunServiceImpl.class.getName());
+	private static SimpleDateFormat ISO_8601 = new SimpleDateFormat("yyyy-MM-dd_HHmmss");
+
+	private final Map<String, Run> runMap;
+	private ExecutionEnvironmentService executionEnvironmentService;
+	private EventAdmin eventAdmin;
+
+	public RunServiceImpl() {
+		runMap = new TreeMap<>();
+	}
+
+	@Override
+	public Set<ExecutionEnvironment> getExecutionEnvironments() {
+		return executionEnvironmentService.getExecutionEnvironments();
+	}
+
+	@Override
+	public Set<ExecutionEnvironment> getExecutionEnvironments(WorkflowBundle workflowBundle) {
+		return getExecutionEnvironments(workflowBundle.getMainProfile());
+	}
+
+	@Override
+	public Set<ExecutionEnvironment> getExecutionEnvironments(Profile profile) {
+		return executionEnvironmentService.getExecutionEnvironments(profile);
+	}
+
+	@Override
+	public List<String> getRuns() {
+		return new ArrayList<>(runMap.keySet());
+	}
+
+	@Override
+	public String createRun(RunProfile runProfile) throws InvalidWorkflowException, RunProfileException {
+		Run run = new Run(runProfile);
+		run.getWorkflowReport().addReportListener(new RunReportListener(run.getID()));
+		runMap.put(run.getID(), run);
+		postEvent(RUN_CREATED, run.getID());
+		return run.getID();
+	}
+
+	@Override
+	public String open(File runFile) throws IOException {
+		try {
+			String runID = runFile.getName();
+			int dot = runID.indexOf('.');
+			if (dot > 0)
+				runID = runID.substring(0, dot);
+			if (!runMap.containsKey(runID)) {
+				Bundle bundle = DataBundles.openBundle(runFile.toPath());
+				Run run = new Run(runID, bundle);
+				runMap.put(run.getID(), run);
+			}
+			postEvent(RUN_OPENED, runID);
+			return runID;
+		} catch (ReaderException | ParseException e) {
+			throw new IOException("Error opening file " + runFile, e);
+		}
+	}
+
+	@Override
+	public void close(String runID) throws InvalidRunIdException, InvalidExecutionIdException {
+		Run run = getRun(runID);
+		try {
+			Bundle dataBundle = run.getDataBundle();
+			DataBundles.closeBundle(dataBundle);
+		} catch (IOException | ClosedFileSystemException e) {
+			logger.log(Level.WARNING, "Error closing data bundle for run " + runID, e);
+		}
+		runMap.remove(runID);
+		postEvent(RUN_CLOSED, runID);
+	}
+
+	@Override
+	public void save(String runID, File runFile) throws InvalidRunIdException, IOException {
+		Run run = getRun(runID);
+		Bundle dataBundle = run.getDataBundle();
+		try {
+			DataBundles.closeAndSaveBundle(dataBundle, runFile.toPath());
+		} catch (InvalidPathException e) {
+			throw new IOException(e);
+		}
+	}
+
+	@Override
+	public void delete(String runID) throws InvalidRunIdException, InvalidExecutionIdException {
+		Run run = getRun(runID);
+		run.delete();
+		Bundle dataBundle = run.getDataBundle();
+		try {
+			DataBundles.closeBundle(dataBundle);
+		} catch (IOException e) {
+			logger.log(Level.WARNING, "Error closing data bundle for run " + runID, e);
+		}
+		runMap.remove(runID);
+		postEvent(RUN_DELETED, runID);
+	}
+
+	@Override
+	public void start(String runID) throws InvalidRunIdException, RunStateException, InvalidExecutionIdException {
+		getRun(runID).start();
+		postEvent(RUN_STARTED, runID);
+	}
+
+	@Override
+	public void pause(String runID) throws InvalidRunIdException, RunStateException, InvalidExecutionIdException {
+		getRun(runID).pause();
+		postEvent(RUN_PAUSED, runID);
+	}
+
+	@Override
+	public void resume(String runID) throws InvalidRunIdException, RunStateException, InvalidExecutionIdException {
+		getRun(runID).resume();
+		postEvent(RUN_RESUMED, runID);
+	}
+
+	@Override
+	public void cancel(String runID) throws InvalidRunIdException, RunStateException, InvalidExecutionIdException {
+		getRun(runID).cancel();
+		postEvent(RUN_STOPPED, runID);
+	}
+
+	@Override
+	public State getState(String runID) throws InvalidRunIdException {
+		return getRun(runID).getState();
+	}
+
+	@Override
+	public Bundle getDataBundle(String runID) throws InvalidRunIdException {
+		return getRun(runID).getDataBundle();
+	}
+
+	@Override
+	public WorkflowReport getWorkflowReport(String runID) throws InvalidRunIdException {
+		return getRun(runID).getWorkflowReport();
+	}
+
+	@Override
+	public Workflow getWorkflow(String runID) throws InvalidRunIdException {
+		return getRun(runID).getWorkflow();
+	}
+
+	@Override
+	public Profile getProfile(String runID) throws InvalidRunIdException {
+		return getRun(runID).getProfile();
+	}
+
+	@Override
+	public String getRunName(String runID) throws InvalidRunIdException {
+		WorkflowReport workflowReport = getWorkflowReport(runID);
+		return workflowReport.getSubject().getName() + "_" + ISO_8601.format(workflowReport.getCreatedDate());
+	}
+
+	private Run getRun(String runID) throws InvalidRunIdException {
+		Run run = runMap.get(runID);
+		if (run == null)
+			throw new InvalidRunIdException("Run ID " + runID + " is not valid");
+		return run;
+	}
+
+	private void postEvent(String topic, String runId) {
+		HashMap<String, String> properties = new HashMap<>();
+		properties.put("RUN_ID", runId);
+		Event event = new Event(topic, properties);
+		eventAdmin.postEvent(event);
+	}
+
+	public void setExecutionEnvironmentService(ExecutionEnvironmentService executionEnvironmentService) {
+		this.executionEnvironmentService = executionEnvironmentService;
+	}
+
+	public void setEventAdmin(EventAdmin eventAdmin) {
+		this.eventAdmin = eventAdmin;
+	}
+
+	public void setWorkflowBundleIO(WorkflowBundleIO workflowBundleIO) {
+		DataBundles.setWfBundleIO(workflowBundleIO);
+	}
+
+	private class RunReportListener implements ReportListener {
+		private final String runId;
+
+		public RunReportListener(String runId) {
+			this.runId = runId;
+		}
+
+		@Override
+		public void outputAdded(Path path, String portName, int[] index) {
+		}
+
+		@Override
+		public void stateChanged(State oldState, State newState) {
+			switch (newState) {
+			case COMPLETED:
+			case FAILED:
+				postEvent(RUN_STOPPED, runId);
+			default:
+				break;
+			}
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-engine/blob/5f1ddb71/taverna-run-impl/src/main/java/org/apache/taverna/platform/run/impl/WorkflowReportJSON.java
----------------------------------------------------------------------
diff --git a/taverna-run-impl/src/main/java/org/apache/taverna/platform/run/impl/WorkflowReportJSON.java b/taverna-run-impl/src/main/java/org/apache/taverna/platform/run/impl/WorkflowReportJSON.java
new file mode 100644
index 0000000..470df04
--- /dev/null
+++ b/taverna-run-impl/src/main/java/org/apache/taverna/platform/run/impl/WorkflowReportJSON.java
@@ -0,0 +1,347 @@
+/*
+* 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.
+*/
+
+package org.apache.taverna.platform.run.impl;
+
+import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL;
+import static com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES;
+import static com.fasterxml.jackson.databind.SerializationFeature.FAIL_ON_EMPTY_BEANS;
+import static com.fasterxml.jackson.databind.SerializationFeature.INDENT_OUTPUT;
+import static com.fasterxml.jackson.databind.SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS;
+import static com.fasterxml.jackson.databind.SerializationFeature.WRITE_DATES_AS_TIMESTAMPS;
+import static com.fasterxml.jackson.databind.SerializationFeature.WRITE_EMPTY_JSON_ARRAYS;
+import static com.fasterxml.jackson.databind.SerializationFeature.WRITE_NULL_MAP_VALUES;
+import static com.fasterxml.jackson.databind.SerializationFeature.WRITE_SINGLE_ELEM_ARRAYS_UNWRAPPED;
+import static java.nio.file.Files.newBufferedWriter;
+import static java.nio.file.StandardOpenOption.CREATE;
+import static java.nio.file.StandardOpenOption.TRUNCATE_EXISTING;
+import static java.nio.file.StandardOpenOption.WRITE;
+import static org.apache.taverna.databundle.DataBundles.getWorkflow;
+import static org.apache.taverna.databundle.DataBundles.getWorkflowBundle;
+import static org.apache.taverna.databundle.DataBundles.getWorkflowRunReport;
+import static org.apache.taverna.databundle.DataBundles.setWorkflowBundle;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Writer;
+import java.net.URI;
+import java.nio.charset.Charset;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.text.ParseException;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+import org.apache.taverna.robundle.Bundle;
+import org.apache.taverna.robundle.manifest.Manifest.PathMixin;
+
+import org.apache.taverna.platform.report.ActivityReport;
+import org.apache.taverna.platform.report.Invocation;
+import org.apache.taverna.platform.report.ProcessorReport;
+import org.apache.taverna.platform.report.State;
+import org.apache.taverna.platform.report.StatusReport;
+import org.apache.taverna.platform.report.WorkflowReport;
+import org.apache.taverna.scufl2.api.activity.Activity;
+import org.apache.taverna.scufl2.api.common.URITools;
+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.ReaderException;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.fasterxml.jackson.databind.util.StdDateFormat;
+
+public class WorkflowReportJSON {
+	private static URITools uriTools = new URITools();
+	private static final StdDateFormat STD_DATE_FORMAT = new StdDateFormat();
+
+	public void save(WorkflowReport wfReport, Path path) throws IOException {
+		ObjectMapper om = makeObjectMapperForSave();
+		try (Writer w = newBufferedWriter(path, Charset.forName("UTF-8"),
+				WRITE, CREATE, TRUNCATE_EXISTING)) {
+			om.writeValue(w, wfReport);
+		}
+	}
+
+	protected static ObjectMapper makeObjectMapperForLoad() {
+		ObjectMapper om = new ObjectMapper();
+		om.disable(FAIL_ON_UNKNOWN_PROPERTIES);
+		return om;
+	}
+
+	protected static ObjectMapper makeObjectMapperForSave() {
+		ObjectMapper om = new ObjectMapper();
+		om.enable(INDENT_OUTPUT);
+		om.disable(FAIL_ON_EMPTY_BEANS);
+		om.enable(ORDER_MAP_ENTRIES_BY_KEYS);
+		om.disable(WRITE_EMPTY_JSON_ARRAYS);
+		om.disable(WRITE_NULL_MAP_VALUES);
+		om.disable(WRITE_SINGLE_ELEM_ARRAYS_UNWRAPPED);
+		om.disable(WRITE_DATES_AS_TIMESTAMPS);
+		om.disable(WRITE_NULL_MAP_VALUES);
+		om.addMixInAnnotations(Path.class, PathMixin.class);
+		om.setSerializationInclusion(NON_NULL);
+		return om;
+	}
+
+	@SuppressWarnings("unused")
+	private void injectContext(ObjectNode objNode) {
+		ObjectNode context = objNode.with("@context");
+		context.put("wfprov", "http://purl.org/wf4ever/wfprov#");
+		context.put("wfdesc", "http://purl.org/wf4ever/wfdesc#");
+		context.put("prov", "http://www.w3.org/ns/prov#");
+	}
+
+	public void save(WorkflowReport wfReport, Bundle dataBundle)
+			throws IOException {
+		Path path = getWorkflowRunReport(dataBundle);
+		save(wfReport, path);
+		if (!Files.exists(getWorkflow(dataBundle)))
+			// Usually already done by Run constructor
+			setWorkflowBundle(wfReport.getDataBundle(), wfReport.getSubject()
+					.getParent());
+	}
+
+	public WorkflowReport load(Bundle bundle) throws IOException,
+			ReaderException, ParseException {
+		Path path = getWorkflowRunReport(bundle);
+		WorkflowBundle workflow = getWorkflowBundle(bundle);
+		return load(path, workflow);
+	}
+
+	public WorkflowReport load(Path workflowReportJson,
+			WorkflowBundle workflowBundle) throws IOException, ParseException {
+		JsonNode json = loadWorkflowReportJson(workflowReportJson);
+		if (!json.isObject())
+			throw new IOException(
+					"Invalid workflow report, expected JSON Object:\n" + json);
+		return parseWorkflowReport(json, workflowReportJson, null,
+				workflowBundle);
+	}
+
+	protected WorkflowReport parseWorkflowReport(JsonNode reportJson,
+			Path workflowReportJson, ActivityReport actReport,
+			WorkflowBundle workflowBundle) throws ParseException {
+		Workflow wf = (Workflow) getSubject(reportJson, workflowBundle);
+		WorkflowReport workflowReport = new WorkflowReport(wf);
+		workflowReport.setParentReport(actReport);
+
+		parseDates(reportJson, workflowReport);
+
+		for (JsonNode invocJson : reportJson.path("invocations"))
+			// NOTE: Invocation constructor will add to parents
+			parseInvocation(invocJson, workflowReportJson, workflowReport);
+
+		for (JsonNode procJson : reportJson.path("processorReports")) {
+			ProcessorReport procReport = parseProcessorReport(procJson,
+					workflowReportJson, workflowReport, workflowBundle);
+			workflowReport.addProcessorReport(procReport);
+		}
+		return workflowReport;
+	}
+
+	protected ProcessorReport parseProcessorReport(JsonNode reportJson,
+			Path workflowReportJson, WorkflowReport workflowReport,
+			WorkflowBundle workflowBundle) throws ParseException {
+		Processor p = (Processor) getSubject(reportJson, workflowBundle);
+		ProcessorReport procReport = new ProcessorReport(p);
+		procReport.setParentReport(workflowReport);
+
+		procReport.setJobsQueued(reportJson.path("jobsQueued").asInt());
+		procReport.setJobsStarted(reportJson.path("jobsStarted").asInt());
+		procReport.setJobsCompleted(reportJson.path("jobsCompleted").asInt());
+		procReport.setJobsCompletedWithErrors(reportJson.path(
+				"jobsCompletedWithErrors").asInt());
+		// TODO: procReport properties
+
+		parseDates(reportJson, procReport);
+
+		for (JsonNode invocJson : reportJson.path("invocations"))
+			parseInvocation(invocJson, workflowReportJson, procReport);
+
+		for (JsonNode actJson : reportJson.path("activityReports")) {
+			ActivityReport activityReport = parseActivityReport(actJson,
+					workflowReportJson, procReport, workflowBundle);
+			procReport.addActivityReport(activityReport);
+		}
+		return procReport;
+	}
+
+	protected ActivityReport parseActivityReport(JsonNode actJson,
+			Path workflowReportJson, ProcessorReport procReport,
+			WorkflowBundle workflowBundle) throws ParseException {
+		Activity a = (Activity) getSubject(actJson, workflowBundle);
+		ActivityReport actReport = new ActivityReport(a);
+		actReport.setParentReport(procReport);
+
+		parseDates(actJson, actReport);
+
+		for (JsonNode invocJson : actJson.path("invocations"))
+			parseInvocation(invocJson, workflowReportJson, actReport);
+
+		JsonNode nestedWf = actJson.get("nestedWorkflowReport");
+		if (nestedWf != null)
+			actReport.setNestedWorkflowReport(parseWorkflowReport(nestedWf,
+					workflowReportJson, actReport, workflowBundle));
+		return actReport;
+	}
+
+	protected void parseInvocation(JsonNode json, Path workflowReportJson,
+			@SuppressWarnings("rawtypes") StatusReport report)
+			throws ParseException {
+		String name = json.path("name").asText();
+
+		String parentId = json.path("parent").asText();
+		Invocation parent = null;
+		if (!parentId.isEmpty()) {
+			@SuppressWarnings("rawtypes")
+			StatusReport parentReport = report.getParentReport();
+			if (parentReport != null)
+				parent = parentReport.getInvocation(parentId);
+		}
+
+		int[] index;
+		if (json.has("index")) {
+			ArrayNode array = (ArrayNode) json.get("index");
+			index = new int[array.size()];
+			for (int i = 0; i < index.length; i++)
+				index[i] = array.get(i).asInt();
+		} else
+			index = new int[0];
+
+		Invocation invocation = new Invocation(name, index, parent, report);
+		Date startedDate = getDate(json, "startedDate");
+		if (startedDate != null)
+			invocation.setStartedDate(startedDate);
+		Date completedDate = getDate(json, "completedDate");
+		if (completedDate != null)
+			invocation.setCompletedDate(completedDate);
+
+		invocation.setInputs(parseValues(json.path("inputs"),
+				workflowReportJson));
+		invocation.setOutputs(parseValues(json.path("outputs"),
+				workflowReportJson));
+	}
+
+	protected Map<String, Path> parseValues(JsonNode json, Path basePath) {
+		SortedMap<String, Path> values = new TreeMap<>();
+		for (String port : iterate(json.fieldNames())) {
+			String pathStr = json.get(port).asText();
+			Path value = basePath.resolve(pathStr);
+			values.put(port, value);
+		}
+		return values;
+	}
+
+	private static <T> Iterable<T> iterate(final Iterator<T> iterator) {
+		return new Iterable<T>() {
+			@Override
+			public Iterator<T> iterator() {
+				return iterator;
+			}
+		};
+	}
+
+	protected void parseDates(JsonNode json,
+			@SuppressWarnings("rawtypes") StatusReport report)
+			throws ParseException {
+		Date createdDate = getDate(json, "createdDate");
+		if (createdDate != null)
+			report.setCreatedDate(createdDate);
+
+		Date startedDate = getDate(json, "startedDate");
+		if (startedDate != null)
+			report.setStartedDate(startedDate);
+
+		// Special case for paused and resumed dates>
+		for (JsonNode s : json.path("pausedDates")) {
+			Date pausedDate = STD_DATE_FORMAT.parse(s.asText());
+			report.setPausedDate(pausedDate);
+		}
+		Date pausedDate = getDate(json, "pausedDate");
+		if (report.getPausedDates().isEmpty() && pausedDate != null) {
+			/*
+			 * "pausedDate" is normally redundant (last value of "pausedDates")
+			 * but here for some reason the list is missing, so we'll parse it
+			 * separately.
+			 * 
+			 * Note that if there was a list, we will ignore "pauseDate" no
+			 * matter its value
+			 */
+			report.setPausedDate(pausedDate);
+		}
+
+		for (JsonNode s : json.path("resumedDates")) {
+			Date resumedDate = STD_DATE_FORMAT.parse(s.asText());
+			report.setResumedDate(resumedDate);
+		}
+		Date resumedDate = getDate(json, "resumedDate");
+		if (report.getResumedDates().isEmpty() && resumedDate != null)
+			// Same fall-back as for "pausedDate" above
+			report.setResumedDate(resumedDate);
+
+		Date cancelledDate = getDate(json, "cancelledDate");
+		if (cancelledDate != null)
+			report.setCancelledDate(cancelledDate);
+
+		Date failedDate = getDate(json, "failedDate");
+		if (failedDate != null)
+			report.setFailedDate(failedDate);
+
+		Date completedDate = getDate(json, "completedDate");
+		if (completedDate != null)
+			report.setCompletedDate(completedDate);
+
+		try {
+			State state = State.valueOf(json.get("state").asText());
+			report.setState(state);
+		} catch (IllegalArgumentException ex) {
+			throw new ParseException("Invalid state: " + json.get("state"), -1);
+		}
+	}
+
+	protected Date getDate(JsonNode json, String name) throws ParseException {
+		String date = json.path(name).asText();
+		if (date.isEmpty())
+			return null;
+		return STD_DATE_FORMAT.parse(date);
+	}
+
+	private WorkflowBean getSubject(JsonNode reportJson,
+			WorkflowBundle workflowBundle) {
+		URI subjectUri = URI.create(reportJson.path("subject").asText());
+		return uriTools.resolveUri(subjectUri, workflowBundle);
+	}
+
+	protected JsonNode loadWorkflowReportJson(Path path) throws IOException,
+			JsonProcessingException {
+		ObjectMapper om = makeObjectMapperForLoad();
+		try (InputStream stream = Files.newInputStream(path)) {
+			return om.readTree(stream);
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-engine/blob/5f1ddb71/taverna-run-impl/src/main/java/uk/org/taverna/platform/run/impl/Run.java
----------------------------------------------------------------------
diff --git a/taverna-run-impl/src/main/java/uk/org/taverna/platform/run/impl/Run.java b/taverna-run-impl/src/main/java/uk/org/taverna/platform/run/impl/Run.java
deleted file mode 100755
index 90b44db..0000000
--- a/taverna-run-impl/src/main/java/uk/org/taverna/platform/run/impl/Run.java
+++ /dev/null
@@ -1,279 +0,0 @@
-/*******************************************************************************
- * Copyright (C) 2010 The University of Manchester
- *
- *  Modifications to the initial code base are copyright of their
- *  respective authors, or their employers as appropriate.
- *
- *  This program is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public License
- *  as published by the Free Software Foundation; either version 2.1 of
- *  the License, or (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful, but
- *  WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this program; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- ******************************************************************************/
-package uk.org.taverna.platform.run.impl;
-
-import static java.util.logging.Level.WARNING;
-import static uk.org.taverna.platform.report.State.CANCELLED;
-import static uk.org.taverna.platform.report.State.COMPLETED;
-import static uk.org.taverna.platform.report.State.CREATED;
-import static uk.org.taverna.platform.report.State.FAILED;
-import static uk.org.taverna.platform.report.State.PAUSED;
-import static uk.org.taverna.platform.report.State.RUNNING;
-
-import java.io.IOException;
-import java.text.ParseException;
-import java.util.Date;
-import java.util.UUID;
-import java.util.logging.Logger;
-
-import org.apache.taverna.robundle.Bundle;
-import org.apache.taverna.robundle.manifest.Manifest;
-
-import org.apache.taverna.databundle.DataBundles;
-import uk.org.taverna.platform.execution.api.ExecutionEnvironment;
-import uk.org.taverna.platform.execution.api.InvalidExecutionIdException;
-import uk.org.taverna.platform.execution.api.InvalidWorkflowException;
-import uk.org.taverna.platform.report.State;
-import uk.org.taverna.platform.report.WorkflowReport;
-import uk.org.taverna.platform.run.api.RunProfile;
-import uk.org.taverna.platform.run.api.RunProfileException;
-import uk.org.taverna.platform.run.api.RunStateException;
-import org.apache.taverna.scufl2.api.container.WorkflowBundle;
-import org.apache.taverna.scufl2.api.core.Workflow;
-import org.apache.taverna.scufl2.api.io.ReaderException;
-import org.apache.taverna.scufl2.api.profiles.Profile;
-
-/**
- * A single run of a {@link Workflow}.
- * 
- * @author David Withers
- */
-public class Run {
-	private static final WorkflowReportJSON workflowReportJson = new WorkflowReportJSON();
-	private static final Logger logger = Logger.getLogger(Run.class.getName());
-
-	private final String ID, executionID;
-	private final ExecutionEnvironment executionEnvironment;
-	private final WorkflowReport workflowReport;
-	private final WorkflowBundle workflowBundle;
-	private final Bundle dataBundle;
-	private final Workflow workflow;
-	private final Profile profile;
-
-	/**
-	 * Constructs a <code>Run</code> from the specified <code>RunProfile</code>.
-	 * 
-	 * @param runProfile
-	 *            the profile to create a <code>Run</code> from
-	 * @throws InvalidWorkflowException
-	 *             if the <code>Workflow</code> specified by the
-	 *             <code>RunProfile</code> is not valid
-	 * @throws RunProfileException
-	 *             if the <code>RunProfile</code> does not contain the correct
-	 *             information to run a <code>Workflow</code>
-	 */
-	public Run(RunProfile runProfile) throws InvalidWorkflowException,
-			RunProfileException {
-		if (runProfile.getWorkflowBundle() == null) {
-			String message = "No WorkflowBundle specified in the RunProfile";
-			logger.warning(message);
-			throw new RunProfileException(message);
-		}
-		workflowBundle = runProfile.getWorkflowBundle();
-		if (runProfile.getWorkflowName() == null) {
-			if (workflowBundle.getMainWorkflow() == null) {
-				String message = "No Workflow specified in either the RunProfile or the WorkflowBundle";
-				logger.warning(message);
-				throw new RunProfileException(message);
-			}
-			logger.info("No Workflow specified - using the main Workflow from the WorkflowBundle");
-			workflow = workflowBundle.getMainWorkflow();
-		} else {
-			workflow = workflowBundle.getWorkflows().getByName(
-					runProfile.getWorkflowName());
-		}
-		if (runProfile.getProfileName() == null) {
-			if (workflowBundle.getMainProfile() == null) {
-				String message = "No Profile specified in either the RunProfile or the WorkflowBundle";
-				logger.warning(message);
-				throw new RunProfileException(message);
-			}
-			logger.info("No Profile specified - using the main Profile from the WorkflowBundle");
-			profile = workflowBundle.getMainProfile();
-		} else {
-			profile = workflowBundle.getProfiles().getByName(
-					runProfile.getProfileName());
-		}
-		if (runProfile.getDataBundle() == null) {
-			String message = "No DataBundle specified in the RunProfile";
-			logger.warning(message);
-			throw new RunProfileException(message);
-		}
-		dataBundle = runProfile.getDataBundle();
-		try {
-			DataBundles.setWorkflowBundle(dataBundle, workflowBundle);
-		} catch (IOException e) {
-			String message = "Could not save workflow bundle to data bundle";
-			logger.log(WARNING, message, e);
-			throw new InvalidWorkflowException(message, e);
-		}
-		if (runProfile.getExecutionEnvironment() == null) {
-			String message = "No ExecutionEnvironment specified in the RunProfile";
-			logger.warning(message);
-			throw new RunProfileException(message);
-		}
-		executionEnvironment = runProfile.getExecutionEnvironment();
-
-		ID = UUID.randomUUID().toString();
-		executionID = executionEnvironment.getExecutionService()
-				.createExecution(executionEnvironment, workflowBundle,
-						workflow, profile, dataBundle);
-		try {
-			workflowReport = executionEnvironment.getExecutionService()
-					.getWorkflowReport(executionID);
-		} catch (InvalidExecutionIdException e) {
-			String message = "Error while creating a execution on the "
-					+ executionEnvironment.getName();
-			logger.severe(message);
-			throw new RuntimeException(message, e);
-		}
-	}
-
-	public Run(String id, Bundle bundle) throws IOException, ReaderException,
-			ParseException {
-		this.ID = id;
-		executionID = null;
-		executionEnvironment = null;
-		workflowReport = workflowReportJson.load(bundle);
-		workflowBundle = DataBundles.getWorkflowBundle(bundle);
-		dataBundle = bundle;
-		workflow = workflowBundle.getMainWorkflow();
-		profile = workflowBundle.getMainProfile();
-	}
-
-	/**
-	 * Returns the identifier for this <code>Run</code>.
-	 * 
-	 * @return the identifier for this <code>Run</code>
-	 */
-	public String getID() {
-		return ID;
-	}
-
-	/**
-	 * Returns the current {@link State} of the <code>Run</code>.
-	 * 
-	 * A <code>Run</code>'s state can be CREATED, RUNNING, COMPLETED, PAUSED,
-	 * CANCELLED or FAILED.
-	 * 
-	 * @return the current <code>State</code> of the <code>Run</code>
-	 */
-	public State getState() {
-		return workflowReport.getState();
-	}
-
-	/**
-	 * Returns the <code>Bundle</code> containing the data values of the run.
-	 * <p>
-	 * 
-	 * @return the <code>Bundle</code> containing the data values for the
-	 *         <code>Workflow</code>
-	 */
-	public Bundle getDataBundle() {
-		if (getWorkflowReport() != null)
-			// Save the workflow report
-			try {
-				workflowReportJson.save(getWorkflowReport(), dataBundle);
-			} catch (IOException e) {
-				logger.log(WARNING,
-						"Can't save workflow report to data bundle", e);
-			}
-		// Update manifest
-		try {
-			Manifest manifest = new Manifest(dataBundle);
-			manifest.populateFromBundle();
-			manifest.writeAsJsonLD();
-		} catch (IOException e) {
-			logger.log(WARNING, "Can't add manifest to data bundle", e);
-		}
-		return dataBundle;
-	}
-
-	/**
-	 * Returns the status report for the run.
-	 * 
-	 * @return the status report for the run
-	 */
-	public WorkflowReport getWorkflowReport() {
-		return workflowReport;
-	}
-
-	public Workflow getWorkflow() {
-		return workflow;
-	}
-
-	public Profile getProfile() {
-		return profile;
-	}
-
-	/**
-	 * Deletes a run.
-	 * 
-	 * @throws InvalidExecutionIdException
-	 */
-	public void delete() throws InvalidExecutionIdException {
-		synchronized (workflowReport) {
-			executionEnvironment.getExecutionService().delete(executionID);
-		}
-	}
-
-	public void start() throws RunStateException, InvalidExecutionIdException {
-		synchronized (workflowReport) {
-			State state = workflowReport.getState();
-			if (!state.equals(CREATED))
-				throw new RunStateException("Cannot start a " + state + " run.");
-			executionEnvironment.getExecutionService().start(executionID);
-		}
-	}
-
-	public void pause() throws RunStateException, InvalidExecutionIdException {
-		synchronized (workflowReport) {
-			State state = workflowReport.getState();
-			if (!state.equals(RUNNING))
-				throw new RunStateException("Cannot pause a " + state + " run.");
-			executionEnvironment.getExecutionService().pause(executionID);
-			workflowReport.setPausedDate(new Date());
-		}
-	}
-
-	public void resume() throws RunStateException, InvalidExecutionIdException {
-		synchronized (workflowReport) {
-			State state = workflowReport.getState();
-			if (!state.equals(PAUSED))
-				throw new RunStateException("Cannot resume a " + state
-						+ " run.");
-			executionEnvironment.getExecutionService().resume(executionID);
-			workflowReport.setResumedDate(new Date());
-		}
-	}
-
-	public void cancel() throws RunStateException, InvalidExecutionIdException {
-		synchronized (workflowReport) {
-			State state = workflowReport.getState();
-			if (state.equals(CANCELLED) || state.equals(COMPLETED)
-					|| state.equals(FAILED))
-				throw new RunStateException("Cannot cancel a " + state
-						+ " run.");
-			executionEnvironment.getExecutionService().cancel(executionID);
-			workflowReport.setCancelledDate(new Date());
-		}
-	}
-}