/*******************************************************************************
* Copyright (c) 2007, 2010 The Planets Project Partners.
*
* All rights reserved. This program and the accompanying
* materials are made available under the terms of the
* Apache License, Version 2.0 which accompanies
* this distribution, and is available at
* http://www.apache.org/licenses/LICENSE-2.0
*
*******************************************************************************/
package eu.planets_project.tb.impl.services.mockups.workflow;
import java.io.File;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.util.Arrays;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.xml.namespace.QName;
import javax.xml.ws.Service;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import eu.planets_project.services.PlanetsException;
import eu.planets_project.services.PlanetsServices;
import eu.planets_project.services.compare.Compare;
import eu.planets_project.services.datatypes.Content;
import eu.planets_project.services.datatypes.DigitalObject;
import eu.planets_project.services.datatypes.Property;
import eu.planets_project.services.identify.Identify;
import eu.planets_project.services.identify.IdentifyResult;
import eu.planets_project.services.migrate.Migrate;
import eu.planets_project.tb.api.model.eval.EvaluationExecutable;
import eu.planets_project.tb.api.services.mockups.workflow.Workflow;
import eu.planets_project.tb.impl.model.eval.EvaluationExecutableImpl;
/**
* @author lindleyA
* This mockup implements the following scenario:
* In-->Takes two files as input
* a) identify using Droid: to analyze a given file and to extract it's pronom Id(s)
* b) extract using XCDL Extractor: to extract it's XCDL representation (if it is supported)
* c) compare using XCDL Comparator: compares the two XCDL descriptions.
* Out<--returns the comparator's responds
*
* It is fully functional in terms of service execution
* Due to the abstinence of a technical registry, the logic of pronom ID mapping to XCEL selection
* is currently provided within this workflow.
* At the moment TIFF and PNG are supported
*
* It however does not follow the Planets (IF) patterns of designing workflows and
* therefore is marked as mockup
*
*/
@Deprecated
public class WorkflowDroidXCDLExtractorComparator implements Workflow{
private static final String URL_DROID = "http://localhost:8080/pserv-pc-droid/Droid?wsdl";
//private static final String URL_XCDLEXTRACTOR = "http://localhost:8080/pserv-pc-extractor/Extractor2Binary?wsdl";
private static final String URL_XCDLEXTRACTOR = "http://planetarium.hki.uni-koeln.de:8080/pserv-pc-extractor/Extractor2Binary?wsdl";
private static final String URL_XCDLCOMPARATOR = "http://localhost:8080/pserv-pp-comparator/ComparatorBasicCompareTwoXcdlValues?wsdl";
//the new extractor interface does not require to hand over the xcel anymore
//private static final String PATH_TO_xcel_tiff = "Planets_XCEL_Exctractor/res/xcl/xcel/xcel_docs/xcel_tiff.xml";
//private static final String PATH_TO_xcel_png = "Planets_XCEL_Exctractor/res/xcl/xcel/xcel_docs/xcel_png.xml";
enum supportedTypes{
TIFF(new String[]{"info:pronom/fmt/7","info:pronom/fmt/8","info:pronom/fmt/9","info:pronom/fmt/10","info:pronom/fmt/152","info:pronom/fmt/153","info:pronom/fmt/154","info:pronom/fmt/155","info:pronom/fmt/156","info:pronom/x-fmt/387","info:pronom/x-fmt/388","info:pronom/x-fmt/399"}/*,PATH_TO_xcel_tiff*/),
PNG(new String[]{"info:pronom/fmt/11","info:pronom/fmt/12","info:pronom/fmt/13"}/*,PATH_TO_xcel_png*/),
JPEG(new String[]{"info:pronom/fmt/41","info:pronom/fmt/42","info:pronom/fmt/43","info:pronom/fmt/44","info:pronom/fmt/112","info:pronom/fmt/149","info:pronom/x-fmt/390","info:pronom/x-fmt/391","info:pronom/x-fmt/398"}/*,PATH_TO_xcel_jpeg*/),
GIF(new String[]{"info:pronom/fmt/3","info:pronom/fmt/4"}/*,PATH_TO_xcel_gif*/),
BMP(new String[]{"info:pronom/fmt/114","info:pronom/fmt/115","info:pronom/fmt/116","info:pronom/fmt/117","info:pronom/fmt/118","info:pronom/fmt/119","info:pronom/x-fmt/25","info:pronom/x-fmt/270"}/*,PATH_TO_xcel_bmp*/);
private String[] idsForType;
//private String xcelPath;
supportedTypes(String[] ids /*, String xcelPath*/){
this.idsForType = ids;
//this.xcelPath = xcelPath;
}
public String[] pronomIDs(){
return this.idsForType;
}
/*public String xcelPath(){
return xcelPath;
}*/
/**
* Returns the XCEL - parsed from the definition files
* @return
* @throws UnsupportedEncodingException
*/
/*private String xcel() throws UnsupportedEncodingException{
return new String(ByteArrayHelper.read(new File(xcelPath())),"UTF-8");
}*/
}
/**
* Returns an EvaluationExecutable containing the XCDLs, etc.
* @param f1
* @param f2
* @return
* @throws Exception
*/
public EvaluationExecutable execute(File f1, File f2){
//check if the results can be returned from the cache else - perform the workflow
if(this.isResultCached(f1, f2)){
//results already cached
return(this.getResultFromCache(f1, f2));
}
//the execution results are packed within this executable
//please note this mockup is not using the concept of the TestbedServiceTemplate
EvaluationExecutable executable = new EvaluationExecutableImpl();
executable.setExecutionStartDate(new GregorianCalendar().getTimeInMillis());
executable.setExecutableInvoked(true);
executable.setExecutionCompleted(false);
try{
//step1: identify using Pronom;
String[] sPronomIDs1 = runDroid(f1);
String[] sPronomIDs2 = runDroid(f2);
//if-else logic - linking pronom results as input for xcdl extraction
@SuppressWarnings("unused")
supportedTypes typeF1,typeF2;
typeF1 = getType(sPronomIDs1);
typeF2 = getType(sPronomIDs2);
//step2: extract the xcdl descriptions
String XCDL1 = runXCDLExtractor(f1 /*, typeF1.xcel()*/);
String XCDL2 = runXCDLExtractor(f2 /*, typeF2.xcel()*/);
//step3: run the XCDL comparison
String result = runXCDLComparator(XCDL1, XCDL2);
executable.setXCDLForSource(XCDL1);
executable.setXCDLForTarget(XCDL2);
executable.setXCDLsComparisonResult(result);
executable.setExecutionSuccess(true);
}catch(Exception e){
executable.setExecutionSuccess(false);
}
//End Workflow; write back the results into the executable
executable.setExecutionEndDate(new GregorianCalendar().getTimeInMillis());
executable.setExecutionCompleted(true);
//add the result to the cache
this.addResultToCache(executable, f1, f2);
return executable;
}
/**
* Takes an Array of PronomIDs and returns the supported type e.g. TIFF, PNG
* If no type is known, supportedTypes = null;
* @param pronomIDs
* @return
*/
private supportedTypes getType(String[] pronomIDs) throws Exception{
supportedTypes typeFound = null;
//iterate over all supportedTypes and check if we match one
for(supportedTypes type : supportedTypes.values()){
List<String> lIDs = Arrays.asList(type.idsForType);
for(int j=0;j<pronomIDs.length;j++){
if(lIDs.contains(pronomIDs[j])){
//we've found a supported type as e.g. TIFF, PNG, etc.
typeFound = type;
}
}
}
if(typeFound ==null){
throw new Exception("The specified file type is currently not supported by this workflow");
}
return typeFound;
}
/**
* Runs droid on a given File and returns an Array of PronomIDs
* @param f1
* @return
* @throws Exception
*/
private String[] runDroid(File f1) throws Exception{
//Step1: identify using droid - returns a status and a list of IDs
URL url = null;
try {
url = new URL(URL_DROID);
} catch (MalformedURLException e) {
e.printStackTrace();
throw e;
}
Service service = Service.create(url, new QName(PlanetsServices.NS,
Identify.NAME));
Identify droid = service.getPort(Identify.class);
byte[] array = FileUtils.readFileToByteArray(f1);
//invoke the service and extract results
IdentifyResult identify = droid.identify(new DigitalObject.Builder(Content.byValue(array)).build(), null);
List<URI> result = identify.getTypes();
String status = identify.getReport().getMessage();
if(!status.equals("Positive")){
throw new Exception("Service execution failed");
}
if(result.size()<1){
throw new Exception("The specified file type is currently not supported by this workflow");
}
String[] strings = new String[result.size()];
for (int i = 0; i < result.size(); i++) {
String string = result.get(i).toASCIIString();
//received 1..n Pronom IDs
strings[i] = string;
}
return strings;
}
/**
* Runs the XCDL extractor on a given file and for a given xcel descriptor
* Returns the XCDL description (UTF-8 encoded) for the provided file
* @param f1
* @param xcel
* @return
* @throws Exception
*/
private String runXCDLExtractor(File f1 /*, String xcel*/) throws Exception{
URL url = null;
try {
url = new URL(URL_XCDLEXTRACTOR);
Service service = Service.create(url, new QName(PlanetsServices.NS,
Migrate.NAME));
Migrate extractor = service.getPort(Migrate.class);
//the service's input
byte[] array = FileUtils.readFileToByteArray(f1);
//the service call and it's result
DigitalObject digitalObject = extractor.migrate(
new DigitalObject.Builder(Content.byValue(array))
.build(), null, null, null).getDigitalObject();
byte[] results = IOUtils.toByteArray(digitalObject.getContent().getInputStream());
String xcdl = new String(results,"UTF-8");
if(xcdl==null){
throw new Exception("XCDL extraction failed - please check service logs for details");
}
return xcdl;
} catch (MalformedURLException e) {
e.printStackTrace();
throw e;
} catch (UnsupportedEncodingException e) {
//xcel file was not UTF-8 encodable
e.printStackTrace();
throw e;
} catch (PlanetsException e) {
//error calling the web-service
e.printStackTrace();
throw e;
}
}
/**
* Runs the XCDLComparator on two given xcdls and returns the comparison result.
* @param xcdl1
* @param xcdl2
* @return
* @throws Exception
*/
private String runXCDLComparator(String xcdl1, String xcdl2) throws Exception{
URL url = null;
try {
url = new URL(URL_XCDLCOMPARATOR);
Service service = Service.create(url, new QName(PlanetsServices.NS,
Compare.NAME));
Compare comparator = service.getPort(Compare.class);
//the service call and it's result
DigitalObject x1 = new DigitalObject.Builder(Content.byValue(xcdl1.getBytes())).build();
DigitalObject x2 = new DigitalObject.Builder(Content.byValue(xcdl2.getBytes())).build();
List<Property> result = comparator.compare(x1, x2, null).getProperties();
if(result==null){
throw new Exception("XCDL comparison failed - please check service logs for details");
}
return result.toString();
} catch (MalformedURLException e) {
e.printStackTrace();
throw e;
}
}
//Info: Map<f1.getAbsolutePath()+f2.getAbsolutePath(), EvaluationExecutable>
private Map<String, EvaluationExecutableImpl> cache = new HashMap<String, EvaluationExecutableImpl>();
/**
*@see isStaticAutoEvaluationWorkflowResultCached
*/
private EvaluationExecutable getResultFromCache(File f1, File f2){
if(cache.containsKey(f1.getAbsolutePath()+f2.getAbsolutePath())){
return (cache.get(f1.getAbsolutePath()+f2.getAbsolutePath())).clone();
}
else{
return null;
}
}
/**
* Check if for a given data pair input and output file if the service
* request has already been issued. If yes the results will be the same and therefore may
* be returned from this cache
* @param f1
* @param f2
* @return
*/
private boolean isResultCached(File f1, File f2){
return cache.containsKey(f1.getAbsolutePath()+f2.getAbsolutePath());
}
/**
*@see isStaticAutoEvaluationWorkflowResultCached
*/
private void addResultToCache(EvaluationExecutable executable, File f1, File f2){
cache.put((f1.getAbsolutePath()+f2.getAbsolutePath()), (EvaluationExecutableImpl)executable);
}
}