blob: 17e8e5bfc37859d2c34e84340714c9694a957372 [file] [log] [blame]
package org.apache.taverna.examples;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URI;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.apache.taverna.scufl2.api.annotation.Annotation;
import org.apache.taverna.scufl2.api.annotation.Revision;
import org.apache.taverna.scufl2.api.common.Child;
import org.apache.taverna.scufl2.api.common.Ported;
import org.apache.taverna.scufl2.api.common.Scufl2Tools;
import org.apache.taverna.scufl2.api.common.URITools;
import org.apache.taverna.scufl2.api.container.WorkflowBundle;
import org.apache.taverna.scufl2.api.core.BlockingControlLink;
import org.apache.taverna.scufl2.api.core.ControlLink;
import org.apache.taverna.scufl2.api.core.DataLink;
import org.apache.taverna.scufl2.api.core.Processor;
import org.apache.taverna.scufl2.api.core.Workflow;
import org.apache.taverna.scufl2.api.io.ReaderException;
import org.apache.taverna.scufl2.api.io.WorkflowBundleIO;
import org.apache.taverna.scufl2.api.io.WorkflowBundleWriter;
import org.apache.taverna.scufl2.api.io.WriterException;
import org.apache.taverna.scufl2.api.port.DepthPort;
import org.apache.taverna.scufl2.api.port.GranularDepthPort;
import org.apache.taverna.scufl2.api.port.Port;
import org.apache.taverna.scufl2.api.profiles.Profile;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.util.ISO8601DateFormat;
public class JsonExport {
public class JsonWriter implements WorkflowBundleWriter {
@Override
public Set<String> getMediaTypes() {
return new HashSet<String>(Arrays.asList("application/ld+json",
"application/json"));
}
@Override
public void writeBundle(WorkflowBundle wfBundle, File destination,
String mediaType) throws WriterException, IOException {
ObjectNode json = toJson(wfBundle);
mapper.writeValue(destination, json);
}
@Override
public void writeBundle(WorkflowBundle wfBundle,
OutputStream output, String mediaType)
throws WriterException, IOException {
ObjectNode json = toJson(wfBundle);
mapper.writeValue(output, json);
}
}
public static void main(String[] args) throws ReaderException, IOException,
WriterException {
new JsonExport().convert(args);
}
private WorkflowBundleIO io = new WorkflowBundleIO();;
private WorkflowBundleWriter jsonWriter = new JsonWriter();
private ObjectMapper mapper = new ObjectMapper();
private Scufl2Tools scufl2Tools = new Scufl2Tools();
private URITools uriTools = new URITools();
public JsonExport() {
mapper.enable(SerializationFeature.INDENT_OUTPUT);
mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
mapper.setDateFormat(new ISO8601DateFormat());
// Adding custom writer dynamically
List<WorkflowBundleWriter> writers = io.getWriters();
writers.add(jsonWriter);
io.setWriters(writers);
}
protected void addPorts(Ported ported, ObjectNode p) {
ArrayNode inputs = mapper.createArrayNode();
for (Port port : ported.getInputPorts()) {
inputs.add(toJson(port));
}
p.put("inputs", inputs);
ArrayNode outputs = mapper.createArrayNode();
for (Port port : ported.getOutputPorts()) {
outputs.add(toJson(port));
// FIXME: Do we need the id for ports? Needed if we add datalinks
}
p.put("outputs", outputs);
}
protected ObjectNode annotations(Child<?> bean) {
ObjectNode node = mapper.createObjectNode();
for (Annotation ann : scufl2Tools.annotationsFor(bean)) {
URI annUri = uriTools.uriForBean(ann);
// TODO: include annotation body?
}
return node;
}
public void convert(String[] filepaths) throws ReaderException,
IOException, WriterException {
if (filepaths.length == 0 || filepaths[0].equals("-h")) {
System.out.println("Export workflow structore as JSON.");
System.out.println("Usage: jsonexport [filename] ...");
System.out.println("If the filename is - the workflow will be read from STDIN and");
System.out.println("JSON written to STDOUT. ");
System.out.println("Otherwise, the file is read as a workflow (t2flow, workflow bundle)");
System.out.println("and written as JSON to a file with the .json extension.");
System.out.println("Multiple filenames can be given. JSON filenames are written to STDOUT");
return;
}
if (filepaths[0].equals("-")) {
// Do piped Stdin/Stdout instead
WorkflowBundle wfBundle = io.readBundle(System.in, null);
io.writeBundle(wfBundle, System.err, "application/ld+json");
return;
}
for (String filepath : filepaths) {
File workflow = new File(filepath);
String filename = workflow.getName();
filename = filename.replaceFirst("\\..*", ".json");
File workflowFile = new File(workflow.getParentFile(), filename);
WorkflowBundle wfBundle = io.readBundle(workflow, null);
io.writeBundle(wfBundle, workflowFile, "application/ld+json");
System.out.println(workflowFile);
}
}
protected ObjectNode toJson(Port port) {
ObjectNode p = mapper.createObjectNode();
p.put("name", port.getName());
p.putPOJO("id", uriTools.relativeUriForBean(port,
scufl2Tools.findParent(WorkflowBundle.class, ((Child<?>)port))));
if (port instanceof DepthPort) {
DepthPort depthPort = (DepthPort) port;
if (depthPort.getDepth() != null) {
p.put("depth", depthPort.getDepth());
}
}
if (port instanceof GranularDepthPort) {
GranularDepthPort granularDepthPort = (GranularDepthPort) port;
if (granularDepthPort.getGranularDepth() != null &&
! granularDepthPort.getGranularDepth().equals(granularDepthPort.getDepth())) {
p.put("granularDepth", granularDepthPort.getGranularDepth());
}
}
p.putAll(annotations((Child<?>)port));
return p;
}
protected JsonNode toJson(Processor proc) {
ObjectNode p = mapper.createObjectNode();
p.putPOJO("id", uriTools.relativeUriForBean(proc, proc.getParent().getParent()));
p.put("name", proc.getName());
addPorts(proc, p);
p.putAll(annotations(proc));
List<Workflow> nested = scufl2Tools.nestedWorkflowsForProcessor(proc,
proc.getParent().getParent().getMainProfile());
if (! nested.isEmpty()) {
if (nested.size() == 1) {
p.put("nestedWorkflow", toJson(nested.iterator().next()));
} else {
ArrayNode list = mapper.createArrayNode();
for (Workflow w : nested) {
list.add(toJson(w));
}
p.put("nestedWorkflow", list);
}
}
return p;
}
protected JsonNode toJson(Revision currentRevision) {
ArrayNode revisions = mapper.createArrayNode();
while (currentRevision != null) {
ObjectNode rev = mapper.createObjectNode();
rev.putPOJO("id", currentRevision.getIdentifier());
if (currentRevision.getGeneratedAtTime() != null) {
rev.putPOJO("generatedAtTime", currentRevision.getGeneratedAtTime());
}
currentRevision = currentRevision.getPreviousRevision();
if (currentRevision != null) {
rev.putPOJO("wasRevisionOf", currentRevision.getIdentifier());
}
revisions.add(rev);
}
return revisions;
}
protected ObjectNode toJson(Workflow workflow) {
ObjectNode wf = mapper.createObjectNode();
wf.putPOJO("id", uriTools.relativeUriForBean(workflow, workflow.getParent()));
wf.put("name", workflow.getName());
wf.put("revisions", toJson(workflow.getCurrentRevision()));
ArrayNode processors = mapper.createArrayNode();
for (Processor p : workflow.getProcessors()) {
processors.add(toJson(p));
}
addPorts(workflow, wf);
wf.put("processors", processors);
ArrayNode datalinks = mapper.createArrayNode();
for (DataLink link : workflow.getDataLinks()) {
datalinks.add(toJson(link));
}
wf.put("datalinks", datalinks);
ArrayNode controlLinks = mapper.createArrayNode();
for (ControlLink link : workflow.getControlLinks()) {
controlLinks.add(toJson(link));
}
wf.put("controllinks", controlLinks);
wf.putAll(annotations(workflow));
return wf;
}
protected JsonNode toJson(ControlLink link) {
ObjectNode l = mapper.createObjectNode();
if (link instanceof BlockingControlLink) {
BlockingControlLink controlLink = (BlockingControlLink) link;
l.putPOJO("block", uriTools.relativeUriForBean(controlLink.getBlock(),
link.getParent().getParent()));
l.putPOJO("untilFinished", uriTools.relativeUriForBean(controlLink.getUntilFinished(),
link.getParent().getParent()));
}
return l;
}
protected JsonNode toJson(DataLink link) {
ObjectNode l = mapper.createObjectNode();
l.putPOJO("receivesFrom", uriTools.relativeUriForBean(link.getReceivesFrom(),
link.getParent().getParent()));
l.putPOJO("sendsTo", uriTools.relativeUriForBean(link.getSendsTo(),
link.getParent().getParent()));
if (link.getMergePosition() != null) {
l.put("mergePosition", link.getMergePosition());
}
return l;
}
public ObjectNode toJson(WorkflowBundle wfBundle) {
ObjectNode root = mapper.createObjectNode();
ArrayNode contextList = root.arrayNode();
root.put("@context", contextList);
ObjectNode context = root.objectNode();
contextList.add("https://w3id.org/scufl2/context");
contextList.add(context);
URI base = wfBundle.getGlobalBaseURI();
context.put("@base", base.toASCIIString());
root.put("id", base.toASCIIString());
// root.put("name", wfBundle.getName());
// root.put("revisions", toJson(wfBundle.getCurrentRevision()));
root.put("workflow", toJson(wfBundle.getMainWorkflow()));
root.put("profile", toJson(wfBundle.getMainProfile()));
return root;
}
private JsonNode toJson(Profile profile) {
ObjectNode pf = mapper.createObjectNode();
pf.putPOJO("id", uriTools.relativeUriForBean(profile, profile.getParent()));
// TODO: Activities and configurations
return pf;
}
}