eu.planets_project.tb.impl.system.ServiceExecutionHandlerImpl.java Source code

Java tutorial

Introduction

Here is the source code for eu.planets_project.tb.impl.system.ServiceExecutionHandlerImpl.java

Source

/*******************************************************************************
 * 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.system;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Map.Entry;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import eu.planets_project.tb.api.data.util.DataHandler;
import eu.planets_project.tb.api.model.Experiment;
import eu.planets_project.tb.api.model.ExperimentExecutable;
import eu.planets_project.tb.api.model.benchmark.BenchmarkGoal;
import eu.planets_project.tb.api.services.TestbedServiceTemplate;
import eu.planets_project.tb.api.services.TestbedServiceTemplate.ServiceOperation;
import eu.planets_project.tb.api.services.mockups.workflow.Workflow;
import eu.planets_project.tb.api.system.ServiceExecutionHandler;
import eu.planets_project.tb.api.system.batch.BatchProcessor;
import eu.planets_project.tb.gui.backing.admin.wsclient.faces.WSClientBean;
import eu.planets_project.tb.impl.data.util.DataHandlerImpl;
import eu.planets_project.tb.impl.exceptions.ServiceInvocationException;
import eu.planets_project.tb.impl.services.mockups.workflow.ExperimentWorkflow;
import eu.planets_project.tb.impl.services.mockups.workflow.WorkflowDroidXCDLExtractorComparator;
import eu.planets_project.tb.impl.system.batch.TestbedBatchProcessorManager;

/**
 * @author Andrew Lindley, ARC
 * This class is responsible for taking the experiment's executable part, building the request, 
 * invoking the actual service, extracting the results from the responds and wrting
 * information back to the experiment's executable
 *
 */
public class ServiceExecutionHandlerImpl implements ServiceExecutionHandler {

    //A Log for this - transient: it's not persisted with this entity
    private Log log = LogFactory.getLog(ServiceExecutionHandlerImpl.class);
    private String sOutputDir = "";
    //this will only be modified once, so therefore the relative position of its elements will not change
    //which is important for mapping them to their output files.
    Map<String, String> hmInputFiles = new HashMap<String, String>();
    //A DataHandler util class for decoding base64 or similar value (and not ref) results
    DataHandler dh = new DataHandlerImpl();

    public ServiceExecutionHandlerImpl() {
    }

    /* (non-Javadoc)
     * @see eu.planets_project.tb.api.system.ExperimentInvoker#executeExperiment(eu.planets_project.tb.api.model.Experiment)
     */
    public void executeExperiment(Experiment exp) {

        //1) Get the required data and build the request
        //ExperimentExecutable already contains the input data
        ExperimentExecutable executable = exp.getExperimentExecutable();
        if (executable == null) {
            log.error("executeExperiment: executable is null!");
            return;
        }

        //DECIDE UPON WHICH BATCH_QUEUE WAS CHOSEN WHAT PROCESSOR TO CALL
        // Look for the batch system... 
        TestbedBatchProcessorManager tbBatchManager = TestbedBatchProcessorManager.getInstance();
        BatchProcessor bp;

        //a) TB-experiment types before version1.0 - these use the ExperimentWorkflow
        if (executable.getBatchSystemIdentifier().equals(BatchProcessor.BATCH_IDENTIFIER_TESTBED_LOCAL)) {
            //get the specific batchProcessor implementation
            bp = tbBatchManager.getBatchProcessor(BatchProcessor.BATCH_IDENTIFIER_TESTBED_LOCAL);
            // Invoke, depending on the experiment type:
            ExperimentWorkflow ewf = executable.getWorkflow();
            log.info("Submitting workflow: " + ewf + " to batch processor: "
                    + BatchProcessor.BATCH_IDENTIFIER_TESTBED_LOCAL);
            log.info("Got inputs #" + executable.getInputData().size());
            String queue_key = bp.submitBatch(exp.getEntityID(), ewf, executable.getInputData());
            //already set: executable.setBatchQueueIdentifier(BatchProcessor.BATCH_QUEUE_TESTBED_LOCAL);
            executable.setBatchExecutionIdentifier(queue_key);
            executable.setExecutableInvoked(true);
            executable.setExecutionCompleted(false);
            log.info("Got key: " + queue_key);
        }

        //b) TB-experiment types using the wee batch processor
        if (executable.getBatchSystemIdentifier().equals(BatchProcessor.BATCH_QUEUE_TESTBED_WEE_LOCAL)) {
            //get the specific batchProcessor implementation
            bp = tbBatchManager.getBatchProcessor(BatchProcessor.BATCH_QUEUE_TESTBED_WEE_LOCAL);
            log.info("Submitting workflow to batch processor: " + BatchProcessor.BATCH_QUEUE_TESTBED_WEE_LOCAL);
            log.info("Got inputs #" + executable.getInputData().size());
            //DataHandler dh = new DataHandlerImpl();
            //NOTE: previously submitting digital objects...
            //List<DigitalObject> digos = dh.convertFileRefsToURLAccessibleDigos(executable.getInputData());
            //submit the batch process to the WEE
            //String queue_key = bp.sumitBatch(exp.getEntityID(), digos, executable.getWEEWorkflowConfig());

            //NOTE: changed to submitting by data registry references..
            //submit the batch process to the WEE passing objects by reference (shared data registry pointers)
            List<URI> digoRefs = new ArrayList<URI>();
            for (String inputDataRef : executable.getInputData()) {
                try {
                    digoRefs.add(new URI(inputDataRef));
                } catch (URISyntaxException err) {
                    log.debug("this shouldn't happen - conversion String -> URI failed for " + inputDataRef);
                }
            }
            String queue_key = bp.sumitBatchByReference(exp.getEntityID(), digoRefs,
                    executable.getWEEWorkflowConfig());

            if ((queue_key != null) && (!queue_key.equals(""))) {
                executable.setBatchExecutionIdentifier(queue_key);
                //executable.setExecutableInvoked(true);
                executable.setExecutionCompleted(false);
                log.info("Got key: " + queue_key);
            } else {
                //something on the batch processor went wrong....
                //FIXME: This is not really sufficient... inform notify_failed?
                executable.setExecutionCompleted(true);
                executable.setExecutionSuccess(false);
            }

        }
    }

    /**
    * Takes the added data and builds up a map structure with the position number
    * as key and the fileRef as value - this is required to create an input - output mapping
    * Map<String position+"", String localInputFileRef>
    * @param inputData
    */
    @SuppressWarnings("unused")
    private void createInputDataMap(Collection<String> inputData) {
        if (inputData != null) {
            Iterator<String> fileRefs = inputData.iterator();
            int count = 0;
            while (fileRefs.hasNext()) {
                this.hmInputFiles.put(count + "", fileRefs.next());
                count++;
            }
        }

    }

    /**
     * Takes the information provided within the TestbedServiceTEmplate to build
     * the web service client.
     * @return
     */
    @SuppressWarnings("unused")
    private WSClientBean createWSClient(TestbedServiceTemplate serviceTemplate, ServiceOperation selOperation)
            throws ServiceInvocationException {
        WSClientBean wsclient = initWSClient();
        wsclient.setWsdlURI(serviceTemplate.getEndpoint());
        String message = wsclient.analyzeWsdl();

        if (!message.equals("success-analyze")) {
            log.error("creating WSClientbean error-analzye");
            throw new ServiceInvocationException("error-analyze");
        }

        wsclient.setServiceSelectItemValue(serviceTemplate.getName());
        wsclient.setOperationSelectItemValue(selOperation.getName());

        return wsclient;
    }

    /**
     * Creates a new WSClientBean ant sets its  working dir
     */
    private WSClientBean initWSClient() {

        //load properties from BackendResources.properties file
        Properties properties = new Properties();
        try {
            java.io.InputStream ResourceFile = getClass().getClassLoader()
                    .getResourceAsStream("eu/planets_project/tb/impl/BackendResources.properties");
            properties.load(ResourceFile);

            //Note: sFileDirBase = ifr_server/bin/../server/default/deploy/jbossweb-tomcat55.sar/ROOT.war
            String sFileDirBase = BackendProperties.getTBFileDir();
            ResourceFile.close();

            //create a new client bean
            WSClientBean wcb = new WSClientBean();
            wcb.setWorkDir(sFileDirBase + "/planets/wsexecution");

            return wcb;

        } catch (IOException e) {
            log.error("read JBoss.FiledirBase from BackendResources.properties failed!" + e.toString());
        }
        return null;
    }

    /**
     * Take the migrated file output (produced by the ServiceRespondsBuilder) and copy the
     *  service's migration output to the Testbed's experiment/output direcotry. 
     *  
     * If the migration output does not correspond to a local file but rather to a URI the content is downloaded 
     * and copied into the Testbed's experiment/output direcotry. 
     *  
     *  This methods also calls renameOutput which produces an outpuf file with the same name as it's input file.
     * @return updated migrationResult with file refs to the Testbed's output dir.
     */
    @SuppressWarnings("unused")
    private Map<String, String> copyFileOutputToOutputDir(Map<String, String> migrationResults) throws IOException {
        Map<String, String> ret = new HashMap<String, String>();
        if (migrationResults != null) {
            Iterator<String> itKeys = migrationResults.keySet().iterator();
            while (itKeys.hasNext()) {
                String key = itKeys.next();
                try {
                    //1)get the File ref, rename it to it's corresponding input file name and 
                    //move it within the testbed's output dir
                    String fileRef = migrationResults.get(key);
                    File fMigrationOutput = new File(fileRef);
                    //VM needs to be able to access this ref as file
                    if (!fMigrationOutput.canRead()) {
                        //this item did not produce a valid migration output
                        throw new IOException("Error reading migration output file from file ref for key: " + key);
                    }
                    //now copy its binary data
                    String ref = dh.storeFile(fMigrationOutput).toString();

                    //finally update the returned migration output reference
                    ret.put(key, ref);

                } catch (IOException e) {
                    //2)no valid output FILE for this input file - no problem
                    //in this case, test if it's an URI and if this is downloadable
                    try {
                        String suriRef = migrationResults.get(key);
                        URI uriRef = new URI(suriRef);

                        //write the file's content as read from the stream
                        String newFileName = dh.storeUriContent(uriRef).toString();

                        //finally update the returned migration output reference
                        ret.put(key, newFileName);
                    } catch (Exception e2) {
                        //no problem - we're not able to handle this output
                        //not output for this input element
                        log.debug(e2.toString());
                    }
                }
            }
        }
        return ret;
    }

    /**
     * Specifies the directory where to copy the migration output files
     * @throws IOException
     */
    @SuppressWarnings("unused")
    private void setDir() throws IOException {
        Properties properties = new Properties();
        try {
            java.io.InputStream ResourceFile = getClass().getClassLoader()
                    .getResourceAsStream("eu/planets_project/tb/impl/BackendResources.properties");
            properties.load(ResourceFile);

            //Note: sFileDirBaase = ifr_server/bin/../server/default/deploy/jbossweb-tomcat55.sar/ROOT.war
            String sFileDirBase = BackendProperties.getTBFileDir();
            sOutputDir = sFileDirBase + properties.getProperty("JBoss.FileOutDir");

            ResourceFile.close();

            //create if it does not already exist
            createOutputDir();

        } catch (IOException e) {
            log.error("read JBossFileDirs from BackendResources.proerties failed!" + e.toString());
            throw e;
        }
    }

    /**
     * Checks if output dir (as defined in the properties file) 
     * e.g. C:\DATA\Implementation\ifr_server\server\default\deploy\jbossweb-tomcat55.sar\ROOT.war\planets-testbed\outputdata
     * exists and otherwise creates it.
     */
    private void createOutputDir() {
        File dir = new File(sOutputDir);
        if (!dir.exists()) {
            log.info("Dir does not exist: mkdirs: " + dir.toString());
            dir.mkdirs();
        }
    }

    /**
     * Takes a given http URI and tries to download its binary content.
     * @param uri
     * @return
     * @throws FileNotFoundException
     * @throws IOException
     */
    @SuppressWarnings("unused")
    private byte[] downloadBinaryFromURI(URI uri) throws FileNotFoundException, IOException {

        InputStream in = null;
        try {
            if (!uri.getScheme().equals("http")) {
                throw new FileNotFoundException("URI schema " + uri.getScheme() + " not supported");
            }

            URLConnection c = uri.toURL().openConnection();
            in = c.getInputStream();
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            byte[] buf = new byte[1024];
            int len;
            while ((len = in.read(buf)) > 0) {
                bos.write(buf, 0, len);
            }
            byte[] data = bos.toByteArray();

            return data;
        } finally {
            in.close();
        }
    }

    /**
     * In the case of a value calls (e.g. as base64 data transmission) this method
     * extracts and decodes the data to a local file and provides a file reference
     * An output file type (e.g. doc) can be specified, which will be used as the result's file type
     * @return
     */
    @SuppressWarnings("unused")
    private Map<String, String> createFilesFromBase64Result(Map<String, String> migrationResults,
            String outputFileType) {
        Map<String, String> ret = new HashMap<String, String>();
        if ((migrationResults == null) || (migrationResults.size() <= 0))
            return ret;

        Iterator<String> itKeys = migrationResults.keySet().iterator();
        while (itKeys.hasNext()) {
            String key = itKeys.next();
            String sBase64value = migrationResults.get(key);

            //decode the base64 String
            byte[] b = DataHandlerImpl.decodeToByteArray(sBase64value);
            try {
                //get the file's new name (same as it's input file) - input and output should have the same key
                String sInputFileName = new File(this.hmInputFiles.get(key)).getName();
                String sOutputFileName = "";
                char delimP = '.';
                int p = sInputFileName.lastIndexOf(delimP);
                String origInputFileMathNr = sInputFileName.substring(0, p);
                sOutputFileName = origInputFileMathNr + "." + outputFileType;

                //now copy the byteArray into the file-location
                String ref = dh.storeBytearray(b, sOutputFileName).toString();

                //finally update the returned migration output reference
                ret.put(key, ref);

            } catch (FileNotFoundException e) {
                System.out.println(e.toString());
            } catch (IOException e) {
                System.out.println(e.toString());
            }
        }

        return ret;
    }

    /* (non-Javadoc)
     * @see eu.planets_project.tb.api.system.ServiceExecutionHandler#executeAutoEvalServices(eu.planets_project.tb.api.model.Experiment)
     * Executable only if the current experiment phase = evaluation
     */
    public void executeAutoEvalServices(Experiment exp) {
        log.info("Attempting to execute the Auto Eval services.");
        //a Planets IF Java Workflow instance (mockup)
        WorkflowDroidXCDLExtractorComparator evalWorkflow = new WorkflowDroidXCDLExtractorComparator();

        //Get the experiment's data we want to add autoEval FileBMGoals for
        Collection<Entry<String, String>> data = exp.getExperimentExecutable().getMigrationDataEntries();

        //iterate over all experiemnt data entries
        for (Entry<String, String> dataEntry : data) {
            DataHandler dh = new DataHandlerImpl();
            try {
                URI inputFileURI = dh.get(dataEntry.getKey()).getDownloadUri();
                //URI outputFileURI = dh.getHttpFileRef(new File(dataEntry.getValue()), false);
                File fInputFile = new File(dataEntry.getKey());
                File fOutputFile = new File(dataEntry.getValue());

                //the fileBMGoals for the file to evaluate
                Collection<BenchmarkGoal> fileBMGoals = exp.getExperimentEvaluation()
                        .getEvaluatedFileBenchmarkGoals(inputFileURI);

                //call the workflow and extract the data from the workflow's result for every fileBMGoal
                for (BenchmarkGoal fileBMGoal : fileBMGoals) {
                    //executes the workflow, extracts the data, writes results into the objects
                    this.executeWorkflowAndExtractResults(fileBMGoal, fInputFile, fOutputFile, evalWorkflow);
                }
            } catch (FileNotFoundException e) {
                // TODO Auto-generated catch block
            }
        }
    }

    /**
     * This method executes a fully functional mockup of the following workflow:
     * 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 
     * This responds is then parsed given the XPath queries within AutoEvalServiceConfig and the BenchmarkGoal objects updated
     * TODO: Andrew: substitute with IF workflow 
     * @param bmGoal - the BM goal to evaluate
     * @param f1 localFile ref input file
     * @param f2 localFile ref output file
     */
    private void executeWorkflowAndExtractResults(BenchmarkGoal bmGoal, File f1, File f2, Workflow evalWorkflow) {
        /*      FIXME ANJ Clear this up.
              //execute the Droid->XCDLExtractor->Comparator workflow
              EvaluationExecutable evalExecutable = evalWorkflow.execute(f1, f2);
                  
              //persist the workflow's data
              bmGoal.setAutoEvaluationExecutable(evalExecutable);
                  
              //in the case the evaluation workflow was successful 
              if(evalExecutable.isExecutableInvoked()&&evalExecutable.isExecutionSuccess()){
                     
                 try {
        AutoEvaluationSettings autoEvalSettings = bmGoal.getAutoEvalSettings();
        EvaluationTestbedServiceTemplateImpl evalService = (EvaluationTestbedServiceTemplateImpl)autoEvalSettings.getEvaluationService();
               
        //fetch the XCDL comparison result
        String wfResult = evalExecutable.getXCDLsComparisonResult();
            
        //try to build a w3c Document structure 
        Document document = this.buildDOM(wfResult);
            
                 //AUSLAGERN IN EIGENE METHODE
        //Iterate over the results and extract metric and evaluation information according to the given XPath definitions
        NodeList nodes = evalService.getAllEvalResultsRootNodes(document);
        if((nodes!=null)&&(nodes.getLength()>0)){
           for(int i=0;i<nodes.getLength();i++){
              Node node = nodes.item(i);
                  
              //e.g. imageHeight
              String sPropertyName = evalService.getEvalResultName(node);
                  
              //mapping of TB BMGoalID to mappedPropertyName
              String mappedPropName = evalService.getMappedPropertyName(bmGoal.getID());
                  
              //check if the values belong to this BMGoal
              if(sPropertyName.equals(mappedPropName)){
                 //e.g. complete
                 String sStatus = evalService.getEvalResultCompStatus(node);
                 //check if the metric was evaluated properly
                 if(sStatus.equals(evalService.getStringForCompStatusSuccess())){
                    //e.g. 32
                    String sSrcVal = evalService.getEvalResultSrcValue(node);
                    //e.g. 32
                    String sTarVal = evalService.getEvalResultTarValue(node);
                    //e.g. <hammingDistance,0.000000>
                    Map<String,String> metric = evalService.getEvalResultMetricNamesAndValues(node);
                        
                    TBEvaluationTypes type = autoEvalSettings.autoValidate(metric);
                    if(type!=null){
                           
                       //now write the extracted auto Eval information back to the BMGoal
                       bmGoal.setSourceValue(sSrcVal);
                       bmGoal.setTargetValue(sTarVal);
                       bmGoal.setEvaluationValue(type.screenName());
                       bmGoal.setWasAutomaticallyEvaluated(true);
                    }
                 }
              }
           }
        }
        else{
           return;
        }
              //END AUSLAGERN IN EIGENE METHODE
                 } catch (Exception e) {
        return;
                 }
              }
              else{
                 //in this case autoEval workflow failed (e.g. due to non supported file type) - the user must evaluate by hand
              }
              */
    }

    /* (non-Javadoc)
     * @see eu.planets_project.tb.api.system.ServiceExecutionHandler#executeExperimentAndAutoEvalServices(eu.planets_project.tb.api.model.Experiment)
     */
    public void executeExperimentAndAutoEvalServices(Experiment exp) {
        //execute the migration/characterisation service
        this.executeExperiment(exp);
        //execute the evaluation services
        this.executeAutoEvalServices(exp);

    }

}