/* * 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: 1574 $ by $Author: glycoslave $ on $Date:: 2009-07-24 #$ */ package org.eurocarbdb.dataaccess.core; // stdlib imports import java.util.Set; import java.util.List; import java.util.HashSet; // 3rd party imports import org.hibernate.Criteria; import org.hibernate.criterion.Order; import org.hibernate.criterion.Criterion; import org.hibernate.criterion.DetachedCriteria; // eurocarb imports import org.eurocarbdb.sugar.Sugar; import org.eurocarbdb.dataaccess.HibernateEntityManager; import org.eurocarbdb.dataaccess.core.GlycanSequence; import org.eurocarbdb.dataaccess.core.seq.SubstructureQuery; import org.eurocarbdb.dataaccess.core.seq.SubstructureQueryCriterion; import org.eurocarbdb.dataaccess.indexes.IndexByContributedDate; import org.eurocarbdb.dataaccess.indexes.Index; // static imports import static java.util.Collections.emptyList; import static org.hibernate.criterion.Restrictions.eq; import static org.hibernate.criterion.Restrictions.not; import static org.hibernate.criterion.Restrictions.idEq; import static org.eurocarbdb.dataaccess.Eurocarb.getEntityManager; import static org.eurocarbdb.dataaccess.core.seq.SubstructureQuery.Option.*; /* class GlycanSequenceRelations *//************************************* *<p> * Collection of utility methods for finding {@link GlycanSequence}s that * are structurally related to each other. Most of these methods are * simple wrappers around the functionality of the {@link SubstructureQuery} * and {@link SubstructureQueryCriterion} classes. *</p> *<p> * Relational queries generally have 2 forms, one that returns a {@link List} * of {@link GlycanSequence}s ordered by a given {@link Index}, and a second * form of the same query that returns the underlying query as a * {@link DetachedCriteria}. *</p> * * @see GlycanSequence#getRelations() * @see SubstructureQuery * @see SubstructureQueryCriterion * @see org.eurocarbdb.action.core.SearchSubstructure * @see Criteria * @see DetachedCriteria * @see HibernateEntityManager#convertToCriteria * * @version $Rev: 1574 $ * @author mjh */ public class GlycanSequenceRelations { /** The {@link GlycanSequence} that any relations query * will be based on. */ private final GlycanSequence gs; private Index<GlycanSequence> index = new IndexByContributedDate<GlycanSequence>(); private GlycanSequenceRelations( GlycanSequence gs ) { this.gs = gs; } /** Factory contructor. */ public static GlycanSequenceRelations of( GlycanSequence gs ) { return new GlycanSequenceRelations( gs ); } /** * Returns a {@link Criterion} that can be used in arbitrary * {@link Criteria} queries to search for {@link GlycanSequence}s * that have this GlycanSequence as a substructure. */ public SubstructureQueryCriterion asCriterion() { return new SubstructureQueryCriterion( new SubstructureQuery( gs )); } /** * Returns a {@link List} of {@link GlycanSequence}s that are equivalent * to (ie: more definite than) this one, ordered by {@link #getIndex} * and limited to the given number of structures; see also * {@link #getEquivalentsCriteria}. */ public List<GlycanSequence> getEquivalents( int max_results ) { return getResults( getEquivalentsCriteria(), max_results ); } /** *<p> * Returns a {@link DetachedCriteria} instance that searches for * {@link GlycanSequence}s that are equivalent to this one; * "equivalent" in this context means structures that are more * <em>definite</em> (that is, fewer <em>indefinite</em>(unknown) * structural elements) versions of this sequence. This means * that if this sequence contains no indefinite elements, that * no sequences will be returned from search. *</p> * * @see HibernateEntityManager#convertToCriteria * @see GlycanSequence#isDefinite */ public DetachedCriteria getEquivalentsCriteria() { SubstructureQueryCriterion crit = this.asCriterion(); crit.getSubstructureQuery() .setOption( Must_Include_All_Non_Reducing_Terminii ) .setOption( Must_Include_Reducing_Terminus ) ; return getDetachedCriteria() .setComment( "GlycanSequenceRelations.getEquivalentsCriteria" ) .add( not( idEq( gs.getGlycanSequenceId() ) ) ) .add( eq( "residueCount", gs.getResidueCount() ) ) .add( crit ) ; } /** * Returns {@link GlycanSequence}s corresponding to * {@link #getLinkageIsomersCriteria}, ordered by {@link #getIndex} * and limited to the given number of structures. * * @param max_results * if negative, return all results, else return no more * than that number of results. */ public List<GlycanSequence> getLinkageIsomers( int max_results ) { return getResults( getLinkageIsomersCriteria(), max_results ); } /** * Returns a {@link DetachedCriteria} instance that searches for * {@link GlycanSequence}s that have the same connection of * Residues and ignoring Linkages (with no ordering). * * @see HibernateEntityManager#convertToCriteria */ public DetachedCriteria getLinkageIsomersCriteria() { SubstructureQueryCriterion crit = this.asCriterion(); crit.getSubstructureQuery() .setOption( Must_Include_All_Non_Reducing_Terminii ) .setOption( Must_Include_Reducing_Terminus ) .setOption( Ignore_Linkages ) ; return getDetachedCriteria() .setComment( "GlycanSequenceRelations.getLinkageIsomersCriteria" ) .add( not( idEq( gs.getGlycanSequenceId() ) ) ) .add( eq( "residueCount", gs.getResidueCount() ) ) .add( crit ) ; } /** * Returns {@link GlycanSequence}s that contain the GlycanSequence * given at construction as a substructure (hence "superstructure"), * ordered by {@link #getIndex} and limited to the given number of structures. * * @param max_results * if negative, return all results, else return no more * than that number of results. */ public List<GlycanSequence> getSuperstructures( int max_results ) { return getResults( getSuperstructuresCriteria(), max_results ); } /** * Returns a {@link DetachedCriteria} that finds {@link GlycanSequence}s * that contain the GlycanSequence given at construction as a * substructure (hence "superstructure"). * * @see HibernateEntityManager#convertToCriteria */ public DetachedCriteria getSuperstructuresCriteria() { return getDetachedCriteria() .setComment( "GlycanSequenceRelations.getSuperstructuresCriteria" ) .add( not( idEq( gs.getGlycanSequenceId() ) ) ) .add( this.asCriterion() ); } public List<GlycanSequence> getStereochemicalEquivalents( int max_results ) { return getResults( getStereochemicalEquivalentsCriteria(), max_results ); } /** * Returns a {@link DetachedCriteria} instance that searches for * {@link GlycanSequence}s that have the same stereochemistry, * disregarding {@link Substituent}s attached to {@link Monosaccharide}s, * so for instance, GlcNAc is stereochemically equivalent to Glc. * * @see org.eurocarbdb.sugar.Basetypes#getBasetypeId * @see HibernateEntityManager#convertToCriteria */ public DetachedCriteria getStereochemicalEquivalentsCriteria() { SubstructureQueryCriterion crit = this.asCriterion(); crit.getSubstructureQuery() .setOption( Must_Include_All_Non_Reducing_Terminii ) .setOption( Must_Include_Reducing_Terminus ) .setOption( Ignore_Monosac_Substituents ) ; return getDetachedCriteria() .setComment( "GlycanSequenceRelations.getStereochemicalEquivalentsCriteria" ) .add( not( idEq( gs.getGlycanSequenceId() ) ) ) .add( eq( "residueCount", gs.getResidueCount() ) ) .add( crit ) ; } /** * Returns the {@link Index} that will be used to order results returned * by search methods returning {@link List}s (but not those that return * {@link Criteria}). * * @see Index#apply(Criteria) * @see HibernateEntityManager#convertToCriteria */ public Index<GlycanSequence> getIndex() { return index; } /** * Sets the {@link Index} that will be used to order results returned * by search methods returning {@link List}s (but not those that return * {@link Criteria}). * * @see Index#apply(Criteria) * @see HibernateEntityManager#convertToCriteria */ public GlycanSequenceRelations setIndex( Index<GlycanSequence> i ) { this.index = i; return this; } //~~~~~~~~~~~~~~~~~~~ PRIVATE METHODS ~~~~~~~~~~~~~~~~~~~~~~~~~~~ /** Creates a {@link GlycanSequence} {@link DetachedCriteria}. */ final DetachedCriteria getDetachedCriteria() { // return getEntityManager().createQuery( GlycanSequence.class ); return DetachedCriteria.forClass( GlycanSequence.class ); } /** * Executes passed {@link DetachedCriteria}, returning given max results, * or all results if negative. * * @see HibernateEntityManager#convertToCriteria */ final List<GlycanSequence> getResults( DetachedCriteria dc, int max_results ) { Criteria c = HibernateEntityManager.convertToCriteria( dc ); if ( max_results > 0 ) c.setMaxResults( max_results ); getIndex().apply( c ); List<GlycanSequence> results = (List<GlycanSequence>) c.list(); if ( results == null ) return emptyList(); return results; } } // end class