/*******************************************************************************
* 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.IOException;
import java.net.URI;
import java.net.URL;
import java.util.HashMap;
import java.util.List;
import java.util.Vector;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import eu.planets_project.services.datatypes.DigitalObject;
import eu.planets_project.services.datatypes.DigitalObjectContent;
import eu.planets_project.services.datatypes.ServiceReport;
import eu.planets_project.services.datatypes.ServiceReport.Status;
import eu.planets_project.services.datatypes.ServiceReport.Type;
import eu.planets_project.services.identify.Identify;
import eu.planets_project.services.identify.IdentifyResult;
import eu.planets_project.tb.gui.backing.exp.ExperimentStageBean;
import eu.planets_project.tb.impl.model.eval.mockup.TecRegMockup;
import eu.planets_project.tb.impl.model.exec.ExecutionStageRecordImpl;
import eu.planets_project.tb.impl.model.measure.MeasurementImpl;
import eu.planets_project.tb.impl.model.measure.MeasurementTarget;
import eu.planets_project.tb.impl.services.wrappers.IdentifyWrapper;
/**
* This is the class that carries the code specific to invoking an Identify experiment.
*
* @author <a href="mailto:Andrew.Jackson@bl.uk">Andy Jackson</a>
*
*/
public class IdentifyWorkflow implements ExperimentWorkflow {
@SuppressWarnings("unused")
private static Log log = LogFactory.getLog(IdentifyWorkflow.class);
/** External property keys */
public static final String PARAM_SERVICE = "identify.service";
/** Internal keys for easy referral to the service+stage combinations. */
public static final String STAGE_IDENTIFY = "Identify";
/** Observable properties for this service type */
public static MeasurementImpl MEASURE_IDENTIFY_FORMAT;
public static MeasurementImpl MEASURE_IDENTIFY_METHOD;
/* (non-Javadoc)
* @see eu.planets_project.tb.impl.services.mockups.workflow.ExperimentWorkflow#getStages()
*/
public List<ExperimentStageBean> getStages() {
List<ExperimentStageBean> stages = new Vector<ExperimentStageBean>();
stages.add( new ExperimentStageBean(STAGE_IDENTIFY, "Identify a digital object."));
return stages;
}
private static HashMap<String,List<MeasurementImpl>> manualObservables;
/** Statically define the observable properties. FIXME Should be built from the TechReg */
private static HashMap<String,List<MeasurementImpl>> observables;
static {
// Set up properties:
MEASURE_IDENTIFY_FORMAT = TecRegMockup.getObservable( TecRegMockup.PROP_DO_FORMAT );
MEASURE_IDENTIFY_METHOD = MeasurementImpl.create(
TecRegMockup.PROP_SERVICE_IDENTIFY_METHOD,
"The identification method.", "",
"The method the service used to identify the digital object.",
null, MeasurementTarget.SERVICE_TARGET );
// Now set up the hash:
observables = new HashMap<String,List<MeasurementImpl>>();
observables.put(STAGE_IDENTIFY, new Vector<MeasurementImpl>() );
// The service succeeded
observables.get(STAGE_IDENTIFY).add(
TecRegMockup.getObservable(TecRegMockup.PROP_SERVICE_EXECUTION_SUCEEDED) );
// The service time
observables.get(STAGE_IDENTIFY).add(
TecRegMockup.getObservable(TecRegMockup.PROP_SERVICE_TIME) );
// The object size:
observables.get(STAGE_IDENTIFY).add(
TecRegMockup.getObservable(TecRegMockup.PROP_DO_SIZE) );
// The measured type:
observables.get(STAGE_IDENTIFY).add( MEASURE_IDENTIFY_FORMAT );
// The identification method employed by the service:
observables.get(STAGE_IDENTIFY).add( MEASURE_IDENTIFY_METHOD );
manualObservables = new HashMap<String,List<MeasurementImpl>>();
manualObservables.put(STAGE_IDENTIFY, new Vector<MeasurementImpl>() );
/*
observables.put( IDENTIFY_SUCCESS,
TecRegMockup.getObservable(TecRegMockup.PROP_SERVICE_EXECUTION_SUCEEDED, STAGE_IDENTIFY) );
// The service time
observables.put( IDENTIFY_SERVICE_TIME,
TecRegMockup.getObservable(TecRegMockup.PROP_SERVICE_TIME, STAGE_IDENTIFY) );
// The object size:
observables.put( IDENTIFY_DO_SIZE,
TecRegMockup.getObservable(TecRegMockup.PROP_DO_SIZE, STAGE_IDENTIFY) );
// The measured type:
observables.put(
IDENTIFY_FORMAT,
new MeasurementImpl(
PROP_IDENTIFY_FORMAT,
"The format of the Digital Object", "",
"The format of a Digital Object, specified as a Planets Format URI.",
STAGE_IDENTIFY, null)
);
// The identification method employed by the service:
observables.put(
IDENTIFY_METHOD,
new MeasurementImpl(
PROP_IDENTIFY_METHOD,
"The identification method.", "",
"The method the service used to identify the digital object.",
STAGE_IDENTIFY, null)
);
*/
}
/* ------------------------------------------------------------- */
/** Parameters for the workflow execution etc */
HashMap<String, String> parameters = new HashMap<String,String>();
/** The holder for the identifier service. */
Identify identifier = null;
URL identifierEndpoint = null;
/* ------------------------------------------------------------- */
/* (non-Javadoc)
* @see eu.planets_project.tb.impl.services.mockups.workflow.ExperimentWorkflow#getObservables()
*/
public HashMap<String,List<MeasurementImpl>> getObservables() {
return observables;
}
/* (non-Javadoc)
* @see eu.planets_project.tb.impl.services.mockups.workflow.ExperimentWorkflow#getManualObservables()
*/
public HashMap<String,List<MeasurementImpl>> getManualObservables() {
return manualObservables;
}
/* (non-Javadoc)
* @see eu.planets_project.tb.impl.services.mockups.workflow.ExperimentWorkflow#setParameters(java.util.HashMap)
*/
public void setParameters(HashMap<String, String> parameters)
throws Exception {
this.parameters = parameters;
// Attempt to connect to the Identify service.
identifierEndpoint = new URL( this.parameters.get(PARAM_SERVICE));
identifier = new IdentifyWrapper( identifierEndpoint );
}
public HashMap<String, String> getParameters(){
return this.parameters;
}
/* (non-Javadoc)
* @see eu.planets_project.tb.impl.services.mockups.workflow.ExperimentWorkflow#execute(eu.planets_project.services.datatypes.DigitalObject, java.util.HashMap)
*/
public WorkflowResult execute( DigitalObject dob ) {
// Invoke the service, timing it along the way:
boolean success = true;
String exceptionReport = "";
IdentifyResult identify = null;
long msBefore = 0, msAfter = 0;
msBefore = System.currentTimeMillis();
try {
identify = identifier.identify(dob,null);
} catch( Exception e ) {
success = false;
exceptionReport = "<p>Service Invocation Failed!<br/>" + e + "</p>";
}
msAfter = System.currentTimeMillis();
// Now prepare the result:
WorkflowResult wr = new WorkflowResult();
// Record this one-stage experiment:
ExecutionStageRecordImpl idStage = new ExecutionStageRecordImpl(null, STAGE_IDENTIFY);
wr.getStages().add( idStage );
// Record the endpoint of the service used for this stage. FIXME Can this be done more automatically, from above?
idStage.setEndpoint(identifierEndpoint);
List<MeasurementImpl> recs = idStage.getMeasurements();
recs.add(new MeasurementImpl(TecRegMockup.PROP_SERVICE_TIME, ""+((msAfter-msBefore)/1000.0) ));
// Now record
try {
if( success && identify.getTypes() != null && identify.getTypes().size() > 0 ) {
recs.add( new MeasurementImpl( TecRegMockup.PROP_SERVICE_EXECUTION_SUCEEDED, "true"));
collectIdentifyResults(recs, identify, dob);
wr.logReport(identify.getReport());
return wr;
}
} catch( Exception e ) {
exceptionReport += "<p>Failed with exception: "+e+"</p>";
}
// Build in a 'service failed' property.
recs.add( new MeasurementImpl( TecRegMockup.PROP_SERVICE_EXECUTION_SUCEEDED, "false"));
// Create a ServiceReport from the exception.
// TODO can we distinguish tool and install error here?
ServiceReport sr = new ServiceReport(Type.ERROR, Status.TOOL_ERROR,
"No info");
if (identify != null && identify.getReport() != null) {
String info = identify.getReport().toString();
sr = new ServiceReport(Type.ERROR, Status.TOOL_ERROR, info);
}
wr.logReport(sr);
return wr;
}
public static void collectIdentifyResults( List<MeasurementImpl> recs, IdentifyResult ident, DigitalObject dob ) {
if( ident == null ) return;
if( ident.getTypes() != null ) {
for( URI format_uri : ident.getTypes() ) {
if( format_uri != null ) {
recs.add( new MeasurementImpl( TecRegMockup.PROP_DO_FORMAT, format_uri.toString()));
}
}
}
if( ident.getMethod() != null ) {
recs.add( new MeasurementImpl( TecRegMockup.PROP_SERVICE_IDENTIFY_METHOD, ident.getMethod().name() ));
}
// Store the size:
recs.add( new MeasurementImpl(TecRegMockup.PROP_DO_SIZE, ""+getContentSize(dob) ) );
return;
}
/*
* Recursive method for computing the total size.
* TODO A badly-formed DigitalObject could cause this method to recurse forever. Can that be stopped?
*/
static long getContentSize( DigitalObject dob ) {
long bytes = 0;
// Get the size at this level:
if( dob.getContent() != null ) {
bytes += getSizeOfContent(dob.getContent());
}
// Return the total:
return bytes;
}
/*
* Attempts to determine the size of the content of a particular DigitalObject.
*/
private static long getSizeOfContent( DigitalObjectContent con ) {
if( con == null ) return 0;
if( con.length() >= 0 ) return con.length();
// Otherwise, read it to work out how big it is.
try {
// Note that this can be misleading, as the available bytes may be less than the total size.
return con.getInputStream().available();
} catch (IOException e) {
e.printStackTrace();
}
return 0;
}
}