org.eurocarbdb.action.core.SearchGlycanSequence.java Source code

Java tutorial

Introduction

Here is the source code for org.eurocarbdb.action.core.SearchGlycanSequence.java

Source

/*
*   EuroCarbDB, a framework for carbohydrate bioinformatics
*
*   Copyright (c) 2006-2009, Eurocarb project, or third-party contributors as
*   indicated by the @author tags or express copyright attribution
*   statements applied by the authors.  
*
*   This copyrighted material is made available to anyone wishing to use, modify,
*   copy, or redistribute it subject to the terms and conditions of the GNU
*   Lesser General Public License, as published by the Free Software Foundation.
*   A copy of this license accompanies this distribution in the file LICENSE.txt.
*
*   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.
*
*   Last commit: $Rev: 1573 $ by $Author: glycoslave $ on $Date:: 2009-07-24 #$  
*/

package org.eurocarbdb.action.core;

//  stdlib imports
import java.util.*;
import java.math.BigDecimal;

//  3rd party imports 
import org.apache.log4j.Logger;

import org.hibernate.Criteria;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.CriteriaSpecification;
import org.hibernate.HibernateException;
import org.hibernate.ScrollableResults;

import org.hibernate.criterion.Order;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.hibernate.criterion.ProjectionList;
import org.hibernate.criterion.Subqueries;

//  eurocarb imports
import org.eurocarbdb.dataaccess.core.*;
import org.eurocarbdb.dataaccess.core.seq.*;
import org.eurocarbdb.action.EurocarbAction;
import org.eurocarbdb.action.BrowseAction;
import org.eurocarbdb.dataaccess.EntityManager;
import org.eurocarbdb.dataaccess.HibernateEntityManager;
import org.eurocarbdb.dataaccess.indexes.*;

import org.eurocarbdb.sugar.Sugar;
import org.eurocarbdb.sugar.SugarSequence;
import org.eurocarbdb.application.glycanbuilder.Glycan;

import org.eurocarbdb.dataaccess.SavedGlycanSequenceSearch;
// import org.eurocarbdb.dataaccess.core.seq.SavedGlycanSubstructureSearch;

//  static imports
import static org.eurocarbdb.util.StringUtils.join;
import static org.eurocarbdb.dataaccess.Eurocarb.getEntityManager;
import static org.eurocarbdb.dataaccess.core.seq.SubstructureQuery.Option.*;

/*  class SearchGlycanSequence  *//****************************************
                                  *
                                  *   Finds a Set of {@link GlycanSequence} objects satisfying a given 
                                  *   set of query predicates. Matched sequences are wrapped together 
                                  *   with their query predicates in a {@link SavedGlycanSequenceSearch} object.
                                  *   
                                  *   @see SavedGlycanSequenceSearch
                                  *   @author mjh
                                  *   @author hirenj
                                  *   @version $Rev: 1573 $
                                  */
public class SearchGlycanSequence extends BrowseAction<GlycanSequence> {

    //~~~~~~~~~~~~~~~~~~~~~~ STATIC FIELDS ~~~~~~~~~~~~~~~~~~~~~~~~~~

    /** Logging handle. */
    static final Logger log = Logger.getLogger(SearchGlycanSequence.class);

    //~~~~~~~~~~~~~~~~~~~~~~~~~~ FIELDS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    private String taxonomyName = null;
    private String tissueName = null;
    private String diseaseName = null;
    private String perturbationName = null;

    private double lowMass = -1, highMass = -1, exactMass = -1, exactMassTolerance = -1;

    private boolean useAvgMass = false;
    private boolean useAvgMassGiven = false;

    private String sequenceGWS;

    // Position to search for the sequence
    private String sequencePosition = null;

    // Stores the input glycan ID that we wish to search for
    private int glycanId = -1;

    private boolean validated = false;

    private boolean isNewQuery = false;

    private List<SavedGlycanSequenceSearch> queryHistory = new java.util.ArrayList<SavedGlycanSequenceSearch>();

    private List<SavedGlycanSequenceSearch> additionalQueries = new java.util.ArrayList<SavedGlycanSequenceSearch>();

    private SavedGlycanSequenceSearch currentSearch;

    private int[] historicalQueriesToRun = {};

    private int[] historicalQueriesToRefine = {};

    /** The {@link List} of {@link Index}es supported by this Action. */
    public static final List<Index<GlycanSequence>> indexes = Arrays.asList(
            new IndexByContributedDate<GlycanSequence>(), new IndexByContributorName<GlycanSequence>(),
            new IndexByMostEvidence<GlycanSequence>(), new IndexByResidueCount<GlycanSequence>());

    //~~~~~~~~~~~~~~~~~~~~~~~~~ METHODS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    //~~~  criteria creation & access methods  ~~~~~

    public Criteria createCriteria() {
        DetachedCriteria crit = createSerializableCriteria();
        crit.setProjection(Projections.distinct(Projections.property("glycanSequenceId")));

        Criteria criteria = getEntityManager().createQuery(GlycanSequence.class);

        criteria.add(Subqueries.propertyIn("glycanSequenceId", crit));

        if (getIndex() != null) {
            getIndex().apply(criteria);
        }

        return criteria;
    }

    private DetachedCriteria createSerializableCriteria() {
        // create base criteria    
        log.debug("creating GlycanSequence criteria");

        DetachedCriteria criteria;

        criteria = DetachedCriteria.forClass(GlycanSequence.class);

        // create biological contexts criteria
        DetachedCriteria bc_criteria = null;
        DetachedCriteria tax_criteria = null;
        DetachedCriteria tissue_criteria = null;
        DetachedCriteria disease_criteria = null;
        DetachedCriteria perturbation_criteria = null;

        if (taxonomyName != null || tissueName != null || diseaseName != null || perturbationName != null) {
            isNewQuery = true;
            log.debug("creating Biological context criteria");
            bc_criteria = criteria.createCriteria("glycanContexts").createCriteria("biologicalContext", "bc");

            // add taxonomy criteria        
            if (taxonomyName != null) {
                log.debug("adding taxonomy query predicates for input string '" + taxonomyName + "'");
                tax_criteria = bc_criteria.createCriteria("taxonomy", "taxa")
                        .createCriteria("taxonomySupertypes", "supertax")
                        .add(Restrictions.ilike("taxon", taxonomyName, MatchMode.EXACT));
            }

            // add tissue criteria
            if (tissueName != null) {
                log.debug("adding tissue query predicates for input string '" + tissueName + "'");

                tissue_criteria = bc_criteria.createCriteria("tissueTaxonomy", "ttax")
                        .add(Restrictions.ilike("tissueTaxon", tissueName, MatchMode.EXACT));
            }

            // add disease criteria
            if (diseaseName != null) {
                log.debug("adding disease query criteria for input string '" + diseaseName + "'");

                disease_criteria = bc_criteria.createCriteria("diseaseContexts").createCriteria("disease", "dis")
                        .add(Restrictions.ilike("diseaseName", diseaseName, MatchMode.EXACT));
            }

            if (perturbationName != null) {
                log.debug("adding perturbation query criteria for input string '" + perturbationName + "'");

                perturbation_criteria = bc_criteria.createCriteria("perturbationContexts")
                        .createCriteria("perturbation", "per")
                        .add(Restrictions.ilike("perturbationName", perturbationName, MatchMode.EXACT));
            }

        }

        // add mass criteria
        boolean mass_query_is_given = false;
        boolean params_are_ok = false;

        if (exactMass > 0 && exactMassTolerance > 0) {
            isNewQuery = true;
            mass_query_is_given = true;
            lowMass = exactMass - exactMassTolerance;
            highMass = exactMass + exactMassTolerance;
            log.debug("adding predicates for exactMass=" + exactMass + " Da +/- " + exactMassTolerance + " Da (ie: "
                    + lowMass + "-" + highMass + " Da)");
            params_are_ok = true;
        } else if (lowMass > 0 && highMass > 0) {
            isNewQuery = true;
            mass_query_is_given = true;
            exactMass = -1;
            exactMassTolerance = -1;
            log.debug("adding predicates for mass range=(" + lowMass + ".." + highMass + " Da)");
            params_are_ok = true;
        }

        if (mass_query_is_given) {
            if (params_are_ok) {
                isNewQuery = true;
                String property = useAvgMass ? "massAverage" : "massMonoisotopic";
                criteria.add(Restrictions.between(property, new BigDecimal(lowMass), new BigDecimal(highMass)));
            } else {
                String msg = "Insufficient mass parameters given, either "
                        + "provide an exactMass + exactMassTolerence + useAvgMass preference, "
                        + "or provide a lowMass + highMass + useAvgMass preference";

                addActionError(msg);
                log.info(msg);
            }
        }

        Glycan glycan = null;

        if (sequenceGWS != null) {
            glycan = Glycan.fromString(sequenceGWS);
            glycan.removeReducingEndModification();
            if (glycan.isEmpty()) {
                glycan = null;
                sequenceGWS = null;
            }
        }

        if (glycan != null) {
            isNewQuery = true;

            // search structure in DB
            String glycoct = glycan.toGlycoCTCondensed();
            SugarSequence seq = new SugarSequence(glycoct);
            SubstructureQuery query = new SubstructureQuery(seq);

            if (sequencePosition != null) {
                if (sequencePosition.equals("Core") || sequencePosition.equals("Core + Terminii"))
                    query.setOption(Must_Include_Reducing_Terminus);

                if (sequencePosition.equals("Terminii") || sequencePosition.equals("Core + Terminii"))
                    query.setOption(Must_Include_All_Non_Reducing_Terminii);
            }

            criteria.add(query.getQueryCriterion());
        }

        if (this.additionalQueries.size() > 1) {
            isNewQuery = true;
        }

        for (SavedGlycanSequenceSearch oldQuery : this.additionalQueries) {

            DetachedCriteria oldCriteria = oldQuery.getQueryCriteria();

            criteria.add(Subqueries.propertyIn("glycanSequenceId", oldCriteria));

            oldCriteria.setProjection(Projections.distinct(Projections.property("glycanSequenceId")));

            this.currentSearch = oldQuery;
        }

        return criteria;
    }
    //~~~~~~~~~~~~  Query history methods ~~~~~~~~~~~~~~~~~~~~~~~~~~~

    public List<SavedGlycanSequenceSearch> getQueryHistory() {
        return queryHistory;
    }

    public void setQueryHistory(List<SavedGlycanSequenceSearch> history) {
        this.queryHistory = history;
    }

    public int[] getHistoricalQueriesToRefine() {
        return this.historicalQueriesToRefine;
    }

    public void setHistoricalQueriesToRefine(int[] ids) {
        this.historicalQueriesToRefine = ids;

        for (int index : ids) {
            if (this.getQueryHistory().size() > index) {
                this.additionalQueries.add(this.getQueryHistory().get(index));
            }
        }

    }

    public int[] getHistoricalQueriesToRun() {
        return this.historicalQueriesToRun;
    }

    public void setHistoricalQueriesToRun(int[] ids) {
        this.historicalQueriesToRun = ids;

        for (int index : ids) {
            if (this.getQueryHistory().size() > index) {
                this.additionalQueries.add(this.getQueryHistory().get(index));
            }
        }

    }

    public List<SavedGlycanSequenceSearch> getAdditionalQueries() {
        return this.additionalQueries;
    }

    public SavedGlycanSequenceSearch getCurrentSearch() {
        return this.currentSearch;
    }

    //~~~~~~~~~~~~  query predicate creation methods  ~~~~~~~~~~~~~~~

    public String getSequenceGWS() {
        return sequenceGWS;
    }

    public void setSequenceGWS(String str) {
        sequenceGWS = str;
    }

    public boolean isSearchCore() {
        return false;
    }

    public boolean isSearchTerminal() {
        return false;
    }

    //   taxonomy query predicates  //

    public void setTaxonomyName(String namestring) {
        if (namestring != null && namestring.trim().length() > 0)
            taxonomyName = namestring.trim();
        else
            taxonomyName = null;
    }

    public String getTaxonomyName() {
        return taxonomyName;
    }

    public void setTissueName(String namestring) {
        if (namestring != null && namestring.trim().length() > 0)
            tissueName = namestring.trim();
        else
            tissueName = null;
    }

    public String getTissueName() {
        return tissueName;
    }

    public void setDiseaseName(String namestring) {
        if (namestring != null && namestring.trim().length() > 0)
            diseaseName = namestring.trim();
        else
            diseaseName = null;
    }

    public String getDiseaseName() {
        return diseaseName;
    }

    /**
    *  Get accessor for perturbationName
    *  Perturbation query string accessor
    */
    public String getPerturbationName() {
        return this.perturbationName;
    }

    /**
    *  Set accessor for perturbationName
    *  @param perturbationName Data to set
    *  Perturbation query string accessor
    */
    public void setPerturbationName(String namestring) {
        if (namestring != null && namestring.trim().length() > 0)
            perturbationName = namestring.trim();
        else
            perturbationName = null;
    }

    //  mass query predicates  //

    public void setAvgMass(boolean b) {
        useAvgMass = b;
        useAvgMassGiven = true;
    }

    public boolean getAvgMass() {
        return useAvgMass;
    }

    public void setMonoisoMass(boolean b) {
        useAvgMass = !b;
        useAvgMassGiven = true;
    }

    public void setDiscreteMass(double mass) {
        exactMass = mass;
    }

    public double getDiscreteMass() {
        return exactMass;
    }

    public void setDiscreteMassTolerance(double tolerance) {
        exactMassTolerance = Math.abs(tolerance);
    }

    public double getDiscreteMassTolerance() {
        return exactMassTolerance;
    }

    public void setLowMass(double mass) {
        lowMass = mass;
    }

    public double getLowMass() {
        return lowMass;
    }

    public void setHighMass(double mass) {
        highMass = mass;
    }

    public double getHighMass() {
        return highMass;
    }

    /**
    *  Get accessor for sequencePosition
    *  Position to search for the sequence
    */
    public String getSequencePosition() {
        return this.sequencePosition;
    }

    /**
    *  Set accessor for sequencePosition
    *  @param sequencePosition Data to set
    *  Position to search for the sequence
    */
    public void setSequencePosition(String sequencePosition) {
        this.sequencePosition = sequencePosition;
    }

    /**
    *  Get accessor for glycanId
    *  Stores the input glycan ID that we wish to search for
    */
    public int getGlycanId() {
        return this.glycanId;
    }

    /**
    *  Set accessor for glycanId
    *  @param glycanId Data to set
    *  Stores the input glycan ID that we wish to search for
    */
    public void setGlycanId(int glycanId) {
        this.glycanId = glycanId;
    }

    public String[] getQueryDescription() {
        ArrayList<String> descriptions = new ArrayList<String>();
        if (getTaxonomyName() != null) {
            descriptions.add("taxonomy equals " + getTaxonomyName());
        }
        if (getTissueName() != null) {
            descriptions.add("tissue equals " + getTissueName());
        }
        if (getDiseaseName() != null) {
            descriptions.add("disease equals " + getDiseaseName());
        }
        if (getPerturbationName() != null) {
            descriptions.add("perturbation equals " + getPerturbationName());
        }
        if (exactMass > 0 || lowMass > 0) {
            String massType = useAvgMass ? "average" : "monoisotopic";
            if (exactMass > 0) {
                descriptions.add(massType + " mass equals " + exactMass + "  " + exactMassTolerance + " Da");
            } else {
                descriptions.add(massType + " between " + lowMass + " and " + highMass + " Da");
            }
        }

        if (getSequenceGWS() != null) {
            descriptions.add(
                    " substructure is found" + ((sequencePosition != null && !"Anywhere".equals(sequencePosition))
                            ? " at " + sequencePosition.toLowerCase()
                            : ""));
        }

        for (SavedGlycanSequenceSearch query : this.additionalQueries) {
            if (query.description != null) {
                descriptions.add(query.description);
            }
        }

        return descriptions.toArray(new String[0]);
    }

    //~~~~~~~~~~~~~~~~~ composition query options ~~~~~~~~~~~~~~~~~~~

    public void setExactComp(String s) {
        /* TODO */ }

    public void setMinComp(String s) {
        /* TODO */ }

    public void setMaxComp(String s) {
        /* TODO */ }

    //~~~~~~~~~~~~~~~~~~~~~~~~ indexing ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    /** Default index is the first index in the list of indexes */
    @Override
    public Index<GlycanSequence> getDefaultIndex() {
        return indexes.get(0);
    }

    @Override
    public List<Index<GlycanSequence>> getIndexes() {
        return indexes;
    }

    public final Class<GlycanSequence> getIndexableType() {
        return GlycanSequence.class;
    }

    //~~~~~~~~~~~~~~~~~~~~~~~ validation ~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    public void validate() {
        //  return unless we're processing input params
        if (getParameters() == null || getParameters().size() == 0)
            return;

        //  only perform validation once, per request
        if (validated)
            return;

        validated = true;
    }

    public List<GlycanSequence> getQueryResults() {
        Criteria query = createCriteria();

        log.info("Performing query: " + query.toString());
        setMessage(query.toString());

        ScrollableResults scroll = null;
        try {

            scroll = query.scroll();

            scroll.last();
            setTotalResults(scroll.getRowNumber() + 1);

            int count = getTotalResults();

            int first = getOffset();
            int max = getMaxResults();

            if (first > 0) {
                query.setFirstResult(first);
            }

            if (max > 0) {
                query.setMaxResults(max);
            }

            List<GlycanSequence> ret = (List<GlycanSequence>) query.list();

            log.debug("query executed ok, results count=" + ret.size());
            return ret;
        } catch (HibernateException e) {
            log.warn("Caught " + e.getClass().getName() + " performing query:", e);

            return Collections.emptyList();
        } finally {
            if (scroll != null)
                scroll.close();
        }
    }

    /*  execute  *///************************************************
    @SuppressWarnings("unchecked")
    public String execute() {
        if (getParameters() == null || getParameters().size() == 0) {
            log.debug("no input params given, returning 'input' view");
            return "input";
        }

        if (getParameters().get("historicalQueriesToRefine") != null) {
            log.debug("refining an existing query, returning 'input' view");
            return "input";
        }

        if (glycanId > 0) {
            return "show";
        }

        validate();
        setResults(getQueryResults());
        if (isNewQuery) {
            SavedGlycanSequenceSearch savedSearch = new SavedGlycanSequenceSearch();
            savedSearch.queryCriteria = createSerializableCriteria();
            savedSearch.description = join(" AND ", getQueryDescription());
            savedSearch.resultCount = getTotalResults();
            savedSearch.sequence = sequenceGWS;

            List<SavedGlycanSequenceSearch> history = this.getQueryHistory();
            history.add(savedSearch);
            this.setQueryHistory(history);
            this.currentSearch = savedSearch;
        }
        return hasActionErrors() ? "input" : "success";
    }

} // end class