org.apache.taverna.scufl2.wfdesc.WfdescSerialiser.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.taverna.scufl2.wfdesc.WfdescSerialiser.java

Source

package org.apache.taverna.scufl2.wfdesc;

/*
 *
 * 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 static org.apache.taverna.scufl2.api.common.Scufl2Tools.NESTED_WORKFLOW;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.apache.jena.ontology.Individual;
import org.apache.jena.ontology.OntModel;
import org.apache.jena.rdf.model.ModelFactory;
import org.apache.jena.rdf.model.Resource;
import org.apache.jena.riot.Lang;
import org.apache.jena.riot.RDFDataMgr;
import org.apache.jena.riot.RiotException;
import org.apache.jena.vocabulary.OWL;
import org.apache.taverna.scufl2.api.activity.Activity;
import org.apache.taverna.scufl2.api.annotation.Annotation;
import org.apache.taverna.scufl2.api.common.Child;
import org.apache.taverna.scufl2.api.common.Named;
import org.apache.taverna.scufl2.api.common.Scufl2Tools;
import org.apache.taverna.scufl2.api.common.URITools;
import org.apache.taverna.scufl2.api.common.Visitor.VisitorWithPath;
import org.apache.taverna.scufl2.api.common.WorkflowBean;
import org.apache.taverna.scufl2.api.configurations.Configuration;
import org.apache.taverna.scufl2.api.container.WorkflowBundle;
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.WriterException;
import org.apache.taverna.scufl2.api.port.InputPort;
import org.apache.taverna.scufl2.api.port.OutputPort;
import org.apache.taverna.scufl2.api.port.WorkflowPort;
import org.apache.taverna.scufl2.api.profiles.ProcessorBinding;
import org.apache.taverna.scufl2.api.profiles.ProcessorPortBinding;
import org.apache.taverna.scufl2.api.profiles.Profile;
import org.apache.taverna.scufl2.wfdesc.ontologies.Prov_o;
import org.apache.taverna.scufl2.wfdesc.ontologies.Roterms;
import org.apache.taverna.scufl2.wfdesc.ontologies.Wf4ever;
import org.apache.taverna.scufl2.wfdesc.ontologies.Wfdesc;

import com.fasterxml.jackson.databind.JsonNode;

public class WfdescSerialiser {

    private static Logger logger = Logger.getLogger(WfdescSerialiser.class.getCanonicalName());

    public static URI REST = URI.create("http://ns.taverna.org.uk/2010/activity/rest");
    public static URI WSDL = URI.create("http://ns.taverna.org.uk/2010/activity/wsdl");
    public static URI SECURITY = WSDL.resolve("wsdl/security");
    public static URI OPERATION = WSDL.resolve("wsdl/operation");
    public static URI BEANSHELL = URI.create("http://ns.taverna.org.uk/2010/activity/beanshell");
    public static URI RSHELL = URI.create("http://ns.taverna.org.uk/2010/activity/rshell");
    public static URI TOOL = URI.create("http://ns.taverna.org.uk/2010/activity/tool");

    private Scufl2Tools scufl2Tools = new Scufl2Tools();
    private URITools uriTools = new URITools();

    public Scufl2Tools getScufl2Tools() {
        return scufl2Tools;
    }

    public URITools getUriTools() {
        return uriTools;
    }

    private String uriForBean(WorkflowBean bean) {
        return uriTools.uriForBean(bean).toASCIIString();
    }

    protected OntModel save(final WorkflowBundle bundle) {
        final OntModel model = ModelFactory.createOntologyModel();
        bundle.accept(new VisitorWithPath() {
            Scufl2Tools scufl2Tools = new Scufl2Tools();

            public boolean visit() {
                WorkflowBean node = getCurrentNode();
                // System.out.println(node);
                if (node instanceof WorkflowBundle) {
                    return true;
                }
                // @SuppressWarnings("rawtypes")

                if (node instanceof org.apache.taverna.scufl2.api.core.Workflow) {
                    entityForBean(node, Wfdesc.Workflow);
                } else if (node instanceof Processor) {
                    Processor processor = (Processor) node;
                    Individual process = entityForBean(processor, Wfdesc.Process);
                    Individual wf = entityForBean(processor.getParent(), Wfdesc.Workflow);
                    wf.addProperty(Wfdesc.hasSubProcess, process);
                } else if (node instanceof InputPort) {
                    WorkflowBean parent = ((Child) node).getParent();
                    Individual input = entityForBean(node, Wfdesc.Input);
                    Individual process = entityForBean(parent, Wfdesc.Process);
                    process.addProperty(Wfdesc.hasInput, input);

                } else if (node instanceof OutputPort) {
                    WorkflowBean parent = ((Child) node).getParent();
                    Individual output = entityForBean(node, Wfdesc.Output);
                    Individual process = entityForBean(parent, Wfdesc.Process);
                    process.addProperty(Wfdesc.hasOutput, output);
                } else if (node instanceof DataLink) {
                    WorkflowBean parent = ((Child) node).getParent();
                    DataLink link = (DataLink) node;
                    Individual dl = entityForBean(link, Wfdesc.DataLink);

                    Individual source = entityForBean(link.getReceivesFrom(), Wfdesc.Output);
                    dl.addProperty(Wfdesc.hasSource, source);

                    Individual sink = entityForBean(link.getSendsTo(), Wfdesc.Input);
                    dl.addProperty(Wfdesc.hasSink, sink);
                    Individual wf = entityForBean(parent, Wfdesc.Workflow);
                    wf.addProperty(Wfdesc.hasDataLink, dl);
                } else if (node instanceof Profile) {
                    // So that we can get at the ProcessorBinding - buy only if
                    // it is the main Profile
                    return node == bundle.getMainProfile();
                } else if (node instanceof ProcessorBinding) {
                    ProcessorBinding b = (ProcessorBinding) node;
                    Activity a = b.getBoundActivity();
                    Processor boundProcessor = b.getBoundProcessor();
                    Individual process = entityForBean(boundProcessor, Wfdesc.Process);

                    // Note: We don't describe the activity and processor
                    // binding in wfdesc. Instead we
                    // assign additional types and attributes to the parent
                    // processor

                    try {
                        URI type = a.getType();
                        Configuration c = scufl2Tools.configurationFor(a, b.getParent());
                        JsonNode json = c.getJson();
                        if (type.equals(BEANSHELL)) {
                            process.addRDFType(Wf4ever.BeanshellScript);
                            String s = json.get("script").asText();
                            process.addProperty(Wf4ever.script, s);
                            JsonNode localDep = json.get("localDependency");
                            if (localDep != null && localDep.isArray()) {
                                for (int i = 0; i < localDep.size(); i++) {
                                    String depStr = localDep.get(i).asText();
                                    // FIXME: Better class for dependency?
                                    Individual dep = model.createIndividual(OWL.Thing);
                                    dep.addLabel(depStr, null);
                                    dep.addComment("JAR dependency", "en");
                                    process.addProperty(Roterms.requiresSoftware, dep);
                                    // Somehow this gets the whole thing to fall
                                    // out of the graph!
                                    // QName depQ = new
                                    // QName("http://google.com/", ""+
                                    // UUID.randomUUID());
                                    // sesameManager.rename(dep, depQ);

                                }
                            }
                        }
                        if (type.equals(RSHELL)) {
                            process.addRDFType(Wf4ever.RScript);
                            String s = json.get("script").asText();
                            process.addProperty(Wf4ever.script, s);
                        }
                        if (type.equals(WSDL)) {
                            process.addRDFType(Wf4ever.SOAPService);
                            JsonNode operation = json.get("operation");
                            URI wsdl = URI.create(operation.get("wsdl").asText());
                            process.addProperty(Wf4ever.wsdlURI, wsdl.toASCIIString());
                            process.addProperty(Wf4ever.wsdlOperationName, operation.get("name").asText());
                            process.addProperty(Wf4ever.rootURI, wsdl.resolve("/").toASCIIString());
                        }
                        if (type.equals(REST)) {
                            process.addRDFType(Wf4ever.RESTService);
                            // System.out.println(json);
                            JsonNode request = json.get("request");
                            String absoluteURITemplate = request.get("absoluteURITemplate").asText();
                            String uriTemplate = absoluteURITemplate.replace("{", "");
                            uriTemplate = uriTemplate.replace("}", "");
                            // TODO: Detect {}
                            try {
                                URI root = new URI(uriTemplate).resolve("/");
                                process.addProperty(Wf4ever.rootURI, root.toASCIIString());
                            } catch (URISyntaxException e) {
                                logger.warning("Potentially invalid URI template: " + absoluteURITemplate);
                                // Uncomment to temporarily break
                                // TestInvalidURITemplate:
                                // rest.getWfRootURI().add(URI.create("http://example.com/FRED"));
                            }
                        }
                        if (type.equals(TOOL)) {
                            process.addRDFType(Wf4ever.CommandLineTool);
                            JsonNode desc = json.get("toolDescription");
                            // System.out.println(json);
                            JsonNode command = desc.get("command");
                            if (command != null) {
                                process.addProperty(Wf4ever.command, command.asText());
                            }
                        }
                        if (type.equals(NESTED_WORKFLOW)) {
                            Workflow nestedWf = scufl2Tools.nestedWorkflowForProcessor(boundProcessor,
                                    b.getParent());
                            // The parent process is a specialization of the
                            // nested workflow
                            // (because the nested workflow could exist as
                            // several processors)
                            specializationOf(boundProcessor, nestedWf);
                            process.addRDFType(Wfdesc.Workflow);

                            // Just like the Processor specializes the nested
                            // workflow, the
                            // ProcessorPorts specialize the WorkflowPort
                            for (ProcessorPortBinding portBinding : b.getInputPortBindings()) {
                                // Map from activity port (not in wfdesc) to
                                // WorkflowPort
                                WorkflowPort wfPort = nestedWf.getInputPorts()
                                        .getByName(portBinding.getBoundActivityPort().getName());
                                if (wfPort == null) {
                                    continue;
                                }
                                specializationOf(portBinding.getBoundProcessorPort(), wfPort);
                            }
                            for (ProcessorPortBinding portBinding : b.getOutputPortBindings()) {
                                WorkflowPort wfPort = nestedWf.getOutputPorts()
                                        .getByName(portBinding.getBoundActivityPort().getName());
                                if (wfPort == null) {
                                    continue;
                                }
                                specializationOf(portBinding.getBoundProcessorPort(), wfPort);
                            }
                        }
                    } catch (IndexOutOfBoundsException ex) {
                    }
                    return false;
                } else {
                    // System.out.println("--NO!");
                    return false;
                }
                for (Annotation ann : scufl2Tools.annotationsFor(node, bundle)) {
                    String annotationBody = ann.getBody().toASCIIString();
                    String baseURI = bundle.getGlobalBaseURI().resolve(ann.getBody()).toASCIIString();
                    InputStream annotationStream;
                    try {
                        annotationStream = bundle.getResources().getResourceAsInputStream(annotationBody);

                        try {
                            // FIXME: Don't just assume Lang.TURTLE
                            RDFDataMgr.read(model, annotationStream, baseURI, Lang.TURTLE);
                        } catch (RiotException e) {
                            logger.log(Level.WARNING, "Can't parse RDF Turtle from " + annotationBody, e);
                        } finally {
                            annotationStream.close();
                        }
                    } catch (IOException e) {
                        logger.log(Level.WARNING, "Can't read " + annotationBody, e);
                    }
                }
                if (node instanceof Named) {
                    Named named = (Named) node;
                    entityForBean(node, OWL.Thing).addLabel(named.getName(), null);
                }
                return true;
            }

            private void specializationOf(WorkflowBean special, WorkflowBean general) {
                Individual specialEnt = entityForBean(special, Prov_o.Entity);
                Individual generalEnt = entityForBean(general, Prov_o.Entity);
                specialEnt.addProperty(Prov_o.specializationOf, generalEnt);
            }

            private Individual entityForBean(WorkflowBean bean, Resource thing) {
                return model.createIndividual(uriForBean(bean), thing);
            }

            // @Override
            // public boolean visitEnter(WorkflowBean node) {
            // if (node instanceof Processor
            // || node instanceof org.apache.taverna.scufl2.api.core.Workflow
            // || node instanceof Port || node instanceof DataLink) {
            // visit(node);
            // return true;
            // }
            // // The other node types (e.g. dispatch stack, configuration) are
            // // not (directly) represented in wfdesc
            //// System.out.println("Skipping " + node);
            // return false;
            // };
        });
        return model;
    }

    public void save(WorkflowBundle wfBundle, OutputStream output) throws WriterException {
        OntModel model;

        final URI baseURI;
        if (wfBundle.getMainWorkflow() != null) {
            Workflow mainWorkflow = wfBundle.getMainWorkflow();
            baseURI = uriTools.uriForBean(mainWorkflow);
            model = save(wfBundle);
        } else {
            throw new WriterException("wfdesc format requires a main workflow");
        }

        model.setNsPrefix("rdfs", "http://www.w3.org/2000/01/rdf-schema#");
        model.setNsPrefix("xsd", "http://www.w3.org/2001/XMLSchema#");
        model.setNsPrefix("owl", "http://www.w3.org/2002/07/owl#");
        model.setNsPrefix("prov", "http://www.w3.org/ns/prov#");
        model.setNsPrefix("wfdesc", "http://purl.org/wf4ever/wfdesc#");
        model.setNsPrefix("wf4ever", "http://purl.org/wf4ever/wf4ever#");
        model.setNsPrefix("roterms", "http://purl.org/wf4ever/roterms#");
        model.setNsPrefix("dc", "http://purl.org/dc/elements/1.1/");
        model.setNsPrefix("dcterms", "http://purl.org/dc/terms/");
        model.setNsPrefix("comp", "http://purl.org/DP/components#");
        model.setNsPrefix("dep", "http://scape.keep.pt/vocab/dependencies#");
        model.setNsPrefix("biocat", "http://biocatalogue.org/attribute/");

        model.setNsPrefix("", "#");

        try {
            model.write(output, Lang.TURTLE.getName(), baseURI.toString());
        } catch (RiotException e) {
            throw new WriterException("Can't write to output", e);
        }

    }

    public void setScufl2Tools(Scufl2Tools scufl2Tools) {
        this.scufl2Tools = scufl2Tools;
    }

    public void setUriTools(URITools uriTools) {
        this.uriTools = uriTools;
    }

}