net.sourceforge.seqware.webservice.resources.tables.FileChildWorkflowRunsResource.java Source code

Java tutorial

Introduction

Here is the source code for net.sourceforge.seqware.webservice.resources.tables.FileChildWorkflowRunsResource.java

Source

/*
 * Copyright (C) 2011 SeqWare
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package net.sourceforge.seqware.webservice.resources.tables;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import net.sf.beanlib.CollectionPropertyName;
import net.sf.beanlib.hibernate3.Hibernate3DtoCopier;
import net.sourceforge.seqware.common.business.FileService;
import net.sourceforge.seqware.common.business.WorkflowRunService;
import net.sourceforge.seqware.common.factory.BeanFactory;
import net.sourceforge.seqware.common.factory.DBAccess;
import net.sourceforge.seqware.common.metadata.MetadataDB;
import net.sourceforge.seqware.common.model.File;
import net.sourceforge.seqware.common.model.IUS;
import net.sourceforge.seqware.common.model.Lane;
import net.sourceforge.seqware.common.model.Processing;
import net.sourceforge.seqware.common.model.WorkflowRun;
import net.sourceforge.seqware.common.model.lists.WorkflowRunList;
import net.sourceforge.seqware.common.model.lists.WorkflowRunList2;
import net.sourceforge.seqware.common.util.Log;
import net.sourceforge.seqware.common.util.xmltools.JaxbObject;
import net.sourceforge.seqware.common.util.xmltools.XmlTools;
import static net.sourceforge.seqware.webservice.resources.BasicResource.testIfNull;

import org.apache.commons.dbutils.DbUtils;
import org.apache.commons.dbutils.ResultSetHandler;
import org.apache.commons.lang.ArrayUtils;
import org.restlet.data.Status;
import org.restlet.resource.Get;
import org.restlet.resource.ResourceException;
import org.w3c.dom.Document;

/**
 * This resource will pull back the workflow runs that are generated from a
 * particular file.
 *
 * In order: a) Workflow runs found via processing, processing_relationship,
 * workflow_run b) Workflow runs found via the IUS, ius_workflow_runs c)
 * Workflow runs found via the lane, lane_workflow_runs
 *
 * @author dyuen
 * @version $Id: $Id
 */
public class FileChildWorkflowRunsResource extends DatabaseResource {
    /**
     * A direct search uses the workflow_run_input_files table rather than 
     * attempting a search via the ius_workflow_run and lane_workflow_run and processing hierarchy
     */
    public static final String DIRECT_SEARCH = "DIRECT_SEARCH";

    /**
     * <p>Constructor for FileChildWorkflowRunsResource.</p>
     */
    public FileChildWorkflowRunsResource() {
        super("file");
    }

    /**
     * <p>getXml.</p>
     * @throws java.sql.SQLException
     */
    @Get
    public void getXml() throws SQLException {
        authenticate();
        final Hibernate3DtoCopier copier = new Hibernate3DtoCopier();
        JaxbObject jaxbTool;
        Log.debug("Dealing with FileChildWorkflowRunsResource");

        if (queryValues.keySet().contains(DIRECT_SEARCH)
                && queryValues.get(DIRECT_SEARCH).equalsIgnoreCase("true")) {
            handleDirectGetXML();
            return;
        }

        FileService fs = BeanFactory.getFileServiceBean();
        Set<File> files = new HashSet<>();
        SEARCH_TYPE searchType = SEARCH_TYPE.CHILDREN_VIA_PROCESSING_RELATIONSHIP;
        Log.debug("File service started");
        for (String key : queryValues.keySet()) {
            Log.debug("key: " + key + " -> " + queryValues.get(key));
            if (key.equals("files")) {
                String value = queryValues.get(key);
                String[] filesSWIDs = value.split(",");
                for (String swid : filesSWIDs) {
                    File findByID = (File) testIfNull(fs.findBySWAccession(Integer.valueOf(swid)));
                    files.add(findByID);
                }
            }
            if (key.equals("search")) {
                String value = queryValues.get(key);
                try {
                    searchType = SEARCH_TYPE.valueOf(value);
                } catch (IllegalArgumentException e) {
                    throw new ResourceException(Status.CLIENT_ERROR_NOT_FOUND, "Object cannot be found");
                }
            }
        }
        Log.debug("Working with " + files.size() + " files and doing a search of type: " + searchType.toString());

        // these variables will be used to return information
        jaxbTool = new JaxbObject<>();
        WorkflowRunList2 eList = new WorkflowRunList2();
        eList.setList(new ArrayList());
        Log.debug("JaxbObjects started");

        assert eList.getList().isEmpty();
        // the logic here is, we consider first workflow_run children found via the children of the processing
        // if that is empty, then we consider workflow_run found via the IUS (ius_workflow_run table)
        // if that is empty, then we consider workflow_run found via the lane (lane_workflow_run table)
        if (searchType == SEARCH_TYPE.CHILDREN_VIA_PROCESSING_RELATIONSHIP) {
            eList = handleWorkflowRunsViaChild(files, copier);
        } else if (searchType == SEARCH_TYPE.CHILDREN_VIA_IUS_WORKFLOW_RUN) {
            eList = handleWorkflowRunsViaIUS(files, copier);
        } else if (searchType == SEARCH_TYPE.CHILDREN_VIA_LANE_WORKFLOW_RUN) {
            eList = handleWorkflowRunsViaLane(files, copier);
        }
        final Document line = XmlTools.marshalToDocument(jaxbTool, eList);
        getResponse().setEntity(XmlTools.getRepresentation(line));
        getResponse().setStatus(Status.SUCCESS_CREATED);
    }

    protected WorkflowRunList2 handleWorkflowRunsViaChild(final Set<File> files, final Hibernate3DtoCopier copier) {
        final WorkflowRunList2 results = new WorkflowRunList2();
        for (File file : files) {
            //1) check if we have children in the processing tree that are relevant
            for (Processing p : file.getProcessings()) {
                for (Processing c : p.getChildren()) {
                    if (c.getWorkflowRun() == null) {
                        continue;
                    }
                    WorkflowRun dto = copier.hibernate2dto(WorkflowRun.class, c.getWorkflowRun());
                    results.add(dto);
                }
            }
        }
        if (results.getList().size() > 0) {
            Log.debug("Found " + results.getList().size() + " workflow runs via Processing children");
        } else {
            Log.debug("Did not find any workflow runs via Processing children");
        }
        return results;
    }

    protected WorkflowRunList2 handleWorkflowRunsViaIUS(Set<File> files, final Hibernate3DtoCopier copier) {
        WorkflowRunList2 result = new WorkflowRunList2();
        Set<WorkflowRun> parentWorkflowRuns = new HashSet<>();
        for (File file : files) {
            //2) check if we have children in the ius_workflow_runs that are relevant
            for (Processing p : file.getProcessings()) {
                WorkflowRun parentRun = p.getWorkflowRun();
                if (parentRun == null) {
                    parentRun = p.getWorkflowRunByAncestorWorkflowRunId();
                }
                if (parentRun == null) {
                    continue;
                }
                parentWorkflowRuns.add(parentRun);
                for (IUS ius : parentRun.getIus()) {
                    for (WorkflowRun anyRun : ius.getWorkflowRuns()) {
                        isWorkflowRunAttached(parentWorkflowRuns, anyRun);
                        WorkflowRun dto = copier.hibernate2dto(WorkflowRun.class, anyRun);
                        result.add(dto);
                    }
                }
            }
        }
        if (result.getList().size() > 0) {
            Log.debug("Found " + result.getList().size() + " workflow runs via ius");
        } else {
            Log.debug("Did not find any workflow runs via ius");
        }
        return result;
    }

    protected WorkflowRunList2 handleWorkflowRunsViaLane(final Set<File> files, final Hibernate3DtoCopier copier) {
        final WorkflowRunList2 result = new WorkflowRunList2();
        Set<WorkflowRun> parentWorkflowRuns = new HashSet<>();
        for (File file : files) {
            //3) check if we have children in the lane_workflow_runs that are relevant
            for (Processing p : file.getProcessings()) {
                WorkflowRun parentRun = p.getWorkflowRun();
                if (parentRun == null) {
                    parentRun = p.getWorkflowRunByAncestorWorkflowRunId();
                }
                if (parentRun == null) {
                    continue;
                }
                parentWorkflowRuns.add(parentRun);
                for (Lane lane : parentRun.getLanes()) {
                    for (WorkflowRun anyRun : lane.getWorkflowRuns()) {
                        if (isWorkflowRunAttached(parentWorkflowRuns, anyRun))
                            continue;
                        final WorkflowRun dto = copier.hibernate2dto(WorkflowRun.class, anyRun);
                        result.add(dto);
                    }
                }
            }
        }
        if (result.getList().size() > 0) {
            Log.debug("Found " + result.getList().size() + " workflow runs via lane");
        } else {
            Log.debug("Did not find any workflow runs via lane");
        }
        return result;
    }

    /**
     * Disallows a workflow run if it should not be considered since it is properly attached to the processing hierarchy
     * @param parentWorkflowRuns
     * @param anyRun
     * @return 
     */
    private boolean isWorkflowRunAttached(Set<WorkflowRun> parentWorkflowRuns, WorkflowRun anyRun) {
        if (parentWorkflowRuns.contains(anyRun)) {
            Log.debug("Disallowed " + anyRun.getSwAccession()
                    + " because we have seen it on the same level as a file");
            return true;
        }
        // check that this workflow run has not actually been linked up into the Processing hierarchy
        if (anyRun.getProcessings() != null && anyRun.getProcessings().size() > 0) {
            Log.debug("Disallowed " + anyRun.getSwAccession()
                    + " because it is already attached via Processing.workflow_run_id");
            return true;
        }
        if (anyRun.getOffspringProcessings() != null && anyRun.getOffspringProcessings().size() > 0) {
            Log.debug("Disallowed " + anyRun.getSwAccession()
                    + " because it is already attached via Processing.ancestor_workflow_run_id");
            return true;
        }
        return false;
    }

    /**
     * Use SQL to directly retrieve relevant workflows runs (defined as any workflow runs that 
     * include one or more files in the set we were given)
     * @param files
     * @param interestingWorkflows
     * @return
     * @throws SQLException 
     */
    protected static WorkflowRunList2 directRetrieveWorkflowRuns(List<Integer> files,
            List<Integer> interestingWorkflows) throws SQLException {
        final Hibernate3DtoCopier copier = new Hibernate3DtoCopier();
        final WorkflowRunList2 runs = new WorkflowRunList2();
        runs.setList(new ArrayList());
        if (files.size() > 0) {

            ResultSet rs = null;
            MetadataDB mdb = null;
            try {
                WorkflowRunService ss = BeanFactory.getWorkflowRunServiceBean();
                StringBuilder query = new StringBuilder();
                query.append("select distinct r.sw_accession from workflow_run r, workflow w, ");
                query.append("workflow_run_input_files rf, file f WHERE r.workflow_run_id = rf.workflow_run_id "
                        + "AND rf.file_id = f.file_id " + "AND w.workflow_id = r.workflow_id " + "AND (");
                // handle file accessions
                for (int i = 0; i < files.size() - 1; i++) {
                    Integer fInt = files.get(i);
                    query.append(" f.sw_accession = ").append(fInt).append(" OR");
                }
                Integer fInt = files.get(files.size() - 1);
                query.append(" f.sw_accession = ").append(fInt).append(")");
                // handle interesting workflow accessions
                if (interestingWorkflows.size() > 0) {
                    query.append(" AND (");
                    for (int i = 0; i < interestingWorkflows.size() - 1; i++) {
                        Integer wInt = interestingWorkflows.get(i);
                        query.append(" w.sw_accession = ").append(wInt).append(" OR");
                    }
                    Integer wInt = interestingWorkflows.get(interestingWorkflows.size() - 1);
                    query.append(" w.sw_accession = ").append(wInt).append(")");
                }

                query.append(" ORDER BY sw_accession");

                Log.info("Executing query: " + query);
                mdb = DBAccess.get();

                List<Integer> workflowSWIDs = mdb.executeQuery(query.toString(),
                        new ResultSetHandler<List<Integer>>() {
                            @Override
                            public List<Integer> handle(ResultSet rs) throws SQLException {
                                List<Integer> ids = new ArrayList<>();
                                while (rs.next()) {
                                    ids.add(rs.getInt("sw_accession"));
                                }
                                return ids;
                            }
                        });

                for (int workflowSWID : workflowSWIDs) {
                    WorkflowRun workflowRun = (WorkflowRun) testIfNull(ss.findBySWAccession(workflowSWID));
                    CollectionPropertyName<WorkflowRun>[] createCollectionPropertyNames = CollectionPropertyName
                            .createCollectionPropertyNames(WorkflowRun.class,
                                    new String[] { "inputFileAccessions" });
                    WorkflowRun dto = copier.hibernate2dto(WorkflowRun.class, workflowRun,
                            ArrayUtils.EMPTY_CLASS_ARRAY, createCollectionPropertyNames);
                    runs.add(dto);
                }
            } finally {
                if (mdb != null) {
                    DbUtils.closeQuietly(mdb.getDb(), mdb.getSql(), rs);
                }
                DBAccess.close();
            }
        }
        return runs;
    }

    private void handleDirectGetXML() throws SQLException, NumberFormatException {
        JaxbObject jaxbTool;
        Log.info("Using direct search");
        List<Integer> files = new ArrayList<>();
        for (String key : queryValues.keySet()) {
            Log.debug("key: " + key + " -> " + queryValues.get(key));
            if (key.equals("files")) {
                String value = queryValues.get(key);
                String[] filesSWIDs = value.split(",");
                for (String swid : filesSWIDs) {
                    files.add(Integer.valueOf(swid));
                }
            }
        }
        Log.debug("Working with " + files.size() + " files");
        WorkflowRunList2 runs = directRetrieveWorkflowRuns(files, new ArrayList<Integer>());
        // these variables will be used to return information
        jaxbTool = new JaxbObject<>();
        Log.debug("JaxbObjects started");
        assert runs.getList().isEmpty();
        final Document line = XmlTools.marshalToDocument(jaxbTool, runs);
        getResponse().setEntity(XmlTools.getRepresentation(line));
        getResponse().setStatus(Status.SUCCESS_CREATED);
    }

    public enum SEARCH_TYPE {
        CHILDREN_VIA_PROCESSING_RELATIONSHIP, CHILDREN_VIA_IUS_WORKFLOW_RUN, CHILDREN_VIA_LANE_WORKFLOW_RUN
    }
}