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

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

http://git-wip-us.apache.org/repos/asf/incubator-taverna-engine/blob/5f1ddb71/taverna-reference-impl/src/main/java/org/apache/taverna/reference/impl/AbstractReferenceServiceImpl.java
----------------------------------------------------------------------
diff --git a/taverna-reference-impl/src/main/java/org/apache/taverna/reference/impl/AbstractReferenceServiceImpl.java b/taverna-reference-impl/src/main/java/org/apache/taverna/reference/impl/AbstractReferenceServiceImpl.java
new file mode 100644
index 0000000..c1c2743
--- /dev/null
+++ b/taverna-reference-impl/src/main/java/org/apache/taverna/reference/impl/AbstractReferenceServiceImpl.java
@@ -0,0 +1,170 @@
+/*
+* 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.reference.impl;
+
+import java.util.List;
+import java.util.Set;
+
+import org.apache.taverna.reference.ErrorDocumentService;
+import org.apache.taverna.reference.ExternalReferenceSPI;
+import org.apache.taverna.reference.ListService;
+import org.apache.taverna.reference.ReferenceContext;
+import org.apache.taverna.reference.ReferenceService;
+import org.apache.taverna.reference.ReferenceServiceException;
+import org.apache.taverna.reference.ReferenceServiceResolutionCallback;
+import org.apache.taverna.reference.ReferenceSetService;
+import org.apache.taverna.reference.StreamToValueConverterSPI;
+import org.apache.taverna.reference.T2Reference;
+import org.apache.taverna.reference.ValueToReferenceConverterSPI;
+
+/**
+ * Implementation of ReferenceService, inject with ReferenceSetService,
+ * ErrorDocumentService and ListService to enable. Inject with an instance
+ * registry of ValueToReferenceConvertorSPI to enable on the fly registration of
+ * otherwise illegal object types. This class contains the basic injection
+ * functionality and the getters for the sub-services, mostly to isolate these
+ * mundane bits of code from the more interesting actual implementation of the
+ * reference service logic.
+ * 
+ * @author Tom Oinn
+ */
+public abstract class AbstractReferenceServiceImpl extends AbstractServiceImpl
+		implements ReferenceService {
+	protected ErrorDocumentService errorDocumentService = null;
+	protected ReferenceSetService referenceSetService = null;
+	protected ListService listService = null;
+	protected List<ValueToReferenceConverterSPI> converters = null;
+	@SuppressWarnings("rawtypes")
+	protected List<StreamToValueConverterSPI> valueBuilders = null;
+
+	/**
+	 * Inject value to reference convertor SPI
+	 */
+	public final void setConverters(
+			List<ValueToReferenceConverterSPI> converters) {
+		this.converters = converters;
+	}
+
+	/**
+	 * Inject stream to value converter SPI
+	 */
+	@SuppressWarnings("rawtypes")
+	public final void setValueBuilders(
+			List<StreamToValueConverterSPI> valueBuilders) {
+		this.valueBuilders = valueBuilders;
+	}
+
+	/**
+	 * Inject error document service
+	 */
+	public final void setErrorDocumentService(ErrorDocumentService eds) {
+		this.errorDocumentService = eds;
+	}
+
+	/**
+	 * Inject reference set service
+	 */
+	public final void setReferenceSetService(ReferenceSetService rss) {
+		this.referenceSetService = rss;
+	}
+
+	/**
+	 * Inject list service
+	 */
+	public final void setListService(ListService ls) {
+		this.listService = ls;
+	}
+
+	/**
+	 * Throw a ReferenceServiceException if methods in ReferenceService are
+	 * called without the necessary sub-services configured.
+	 */
+	protected final void checkServices() throws ReferenceServiceException {
+		if (errorDocumentService == null)
+			throw new ReferenceServiceException(
+					"Reference service must be configued with an "
+							+ "instance of ErrorDocumentService to function");
+		if (referenceSetService == null)
+			throw new ReferenceServiceException(
+					"Reference service must be configued with an "
+							+ "instance of ReferenceSetService to function");
+		if (listService == null)
+			throw new ReferenceServiceException(
+					"Reference service must be configued with an "
+							+ "instance of ListService to function");
+	}
+
+	/**
+	 * Check whether the converter registry has been defined, throw a
+	 * ReferenceServiceException if not
+	 */
+	protected final void checkConverterRegistry()
+			throws ReferenceServiceException {
+		if (converters == null)
+			throw new ReferenceServiceException(
+					"Reference service must be configued with an "
+							+ "instance registry of ValueToReferenceConvertorSPI "
+							+ "to enable on the fly mapping of arbitrary objects "
+							+ "during compound registration");
+	}
+
+	@Override
+	public final ErrorDocumentService getErrorDocumentService() {
+		checkServices();
+		return this.errorDocumentService;
+	}
+
+	@Override
+	public final ListService getListService() {
+		checkServices();
+		return this.listService;
+	}
+
+	@Override
+	public final ReferenceSetService getReferenceSetService() {
+		checkServices();
+		return this.referenceSetService;
+	}
+
+	/**
+	 * Wraps the synchronous form, using the executeRunnable method to schedule
+	 * it.
+	 */
+	@Override
+	public void resolveIdentifierAsynch(final T2Reference id,
+			final Set<Class<ExternalReferenceSPI>> ensureTypes,
+			final ReferenceContext context,
+			final ReferenceServiceResolutionCallback callback)
+			throws ReferenceServiceException {
+		checkServices();
+		Runnable r = new Runnable() {
+			@Override
+			public void run() {
+				try {
+					callback.identifierResolved(resolveIdentifier(id,
+							ensureTypes, context));
+				} catch (ReferenceServiceException rse) {
+					callback.resolutionFailed(rse);
+				}
+			}
+		};
+		executeRunnable(r);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-engine/blob/5f1ddb71/taverna-reference-impl/src/main/java/org/apache/taverna/reference/impl/AbstractReferenceSetServiceImpl.java
----------------------------------------------------------------------
diff --git a/taverna-reference-impl/src/main/java/org/apache/taverna/reference/impl/AbstractReferenceSetServiceImpl.java b/taverna-reference-impl/src/main/java/org/apache/taverna/reference/impl/AbstractReferenceSetServiceImpl.java
new file mode 100644
index 0000000..d84d7a8
--- /dev/null
+++ b/taverna-reference-impl/src/main/java/org/apache/taverna/reference/impl/AbstractReferenceSetServiceImpl.java
@@ -0,0 +1,159 @@
+/*
+* 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.reference.impl;
+
+import java.util.Set;
+
+import org.apache.taverna.reference.DaoException;
+import org.apache.taverna.reference.ExternalReferenceSPI;
+import org.apache.taverna.reference.ReferenceContext;
+import org.apache.taverna.reference.ReferenceSet;
+import org.apache.taverna.reference.ReferenceSetAugmentor;
+import org.apache.taverna.reference.ReferenceSetDao;
+import org.apache.taverna.reference.ReferenceSetService;
+import org.apache.taverna.reference.ReferenceSetServiceCallback;
+import org.apache.taverna.reference.ReferenceSetServiceException;
+import org.apache.taverna.reference.T2Reference;
+import org.apache.taverna.reference.T2ReferenceGenerator;
+
+/**
+ * Abstract implementation of ReferenceSetService, inject with an appropriate
+ * ReferenceSetDao to enable. Implements translation functionality as long as an
+ * appropriate ReferenceSetAugmentor implementation is injected. Contains
+ * injectors for id generation and dao along with other bookkeeping, leaving the
+ * implementation of the actual service logic to the subclass.
+ * 
+ * @author Tom Oinn
+ */
+public abstract class AbstractReferenceSetServiceImpl extends
+		AbstractServiceImpl implements ReferenceSetService {
+	protected ReferenceSetDao referenceSetDao = null;
+	protected T2ReferenceGenerator t2ReferenceGenerator = null;
+	protected ReferenceSetAugmentor referenceSetAugmentor = null;
+
+	/**
+	 * Inject the reference set data access object.
+	 */
+	public final void setReferenceSetDao(ReferenceSetDao dao) {
+		this.referenceSetDao = dao;
+	}
+
+	/**
+	 * Inject the T2Reference generator used to allocate new IDs when
+	 * registering sets of ExternalReferenceSPI
+	 */
+	public final void setT2ReferenceGenerator(T2ReferenceGenerator t2rg) {
+		this.t2ReferenceGenerator = t2rg;
+	}
+
+	/**
+	 * Inject the ReferenceSetAugmentor used to translate or construct new
+	 * ExternalReferenceSPI instances within a ReferenceSet
+	 */
+	public final void setReferenceSetAugmentor(ReferenceSetAugmentor rse) {
+		this.referenceSetAugmentor = rse;
+	}
+
+	/**
+	 * Check that the reference set dao is configured
+	 * 
+	 * @throws ReferenceSetServiceException
+	 *             if the dao is still null
+	 */
+	protected final void checkDao() throws ReferenceSetServiceException {
+		if (referenceSetDao == null)
+			throw new ReferenceSetServiceException(
+					"ReferenceSetDao not initialized, reference set "
+							+ "service operations are not available");
+	}
+
+	/**
+	 * Check that the t2reference generator is configured
+	 * 
+	 * @throws ReferenceSetServiceException
+	 *             if the generator is still null
+	 */
+	protected final void checkGenerator() throws ReferenceSetServiceException {
+		if (t2ReferenceGenerator == null)
+			throw new ReferenceSetServiceException(
+					"T2ReferenceGenerator not initialized, reference "
+							+ "set service operations not available");
+	}
+
+	/**
+	 * Check that the reference set augmentor is configured
+	 * 
+	 * @throws ReferenceSetServiceException
+	 *             if the reference set augmentor is still null
+	 */
+	protected final void checkAugmentor() throws ReferenceSetServiceException {
+		if (referenceSetAugmentor == null)
+			throw new ReferenceSetServiceException(
+					"ReferenceSetAugmentor not initialized, reference "
+							+ "set service operations not available");
+	}
+
+	@Override
+	public final void getReferenceSetAsynch(final T2Reference id,
+			final ReferenceSetServiceCallback callback)
+			throws ReferenceSetServiceException {
+		checkDao();
+		Runnable r = new Runnable() {
+			@Override
+			public void run() {
+				try {
+					ReferenceSet rs = referenceSetDao.get(id);
+					callback.referenceSetRetrieved(rs);
+				} catch (DaoException de) {
+					callback.referenceSetRetrievalFailed(new ReferenceSetServiceException(
+							de));
+				}
+			}
+		};
+		executeRunnable(r);
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public final void getReferenceSetWithAugmentationAsynch(
+			final T2Reference id,
+			final Set<Class<ExternalReferenceSPI>> ensureTypes,
+			final ReferenceContext context,
+			final ReferenceSetServiceCallback callback)
+			throws ReferenceSetServiceException {
+		checkDao();
+		checkAugmentor();
+		Runnable r = new Runnable() {
+			@Override
+			public void run() {
+				try {
+					callback.referenceSetRetrieved(getReferenceSetWithAugmentation(
+							id, ensureTypes, context));
+				} catch (ReferenceSetServiceException rsse) {
+					callback.referenceSetRetrievalFailed(rsse);
+				}
+			}
+		};
+		executeRunnable(r);
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-engine/blob/5f1ddb71/taverna-reference-impl/src/main/java/org/apache/taverna/reference/impl/AbstractServiceImpl.java
----------------------------------------------------------------------
diff --git a/taverna-reference-impl/src/main/java/org/apache/taverna/reference/impl/AbstractServiceImpl.java b/taverna-reference-impl/src/main/java/org/apache/taverna/reference/impl/AbstractServiceImpl.java
new file mode 100644
index 0000000..b97e036
--- /dev/null
+++ b/taverna-reference-impl/src/main/java/org/apache/taverna/reference/impl/AbstractServiceImpl.java
@@ -0,0 +1,43 @@
+/*
+* 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.reference.impl;
+
+/**
+ * Abstract superclass for all service implementation objects, will be used to
+ * allow injection of thread pooling logic as and when we implement it.
+ * 
+ * @author Tom Oinn
+ */
+public class AbstractServiceImpl {
+	/**
+	 * Schedule a runnable for execution - current naive implementation uses a
+	 * new thread and executes immediately, but this is where any thread pool
+	 * logic would go if we wanted to add that.
+	 * 
+	 * @param r
+	 */
+	protected void executeRunnable(Runnable r) {
+		makeExecutionThread(r).start();
+	}
+
+	protected Thread makeExecutionThread(Runnable r) {
+		return new Thread(r);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-engine/blob/5f1ddb71/taverna-reference-impl/src/main/java/org/apache/taverna/reference/impl/AbstractT2ReferenceGenerator.java
----------------------------------------------------------------------
diff --git a/taverna-reference-impl/src/main/java/org/apache/taverna/reference/impl/AbstractT2ReferenceGenerator.java b/taverna-reference-impl/src/main/java/org/apache/taverna/reference/impl/AbstractT2ReferenceGenerator.java
new file mode 100644
index 0000000..29b6db7
--- /dev/null
+++ b/taverna-reference-impl/src/main/java/org/apache/taverna/reference/impl/AbstractT2ReferenceGenerator.java
@@ -0,0 +1,110 @@
+/*
+* 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.reference.impl;
+
+import static org.apache.taverna.reference.T2ReferenceType.ErrorDocument;
+import static org.apache.taverna.reference.T2ReferenceType.IdentifiedList;
+import static org.apache.taverna.reference.T2ReferenceType.ReferenceSet;
+
+import java.util.List;
+
+import org.apache.taverna.reference.ReferenceContext;
+import org.apache.taverna.reference.T2Reference;
+import org.apache.taverna.reference.T2ReferenceGenerator;
+import org.apache.taverna.reference.WorkflowRunIdEntity;
+
+/**
+ * An abstract class for implementing simple {@link T2ReferenceGenerator}s.
+ * 
+ * @author Stian Soiland-Reyes
+ */
+public abstract class AbstractT2ReferenceGenerator implements
+		T2ReferenceGenerator {
+	public AbstractT2ReferenceGenerator() {
+		super();
+	}
+
+	private void initReferenceNamespace(T2ReferenceImpl r, ReferenceContext context) {
+		if (context == null) {
+			// this is not good, just use the default namespace
+			r.setNamespacePart(getNamespace());
+			return;
+		}
+
+		List<WorkflowRunIdEntity> workflowRunIdEntities = context
+				.getEntities(WorkflowRunIdEntity.class);
+		if (workflowRunIdEntities == null || workflowRunIdEntities.isEmpty()) {
+			// this is not good, just use the default namespace
+			r.setNamespacePart(getNamespace());
+			return;
+		}
+
+		// there should be only one wf run id entity
+		String workflowRunId = ((WorkflowRunIdEntity) workflowRunIdEntities
+				.get(0)).getWorkflowRunId();
+		r.setNamespacePart(workflowRunId);
+	}
+
+	@Override
+	public synchronized T2Reference nextReferenceSetReference(
+			ReferenceContext context) {
+		T2ReferenceImpl r = new T2ReferenceImpl();
+		initReferenceNamespace(r, context);
+		r.setLocalPart(getNextLocalPart());
+		r.setReferenceType(ReferenceSet);
+		r.setDepth(0);
+		r.setContainsErrors(false);
+		return r;
+	}
+
+	/**
+	 * Generate a new local part for a new {@link T2Reference reference}. The
+	 * local part should be unique within this
+	 * {@link T2ReferenceGenerator#getNamespace() namespace}.
+	 * 
+	 * @return A new, unique local part to identify a new reference.
+	 */
+	protected abstract String getNextLocalPart();
+
+	@Override
+	public T2Reference nextListReference(boolean containsErrors, int listDepth,
+			ReferenceContext context) {
+		T2ReferenceImpl r = new T2ReferenceImpl();
+		initReferenceNamespace(r, context);
+		r.setLocalPart(getNextLocalPart());
+		r.setReferenceType(IdentifiedList);
+		r.setDepth(listDepth);
+		r.setContainsErrors(containsErrors);
+		return r;
+	}
+
+	@Override
+	public T2Reference nextErrorDocumentReference(int depth,
+			ReferenceContext context) {
+		T2ReferenceImpl r = new T2ReferenceImpl();
+		initReferenceNamespace(r, context);
+		r.setLocalPart(getNextLocalPart());
+		r.setReferenceType(ErrorDocument);
+		r.setDepth(depth);
+		// This is an error document, it contains errors by definition
+		r.setContainsErrors(true);
+		return r;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-engine/blob/5f1ddb71/taverna-reference-impl/src/main/java/org/apache/taverna/reference/impl/CacheAspect.java
----------------------------------------------------------------------
diff --git a/taverna-reference-impl/src/main/java/org/apache/taverna/reference/impl/CacheAspect.java b/taverna-reference-impl/src/main/java/org/apache/taverna/reference/impl/CacheAspect.java
new file mode 100644
index 0000000..b7aa5f6
--- /dev/null
+++ b/taverna-reference-impl/src/main/java/org/apache/taverna/reference/impl/CacheAspect.java
@@ -0,0 +1,126 @@
+/*
+* 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.reference.impl;
+
+import org.apache.taverna.reference.DaoException;
+import org.apache.taverna.reference.Identified;
+import org.apache.taverna.reference.ReferenceServiceCacheProvider;
+import org.apache.taverna.reference.T2Reference;
+
+import org.aspectj.lang.ProceedingJoinPoint;
+
+/**
+ * An aspect used to intercept calls to the various data access objects and
+ * divert through a write-through cache provider
+ * 
+ * @author Tom Oinn
+ */
+public class CacheAspect {
+	private ReferenceServiceCacheProvider cacheProvider;
+
+	/**
+	 * Return an injected ReferenceServiceCacheProvider
+	 */
+	private final ReferenceServiceCacheProvider getCacheProvider() {
+		return cacheProvider;
+	}
+
+	/**
+	 * Inject an instance of ReferenceServiceCacheProvider
+	 * 
+	 * @param cacheProvider
+	 *            the cache provider to use
+	 */
+	public final void setCacheProvider(
+			final ReferenceServiceCacheProvider cacheProvider) {
+		this.cacheProvider = cacheProvider;
+	}
+
+	/**
+	 * Handle a 'get by T2Reference' operation on a Dao
+	 * 
+	 * @param pjp
+	 *            the join point representing the ongoing method call to the dao
+	 * @return the entity identified by the T2Reference supplied to the method
+	 *         to which this advice applies
+	 * @throws DaoException
+	 *             if anything goes wrong
+	 */
+	public final Identified getObject(final ProceedingJoinPoint pjp)
+			throws DaoException {
+		Identified result = null;
+
+		// Get the T2Reference from the argument to the get method
+		T2Reference id = (T2Reference) pjp.getArgs()[0];
+		if (id != null) {
+			result = getCacheProvider().get(id);
+			if (result != null)
+				return result;
+		}
+		// If we miss the cache then call the method as usual
+		try {
+			result = (Identified) pjp.proceed();
+		} catch (DaoException e) {
+			throw e;
+		} catch (Throwable e) {
+			throw new DaoException("Unexpected exception type during aspect "
+					+ "based invocation", e);
+		}
+
+		// Write back to the cache
+		if (result != null)
+			getCacheProvider().put(result);
+
+		return result;
+	}
+
+	/**
+	 * Called around a write or update operation on the backing store, writes
+	 * through to the cache after modifying the state of the backing store and
+	 * before returning from the dao method
+	 * 
+	 * @param pjp
+	 *            join point representing the ongoing method invocation to cache
+	 * @throws DaoException
+	 *             if anything goes wrong
+	 */
+	public void putObject(final ProceedingJoinPoint pjp) throws DaoException {
+		// Get the Identified being stored by the method we're advising
+		Identified storedObject = (Identified) pjp.getArgs()[0];
+
+		try {
+			// Run the store or update method
+			pjp.proceed();
+		} catch (DaoException e) {
+			throw e;
+		} catch (Throwable e) {
+			throw new DaoException("Unexpected exception type during aspect "
+					+ "based invocation", e);
+		}
+
+		/*
+		 * Assuming the method isn't null and has an identifier (which it will
+		 * if we haven't thrown an exception before now) write it back to the
+		 * cache provider
+		 */
+		if (storedObject != null && storedObject.getId() != null)
+			getCacheProvider().put(storedObject);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-engine/blob/5f1ddb71/taverna-reference-impl/src/main/java/org/apache/taverna/reference/impl/ContextualizedT2ReferenceImpl.java
----------------------------------------------------------------------
diff --git a/taverna-reference-impl/src/main/java/org/apache/taverna/reference/impl/ContextualizedT2ReferenceImpl.java b/taverna-reference-impl/src/main/java/org/apache/taverna/reference/impl/ContextualizedT2ReferenceImpl.java
new file mode 100644
index 0000000..1eca847
--- /dev/null
+++ b/taverna-reference-impl/src/main/java/org/apache/taverna/reference/impl/ContextualizedT2ReferenceImpl.java
@@ -0,0 +1,60 @@
+/*
+* 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.reference.impl;
+
+import org.apache.taverna.reference.ContextualizedT2Reference;
+import org.apache.taverna.reference.T2Reference;
+
+/**
+ * Simple implementation of ContextualizedT2Reference
+ * 
+ * @author Tom Oinn
+ */
+public class ContextualizedT2ReferenceImpl implements ContextualizedT2Reference {
+	private T2Reference reference;
+	private int[] index;
+
+	public ContextualizedT2ReferenceImpl(T2Reference ref, int[] context) {
+		this.reference = ref;
+		this.index = context;
+	}
+
+	@Override
+	public int[] getIndex() {
+		return this.index;
+	}
+
+	@Override
+	public T2Reference getReference() {
+		return this.reference;
+	}
+
+	@Override
+	public String toString() {
+		StringBuilder sb = new StringBuilder("[");
+		String sep = "";
+		for (int idx : index) {
+			sb.append(sep).append(idx);
+			sep = ",";
+		}
+		return sb.append("]").append(reference).toString();
+	}
+	
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-engine/blob/5f1ddb71/taverna-reference-impl/src/main/java/org/apache/taverna/reference/impl/EmptyReferenceContext.java
----------------------------------------------------------------------
diff --git a/taverna-reference-impl/src/main/java/org/apache/taverna/reference/impl/EmptyReferenceContext.java b/taverna-reference-impl/src/main/java/org/apache/taverna/reference/impl/EmptyReferenceContext.java
new file mode 100644
index 0000000..74ee5db
--- /dev/null
+++ b/taverna-reference-impl/src/main/java/org/apache/taverna/reference/impl/EmptyReferenceContext.java
@@ -0,0 +1,45 @@
+/*
+* 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.reference.impl;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.taverna.reference.ReferenceContext;
+
+/**
+ * A trivial implementation of ReferenceContext, used if the context parameter
+ * to any service method is null.
+ * 
+ * @author Tom Oinn
+ */
+public class EmptyReferenceContext implements ReferenceContext {
+	/**
+	 * Return an empty entity set for all queries.
+	 */
+	@Override
+	public <T> List<T> getEntities(Class<T> arg0) {
+		return new ArrayList<>();
+	}
+
+	@Override
+	public void addEntity(Object entity) {
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-engine/blob/5f1ddb71/taverna-reference-impl/src/main/java/org/apache/taverna/reference/impl/ErrorDocumentImpl.java
----------------------------------------------------------------------
diff --git a/taverna-reference-impl/src/main/java/org/apache/taverna/reference/impl/ErrorDocumentImpl.java b/taverna-reference-impl/src/main/java/org/apache/taverna/reference/impl/ErrorDocumentImpl.java
new file mode 100644
index 0000000..96bf3af
--- /dev/null
+++ b/taverna-reference-impl/src/main/java/org/apache/taverna/reference/impl/ErrorDocumentImpl.java
@@ -0,0 +1,119 @@
+/*
+* 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.reference.impl;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.taverna.reference.ErrorDocument;
+import org.apache.taverna.reference.StackTraceElementBean;
+import org.apache.taverna.reference.T2Reference;
+import org.apache.taverna.reference.h3.HibernateMappedEntity;
+
+/**
+ * Simple bean implementation of ErrorDocument
+ * 
+ * @author Tom Oinn
+ */
+public class ErrorDocumentImpl extends AbstractEntityImpl implements
+		ErrorDocument, HibernateMappedEntity {
+	private String exceptionMessage = "";
+	private String message = "";
+	List<StackTraceElementBean> stackTrace;
+	Set<T2Reference> errorReferences = new HashSet<>();
+	
+	public ErrorDocumentImpl() {
+		this.stackTrace = new ArrayList<>();
+	}
+
+	@Override
+	public String getExceptionMessage() {
+		return this.exceptionMessage;
+	}
+
+	public void setExceptionMessage(String exceptionMessage) {
+		this.exceptionMessage = exceptionMessage;
+	}
+
+	@Override
+	public String getMessage() {
+		return this.message;
+	}
+
+	public void setMessage(String message) {
+		this.message = message;
+	}
+
+	/**
+	 * From interface, not used by hibernate internally
+	 */
+	@Override
+	public List<StackTraceElementBean> getStackTraceStrings() {
+		return this.stackTrace;
+	}
+
+	/**
+	 * Used by Hibernate to bodge around problems with interface types in the
+	 * API
+	 */
+	@SuppressWarnings({ "unchecked", "rawtypes" })
+	public void setStackTraceList(List newList) {
+		this.stackTrace = newList;
+	}
+
+	/**
+	 * Used by Hibernate to bodge around problems with interface types in the
+	 * API
+	 */
+	@SuppressWarnings("rawtypes")
+	public List getStackTraceList() {
+		return this.stackTrace;
+	}
+
+	@Override
+	public Set<T2Reference> getErrorReferences() {
+		return errorReferences;
+	}
+
+	/**
+	 * Used by Hibernate to bodge around problems with interface types in the
+	 * API
+	 */
+	@SuppressWarnings({ "unchecked", "rawtypes" })
+	public void setErrorReferenceSet(Set errorReferenceSet) {
+		this.errorReferences = errorReferenceSet;
+	}
+	
+	/**
+	 * Used by Hibernate to bodge around problems with interface types in the
+	 * API
+	 */
+	@SuppressWarnings("rawtypes")
+	public Set getErrorReferenceSet() {
+		return this.errorReferences;
+	}
+	
+	@Override
+	public String toString() {
+		return getMessage();
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-engine/blob/5f1ddb71/taverna-reference-impl/src/main/java/org/apache/taverna/reference/impl/ErrorDocumentServiceImpl.java
----------------------------------------------------------------------
diff --git a/taverna-reference-impl/src/main/java/org/apache/taverna/reference/impl/ErrorDocumentServiceImpl.java b/taverna-reference-impl/src/main/java/org/apache/taverna/reference/impl/ErrorDocumentServiceImpl.java
new file mode 100644
index 0000000..5592ef4
--- /dev/null
+++ b/taverna-reference-impl/src/main/java/org/apache/taverna/reference/impl/ErrorDocumentServiceImpl.java
@@ -0,0 +1,162 @@
+/*
+* 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.reference.impl;
+
+import static org.apache.taverna.reference.impl.T2ReferenceImpl.getAsImpl;
+
+import java.util.Set;
+
+import org.apache.taverna.reference.ErrorDocument;
+import org.apache.taverna.reference.ErrorDocumentService;
+import org.apache.taverna.reference.ErrorDocumentServiceException;
+import org.apache.taverna.reference.ReferenceContext;
+import org.apache.taverna.reference.ReferenceServiceException;
+import org.apache.taverna.reference.T2Reference;
+
+/**
+ * Implementation of ErrorDocumentService, inject with an appropriate
+ * ErrorDocumentDao and T2ReferenceGenerator to enable.
+ * 
+ * @author Tom Oinn
+ */
+public class ErrorDocumentServiceImpl extends AbstractErrorDocumentServiceImpl
+		implements ErrorDocumentService {
+	@Override
+	public ErrorDocument getError(T2Reference id)
+			throws ErrorDocumentServiceException {
+		checkDao();
+		try {
+			return errorDao.get(id);
+		} catch (Throwable t) {
+			throw new ErrorDocumentServiceException(t);
+		}
+	}
+
+	/**
+	 * Register the specified error and any child errors (which have the same
+	 * namespace and local part but a lower depth, down to depth of zero
+	 */
+	@Override
+	public ErrorDocument registerError(String message, Throwable t, int depth,
+			ReferenceContext context) throws ErrorDocumentServiceException {
+		checkDao();
+		checkGenerator();
+
+		T2Reference ref = t2ReferenceGenerator.nextErrorDocumentReference(
+				depth, context);
+		T2ReferenceImpl typedId = getAsImpl(ref);
+
+		ErrorDocument docToReturn = null;
+		for (; depth >= 0; depth--) {
+			ErrorDocumentImpl edi = new ErrorDocumentImpl();
+			if (docToReturn == null)
+				docToReturn = edi;
+			edi.setTypedId(typedId);
+			if (message != null)
+				edi.setMessage(message);
+			else
+				edi.setMessage("");
+			if (t != null) {
+				edi.setExceptionMessage(t.toString());
+				for (StackTraceElement ste : t.getStackTrace()) {
+					StackTraceElementBeanImpl stebi = new StackTraceElementBeanImpl();
+					stebi.setClassName(ste.getClassName());
+					stebi.setFileName(ste.getFileName());
+					stebi.setLineNumber(ste.getLineNumber());
+					stebi.setMethodName(ste.getMethodName());
+					edi.stackTrace.add(stebi);
+				}
+			} else
+				edi.setExceptionMessage("");
+			try {
+				errorDao.store(edi);
+			} catch (Throwable t2) {
+				throw new ErrorDocumentServiceException(t2);
+			}
+			if (depth > 0)
+				typedId = typedId.getDeeperErrorReference();
+		}
+		return docToReturn;
+	}
+
+	@Override
+	public ErrorDocument registerError(String message, Set<T2Reference> errors,
+			int depth, ReferenceContext context)
+			throws ErrorDocumentServiceException {
+		checkDao();
+		checkGenerator();
+
+		T2Reference ref = t2ReferenceGenerator.nextErrorDocumentReference(
+				depth, context);
+		T2ReferenceImpl typedId = T2ReferenceImpl.getAsImpl(ref);
+
+		ErrorDocument docToReturn = null;
+		for (; depth >= 0; depth--) {
+			ErrorDocumentImpl edi = new ErrorDocumentImpl();
+			if (docToReturn == null)
+				docToReturn = edi;
+			edi.setTypedId(typedId);
+			if (message != null)
+				edi.setMessage(message);
+			else
+				edi.setMessage("");
+			if (errors != null)
+				edi.setErrorReferenceSet(errors);
+			edi.setExceptionMessage("");
+
+			try {
+				errorDao.store(edi);
+			} catch (Throwable t2) {
+				throw new ErrorDocumentServiceException(t2);
+			}
+			if (depth > 0)
+				typedId = typedId.getDeeperErrorReference();
+		}
+		return docToReturn;
+	}
+
+	@Override
+	public T2Reference getChild(T2Reference errorId)
+			throws ErrorDocumentServiceException {
+		T2ReferenceImpl refImpl = getAsImpl(errorId);
+		try {
+			return refImpl.getDeeperErrorReference();
+		} catch (Throwable t) {
+			throw new ErrorDocumentServiceException(t);
+		}
+	}
+
+	@Override
+	public boolean delete(T2Reference reference)
+			throws ReferenceServiceException {
+		checkDao();
+		ErrorDocument doc = errorDao.get(reference);
+		if (doc == null)
+			return false;
+		return errorDao.delete(doc);
+	}
+
+	@Override
+	public void deleteErrorDocumentsForWorkflowRun(String workflowRunId)
+			throws ReferenceServiceException {
+		checkDao();
+		errorDao.deleteErrorDocumentsForWFRun(workflowRunId);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-engine/blob/5f1ddb71/taverna-reference-impl/src/main/java/org/apache/taverna/reference/impl/HibernateErrorDocumentDao.java
----------------------------------------------------------------------
diff --git a/taverna-reference-impl/src/main/java/org/apache/taverna/reference/impl/HibernateErrorDocumentDao.java b/taverna-reference-impl/src/main/java/org/apache/taverna/reference/impl/HibernateErrorDocumentDao.java
new file mode 100644
index 0000000..fe86880
--- /dev/null
+++ b/taverna-reference-impl/src/main/java/org/apache/taverna/reference/impl/HibernateErrorDocumentDao.java
@@ -0,0 +1,153 @@
+/*
+* 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.reference.impl;
+
+import static org.apache.taverna.reference.T2ReferenceType.ErrorDocument;
+
+import java.util.List;
+
+import org.apache.taverna.reference.DaoException;
+import org.apache.taverna.reference.ErrorDocument;
+import org.apache.taverna.reference.ErrorDocumentDao;
+import org.apache.taverna.reference.T2Reference;
+import org.apache.taverna.reference.annotations.DeleteIdentifiedOperation;
+import org.apache.taverna.reference.annotations.GetIdentifiedOperation;
+import org.apache.taverna.reference.annotations.PutIdentifiedOperation;
+
+import org.hibernate.Query;
+import org.hibernate.Session;
+import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
+
+/**
+ * An implementation of ErrorDocumentDao based on Spring's HibernateDaoSupport.
+ * To use this in spring inject a property 'sessionFactory' with either a
+ * {@link org.springframework.orm.hibernate3.LocalSessionFactoryBean
+ * LocalSessionFactoryBean} or the equivalent class from the T2Platform module
+ * to add SPI based implementation discovery and mapping. To use outside of
+ * Spring ensure you call the setSessionFactory(..) method before using this
+ * (but really, use it from Spring, so much easier).
+ * 
+ * @author Tom Oinn
+ */
+public class HibernateErrorDocumentDao extends HibernateDaoSupport implements
+		ErrorDocumentDao {
+	private static final String GET_ERRORS_FOR_RUN = "FROM ErrorDocumentImpl WHERE namespacePart = :workflow_run_id";
+
+	/**
+	 * Fetch an ErrorDocument list by id
+	 * 
+	 * @param ref
+	 *            the T2Reference to fetch
+	 * @return a retrieved identified list of T2 references
+	 * @throws DaoException
+	 *             if the supplied reference is of the wrong type or if
+	 *             something goes wrong fetching the data or connecting to the
+	 *             database
+	 */
+	@Override
+	@GetIdentifiedOperation
+	public ErrorDocument get(T2Reference ref) throws DaoException {
+		if (ref == null)
+			throw new DaoException(
+					"Supplied reference is null, can't retrieve.");
+		if (!ref.getReferenceType().equals(ErrorDocument))
+			throw new DaoException(
+					"This dao can only retrieve reference of type T2Reference.ErrorDocument");
+		if (!(ref instanceof T2ReferenceImpl))
+			throw new DaoException(
+					"Reference must be an instance of T2ReferenceImpl");
+
+		try {
+			return (ErrorDocumentImpl) getHibernateTemplate().get(
+					ErrorDocumentImpl.class,
+					((T2ReferenceImpl) ref).getCompactForm());
+		} catch (Exception ex) {
+			throw new DaoException(ex);
+		}
+	}
+
+	@Override
+	@PutIdentifiedOperation
+	public void store(ErrorDocument theDocument) throws DaoException {
+		if (theDocument.getId() == null)
+			throw new DaoException(
+					"Supplied error document set has a null ID, allocate "
+							+ "an ID before calling the store method in the dao.");
+		if (!theDocument.getId().getReferenceType().equals(ErrorDocument))
+			throw new DaoException("Strangely the list ID doesn't have type "
+					+ "T2ReferenceType.ErrorDocument, something has probably "
+					+ "gone badly wrong somewhere earlier!");
+		if (!(theDocument instanceof ErrorDocumentImpl))
+			throw new DaoException(
+					"Supplied ErrorDocument not an instance of ErrorDocumentImpl");
+
+		try {
+			getHibernateTemplate().save(theDocument);
+		} catch (Exception ex) {
+			throw new DaoException(ex);
+		}
+	}
+
+	@Override
+	@DeleteIdentifiedOperation
+	public boolean delete(ErrorDocument theDocument) throws DaoException {
+		if (theDocument.getId() == null)
+			throw new DaoException(
+					"Supplied error document set has a null ID, allocate "
+							+ "an ID before calling the store method in the dao.");
+		if (!theDocument.getId().getReferenceType()
+				.equals(ErrorDocument))
+			throw new DaoException("Strangely the list ID doesn't have type "
+					+ "T2ReferenceType.ErrorDocument, something has probably "
+					+ "gone badly wrong somewhere earlier!");
+		if (!(theDocument instanceof ErrorDocumentImpl))
+			throw new DaoException(
+					"Supplied ErrorDocument not an instance of ErrorDocumentImpl");
+
+		try {
+			getHibernateTemplate().delete(theDocument);
+			return true;
+		} catch (Exception ex) {
+			throw new DaoException(ex);
+		}
+	}
+
+	@Override
+	@SuppressWarnings("unchecked")
+	@DeleteIdentifiedOperation
+	public synchronized void deleteErrorDocumentsForWFRun(String workflowRunId)
+			throws DaoException {
+		try {
+			// Select all ErrorDocuments for this wf run
+			Session session = getSession();
+			Query selectQuery = session.createQuery(GET_ERRORS_FOR_RUN);
+			selectQuery.setString("workflow_run_id", workflowRunId);
+			List<ErrorDocument> errorDocuments = selectQuery.list();
+			session.close();
+			/*
+			 * need to close before we do delete otherwise hibernate complains
+			 * that two sessions are accessing collection
+			 */
+			getHibernateTemplate().deleteAll(errorDocuments);
+		} catch (Exception ex) {
+			throw new DaoException(ex);
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-engine/blob/5f1ddb71/taverna-reference-impl/src/main/java/org/apache/taverna/reference/impl/HibernateListDao.java
----------------------------------------------------------------------
diff --git a/taverna-reference-impl/src/main/java/org/apache/taverna/reference/impl/HibernateListDao.java b/taverna-reference-impl/src/main/java/org/apache/taverna/reference/impl/HibernateListDao.java
new file mode 100644
index 0000000..f7c0cbd
--- /dev/null
+++ b/taverna-reference-impl/src/main/java/org/apache/taverna/reference/impl/HibernateListDao.java
@@ -0,0 +1,150 @@
+/*
+* 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.reference.impl;
+
+import static org.apache.taverna.reference.T2ReferenceType.IdentifiedList;
+
+import java.util.List;
+
+import org.apache.taverna.reference.DaoException;
+import org.apache.taverna.reference.IdentifiedList;
+import org.apache.taverna.reference.ListDao;
+import org.apache.taverna.reference.T2Reference;
+import org.apache.taverna.reference.annotations.DeleteIdentifiedOperation;
+import org.apache.taverna.reference.annotations.GetIdentifiedOperation;
+import org.apache.taverna.reference.annotations.PutIdentifiedOperation;
+
+import org.hibernate.Query;
+import org.hibernate.Session;
+import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
+
+/**
+ * An implementation of ListDao based on Spring's HibernateDaoSupport. To use
+ * this in spring inject a property 'sessionFactory' with either a
+ * {@link org.springframework.orm.hibernate3.LocalSessionFactoryBean
+ * LocalSessionFactoryBean} or the equivalent class from the T2Platform module
+ * to add SPI based implementation discovery and mapping. To use outside of
+ * Spring ensure you call the setSessionFactory(..) method before using this
+ * (but really, use it from Spring, so much easier).
+ * 
+ * @author Tom Oinn
+ */
+public class HibernateListDao extends HibernateDaoSupport implements ListDao {
+	private static final String GET_LISTS_FOR_RUN = "FROM T2ReferenceListImpl WHERE namespacePart = :workflow_run_id";
+
+	/**
+	 * Fetch a t2reference list by id
+	 * 
+	 * @param ref
+	 *            the T2Reference to fetch
+	 * @return a retrieved identified list of T2 references
+	 * @throws DaoException
+	 *             if the supplied reference is of the wrong type or if
+	 *             something goes wrong fetching the data or connecting to the
+	 *             database
+	 */
+	@Override
+	@GetIdentifiedOperation
+	public IdentifiedList<T2Reference> get(T2Reference ref) throws DaoException {
+		if (ref == null)
+			throw new DaoException(
+					"Supplied reference is null, can't retrieve.");
+		if (!ref.getReferenceType().equals(IdentifiedList))
+			throw new DaoException(
+					"This dao can only retrieve reference of type T2Reference.IdentifiedList");
+		if (!(ref instanceof T2ReferenceImpl))
+			throw new DaoException(
+					"Reference must be an instance of T2ReferenceImpl");
+
+		try {
+			return (T2ReferenceListImpl) getHibernateTemplate().get(
+					T2ReferenceListImpl.class,
+					((T2ReferenceImpl) ref).getCompactForm());
+		} catch (Exception ex) {
+			throw new DaoException(ex);
+		}
+	}
+
+	@Override
+	@PutIdentifiedOperation
+	public void store(IdentifiedList<T2Reference> theList) throws DaoException {
+		if (theList.getId() == null)
+			throw new DaoException("Supplied list set has a null ID, allocate "
+					+ "an ID before calling the store method in the dao.");
+		if (!theList.getId().getReferenceType().equals(IdentifiedList))
+			throw new DaoException("Strangely the list ID doesn't have type "
+					+ "T2ReferenceType.IdentifiedList, something has probably "
+					+ "gone badly wrong somewhere earlier!");
+		if (!(theList instanceof T2ReferenceListImpl))
+			throw new DaoException(
+					"Supplied identifier list not an instance of T2ReferenceList");
+
+		try {
+			getHibernateTemplate().save(theList);
+		} catch (Exception ex) {
+			throw new DaoException(ex);
+		}
+	}
+
+	@Override
+	public boolean delete(IdentifiedList<T2Reference> theList)
+			throws DaoException {
+		if (theList.getId() == null)
+			throw new DaoException("Supplied list set has a null ID, allocate "
+					+ "an ID before calling the store method in the dao.");
+		if (!theList.getId().getReferenceType().equals(IdentifiedList))
+			throw new DaoException("Strangely the list ID doesn't have type "
+					+ "T2ReferenceType.IdentifiedList, something has probably "
+					+ "gone badly wrong somewhere earlier!");
+		if (!(theList instanceof T2ReferenceListImpl))
+			throw new DaoException(
+					"Supplied identifier list not an instance of T2ReferenceList");
+
+		try {
+			getHibernateTemplate().delete(theList);
+			return true;
+		} catch (Exception ex) {
+			throw new DaoException(ex);
+		}
+	}
+
+	@Override
+	@SuppressWarnings("unchecked")
+	@DeleteIdentifiedOperation
+	public synchronized void deleteIdentifiedListsForWFRun(String workflowRunId)
+			throws DaoException {
+		try {
+			// Select all T2Reference lists for this wf run
+			Session session = getSession();
+			Query selectQuery = session.createQuery(GET_LISTS_FOR_RUN);
+			selectQuery.setString("workflow_run_id", workflowRunId);
+			List<IdentifiedList<T2Reference>> identifiedLists = selectQuery
+					.list();
+			session.close();
+			/*
+			 * need to close before we do delete otherwise hibernate complains
+			 * that two sessions are accessing collection
+			 */
+			getHibernateTemplate().deleteAll(identifiedLists);
+		} catch (Exception ex) {
+			throw new DaoException(ex);
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-engine/blob/5f1ddb71/taverna-reference-impl/src/main/java/org/apache/taverna/reference/impl/HibernateReferenceSetDao.java
----------------------------------------------------------------------
diff --git a/taverna-reference-impl/src/main/java/org/apache/taverna/reference/impl/HibernateReferenceSetDao.java b/taverna-reference-impl/src/main/java/org/apache/taverna/reference/impl/HibernateReferenceSetDao.java
new file mode 100644
index 0000000..c710aa7
--- /dev/null
+++ b/taverna-reference-impl/src/main/java/org/apache/taverna/reference/impl/HibernateReferenceSetDao.java
@@ -0,0 +1,197 @@
+/*******************************************************************************
+ * Copyright (C) 2007 The University of Manchester   
+ * 
+ *  Modifications to the initial code base are copyright of their
+ *  respective authors, or their employers as appropriate.
+ * 
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1 of
+ *  the License, or (at your option) any later version.
+ *    
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *    
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+package org.apache.taverna.reference.impl;
+
+import static org.apache.taverna.reference.T2ReferenceType.ReferenceSet;
+
+import java.util.List;
+
+import org.apache.taverna.reference.DaoException;
+import org.apache.taverna.reference.ReferenceSet;
+import org.apache.taverna.reference.ReferenceSetDao;
+import org.apache.taverna.reference.T2Reference;
+import org.apache.taverna.reference.annotations.DeleteIdentifiedOperation;
+import org.apache.taverna.reference.annotations.GetIdentifiedOperation;
+import org.apache.taverna.reference.annotations.PutIdentifiedOperation;
+
+import org.hibernate.Query;
+import org.hibernate.Session;
+import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
+
+/**
+ * An implementation of ReferenceSetDao based on Spring's HibernateDaoSupport.
+ * To use this in spring inject a property 'sessionFactory' with either a
+ * {@link org.springframework.orm.hibernate3.LocalSessionFactoryBean
+ * LocalSessionFactoryBean} or the equivalent class from the T2Platform module
+ * to add SPI based implementation discovery and mapping. To use outside of
+ * Spring ensure you call the setSessionFactory(..) method before using this
+ * (but really, use it from Spring, so much easier).
+ * 
+ * @author Tom Oinn
+ */
+public class HibernateReferenceSetDao extends HibernateDaoSupport implements
+		ReferenceSetDao {
+	private static final String GET_REFSETS_FOR_RUN = "FROM ReferenceSetImpl WHERE namespacePart = :workflow_run_id";
+
+	/**
+	 * Store the specified new reference set
+	 * 
+	 * @param rs
+	 *            a reference set, must not already exist in the database.
+	 * @throws DaoException
+	 *             if the entry already exists in the database, if the supplied
+	 *             reference set isn't an instance of ReferenceSetImpl or if
+	 *             something else goes wrong connecting to the database
+	 */
+	@Override
+	@PutIdentifiedOperation
+	public void store(ReferenceSet rs) throws DaoException {
+		if (rs.getId() == null)
+			throw new DaoException(
+					"Supplied reference set has a null ID, allocate "
+							+ "an ID before calling the store method in the dao.");
+		if (!rs.getId().getReferenceType().equals(ReferenceSet))
+			throw new DaoException(
+					"Strangely the reference set ID doesn't have type "
+							+ "T2ReferenceType.ReferenceSet, something has probably "
+							+ "gone badly wrong somewhere earlier!");
+		if (!(rs instanceof ReferenceSetImpl))
+			throw new DaoException(
+					"Supplied reference set not an instance of ReferenceSetImpl");
+
+		try {
+			getHibernateTemplate().save(rs);
+		} catch (Exception ex) {
+			throw new DaoException(ex);
+		}
+	}
+
+	/**
+	 * Update a pre-existing entry in the database
+	 * 
+	 * @param rs
+	 *            the reference set to update. This must already exist in the
+	 *            database
+	 * @throws DaoException
+	 */
+	@Override
+	@PutIdentifiedOperation
+	public void update(ReferenceSet rs) throws DaoException {
+		if (rs.getId() == null)
+			throw new DaoException(
+					"Supplied reference set has a null ID, allocate "
+							+ "an ID before calling the store method in the dao.");
+		if (!rs.getId().getReferenceType().equals(ReferenceSet))
+			throw new DaoException(
+					"Strangely the reference set ID doesn't have type "
+							+ "T2ReferenceType.ReferenceSet, something has probably "
+							+ "gone badly wrong somewhere earlier!");
+		if (!(rs instanceof ReferenceSetImpl))
+			throw new DaoException(
+					"Supplied reference set not an instance of ReferenceSetImpl");
+
+		try {
+			getHibernateTemplate().update(rs);
+		} catch (Exception ex) {
+			throw new DaoException(ex);
+		}
+	}
+
+	/**
+	 * Fetch a reference set by id
+	 * 
+	 * @param ref
+	 *            the ReferenceSetT2ReferenceImpl to fetch
+	 * @return a retrieved ReferenceSetImpl
+	 * @throws DaoException
+	 *             if the supplied reference is of the wrong type or if
+	 *             something goes wrong fetching the data or connecting to the
+	 *             database
+	 */
+	@Override
+	@GetIdentifiedOperation
+	public ReferenceSetImpl get(T2Reference ref) throws DaoException {
+		if (ref == null)
+			throw new DaoException(
+					"Supplied reference is null, can't retrieve.");
+		if (!ref.getReferenceType().equals(ReferenceSet))
+			throw new DaoException(
+					"This dao can only retrieve reference of type T2Reference.ReferenceSet");
+		if (!(ref instanceof T2ReferenceImpl))
+			throw new DaoException(
+					"Reference must be an instance of T2ReferenceImpl");
+
+		try {
+			return (ReferenceSetImpl) getHibernateTemplate().get(
+					ReferenceSetImpl.class,
+					((T2ReferenceImpl) ref).getCompactForm());
+		} catch (Exception ex) {
+			throw new DaoException(ex);
+		}
+	}
+
+	@Override
+	@DeleteIdentifiedOperation
+	public boolean delete(ReferenceSet rs) throws DaoException {
+		if (rs.getId() == null)
+			throw new DaoException(
+					"Supplied reference set has a null ID, allocate "
+							+ "an ID before calling the store method in the dao.");
+		if (!rs.getId().getReferenceType().equals(ReferenceSet))
+			throw new DaoException(
+					"Strangely the reference set ID doesn't have type "
+							+ "T2ReferenceType.ReferenceSet, something has probably "
+							+ "gone badly wrong somewhere earlier!");
+		if (!(rs instanceof ReferenceSetImpl))
+			throw new DaoException(
+					"Supplied reference set not an instance of ReferenceSetImpl");
+
+		try {
+			getHibernateTemplate().delete(rs);
+			return true;
+		} catch (Exception ex) {
+			throw new DaoException(ex);
+		}
+	}
+
+	@Override
+	@SuppressWarnings("unchecked")
+	@DeleteIdentifiedOperation
+	public synchronized void deleteReferenceSetsForWFRun(String workflowRunId)
+			throws DaoException {
+		try {
+			// Select all ReferenceSets for this wf run
+			Session session = getSession();
+			Query selectQuery = session
+					.createQuery(GET_REFSETS_FOR_RUN);
+			selectQuery.setString("workflow_run_id", workflowRunId);
+			List<ReferenceSet> referenceSets = selectQuery.list();
+			session.close();
+			/*
+			 * need to close before we do delete otherwise hibernate complains
+			 * that two sessions are accessing collection
+			 */
+			getHibernateTemplate().deleteAll(referenceSets);
+		} catch (Exception ex) {
+			throw new DaoException(ex);
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-engine/blob/5f1ddb71/taverna-reference-impl/src/main/java/org/apache/taverna/reference/impl/IdentifiedArrayList.java
----------------------------------------------------------------------
diff --git a/taverna-reference-impl/src/main/java/org/apache/taverna/reference/impl/IdentifiedArrayList.java b/taverna-reference-impl/src/main/java/org/apache/taverna/reference/impl/IdentifiedArrayList.java
new file mode 100644
index 0000000..43325dc
--- /dev/null
+++ b/taverna-reference-impl/src/main/java/org/apache/taverna/reference/impl/IdentifiedArrayList.java
@@ -0,0 +1,252 @@
+/*******************************************************************************
+ * Copyright (C) 2007 The University of Manchester   
+ * 
+ *  Modifications to the initial code base are copyright of their
+ *  respective authors, or their employers as appropriate.
+ * 
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1 of
+ *  the License, or (at your option) any later version.
+ *    
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *    
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+package org.apache.taverna.reference.impl;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+
+import org.apache.taverna.reference.IdentifiedList;
+
+/**
+ * Implementation of IdentifiedList which delegates to an ArrayList for its
+ * storage functionality.
+ * 
+ * @author Tom Oinn
+ * 
+ * @param <T>
+ */
+public class IdentifiedArrayList<T> extends AbstractEntityImpl implements
+		IdentifiedList<T> {
+	protected List<T> listDelegate = null;
+
+	// Constructors copied from ArrayList for convenience
+	public IdentifiedArrayList() {
+		super();
+		this.listDelegate = new ArrayList<>();
+	}
+
+	public IdentifiedArrayList(Collection<T> c) {
+		super();
+		this.listDelegate = new ArrayList<>(c);
+	}
+
+	public IdentifiedArrayList(int initialCapacity) {
+		super();
+		this.listDelegate = new ArrayList<>(initialCapacity);
+	}
+
+	private void checkUndefinedId() {
+		if (this.getId() != null)
+			throw new IllegalStateException(
+					"Attempt made to modify a list which has already been named");
+	}
+
+	@Override
+	public boolean add(T e) {
+		checkUndefinedId();
+		return listDelegate.add(e);
+	}
+
+	@Override
+	public void add(int index, T element) {
+		checkUndefinedId();
+		listDelegate.add(index, element);
+	}
+
+	@Override
+	public boolean addAll(Collection<? extends T> c) {
+		checkUndefinedId();
+		return listDelegate.addAll(c);
+	}
+
+	@Override
+	public boolean addAll(int index, Collection<? extends T> c) {
+		checkUndefinedId();
+		return listDelegate.addAll(index, c);
+	}
+
+	@Override
+	public void clear() {
+		checkUndefinedId();
+		listDelegate.clear();
+	}
+
+	@Override
+	public boolean contains(Object o) {
+		return listDelegate.contains(o);
+	}
+
+	@Override
+	public boolean containsAll(Collection<?> c) {
+		return listDelegate.containsAll(c);
+	}
+
+	@Override
+	public T get(int index) {
+		return listDelegate.get(index);
+	}
+
+	@Override
+	public int indexOf(Object o) {
+		return listDelegate.indexOf(o);
+	}
+
+	@Override
+	public boolean isEmpty() {
+		return listDelegate.isEmpty();
+	}
+
+	@Override
+	public Iterator<T> iterator() {
+		return listDelegate.iterator();
+	}
+
+	@Override
+	public int lastIndexOf(Object o) {
+		return listDelegate.lastIndexOf(o);
+	}
+
+	/**
+	 * The ListIterator can modify the list contents, so wrap the delegate's
+	 * list iterator and use as a delegate itself, checking for null ID on
+	 * operations which set list properties.
+	 * 
+	 * @param iteratorDelegate
+	 *            ListIterator to wrap.
+	 * @return wrapped ListIterator which throws IllegalStateException on calls
+	 *         which modify the list if the ID has been set to a non-null value
+	 */
+	private ListIterator<T> getCheckedListIterator(
+			final ListIterator<T> iteratorDelegate) {
+		return new ListIterator<T>() {
+			@Override
+			public void add(T e) {
+				checkUndefinedId();
+				iteratorDelegate.add(e);
+			}
+
+			@Override
+			public boolean hasNext() {
+				return iteratorDelegate.hasNext();
+			}
+
+			@Override
+			public boolean hasPrevious() {
+				return iteratorDelegate.hasPrevious();
+			}
+
+			@Override
+			public T next() {
+				return iteratorDelegate.next();
+			}
+
+			@Override
+			public int nextIndex() {
+				return iteratorDelegate.nextIndex();
+			}
+
+			@Override
+			public T previous() {
+				return iteratorDelegate.previous();
+			}
+
+			@Override
+			public int previousIndex() {
+				return iteratorDelegate.previousIndex();
+			}
+
+			@Override
+			public void remove() {
+				checkUndefinedId();
+				iteratorDelegate.remove();
+			}
+
+			@Override
+			public void set(T e) {
+				checkUndefinedId();
+				iteratorDelegate.set(e);
+			}
+		};
+	}
+
+	@Override
+	public ListIterator<T> listIterator() {
+		return getCheckedListIterator(listDelegate.listIterator());
+	}
+
+	@Override
+	public ListIterator<T> listIterator(int index) {
+		return getCheckedListIterator(listDelegate.listIterator(index));
+	}
+
+	@Override
+	public boolean remove(Object o) {
+		checkUndefinedId();
+		return listDelegate.remove(o);
+	}
+
+	@Override
+	public T remove(int index) {
+		checkUndefinedId();
+		return listDelegate.remove(index);
+	}
+
+	@Override
+	public boolean removeAll(Collection<?> c) {
+		checkUndefinedId();
+		return listDelegate.removeAll(c);
+	}
+
+	@Override
+	public boolean retainAll(Collection<?> c) {
+		checkUndefinedId();
+		return listDelegate.retainAll(c);
+	}
+
+	@Override
+	public T set(int index, T element) {
+		checkUndefinedId();
+		return listDelegate.set(index, element);
+	}
+
+	@Override
+	public int size() {
+		return listDelegate.size();
+	}
+
+	@Override
+	public List<T> subList(int fromIndex, int toIndex) {
+		return listDelegate.subList(fromIndex, toIndex);
+	}
+
+	@Override
+	public Object[] toArray() {
+		return listDelegate.toArray();
+	}
+
+	@Override
+	public <U> U[] toArray(U[] a) {
+		return listDelegate.toArray(a);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-engine/blob/5f1ddb71/taverna-reference-impl/src/main/java/org/apache/taverna/reference/impl/InMemoryErrorDocumentDao.java
----------------------------------------------------------------------
diff --git a/taverna-reference-impl/src/main/java/org/apache/taverna/reference/impl/InMemoryErrorDocumentDao.java b/taverna-reference-impl/src/main/java/org/apache/taverna/reference/impl/InMemoryErrorDocumentDao.java
new file mode 100644
index 0000000..d06ecbe
--- /dev/null
+++ b/taverna-reference-impl/src/main/java/org/apache/taverna/reference/impl/InMemoryErrorDocumentDao.java
@@ -0,0 +1,69 @@
+/*******************************************************************************
+ * Copyright (C) 2007 The University of Manchester   
+ * 
+ *  Modifications to the initial code base are copyright of their
+ *  respective authors, or their employers as appropriate.
+ * 
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1 of
+ *  the License, or (at your option) any later version.
+ *    
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *    
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ ******************************************************************************/
+package org.apache.taverna.reference.impl;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.apache.taverna.reference.DaoException;
+import org.apache.taverna.reference.ErrorDocument;
+import org.apache.taverna.reference.ErrorDocumentDao;
+import org.apache.taverna.reference.T2Reference;
+
+/**
+ * A trivial in-memory implementation of ErrorDocumentDao for either testing or
+ * very lightweight embedded systems. Uses a java Map as the backing store.
+ * 
+ * @author Tom Oinn
+ */
+public class InMemoryErrorDocumentDao implements ErrorDocumentDao {
+	private Map<T2Reference, ErrorDocument> store;
+
+	public InMemoryErrorDocumentDao() {
+		this.store = new ConcurrentHashMap<>();
+	}
+
+	@Override
+	public synchronized ErrorDocument get(T2Reference reference)
+			throws DaoException {
+		return store.get(reference);
+	}
+
+	@Override
+	public synchronized void store(ErrorDocument theDoc) throws DaoException {
+		store.put(theDoc.getId(), theDoc);
+	}
+
+	@Override
+	public synchronized boolean delete(ErrorDocument theDoc)
+			throws DaoException {
+		return store.remove(theDoc.getId()) != null;
+	}
+
+	@Override
+	public synchronized void deleteErrorDocumentsForWFRun(String workflowRunId)
+			throws DaoException {
+		for (T2Reference reference : store.keySet())
+			if (reference.getNamespacePart().equals(workflowRunId))
+				store.remove(reference);
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-engine/blob/5f1ddb71/taverna-reference-impl/src/main/java/org/apache/taverna/reference/impl/InMemoryListDao.java
----------------------------------------------------------------------
diff --git a/taverna-reference-impl/src/main/java/org/apache/taverna/reference/impl/InMemoryListDao.java b/taverna-reference-impl/src/main/java/org/apache/taverna/reference/impl/InMemoryListDao.java
new file mode 100644
index 0000000..00bb188
--- /dev/null
+++ b/taverna-reference-impl/src/main/java/org/apache/taverna/reference/impl/InMemoryListDao.java
@@ -0,0 +1,68 @@
+/*
+* 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.reference.impl;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.apache.taverna.reference.DaoException;
+import org.apache.taverna.reference.IdentifiedList;
+import org.apache.taverna.reference.ListDao;
+import org.apache.taverna.reference.T2Reference;
+
+/**
+ * A trivial in-memory implementation of ListDao for either testing or very
+ * lightweight embedded systems. Uses a java Map as the backing store.
+ * 
+ * @author Tom Oinn
+ */
+public class InMemoryListDao implements ListDao {
+	private Map<T2Reference, IdentifiedList<T2Reference>> store;
+
+	public InMemoryListDao() {
+		this.store = new ConcurrentHashMap<>();
+	}
+
+	@Override
+	public synchronized IdentifiedList<T2Reference> get(T2Reference reference)
+			throws DaoException {
+		return store.get(reference);
+	}
+
+	@Override
+	public synchronized void store(IdentifiedList<T2Reference> theList)
+			throws DaoException {
+		store.put(theList.getId(), theList);
+	}
+
+	@Override
+	public boolean delete(IdentifiedList<T2Reference> theList)
+			throws DaoException {
+		return (store.remove(theList.getId()) != null);
+	}
+
+	@Override
+	public synchronized void deleteIdentifiedListsForWFRun(String workflowRunId)
+			throws DaoException {
+		for (T2Reference reference : store.keySet())
+			if (reference.getNamespacePart().equals(workflowRunId))
+				store.remove(reference);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-engine/blob/5f1ddb71/taverna-reference-impl/src/main/java/org/apache/taverna/reference/impl/InMemoryReferenceSetDao.java
----------------------------------------------------------------------
diff --git a/taverna-reference-impl/src/main/java/org/apache/taverna/reference/impl/InMemoryReferenceSetDao.java b/taverna-reference-impl/src/main/java/org/apache/taverna/reference/impl/InMemoryReferenceSetDao.java
new file mode 100644
index 0000000..76c0e56
--- /dev/null
+++ b/taverna-reference-impl/src/main/java/org/apache/taverna/reference/impl/InMemoryReferenceSetDao.java
@@ -0,0 +1,71 @@
+/*
+* 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.reference.impl;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.apache.taverna.reference.DaoException;
+import org.apache.taverna.reference.ReferenceSet;
+import org.apache.taverna.reference.ReferenceSetDao;
+import org.apache.taverna.reference.T2Reference;
+
+/**
+ * A trivial in-memory implementation of ReferenceSetDao for either testing or
+ * very lightweight embedded systems. Uses a java Map as the backing store.
+ * 
+ * @author Tom Oinn
+ */
+public class InMemoryReferenceSetDao implements ReferenceSetDao {
+	private Map<T2Reference, ReferenceSet> store;
+
+	public InMemoryReferenceSetDao() {
+		this.store = new ConcurrentHashMap<>();
+	}
+
+	@Override
+	public synchronized ReferenceSet get(T2Reference reference)
+			throws DaoException {
+		return store.get(reference);
+	}
+
+	@Override
+	public synchronized void store(ReferenceSet refSet) throws DaoException {
+		store.put(refSet.getId(), refSet);
+	}
+
+	@Override
+	public synchronized void update(ReferenceSet refSet) throws DaoException {
+		store.put(refSet.getId(), refSet);
+	}
+
+	@Override
+	public synchronized boolean delete(ReferenceSet refSet) throws DaoException {
+		return store.remove(refSet.getId()) != null;
+	}
+
+	@Override
+	public synchronized void deleteReferenceSetsForWFRun(String workflowRunId)
+			throws DaoException {
+		for (T2Reference reference : store.keySet())
+			if (reference.getNamespacePart().equals(workflowRunId))
+				store.remove(reference);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-taverna-engine/blob/5f1ddb71/taverna-reference-impl/src/main/java/org/apache/taverna/reference/impl/ListServiceImpl.java
----------------------------------------------------------------------
diff --git a/taverna-reference-impl/src/main/java/org/apache/taverna/reference/impl/ListServiceImpl.java b/taverna-reference-impl/src/main/java/org/apache/taverna/reference/impl/ListServiceImpl.java
new file mode 100644
index 0000000..5cc1d60
--- /dev/null
+++ b/taverna-reference-impl/src/main/java/org/apache/taverna/reference/impl/ListServiceImpl.java
@@ -0,0 +1,135 @@
+/*
+* 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.reference.impl;
+
+import static org.apache.taverna.reference.impl.T2ReferenceImpl.getAsImpl;
+
+import java.util.List;
+
+import org.apache.taverna.reference.DaoException;
+import org.apache.taverna.reference.IdentifiedList;
+import org.apache.taverna.reference.ListService;
+import org.apache.taverna.reference.ListServiceException;
+import org.apache.taverna.reference.ReferenceContext;
+import org.apache.taverna.reference.ReferenceServiceException;
+import org.apache.taverna.reference.T2Reference;
+
+/**
+ * Implementation of ListService, inject with an appropriate ListDao and
+ * T2ReferenceGenerator to enable.
+ * 
+ * @author Tom Oinn
+ */
+public class ListServiceImpl extends AbstractListServiceImpl implements
+		ListService {
+	@Override
+	public IdentifiedList<T2Reference> getList(T2Reference id)
+			throws ListServiceException {
+		checkDao();
+		try {
+			return listDao.get(id);
+		} catch (DaoException de) {
+			throw new ListServiceException(de);
+		}
+	}
+
+	@Override
+	public IdentifiedList<T2Reference> registerEmptyList(int depth,
+			ReferenceContext context) throws ListServiceException {
+		if (depth < 1)
+			throw new ListServiceException(
+					"Can't register empty lists of depth " + depth);
+		checkDao();
+		checkGenerator();
+		T2ReferenceImpl newReference = getAsImpl(t2ReferenceGenerator
+				.nextListReference(false, depth, context));
+		T2ReferenceListImpl newList = new T2ReferenceListImpl();
+		newList.setTypedId(newReference);
+		try {
+			listDao.store(newList);
+			return newList;
+		} catch (DaoException de) {
+			throw new ListServiceException(de);
+		}
+	}
+
+	@Override
+	public IdentifiedList<T2Reference> registerList(List<T2Reference> items,
+			ReferenceContext context) throws ListServiceException {
+		checkDao();
+		checkGenerator();
+		if (items.isEmpty())
+			throw new ListServiceException(
+					"Can't register an empty list with this method,"
+							+ " use the registerEmptyList instead");
+		/*
+		 * Track whether there are any items in the collection which are or
+		 * contain error documents.
+		 */
+		boolean containsErrors = false;
+		// Track depth, ensure that all items have the same depth, fail if not.
+		int depth = items.get(0).getDepth();
+		if (depth < 0)
+			throw new ListServiceException(
+					"Can't register list of depth less than 1, but first item "
+							+ items.get(0) + " has depth " + depth);
+		T2ReferenceListImpl newList = new T2ReferenceListImpl();
+		int counter = 0;
+		for (T2Reference ref : items) {
+			if (ref.getDepth() != depth)
+				throw new ListServiceException(
+						"Mismatched depths in list registration; reference at index '"
+								+ counter + "' has depth " + ref.getDepth()
+								+ " but all preceeding items have depth "
+								+ depth);
+			if (ref.containsErrors())
+				// The collection's reference contains errors if any child does
+				containsErrors = true;
+			newList.add(ref);
+			counter++;
+		}
+		try {
+			T2ReferenceImpl newReference = getAsImpl(t2ReferenceGenerator
+					.nextListReference(containsErrors, depth + 1, context));
+			newList.setTypedId(newReference);
+			listDao.store(newList);
+			return newList;
+		} catch (Throwable t) {
+			throw new ListServiceException(t);
+		}
+	}
+
+	@Override
+	public boolean delete(T2Reference reference)
+			throws ReferenceServiceException {
+		checkDao();
+		IdentifiedList<T2Reference> list = listDao.get(reference);
+		if (list == null)
+			return false;
+		return listDao.delete(list);
+	}
+
+	@Override
+	public void deleteIdentifiedListsForWorkflowRun(String workflowRunId)
+			throws ReferenceServiceException {
+		checkDao();
+		listDao.deleteIdentifiedListsForWFRun(workflowRunId);
+	}
+}