| 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; |
| } |
| } |