001/*
002 *                    BioJava development code
003 *
004 * This code may be freely distributed and modified under the
005 * terms of the GNU Lesser General Public Licence.  This should
006 * be distributed with the code.  If you do not have a copy,
007 * see:
008 *
009 *      http://www.gnu.org/copyleft/lesser.html
010 *
011 * Copyright for this code is held jointly by the individual
012 * authors.  These should be listed in @author doc comments.
013 *
014 * For more information on the BioJava project and its aims,
015 * or to join the biojava-l mailing list, visit the home page
016 * at:
017 *
018 *      http://www.biojava.org/
019 *
020 */
021
022package org.biojavax.bio.db.biosql;
023import java.lang.reflect.Method;
024
025import org.biojava.bio.symbol.Alphabet;
026import org.biojava.bio.symbol.FiniteAlphabet;
027import org.biojava.bio.symbol.SymbolList;
028import org.biojavax.CrossRef;
029import org.biojavax.CrossReferenceResolver;
030import org.biojavax.Namespace;
031import org.biojavax.RichObjectFactory;
032import org.biojavax.SimpleNamespace;
033import org.biojavax.bio.BioEntry;
034import org.biojavax.bio.seq.InfinitelyAmbiguousSymbolList;
035import org.biojavax.bio.seq.RichSequence;
036
037/**
038 * A simple implementation of CrossReferenceResolver
039 * @author Richard Holland
040 * @author Mark Schreiber
041 * @author David Scott
042 * @since 1.5
043 */
044public class BioSQLCrossReferenceResolver implements CrossReferenceResolver {
045    
046    private Object session;
047    private Method createQuery;
048    private Method setParameter;
049    private Method uniqueResult;
050    
051    /**
052     * Requires a Hibernate session to work correctly. The session parameter
053     * is a Hibernate Session object and must not be null. It is this session
054     * that database objects will be retrieved from/persisted to.
055     * @see <a href="http://www.hibernate.org/hib_docs/v3/api/org/hibernate/Session.html"> org.hibernate.Session</a>
056     */
057    public BioSQLCrossReferenceResolver(Object session) {
058        try {
059            // Lazy load the Session class from Hibernate.
060            Class hibernateSession = session.getClass();
061            Class realHibernateSession = Class.forName("org.hibernate.Session");
062            // Test to see if our parameter is really a Session
063            if (!realHibernateSession.isAssignableFrom(hibernateSession))
064                throw new IllegalArgumentException("Parameter must be a org.hibernate.Session object");
065            this.session = session;
066            // Lookup the createQuery method
067            this.createQuery = hibernateSession.getMethod("createQuery", new Class[]{String.class});
068            // Lazy load the Query class from Hibernate.
069            Class hibernateQuery = Class.forName("org.hibernate.Query");
070            // Lookup the setParameter and uniqueQuery methods
071            this.setParameter = hibernateQuery.getMethod("setParameter", new Class[]{int.class,Object.class});
072            this.uniqueResult = hibernateQuery.getMethod("uniqueResult", new Class[]{});
073        } catch (ClassNotFoundException e) {
074            throw new RuntimeException(e);
075        } catch (NoSuchMethodException e) {
076            throw new RuntimeException(e);
077        }
078    }
079    
080    /**
081     * {@inheritDoc}
082     */
083    public SymbolList getRemoteSymbolList(CrossRef cr, Alphabet a) {
084        BioEntry be = this.getRemoteBioEntry(cr);
085        if (be instanceof RichSequence) return (RichSequence)be;
086        // If we get here we didn't find it, so we must create a dummy sequence instead
087        if (!(a instanceof FiniteAlphabet)) throw new IllegalArgumentException("Cannot construct dummy symbol list for a non-finite alphabet");
088        return new InfinitelyAmbiguousSymbolList((FiniteAlphabet)a);
089    }
090    
091    /**
092     * {@inheritDoc}
093     */
094    public BioEntry getRemoteBioEntry(CrossRef cr){
095        Namespace ns = (Namespace)RichObjectFactory.getObject(SimpleNamespace.class, new Object[]{cr.getDbname()});
096        try {
097            // Build the query object
098            String queryText = "from BioEntry where namespace = ? and accession = ? and version = ?";
099            Object query = this.createQuery.invoke(this.session, new Object[]{queryText});
100            // Set the parameters
101            query = this.setParameter.invoke(query, new Object[]{new Integer(0), ns}); 
102            query = this.setParameter.invoke(query, new Object[]{new Integer(1), cr.getAccession()}); 
103            query = this.setParameter.invoke(query, new Object[]{new Integer(2), new Integer(cr.getVersion())}); 
104            // Get the results
105            Object result = this.uniqueResult.invoke(query, (Object[])null);
106            // Return the found object, if found - null if not.
107            return (BioEntry)result;
108        } catch (Exception e) {
109            // Throw the exception with our nice message
110            throw new RuntimeException("Error while trying to locate remote cross reference "+cr,e);
111        }
112    }
113}
114