Merge branch 'patch-2' of https://github.com/matthiaskoenig/incubator-taverna-language
This closes #34.
Contributed by Matthias König
diff --git a/pom.xml b/pom.xml
index d597b19..9dcb863 100644
--- a/pom.xml
+++ b/pom.xml
@@ -24,7 +24,7 @@
</parent>
<groupId>org.apache.taverna.language</groupId>
<artifactId>apache-taverna-language</artifactId>
- <version>0.15.2-incubating-SNAPSHOT</version>
+ <version>0.16.0-incubating-SNAPSHOT</version>
<packaging>pom</packaging>
<name>Apache Taverna Language APIs (Scufl2, Databundle)</name>
diff --git a/taverna-baclava-language/pom.xml b/taverna-baclava-language/pom.xml
index 1157e64..567b992 100644
--- a/taverna-baclava-language/pom.xml
+++ b/taverna-baclava-language/pom.xml
@@ -23,7 +23,7 @@
<parent>
<groupId>org.apache.taverna.language</groupId>
<artifactId>apache-taverna-language</artifactId>
- <version>0.15.2-incubating-SNAPSHOT</version>
+ <version>0.16.0-incubating-SNAPSHOT</version>
</parent>
<artifactId>taverna-baclava-language</artifactId>
<name>Apache Taverna Baclava support</name>
diff --git a/taverna-databundle/pom.xml b/taverna-databundle/pom.xml
index cb9bb61..25f76b9 100644
--- a/taverna-databundle/pom.xml
+++ b/taverna-databundle/pom.xml
@@ -21,7 +21,7 @@
<parent>
<groupId>org.apache.taverna.language</groupId>
<artifactId>apache-taverna-language</artifactId>
- <version>0.15.2-incubating-SNAPSHOT</version>
+ <version>0.16.0-incubating-SNAPSHOT</version>
</parent>
<artifactId>taverna-databundle</artifactId>
<name>Apache Taverna Databundle API</name>
diff --git a/taverna-databundle/src/main/java/org/apache/taverna/databundle/DataBundles.java b/taverna-databundle/src/main/java/org/apache/taverna/databundle/DataBundles.java
index c491d13..897bc15 100644
--- a/taverna-databundle/src/main/java/org/apache/taverna/databundle/DataBundles.java
+++ b/taverna-databundle/src/main/java/org/apache/taverna/databundle/DataBundles.java
@@ -1,6 +1,4 @@
-package org.apache.taverna.databundle;
/*
- *
* 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
@@ -18,8 +16,8 @@
* specific language governing permissions and limitations
* under the License.
*
-*/
-
+ */
+package org.apache.taverna.databundle;
import static java.nio.file.Files.createDirectories;
import static java.nio.file.Files.delete;
@@ -33,10 +31,16 @@
import static java.nio.file.StandardOpenOption.CREATE;
import static java.nio.file.StandardOpenOption.TRUNCATE_EXISTING;
+import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.io.UncheckedIOException;
+import java.lang.reflect.Array;
+import java.net.MalformedURLException;
import java.net.URI;
+import java.net.URL;
+import java.net.URLStreamHandler;
import java.nio.charset.Charset;
import java.nio.file.DirectoryIteratorException;
import java.nio.file.DirectoryStream;
@@ -45,19 +49,25 @@
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
+import java.util.Collection;
+import java.util.EnumSet;
import java.util.List;
import java.util.NavigableMap;
import java.util.TreeMap;
import java.util.UUID;
-import java.util.logging.Logger;
import java.util.logging.Level;
+import java.util.logging.Logger;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
+import org.apache.taverna.databundle.DataBundles.ResolveOptions;
+import org.apache.taverna.robundle.Bundle;
+import org.apache.taverna.robundle.Bundles;
import org.apache.taverna.scufl2.api.container.WorkflowBundle;
import org.apache.taverna.scufl2.api.io.ReaderException;
import org.apache.taverna.scufl2.api.io.WorkflowBundleIO;
import org.apache.taverna.scufl2.api.io.WriterException;
-import org.apache.taverna.robundle.Bundle;
-import org.apache.taverna.robundle.Bundles;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
@@ -68,7 +78,6 @@
* The style of using this class is similar to that of {@link Files}. In fact, a
* data bundle is implemented as a set of {@link Path}s.
*
- * @author Stian Soiland-Reyes
*/
public class DataBundles extends Bundles {
private static final class OBJECT_MAPPER {
@@ -440,7 +449,279 @@
throw ex.getCause();
}
}
+
+ public enum ResolveOptions {
+ /**
+ * Leaf values are represented as bundle {@link Path}s, except errors as
+ * {@link ErrorDocument} and references as {@link URL}. Note that specifying this
+ * option does not negate any of the other options like {@link #BYTES}.
+ */
+ DEFAULT,
+ /**
+ * Leaf values should be represented as a {@link String} (NOTE: This won't work well if the path is a binary)
+ */
+ STRING,
+ /**
+ * Leaf values should be represented as a <code>byte[]</code>
+ */
+ BYTES,
+ /**
+ * Leaf values should always be represented as {@link URI}s (except errors)
+ */
+ URI,
+ /**
+ * Leaf values should be represented as bundle {@link Path}s (even if they are errors)
+ */
+ PATH,
+ /**
+ * Replace errors with <code>null</code>, or the empty string if {@link #REPLACE_NULL} is also specified.
+ */
+ REPLACE_ERRORS,
+ /**
+ * Instead of returning <code>null</code>, return the empty
+ * {@link String} "", or empty byte[] if {@link #BYTES} is specified, or
+ * the missing path if {@link #PATH} is specified.
+ */
+ REPLACE_NULL
+ }
+
+ /**
+ * Deeply resolve a {@link Path} to JVM objects.
+ * <p>
+ * This method is intended mainly for presentational uses
+ * with a particular input/output port from
+ * {@link #getPorts(Path)} or {@link #getPort(Path, String)}.
+ * <p>
+ * Note that as all lists are resolved deeply (including lists of lists)
+ * and when using options {@link ResolveOptions#STRING} or {@link ResolveOptions#BYTES}
+ * the full content of the values are read into memory, this
+ * method can be time-consuming.
+ * <p>
+ * If the path is <code>null</code> or {@link #isMissing(Path)},
+ * <code>null</code> is returned, unless the option
+ * {@link ResolveOptions#REPLACE_NULL} is specified, which would return the
+ * empty String "".
+ * <p>
+ * If the path {@link #isValue(Path)} and the option
+ * {@link ResolveOptions#STRING} is specified, its
+ * {@link #getStringValue(Path)} is returned (assuming an UTF-8 encoding).
+ * NOTE: Binary formats (e.g. PNG) will NOT be represented correctly read as
+ * UTF-8 String and should instead be read directly with
+ * {@link Files#newInputStream(Path, java.nio.file.OpenOption...)}. Note
+ * that this could consume a large amount of memory as no size checks are
+ * performed.
+ * <p>
+ * If the option {@link ResolveOptions#URI} is specified, all non-missing
+ * non-error leaf values are resolved as a {@link URI}. If the path is a
+ * {@link #isReference(Path)} the URI will be the reference from
+ * {@link #getReference(Path)}, otherwise the URI will
+ * identify a {@link Path} within the current {@link Bundle}.
+ * <p>
+ * If the path {@link #isValue(Path)} and the option
+ * {@link ResolveOptions#BYTES} is specified, the complete content is returned as
+ * a <code>byte[]</code>. Note that this could consume a large amount of memory
+ * as no size checks are performed.
+ * <p>
+ * If the path {@link #isError(Path)}, the corresponding
+ * {@link ErrorDocument} is returned, except when the option
+ * {@link ResolveOptions#REPLACE_ERRORS} is specified, which means errors are
+ * returned as <code>null</code> (or <code>""</code> if {@link ResolveOptions#REPLACE_NULL} is also specified).
+ * <p>
+ * If the path {@link #isReference(Path)} and the option
+ * {@link ResolveOptions#URI} is <strong>not</strong> set,
+ * either a {@link File} or a {@link URL} is returned,
+ * depending on its protocol. If the reference protocol has no
+ * corresponding {@link URLStreamHandler}, a {@link URI} is returned
+ * instead.
+ * <p>
+ * If the path {@link #isList(Path)}, a {@link List} is returned
+ * corresponding to resolving the paths from {@link #getList(Path)}. using
+ * this method with the same options.
+ * <p>
+ * If none of the above, the {@link Path} itself is returned. This is
+ * thus the default for non-reference non-error leaf values if neither
+ * {@link ResolveOptions#STRING}, {@link ResolveOptions#BYTES} or
+ * {@link ResolveOptions#URI} are specified.
+ * To force returning of {@link Path}s for all non-missing leaf values, specify
+ * {@link ResolveOptions#PATH};
+ *
+ * @param path
+ * Data bundle path to resolve
+ * @param options
+ * Resolve options
+ * @return <code>null</code>, a {@link String}, {@link ErrorDocument},
+ * {@link URL}, {@link File}, {@link Path} or {@link List}
+ * (containing any of these) depending on the path type and the options.
+ * @throws IOException
+ * If the path (or any of the path in a contained list) can't be
+ * accessed
+ */
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ public static Object resolve(Path path, ResolveOptions... options) throws IOException {
+ EnumSet<ResolveOptions> opt;
+ if (options.length == 0) {
+ opt = EnumSet.of(ResolveOptions.DEFAULT); // no-op
+ } else {
+ opt = EnumSet.of(ResolveOptions.DEFAULT, options);
+ }
+
+ if (opt.contains(ResolveOptions.BYTES) && opt.contains(ResolveOptions.STRING)) {
+ throw new IllegalArgumentException("Incompatible options: BYTES and STRING");
+ }
+ if (opt.contains(ResolveOptions.BYTES) && opt.contains(ResolveOptions.PATH)) {
+ throw new IllegalArgumentException("Incompatible options: BYTES and PATH");
+ }
+ if (opt.contains(ResolveOptions.BYTES) && opt.contains(ResolveOptions.URI)) {
+ throw new IllegalArgumentException("Incompatible options: BYTES and URI");
+ }
+ if (opt.contains(ResolveOptions.STRING) && opt.contains(ResolveOptions.PATH)) {
+ throw new IllegalArgumentException("Incompatible options: STRING and PATH");
+ }
+ if (opt.contains(ResolveOptions.STRING) && opt.contains(ResolveOptions.URI)) {
+ throw new IllegalArgumentException("Incompatible options: STRING and URI");
+ }
+ if (opt.contains(ResolveOptions.PATH) && opt.contains(ResolveOptions.URI)) {
+ throw new IllegalArgumentException("Incompatible options: PATH and URI");
+ }
+
+ if (path == null || isMissing(path)) {
+ if (! opt.contains(ResolveOptions.REPLACE_NULL)) {
+ return null;
+ }
+ if (opt.contains(ResolveOptions.BYTES)) {
+ return new byte[0];
+ }
+ if (opt.contains(ResolveOptions.PATH)) {
+ return path;
+ }
+ if (opt.contains(ResolveOptions.URI)) {
+ return path.toUri();
+ }
+ // STRING and DEFAULT
+ return "";
+
+
+ }
+
+ if (isList(path)) {
+ List<Path> list = getList(path);
+ List<Object> objectList = new ArrayList<Object>(list.size());
+ for (Path pathElement : list) {
+ objectList.add(resolve(pathElement, options));
+ }
+ return objectList;
+ }
+ if (opt.contains(ResolveOptions.PATH)) {
+ return path;
+ }
+ if (isError(path)) {
+ if (opt.contains(ResolveOptions.REPLACE_ERRORS)) {
+ return opt.contains(ResolveOptions.REPLACE_NULL) ? "" : null;
+ }
+ return getError(path);
+ }
+ if (opt.contains(ResolveOptions.URI)) {
+ if (isReference(path)) {
+ return getReference(path);
+ } else {
+ return path.toUri();
+ }
+ }
+ if (isReference(path)) {
+ URI reference = getReference(path);
+ String scheme = reference.getScheme();
+ if ("file".equals(scheme)) {
+ return new File(reference);
+ } else {
+ try {
+ return reference.toURL();
+ } catch (IllegalArgumentException|MalformedURLException e) {
+ return reference;
+ }
+ }
+ }
+ if (isValue(path)) {
+ if (opt.contains(ResolveOptions.BYTES)) {
+ return Files.readAllBytes(path);
+ }
+ if (opt.contains(ResolveOptions.STRING)) {
+ return getStringValue(path);
+ }
+ }
+ // Fall-back - return Path as-is
+ return path;
+ }
+
+ /**
+ * Deeply resolve path as a {@link Stream} that only contain leaf elements of
+ * the specified class.
+ * <p>
+ * This method is somewhat equivalent to {@link #resolve(Path, ResolveOptions...)}, but
+ * the returned stream is not in any particular order, and will contain the leaf
+ * items from all deep lists. Empty lists and error documents are ignored.
+ * <p>
+ * Any {@link IOException}s occurring during resolution are
+ * wrapped as {@link UncheckedIOException}.
+ * <p>
+ * Supported types include:
+ * <ul>
+ * <li>{@link String}.class</li>
+ * <li><code>byte[].class</code></li>
+ * <li>{@link Path}.class</li>
+ * <li>{@link URI}.class</li>
+ * <li>{@link URL}.class</li>
+ * <li>{@link File}.class</li>
+ * <li>{@link ErrorDocument}.class</li>
+ * <li>{@link Object}.class</li>
+ * </ul>
+ *
+ * @param path Data bundle path to resolve
+ * @param type Type of objects to return, e.g. <code>String.class</code>
+ * @return A {@link Stream} of resolved objects, or an empty stream if no such objects were resolved.
+ * @throws UncheckedIOException If the path could not be accessed.
+ */
+ public static <T> Stream<T> resolveAsStream(Path path, Class<T> type) throws UncheckedIOException {
+ ResolveOptions options;
+ if (type == String.class) {
+ options = ResolveOptions.STRING;
+ } else if (type == byte[].class) {
+ options = ResolveOptions.BYTES;
+ } else if (type == Path.class) {
+ options = ResolveOptions.PATH;
+ } else if (type == URI.class) {
+ options = ResolveOptions.URI;
+ } else {
+ // Dummy-option, we'll filter on the returned type anyway
+ options = ResolveOptions.DEFAULT;
+ }
+ if (isList(path)) {
+ // return Stream of unordered list of resolved list items,
+ // recursing to find the leaf nodes
+ try {
+ return Files.walk(path)
+ // avoid re-recursion
+ .filter(p -> !Files.isDirectory(p))
+ .flatMap(p -> resolveItemAsStream(p, type, options));
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ } else {
+ return resolveItemAsStream(path, type, options);
+ }
+ }
+ private static <T> Stream<T> resolveItemAsStream(Path path, Class<T> type, ResolveOptions options) throws UncheckedIOException {
+ try {
+ Object value = resolve(path, options);
+ if (type.isInstance(value)) {
+ return Stream.of(type.cast(value));
+ }
+ return Stream.empty();
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ }
+
public static WorkflowBundleIO getWfBundleIO() {
if (wfBundleIO == null)
wfBundleIO = new WorkflowBundleIO();
diff --git a/taverna-databundle/src/main/java/org/apache/taverna/databundle/ErrorDocument.java b/taverna-databundle/src/main/java/org/apache/taverna/databundle/ErrorDocument.java
index ec551b8..6eea2e6 100644
--- a/taverna-databundle/src/main/java/org/apache/taverna/databundle/ErrorDocument.java
+++ b/taverna-databundle/src/main/java/org/apache/taverna/databundle/ErrorDocument.java
@@ -59,4 +59,11 @@
trace = "";
this.trace = trace;
}
+
+ @Override
+ public String toString() {
+ return "Error: " + getMessage() + "\n" + trace;
+ // TODO: also include the causedBy paths?
+ }
+
}
diff --git a/taverna-databundle/src/test/java/org/apache/taverna/databundle/TestDataBundles.java b/taverna-databundle/src/test/java/org/apache/taverna/databundle/TestDataBundles.java
index c5d692d..0a67b95 100644
--- a/taverna-databundle/src/test/java/org/apache/taverna/databundle/TestDataBundles.java
+++ b/taverna-databundle/src/test/java/org/apache/taverna/databundle/TestDataBundles.java
@@ -21,11 +21,17 @@
*/
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
+import java.net.URL;
import java.nio.charset.Charset;
import java.nio.file.DirectoryStream;
import java.nio.file.FileAlreadyExistsException;
@@ -37,9 +43,9 @@
import java.util.List;
import java.util.Map;
import java.util.UUID;
+import java.util.stream.Stream;
-import org.apache.taverna.databundle.DataBundles;
-import org.apache.taverna.databundle.ErrorDocument;
+import org.apache.taverna.databundle.DataBundles.ResolveOptions;
import org.apache.taverna.robundle.Bundle;
import org.apache.taverna.scufl2.api.container.WorkflowBundle;
import org.apache.taverna.scufl2.api.io.WorkflowBundleIO;
@@ -185,7 +191,7 @@
public void getInputs() throws Exception {
Path inputs = DataBundles.getInputs(dataBundle);
assertTrue(Files.isDirectory(inputs));
- // Second time should not fail because it already exists
+ // Second time should not fail because it alreadresolvy exists
inputs = DataBundles.getInputs(dataBundle);
assertTrue(Files.isDirectory(inputs));
assertEquals(dataBundle.getRoot(), inputs.getParent());
@@ -523,6 +529,273 @@
}
@Test
+ public void resolveString() throws Exception {
+ Path inputs = DataBundles.getInputs(dataBundle);
+ Path list = DataBundles.getPort(inputs, "in1");
+ DataBundles.createList(list);
+ // 0 string value
+ DataBundles.setStringValue(DataBundles.newListItem(list), "test0");
+ // 1 http:// reference
+ URI reference = URI.create("http://example.com/");
+ DataBundles.setReference(DataBundles.newListItem(list), reference);
+ // 2 file:/// reference
+ Path tmpFile = Files.createTempFile("test", ".txt");
+ URI fileRef = tmpFile.toUri();
+ assertEquals("file", fileRef.getScheme());
+ DataBundles.setReference(DataBundles.newListItem(list), fileRef);
+ // 3 empty (null)
+ // 4 error
+ DataBundles.setError(DataBundles.getListItem(list, 4), "Example error", "1. Tried it\n2. Didn't work");
+
+
+
+
+ Object resolved = DataBundles.resolve(list, ResolveOptions.STRING);
+ assertTrue("Didn't resolve to a list", resolved instanceof List);
+
+ List resolvedList = (List) resolved;
+ assertEquals("Unexpected list size", 5, resolvedList.size());
+
+ assertTrue(resolvedList.get(0) instanceof String);
+ assertEquals("test0", resolvedList.get(0));
+
+ assertTrue(resolvedList.get(1) instanceof URL);
+ assertEquals(reference, ((URL)resolvedList.get(1)).toURI());
+
+ assertTrue(resolvedList.get(2) instanceof File);
+ assertEquals(tmpFile.toFile(), resolvedList.get(2));
+
+ assertNull(resolvedList.get(3));
+ assertTrue(resolvedList.get(4) instanceof ErrorDocument);
+ assertEquals("Example error", ((ErrorDocument)resolvedList.get(4)).getMessage());
+
+ }
+
+ @Test
+ public void resolveNestedString() throws Exception {
+ Path inputs = DataBundles.getInputs(dataBundle);
+ Path list = DataBundles.getPort(inputs, "in1");
+ DataBundles.createList(list);
+
+
+ Path nested0 = DataBundles.newListItem(list);
+ DataBundles.newListItem(nested0);
+ DataBundles.setStringValue(DataBundles.newListItem(nested0), "test0,0");
+ DataBundles.setStringValue(DataBundles.newListItem(nested0), "test0,1");
+ DataBundles.setStringValue(DataBundles.newListItem(nested0), "test0,2");
+ Path nested1 = DataBundles.newListItem(list);
+ DataBundles.newListItem(nested1); // empty
+ Path nested2 = DataBundles.newListItem(list);
+ DataBundles.newListItem(nested2);
+ DataBundles.setStringValue(DataBundles.newListItem(nested2), "test2,0");
+
+
+
+ List<List<String>> resolved = (List<List<String>>) DataBundles.resolve(list, ResolveOptions.STRING);
+
+ assertEquals("Unexpected list size", 3, resolved.size());
+ assertEquals("Unexpected sublist[0] size", 3, resolved.get(0).size());
+ assertEquals("Unexpected sublist[1] size", 0, resolved.get(1).size());
+ assertEquals("Unexpected sublist[2] size", 1, resolved.get(2).size());
+
+
+ assertEquals("test0,0", resolved.get(0).get(0));
+ assertEquals("test0,1", resolved.get(0).get(1));
+ assertEquals("test0,2", resolved.get(0).get(2));
+ assertEquals("test2,0", resolved.get(2).get(0));
+ }
+
+
+ @Test
+ public void resolveStream() throws Exception {
+ Path inputs = DataBundles.getInputs(dataBundle);
+ Path list = DataBundles.getPort(inputs, "in1");
+ DataBundles.createList(list);
+
+ Path nested0 = DataBundles.newListItem(list);
+ DataBundles.newListItem(nested0);
+ DataBundles.setStringValue(DataBundles.newListItem(nested0), "test0,0");
+ DataBundles.setStringValue(DataBundles.newListItem(nested0), "test0,1");
+ DataBundles.setStringValue(DataBundles.newListItem(nested0), "test0,2");
+ DataBundles.setError(DataBundles.newListItem(nested0), "Ignore me", "This error is hidden");
+ Path nested1 = DataBundles.newListItem(list);
+ DataBundles.newListItem(nested1); // empty
+ Path nested2 = DataBundles.newListItem(list);
+ DataBundles.newListItem(nested2);
+ DataBundles.setStringValue(DataBundles.newListItem(nested2), "test2,0");
+ DataBundles.setReference(DataBundles.newListItem(nested2), URI.create("http://example.com/"));
+
+
+
+ assertEquals(6, DataBundles.resolveAsStream(list, Object.class).count());
+ assertEquals(6, DataBundles.resolveAsStream(list, Path.class).count());
+ assertEquals(5, DataBundles.resolveAsStream(list, URI.class).count());
+ assertEquals(1, DataBundles.resolveAsStream(list, URL.class).count());
+ assertEquals(0, DataBundles.resolveAsStream(list, File.class).count());
+ assertEquals(1, DataBundles.resolveAsStream(list, ErrorDocument.class).count());
+ // Let's have a look at one of the types in detail
+ assertEquals(4, DataBundles.resolveAsStream(list, String.class).count());
+ Stream<String> resolved = DataBundles.resolveAsStream(list, String.class);
+ Object[] strings = resolved.sorted().map(t -> t.replace("test", "X")).toArray();
+ // NOTE: We can only assume the below order because we used .sorted()
+ assertEquals("X0,0", strings[0]);
+ assertEquals("X0,1", strings[1]);
+ assertEquals("X0,2", strings[2]);
+ assertEquals("X2,0", strings[3]);
+ }
+
+ @Test
+ public void resolveURIs() throws Exception {
+ Path inputs = DataBundles.getInputs(dataBundle);
+ Path list = DataBundles.getPort(inputs, "in1");
+ DataBundles.createList(list);
+ // 0 string value
+ Path test0 = DataBundles.newListItem(list);
+ DataBundles.setStringValue(test0, "test0");
+ // 1 http:// reference
+ URI reference = URI.create("http://example.com/");
+ DataBundles.setReference(DataBundles.newListItem(list), reference);
+ // 2 file:/// reference
+ Path tmpFile = Files.createTempFile("test", ".txt");
+ URI fileRef = tmpFile.toUri();
+ assertEquals("file", fileRef.getScheme());
+ DataBundles.setReference(DataBundles.newListItem(list), fileRef);
+ // 3 empty (null)
+ // 4 error
+ Path error4 = DataBundles.getListItem(list, 4);
+ DataBundles.setError(error4, "Example error", "1. Tried it\n2. Didn't work");
+
+ List resolved = (List) DataBundles.resolve(list, ResolveOptions.URI);
+ assertEquals(test0.toUri(), resolved.get(0));
+ assertEquals(reference, resolved.get(1));
+ assertEquals(fileRef, resolved.get(2));
+ assertNull(resolved.get(3));
+ // NOTE: Need to get the Path again due to different file extension
+ assertTrue(resolved.get(4) instanceof ErrorDocument);
+ //assertTrue(DataBundles.getListItem(list, 4).toUri(), resolved.get(4));
+ }
+
+
+ @Test
+ public void resolvePaths() throws Exception {
+ Path inputs = DataBundles.getInputs(dataBundle);
+ Path list = DataBundles.getPort(inputs, "in1");
+ DataBundles.createList(list);
+ // 0 string value
+ Path test0 = DataBundles.newListItem(list);
+ DataBundles.setStringValue(test0, "test0");
+ // 1 http:// reference
+ URI reference = URI.create("http://example.com/");
+ Path test1 = DataBundles.setReference(DataBundles.newListItem(list), reference);
+ // 2 file:/// reference
+ Path tmpFile = Files.createTempFile("test", ".txt");
+ URI fileRef = tmpFile.toUri();
+ assertEquals("file", fileRef.getScheme());
+ Path test2 = DataBundles.setReference(DataBundles.newListItem(list), fileRef);
+ // 3 empty (null)
+ // 4 error
+ Path error4 = DataBundles.setError(DataBundles.getListItem(list, 4), "Example error", "1. Tried it\n2. Didn't work");
+
+ List<Path> resolved = (List<Path>) DataBundles.resolve(list, ResolveOptions.PATH);
+ assertEquals(test0, resolved.get(0));
+ assertEquals(test1, resolved.get(1));
+ assertEquals(test2, resolved.get(2));
+ assertNull(resolved.get(3));
+ assertEquals(error4, resolved.get(4));
+ }
+
+ @Test
+ public void resolveReplaceError() throws Exception {
+ Path inputs = DataBundles.getInputs(dataBundle);
+ Path list = DataBundles.getPort(inputs, "in1");
+ DataBundles.createList(list);
+ // 0 string value
+ DataBundles.setStringValue(DataBundles.newListItem(list), "test0");
+ // 1 error
+ DataBundles.setError(DataBundles.newListItem(list),
+ "Example error", "1. Tried it\n2. Didn't work");
+
+ List resolved = (List) DataBundles.resolve(list, ResolveOptions.STRING, ResolveOptions.REPLACE_ERRORS);
+ assertEquals("test0", resolved.get(0));
+ assertNull(resolved.get(1));
+ }
+
+ @Test
+ public void resolveReplaceNull() throws Exception {
+ Path inputs = DataBundles.getInputs(dataBundle);
+ Path list = DataBundles.getPort(inputs, "in1");
+ DataBundles.createList(list);
+ // 0 string value
+ Path test0 = DataBundles.newListItem(list);
+ DataBundles.setStringValue(test0, "test0");
+ // 1 empty
+ // 2 error
+ DataBundles.setError(DataBundles.getListItem(list, 2),
+ "Example error", "1. Tried it\n2. Didn't work");
+
+ List resolved = (List) DataBundles.resolve(list, ResolveOptions.REPLACE_ERRORS, ResolveOptions.REPLACE_NULL);
+ assertEquals(test0, resolved.get(0));
+ assertEquals("", resolved.get(1));
+ assertEquals("", resolved.get(2));
+ }
+
+
+ @Test
+ public void resolveDefault() throws Exception {
+ Path inputs = DataBundles.getInputs(dataBundle);
+ Path list = DataBundles.getPort(inputs, "in1");
+ DataBundles.createList(list);
+ // 0 string value
+ Path test0 = DataBundles.newListItem(list);
+ DataBundles.setStringValue(test0, "test0");
+ // 1 http:// reference
+ URI reference = URI.create("http://example.com/");
+ Path test1 = DataBundles.setReference(DataBundles.newListItem(list), reference);
+ // 2 file:/// reference
+ Path tmpFile = Files.createTempFile("test", ".txt");
+ URI fileRef = tmpFile.toUri();
+ assertEquals("file", fileRef.getScheme());
+ Path test2 = DataBundles.setReference(DataBundles.newListItem(list), fileRef);
+ // 3 empty (null)
+ // 4 error
+ Path error4 = DataBundles.setError(DataBundles.getListItem(list, 4), "Example error", "1. Tried it\n2. Didn't work");
+
+ List resolved = (List) DataBundles.resolve(list, ResolveOptions.DEFAULT);
+ assertEquals(test0, resolved.get(0));
+ assertTrue(resolved.get(1) instanceof URL);
+ assertEquals("http://example.com/", resolved.get(1).toString());
+ assertTrue(resolved.get(2) instanceof File);
+ assertEquals(tmpFile.toFile(), resolved.get(2));
+ assertNull(resolved.get(3));
+ assertTrue(resolved.get(4) instanceof ErrorDocument);
+ }
+
+ @Test
+ public void resolveBinaries() throws Exception {
+ Path inputs = DataBundles.getInputs(dataBundle);
+ Path list = DataBundles.getPort(inputs, "in1");
+ Path item = DataBundles.newListItem(list);
+
+ byte[] bytes = new byte[] {
+ // Those lovely lower bytes who don't work well in UTF-8
+ 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,
+ // and some higher ones for fun
+ -1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,-13,-14,-15,-16,-17,-18,
+ -19,-20,-21,-22,-23,-24,-25,-26,-27,-28,-29,-30,-31
+ };
+ Files.write(item, bytes);
+
+
+ List resolvedBytes = (List)DataBundles.resolve(list, ResolveOptions.BYTES);
+ assertArrayEquals(bytes, (byte[])resolvedBytes.get(0));
+
+ List resolvedString = (List)DataBundles.resolve(list, ResolveOptions.STRING);
+ // The below will always fail as several of the above bytes are not parsed as valid UTF-8
+ // but instead be substituted with replacement characters.
+ //assertArrayEquals(bytes, ((String)resolvedString.get(0)).getBytes(StandardCharsets.UTF_8));
+ }
+
+ @Test
public void setErrorArgs() throws Exception {
Path inputs = DataBundles.getInputs(dataBundle);
Path portIn1 = DataBundles.getPort(inputs, "in1");
@@ -765,6 +1038,7 @@
Files.probeContentType(wf));
}
+ // TODO: Why was this ignored? Check with taverna-language-0.15.x RC emails
@Ignore
@Test
public void getWorkflowBundle() throws Exception {
diff --git a/taverna-robundle/README.md b/taverna-robundle/README.md
index bb9e8a3..edf40cb 100644
--- a/taverna-robundle/README.md
+++ b/taverna-robundle/README.md
@@ -26,7 +26,7 @@
<dependency>
<groupId>org.apache.taverna.language</groupId>
<artifactId>taverna-robundle</artifactId>
- <version>>0.15.0-incubating</version>
+ <version>0.15.1-incubating</version>
</dependency>
</dependencies>
```
diff --git a/taverna-robundle/pom.xml b/taverna-robundle/pom.xml
index a6fe7d7..b9d6d75 100644
--- a/taverna-robundle/pom.xml
+++ b/taverna-robundle/pom.xml
@@ -21,7 +21,7 @@
<parent>
<groupId>org.apache.taverna.language</groupId>
<artifactId>apache-taverna-language</artifactId>
- <version>0.15.2-incubating-SNAPSHOT</version>
+ <version>0.16.0-incubating-SNAPSHOT</version>
</parent>
<artifactId>taverna-robundle</artifactId>
<name>Apache Taverna RO Bundle API</name>
diff --git a/taverna-scufl2-annotation/pom.xml b/taverna-scufl2-annotation/pom.xml
index ca6ee7a..b5d7ea2 100644
--- a/taverna-scufl2-annotation/pom.xml
+++ b/taverna-scufl2-annotation/pom.xml
@@ -20,7 +20,7 @@
<parent>
<groupId>org.apache.taverna.language</groupId>
<artifactId>apache-taverna-language</artifactId>
- <version>0.15.2-incubating-SNAPSHOT</version>
+ <version>0.16.0-incubating-SNAPSHOT</version>
</parent>
<artifactId>taverna-scufl2-annotation</artifactId>
<packaging>bundle</packaging>
diff --git a/taverna-scufl2-api/pom.xml b/taverna-scufl2-api/pom.xml
index dd8cd5a..4d98c3f 100644
--- a/taverna-scufl2-api/pom.xml
+++ b/taverna-scufl2-api/pom.xml
@@ -20,7 +20,7 @@
<parent>
<groupId>org.apache.taverna.language</groupId>
<artifactId>apache-taverna-language</artifactId>
- <version>0.15.2-incubating-SNAPSHOT</version>
+ <version>0.16.0-incubating-SNAPSHOT</version>
</parent>
<artifactId>taverna-scufl2-api</artifactId>
<packaging>bundle</packaging>
diff --git a/taverna-scufl2-examples/pom.xml b/taverna-scufl2-examples/pom.xml
index cd5177e..f69d73b 100644
--- a/taverna-scufl2-examples/pom.xml
+++ b/taverna-scufl2-examples/pom.xml
@@ -20,7 +20,7 @@
<parent>
<groupId>org.apache.taverna.language</groupId>
<artifactId>apache-taverna-language</artifactId>
- <version>0.15.2-incubating-SNAPSHOT</version>
+ <version>0.16.0-incubating-SNAPSHOT</version>
</parent>
<artifactId>taverna-scufl2-examples</artifactId>
<packaging>bundle</packaging>
diff --git a/taverna-scufl2-integration-tests/pom.xml b/taverna-scufl2-integration-tests/pom.xml
index 635b53e..5fcff46 100644
--- a/taverna-scufl2-integration-tests/pom.xml
+++ b/taverna-scufl2-integration-tests/pom.xml
@@ -20,7 +20,7 @@
<parent>
<groupId>org.apache.taverna.language</groupId>
<artifactId>apache-taverna-language</artifactId>
- <version>0.15.2-incubating-SNAPSHOT</version>
+ <version>0.16.0-incubating-SNAPSHOT</version>
</parent>
<artifactId>taverna-scufl2-integration-tests</artifactId>
<name>Apache Taverna Scufl 2 integration tests</name>
diff --git a/taverna-scufl2-schemas/pom.xml b/taverna-scufl2-schemas/pom.xml
index ab21af4..61aa1bc 100644
--- a/taverna-scufl2-schemas/pom.xml
+++ b/taverna-scufl2-schemas/pom.xml
@@ -20,7 +20,7 @@
<parent>
<groupId>org.apache.taverna.language</groupId>
<artifactId>apache-taverna-language</artifactId>
- <version>0.15.2-incubating-SNAPSHOT</version>
+ <version>0.16.0-incubating-SNAPSHOT</version>
</parent>
<artifactId>taverna-scufl2-schemas</artifactId>
<packaging>bundle</packaging>
diff --git a/taverna-scufl2-scufl/pom.xml b/taverna-scufl2-scufl/pom.xml
index 2432713..6b5cc81 100644
--- a/taverna-scufl2-scufl/pom.xml
+++ b/taverna-scufl2-scufl/pom.xml
@@ -20,7 +20,7 @@
<parent>
<groupId>org.apache.taverna.language</groupId>
<artifactId>apache-taverna-language</artifactId>
- <version>0.15.2-incubating-SNAPSHOT</version>
+ <version>0.16.0-incubating-SNAPSHOT</version>
</parent>
<artifactId>taverna-scufl2-scufl</artifactId>
<packaging>bundle</packaging>
diff --git a/taverna-scufl2-t2flow/pom.xml b/taverna-scufl2-t2flow/pom.xml
index b2a0dbd..0e2a0cf 100644
--- a/taverna-scufl2-t2flow/pom.xml
+++ b/taverna-scufl2-t2flow/pom.xml
@@ -20,7 +20,7 @@
<parent>
<groupId>org.apache.taverna.language</groupId>
<artifactId>apache-taverna-language</artifactId>
- <version>0.15.2-incubating-SNAPSHOT</version>
+ <version>0.16.0-incubating-SNAPSHOT</version>
</parent>
<artifactId>taverna-scufl2-t2flow</artifactId>
<packaging>bundle</packaging>
diff --git a/taverna-scufl2-ucfpackage/pom.xml b/taverna-scufl2-ucfpackage/pom.xml
index dbae3ed..976d299 100644
--- a/taverna-scufl2-ucfpackage/pom.xml
+++ b/taverna-scufl2-ucfpackage/pom.xml
@@ -20,7 +20,7 @@
<parent>
<groupId>org.apache.taverna.language</groupId>
<artifactId>apache-taverna-language</artifactId>
- <version>0.15.2-incubating-SNAPSHOT</version>
+ <version>0.16.0-incubating-SNAPSHOT</version>
</parent>
<artifactId>taverna-scufl2-ucfpackage</artifactId>
<packaging>bundle</packaging>
diff --git a/taverna-scufl2-wfbundle/pom.xml b/taverna-scufl2-wfbundle/pom.xml
index b810e4a..b7efe33 100644
--- a/taverna-scufl2-wfbundle/pom.xml
+++ b/taverna-scufl2-wfbundle/pom.xml
@@ -20,7 +20,7 @@
<parent>
<groupId>org.apache.taverna.language</groupId>
<artifactId>apache-taverna-language</artifactId>
- <version>0.15.2-incubating-SNAPSHOT</version>
+ <version>0.16.0-incubating-SNAPSHOT</version>
</parent>
<artifactId>taverna-scufl2-wfbundle</artifactId>
<packaging>bundle</packaging>
diff --git a/taverna-scufl2-wfdesc/pom.xml b/taverna-scufl2-wfdesc/pom.xml
index c60646c..ddf7e91 100755
--- a/taverna-scufl2-wfdesc/pom.xml
+++ b/taverna-scufl2-wfdesc/pom.xml
@@ -14,7 +14,7 @@
<parent>
<groupId>org.apache.taverna.language</groupId>
<artifactId>apache-taverna-language</artifactId>
- <version>0.15.2-incubating-SNAPSHOT</version>
+ <version>0.16.0-incubating-SNAPSHOT</version>
</parent>
<artifactId>taverna-scufl2-wfdesc</artifactId>
<packaging>bundle</packaging>
diff --git a/taverna-tavlang-tool/pom.xml b/taverna-tavlang-tool/pom.xml
index 4e0317c..2ee2135 100644
--- a/taverna-tavlang-tool/pom.xml
+++ b/taverna-tavlang-tool/pom.xml
@@ -20,7 +20,7 @@
<parent>
<groupId>org.apache.taverna.language</groupId>
<artifactId>apache-taverna-language</artifactId>
- <version>0.15.2-incubating-SNAPSHOT</version>
+ <version>0.16.0-incubating-SNAPSHOT</version>
</parent>
<artifactId>taverna-tavlang-tool</artifactId>
<name>Apache Taverna tavlang tool</name>