blob: e218bc6a19d0d1ba188fe7d40d73c6bb9619a085 [file] [log] [blame]
/*******************************************************************************
* 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 net.sf.taverna.t2.commandline.data;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import net.sf.taverna.t2.commandline.exceptions.ReadInputException;
import net.sf.taverna.t2.invocation.InvocationContext;
import net.sf.taverna.t2.invocation.WorkflowDataToken;
import net.sf.taverna.t2.reference.DereferenceException;
import net.sf.taverna.t2.reference.ErrorDocument;
import net.sf.taverna.t2.reference.IdentifiedList;
import net.sf.taverna.t2.reference.T2Reference;
import net.sf.taverna.t2.reference.T2ReferenceType;
import org.apache.log4j.Logger;
import org.embl.ebi.escience.baclava.DataThing;
import org.embl.ebi.escience.baclava.factory.DataThingFactory;
import org.embl.ebi.escience.baclava.factory.DataThingXMLFactory;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.Namespace;
import org.jdom.input.SAXBuilder;
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;
/**
* Handles creating and reading of Baclava documents.
* Baclava is a standard originating from Taverna 1.
*
* @author Stuart Owen
*
*/
public class BaclavaDocumentHandler {
private static Namespace namespace = Namespace.getNamespace("b",
"http://org.embl.ebi.escience/baclava/0.1alpha");
private static final Logger logger = Logger
.getLogger(BaclavaDocumentHandler.class);
public Map<String, DataThing> readInputDocument(String inputDocPath)
throws ReadInputException {
URL url;
try {
url = new URL("file:");
} catch (MalformedURLException e1) {
// Should never happen, but just incase:
throw new ReadInputException(
"The was an internal error setting up the URL to open the inputs. You should contact Taverna support.",
e1);
}
URL inputDocURL;
try {
inputDocURL = new URL(url, inputDocPath);
} catch (MalformedURLException e1) {
throw new ReadInputException(
"The a error reading the input document from : "
+ inputDocPath + ", " + e1.getMessage(), e1);
}
SAXBuilder builder = new SAXBuilder();
Document inputDoc;
try {
inputDoc = builder.build(inputDocURL.openStream());
} catch (IOException e) {
throw new ReadInputException(
"There was an error reading the input document file: "
+ e.getMessage(), e);
} catch (JDOMException e) {
throw new ReadInputException(
"There was a error processing the input document XML: "
+ e.getMessage(), e);
}
Map<String, DataThing> things = DataThingXMLFactory
.parseDataDocument(inputDoc);
return things;
}
public void storeDocument(Map<String, WorkflowDataToken> finalResults,
File outputFile) throws DereferenceException, IOException {
Map<String, DataThing> dataThings = backDataThingMapFromWorkflowDataTokens(finalResults);
// Build the string containing the XML document from the result map
Document doc = getDataDocument(dataThings);
XMLOutputter xo = new XMLOutputter(Format.getPrettyFormat());
String xmlString = xo.outputString(doc);
PrintWriter out = new PrintWriter(new FileWriter(outputFile));
out.print(xmlString);
out.flush();
out.close();
}
protected Object convertReferencesToObjects(T2Reference reference,
InvocationContext context) {
if (reference.getReferenceType() == T2ReferenceType.ReferenceSet) {
// Dereference the object
Object dataValue;
dataValue = context.getReferenceService().renderIdentifier(
reference, Object.class, context);
return dataValue;
} else if (reference.getReferenceType() == T2ReferenceType.ErrorDocument) {
// Dereference the ErrorDocument and convert it to some string
// representation
ErrorDocument errorDocument = (ErrorDocument) context
.getReferenceService().resolveIdentifier(reference, null,
context);
String errorString = ErrorDocumentHandler.buildErrorDocumentString(
errorDocument, context);
return errorString;
} else { // it is an IdentifiedList<T2Reference> - go recursively
IdentifiedList<T2Reference> identifiedList = context
.getReferenceService().getListService().getList(reference);
List<Object> list = new ArrayList<Object>();
for (int j = 0; j < identifiedList.size(); j++) {
T2Reference ref = identifiedList.get(j);
list.add(convertReferencesToObjects(ref, context));
}
return list;
}
}
/**
* Returns a org.jdom.Document from a map of port named to DataThingS
* containing the port's results.
*/
public static Document getDataDocument(Map<String, DataThing> dataThings) {
Element rootElement = new Element("dataThingMap", namespace);
Document theDocument = new Document(rootElement);
for (Iterator<String> i = dataThings.keySet().iterator(); i.hasNext();) {
String key = (String) i.next();
DataThing value = (DataThing) dataThings.get(key);
Element dataThingElement = new Element("dataThing", namespace);
dataThingElement.setAttribute("key", key);
dataThingElement.addContent(value.getElement());
rootElement.addContent(dataThingElement);
}
return theDocument;
}
/**
* Returns a map of port names to DataThings from a map of port names to a
* list of (lists of ...) result objects.
*/
protected Map<String, DataThing> bakeDataThingMap(
Map<String, Object> resultMap) {
Map<String, DataThing> dataThingMap = new HashMap<String, DataThing>();
for (Iterator<String> i = resultMap.keySet().iterator(); i.hasNext();) {
String portName = (String) i.next();
dataThingMap.put(portName, DataThingFactory.bake(resultMap
.get(portName)));
}
return dataThingMap;
}
protected Map<String, DataThing> backDataThingMapFromWorkflowDataTokens(
Map<String, WorkflowDataToken> tokenMap)
throws DereferenceException, IOException {
Map<String, DataThing> dataThingMap = new HashMap<String, DataThing>();
for (Iterator<String> i = tokenMap.keySet().iterator(); i.hasNext();) {
String portName = (String) i.next();
WorkflowDataToken token = tokenMap.get(portName);
InvocationContext context = token.getContext();
List<String> mimeTypeList = new ArrayList<String>();
if (token.getData().getReferenceType() == T2ReferenceType.ReferenceSet) {
mimeTypeList
.addAll(MimeTypeHandler.determineMimeTypes(token.getData(), context));
DataThing thingy = DataThingFactory.bake(convertReferencesToObjects(token.getData(), context));
thingy.getMetadata().setMIMETypes(mimeTypeList);
dataThingMap.put(portName, thingy);
} else if (token.getData().getReferenceType() == T2ReferenceType.ErrorDocument) {
DataThing thingy = DataThingFactory.bake(convertReferencesToObjects(token.getData(), context));
thingy.getMetadata().addMIMEType("text/plain");
dataThingMap.put(portName, thingy);
} else {
IdentifiedList<T2Reference> identifiedList = context
.getReferenceService().getListService().getList(
token.getData());
List<Object> list = new ArrayList<Object>();
for (int j = 0; j < identifiedList.size(); j++) {
T2Reference ref = identifiedList.get(j);
list.add(convertReferencesToObjects(ref, context));
}
// ripple through to get the leaf, to find its mimetype. Seems a
// limitation of Baclava
// is that the mime-type is set on the entire list, and is not
// possible for individual items
T2Reference ref = token.getData();
while (ref.getReferenceType() != T2ReferenceType.ReferenceSet
&& ref.getReferenceType() != T2ReferenceType.ErrorDocument) {
identifiedList = context.getReferenceService()
.getListService().getList(ref);
ref = identifiedList.get(0);
}
mimeTypeList.addAll(MimeTypeHandler.determineMimeTypes(ref, context));
DataThing thingy = DataThingFactory.bake(list);
thingy.getMetadata().setMIMETypes(mimeTypeList);
dataThingMap.put(portName, thingy);
}
}
return dataThingMap;
}
}