001/* 002 * BioSQLRichSequenceHandler.java 003 * 004 * Created on March 7, 2006, 3:12 PM 005 */ 006 007package org.biojavax.bio.db.biosql; 008 009import java.lang.reflect.Method; 010import java.util.ArrayList; 011import java.util.Iterator; 012import java.util.List; 013 014import org.biojava.bio.BioError; 015import org.biojava.bio.BioException; 016import org.biojava.bio.symbol.Alphabet; 017import org.biojava.bio.symbol.Edit; 018import org.biojava.bio.symbol.IllegalAlphabetException; 019import org.biojava.bio.symbol.IllegalSymbolException; 020import org.biojava.bio.symbol.SimpleSymbolList; 021import org.biojava.bio.symbol.Symbol; 022import org.biojava.bio.symbol.SymbolList; 023import org.biojava.utils.ChangeVetoException; 024import org.biojavax.bio.seq.DummyRichSequenceHandler; 025import org.biojavax.bio.seq.RichSequence; 026import org.biojavax.bio.seq.SimpleRichSequence; 027import org.biojavax.bio.seq.RichLocation.Tools; 028 029/** 030 * A handler which loads sequence data from a BioSQL database, caching it where possible. 031 * Note that this data is read-only. If you want to modify it permanently, you must use 032 * BioSQLRichSequenceDB.getRichSequence() to convert the original sequence into a proper 033 * SimpleRichSequence. 034 * @author Richard Holland 035 * @author David Scott 036 * @since 1.5 037 */ 038public class BioSQLRichSequenceHandler extends DummyRichSequenceHandler { 039 040 // the Hibernate session. 041 private Object session; 042 private Method createQuery; 043 private Method setParameter; 044 private Method uniqueResult; 045 046 /** 047 * Requires a Hibernate session to work correctly. The session parameter 048 * is a Hibernate Session object and must not be null. It is this session 049 * that database objects will be retrieved from/persisted to. 050 * @see <a href="http://www.hibernate.org/hib_docs/v3/api/org/hibernate/Session.html"> org.hibernate.Session</a> 051 */ 052 public BioSQLRichSequenceHandler(Object session) { 053 super(); 054 try { 055 // Lazy load the Session class from Hibernate. 056 Class hibernateSession = session.getClass(); 057 Class realHibernateSession = Class.forName("org.hibernate.Session"); 058 // Test to see if our parameter is really a Session 059 if (!realHibernateSession.isAssignableFrom(hibernateSession)) 060 throw new IllegalArgumentException("Parameter must be a org.hibernate.Session object"); 061 this.session = session; 062 // Lookup the createQuery method 063 this.createQuery = hibernateSession.getMethod("createQuery", new Class[]{String.class}); 064 // Lazy load the Query class from Hibernate. 065 Class hibernateQuery = Class.forName("org.hibernate.Query"); 066 // Lookup the setParameter and uniqueQuery methods 067 this.setParameter = hibernateQuery.getMethod("setParameter", new Class[]{int.class,Object.class}); 068 this.uniqueResult = hibernateQuery.getMethod("uniqueResult", new Class[]{}); 069 } catch (ClassNotFoundException e) { 070 throw new RuntimeException(e); 071 } catch (NoSuchMethodException e) { 072 throw new RuntimeException(e); 073 } 074 } 075 076 /** 077 * {@inheritDoc} 078 */ 079 public void edit(RichSequence seq, Edit edit) throws IndexOutOfBoundsException, IllegalAlphabetException, ChangeVetoException { 080 if (seq instanceof SimpleRichSequence) super.edit(seq,edit); 081 throw new ChangeVetoException("Cannot modify this sequence. Convert to a SimpleRichSequence first."); 082 } 083 084 /** 085 * {@inheritDoc} 086 */ 087 public Symbol symbolAt(RichSequence seq, int index) throws IndexOutOfBoundsException { 088 if (seq instanceof SimpleRichSequence) return super.symbolAt(seq,index); 089 return this.subList(seq, index, index).symbolAt(1); 090 } 091 092 /** 093 * {@inheritDoc} 094 */ 095 public List toList(RichSequence seq) { 096 if (seq instanceof SimpleRichSequence) return super.toList(seq); 097 if (seq.length()==0) return new ArrayList(); // empty list for empty seq 098 else return this.subList(seq,1,seq.length()).toList(); 099 } 100 101 /** 102 * {@inheritDoc} 103 */ 104 public String subStr(RichSequence seq, int start, int end) throws IndexOutOfBoundsException { 105 if (seq instanceof SimpleRichSequence) return super.subStr(seq,start,end); 106 if (seq.length()==0) return ""; // empty seq 107 else if (seq.getCircular()) { 108 StringBuffer result = new StringBuffer(); // place to store the resulting substring 109 int[] modLocation = Tools.modulateCircularLocation(start,end,seq.length()); 110 int modStart = modLocation[0]; 111 int modEnd = modLocation[1]; 112 int modLength = (modEnd - modStart)+1; 113 int seqLength = seq.length(); 114 if (modStart==0) modStart = seqLength; 115 if (modEnd==0) modEnd = seqLength; 116 if (modEnd>seqLength) { 117 // add it in chunks 118 int remaining = modLength; 119 int chunkSize = (seqLength-modStart)+1; 120 // add modStart -> seqLength 121 result.append(this.seqSubString(seq, modStart, seqLength)); 122 remaining -= chunkSize; 123 // repeat add seqLength 124 while (remaining > seqLength) { 125 chunkSize = seqLength; 126 // add 0 -> seqLength 127 result.append(this.seqSubString(seq, 1, seqLength)); 128 remaining -= chunkSize; 129 } 130 // add 0 -> remaining 131 chunkSize = remaining; 132 result.append(this.seqSubString(seq, 1, chunkSize)); 133 } else { 134 // add modStart->modEnd 135 result.append(this.seqSubString(seq, modStart, modEnd)); 136 } 137 return result.toString(); 138 } else { 139 return this.seqSubString(seq, start, end); 140 } 141 } 142 143 /** 144 * {@inheritDoc} 145 */ 146 public SymbolList subList(RichSequence seq, int start, int end) throws IndexOutOfBoundsException { 147 if (seq instanceof SimpleRichSequence) return super.subList(seq,start,end); 148 return this.convertToSymbolList(this.subStr(seq,start,end),seq.getAlphabet()); 149 } 150 151 /** 152 * {@inheritDoc} 153 */ 154 public String seqString(RichSequence seq) { 155 if (seq instanceof SimpleRichSequence) return super.seqString(seq); 156 // load whole stringSequence property from Sequence 157 try { 158 // Build the query object 159 String queryText = "select s.stringSequence from Sequence as s where s.namespace = ? and s.name = ?"; 160 Object query = this.createQuery.invoke(this.session, new Object[]{queryText}); 161 // Set the parameters 162 query = this.setParameter.invoke(query, new Object[]{new Integer(0), seq.getNamespace()}); 163 query = this.setParameter.invoke(query, new Object[]{new Integer(1), seq.getName()}); 164 // Get the results 165 Object result = this.uniqueResult.invoke(query,(Object[]) null); 166 // Return the found object, if found - null if not. 167 return (String)result; 168 } catch (Exception e) { 169 // Throw the exception with our nice message 170 throw new RuntimeException("Error while trying to locate full sequence "+seq,e); 171 } 172 } 173 174 private String seqSubString(RichSequence seq, int start, int end) { 175 // load whole stringSequence property from Sequence 176 try { 177 // Build the query object 178 String queryText = "select substring(s.stringSequence,?,?) from Sequence as s where s.namespace = ? and s.name = ?"; 179 Object query = this.createQuery.invoke(this.session, new Object[]{queryText}); 180 // Set the parameters 181 query = this.setParameter.invoke(query, new Object[]{new Integer(0), new Integer(start)}); 182 query = this.setParameter.invoke(query, new Object[]{new Integer(1), new Integer((end-start)+1)}); 183 query = this.setParameter.invoke(query, new Object[]{new Integer(2), seq.getNamespace()}); 184 query = this.setParameter.invoke(query, new Object[]{new Integer(3), seq.getName()}); 185 // Get the results 186 Object result = this.uniqueResult.invoke(query,(Object[]) null); 187 // Return the found object, if found - null if not. 188 return (String)result; 189 } catch (Exception e) { 190 // Throw the exception with our nice message 191 throw new RuntimeException("Error while trying to locate full sequence "+seq,e); 192 } 193 } 194 195 /** 196 * {@inheritDoc} 197 */ 198 public Iterator iterator(RichSequence seq) { 199 if (seq instanceof SimpleRichSequence) return super.iterator(seq); 200 return this.toList(seq).iterator(); 201 } 202 203 private SymbolList convertToSymbolList(String seq, Alphabet alpha) { 204 try { 205 return new SimpleSymbolList(alpha.getTokenization("token"), seq); 206 } catch (IllegalSymbolException e) { 207 throw new BioError("Found bad symbols in sequence string!",e); 208 } catch (BioException e) { 209 throw new BioError("Found general exception in sequence string!",e); 210 } 211 } 212}