001    /**
002     * Copyright (C) 2010 The Roslin Institute <contact andy.law@roslin.ed.ac.uk>
003     *
004     * This file is part of the Ensembl Java API demonstration project developed by the
005     * Bioinformatics Group at The Roslin Institute, The Royal (Dick) School of
006     * Veterinary Studies, University of Edinburgh.
007     *
008     * This is free software: you can redistribute it and/or modify
009     * it under the terms of the GNU General Public License (version 3) as published by
010     * the Free Software Foundation.
011     *
012     * This software is distributed in the hope that it will be useful,
013     * but WITHOUT ANY WARRANTY; without even the implied warranty of
014     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
015     * GNU General Public License for more details.
016     *
017     * You should have received a copy of the GNU General Public License
018     * in this software distribution. If not, see <http://www.gnu.org/licenses/gpl-3.0.html/>.
019     */
020    
021    package uk.ac.roslin.ensembl.dao.database.coreaccess;
022    
023    import uk.ac.roslin.ensembl.datasourceaware.core.DACoordinateSystem;
024    import java.util.ArrayList;
025    import java.util.List;
026    import java.util.HashMap;
027    import org.apache.ibatis.session.SqlSession;
028    import uk.ac.roslin.ensembl.biojava3.EnsemblDNASequenceReader;
029    import uk.ac.roslin.ensembl.dao.coreaccess.DNASequenceDAO;
030    import uk.ac.roslin.ensembl.datasourceaware.core.DAAssembledDNASequence;
031    import uk.ac.roslin.ensembl.datasourceaware.core.DAChromosome;
032    import uk.ac.roslin.ensembl.datasourceaware.core.DADNASequence;
033    import uk.ac.roslin.ensembl.mapper.handler.DBResultHandler;
034    import uk.ac.roslin.ensembl.dao.database.factory.DBDAOCollectionCoreFactory;
035    import uk.ac.roslin.ensembl.dao.database.factory.DBDAOSingleSpeciesCoreFactory;
036    import uk.ac.roslin.ensembl.mapper.core.SequenceMapper;
037    import uk.ac.roslin.ensembl.exception.DAOException;
038    import uk.ac.roslin.ensembl.model.core.DNASequence;
039    import uk.ac.roslin.ensembl.config.EnsemblCoordSystemType;
040    import uk.ac.roslin.ensembl.dao.factory.DAOCollectionCoreFactory;
041    import uk.ac.roslin.ensembl.dao.factory.DAOSingleSpeciesCoreFactory;
042    import uk.ac.roslin.ensembl.model.core.CoordinateSystem;
043    
044    /**
045     *
046     * @author paterson
047     */
048    public class DBDNASequenceDAO extends DBCoreObjectDAO implements DNASequenceDAO{
049        
050        public DBDNASequenceDAO()  {
051            super();
052        }
053    
054        public DBDNASequenceDAO(DAOSingleSpeciesCoreFactory factory)  {
055            super(factory);
056        }
057    
058        public DBDNASequenceDAO(DAOCollectionCoreFactory factory) {
059            super(factory);
060        }
061    
062        @Override
063        public String getSequenceByStartStop(EnsemblDNASequenceReader reader, Integer start, Integer stop) throws DAOException {
064    
065    
066            if (reader==null || reader.getSeqRegionID()==null) {
067                throw new DAOException("Invalid parameter handed to getSequenceByStartStop(EnsemblDNASequenceReader reader, Integer start, Integer stop)");
068            }
069    
070            String out = null;
071    
072            Integer id = reader.getSeqRegionID();
073            Integer begin = start;
074            Integer end = stop;
075    
076            HashMap parameters = new HashMap();
077            parameters.put("id", id);
078    
079            SqlSession session = null;
080    
081            try {
082                session = this.getFactory().getNewSqlSession();
083                SequenceMapper mapper = session.getMapper(SequenceMapper.class);
084    
085                if (stop ==null && start ==null) {
086                    out = mapper.getSequence(parameters);
087                } else if (stop==null && start != null) {
088                    parameters.put("start", begin);
089                    out = mapper.getSequenceStart(parameters);
090                } else {
091                    parameters.put("start", begin);
092                    parameters.put("stop", end);
093                    out = mapper.getSequenceStartStop(parameters);
094                }
095    
096    
097    
098            } catch (Exception e) {
099                throw new DAOException("Failed to call getSequenceByStartStop", e);
100            } finally {
101                if (session != null) {
102                    session.close();
103                }
104            }
105    
106            return out;
107        }
108    
109       
110        @Override
111        public String getFullSequence(EnsemblDNASequenceReader reader) throws DAOException {
112            return this.getSequenceByStartStop(reader, null, null);
113        }
114    
115        @Override
116        public DADNASequence getSequenceByID(Integer id) throws DAOException {
117    
118            if (id==null ) {
119                throw new DAOException("Invalid parameter handed to getSequenceByID(Integer id)");
120            }
121    
122            DADNASequence seq = null;
123    
124            HashMap parameters = new HashMap();
125            List<HashMap> results = null;
126            parameters.put("id", id);
127    
128            SequenceRowHandler handler = null;
129            SqlSession session = null;
130    
131            try {
132                session = this.getFactory().getNewSqlSession();
133                SequenceMapper mapper = session.getMapper(SequenceMapper.class);
134                results = mapper.getSequenceByID(parameters);
135            } catch (Exception e) {
136                throw new DAOException("Failed to call getSequenceByID", e);
137            } finally {
138                if (session != null) {
139                    session.close();
140                }
141            }
142    
143            if (results ==null || results.isEmpty()) {
144                return null;
145            }
146    
147            handler = new SequenceRowHandler(results);
148            handler.handleResult();
149            seq = handler.getObjectResult();
150    
151    
152            return seq;
153        }
154    
155        @Override
156        public DADNASequence getValidatedSequence(DNASequence seq) throws DAOException {
157    
158            if (seq==null ||  seq.getId()==null) {
159                return null;
160            }
161    
162           if ( !(seq instanceof DADNASequence) ) {
163               throw new DAOException("Illegal attempt to validate a non DA sequence ");
164           }
165    
166            DADNASequence inseq = (DADNASequence) seq;
167            List<HashMap> results = null;
168    
169            DADNASequence newSeq = null;
170    
171            HashMap parameters = new HashMap();
172            parameters.put("id", inseq.getId());
173    
174            SequenceRowHandler handler = null;
175            SqlSession session = null;
176    
177            try {
178                session = this.getFactory().getNewSqlSession();
179                SequenceMapper mapper = session.getMapper(SequenceMapper.class);
180                results = mapper.getSequenceByID(parameters);
181            } catch (Exception e) {
182                throw new DAOException("Failed to call getValidatedSequence", e);
183            } finally {
184                if (session != null) {
185                    session.close();
186                }
187            }
188    
189            if (results ==null || results.isEmpty()) {
190                //this punts back the original sequence - ie it has not been validated
191                //so would probably be the wrong behavious
192                //return inseq;
193                return null;
194            }
195    
196            handler = new SequenceRowHandler(results);
197            handler.handleResult();
198            newSeq = handler.getObjectResult();
199    
200            if (newSeq==null) {
201                //this punts back the original sequence - ie it has not been validated
202                //so would probably be the wrong behavious
203                //return inseq;
204                return null;
205            }
206    
207            //if object is a DAChromosome, that will be the cached version,
208            //so return it
209            if (newSeq instanceof DAChromosome) {
210                return newSeq;
211            }
212    
213            //if the objects are same class, re-intitialize the original
214            if (inseq.getClass().equals(newSeq.getClass()) ) {
215    
216                inseq.setDBSeqLength(newSeq.getDBSeqLength());
217                inseq.setCoordSystem(newSeq.getCoordSystem());
218                inseq.setName(newSeq.getName());
219    
220                return inseq;
221                
222            }
223            //otherwise retrun the new object
224            else {
225                //beware may want to copy some data from inseq to newSeq
226                return newSeq;
227            }
228    
229    
230        }
231    
232    
233        @Override
234        public List<? extends DNASequence> getValidatedSequences(List<? extends DNASequence> in_sequences) throws DAOException {
235    
236            List<DADNASequence> out_sequences = new ArrayList<DADNASequence>();
237    
238            if (in_sequences==null || in_sequences.isEmpty()) {
239                return out_sequences;
240            }
241    
242            List<HashMap> results = null;
243            List<DADNASequence> retrievedSeqs = null;
244            List<Integer> outIDs = new ArrayList();
245    
246            // make a map of the incoming sequences that are to be validated (that have an id)
247            HashMap<Integer, DNASequence> in_idHash = new HashMap<Integer, DNASequence>();
248            for (DNASequence s: in_sequences ) {
249                if (s.getId()!= null //&& s instanceof DADNASequence
250                        ) {
251                    in_idHash.put(s.getId(), s);
252                } 
253            }
254    
255    
256            //if we dont have any sequences to validate - return empty list
257            if (in_idHash.isEmpty() || in_idHash.keySet().isEmpty() ) {
258                return out_sequences;
259            }
260    
261            List<Integer> in_ids = new ArrayList<Integer>() {};
262    
263            for (Integer i: in_idHash.keySet()) {
264                in_ids.add(i);
265            }
266    
267            HashMap parameters = new HashMap();
268            parameters.put("ids", in_ids);
269    
270            SequenceRowHandler handler = null;
271            SqlSession session = null;
272    
273            try {
274                session = this.getFactory().getNewSqlSession();
275                SequenceMapper mapper = session.getMapper(SequenceMapper.class);
276                results = mapper.getSequenceByID(parameters);
277            } catch (Exception e) {
278                throw new DAOException("Failed to call getValidatedSequences", e);
279            } finally {
280                if (session != null) {
281                    session.close();
282                }
283            }
284    
285            if (results ==null || results.isEmpty()) {
286                 return  in_sequences;
287            }
288    
289            handler = new SequenceRowHandler(results);
290            handler.handleResult();
291            retrievedSeqs  = handler.getListResult();
292    
293    
294            if (retrievedSeqs == null || retrievedSeqs.isEmpty() ) {
295                return  in_sequences;
296            }
297    
298    
299            for (DADNASequence newSeq : retrievedSeqs) {
300    
301                //if object is a DAChromosome, that will be the cached version,
302                //so use it
303                if (newSeq instanceof DAChromosome) {
304                    out_sequences.add(newSeq);
305                    outIDs.add(newSeq.getId());
306                }
307    
308    
309                else if (in_idHash.get(newSeq.getId()).getClass().equals(newSeq.getClass())) {
310    
311                    //if the new sequence is just the same type as the original
312                    //just modify the original and use it in the reretruned List
313                    in_idHash.get(newSeq.getId()).setDBSeqLength(newSeq.getDBSeqLength());
314                    in_idHash.get(newSeq.getId()).setCoordSystem(newSeq.getCoordSystem());
315                    in_idHash.get(newSeq.getId()).setName(newSeq.getName());
316                    try {
317                        out_sequences.add((DADNASequence) in_idHash.get(newSeq.getId()));
318                        outIDs.add(newSeq.getId());
319                    } catch (ClassCastException cce) { }
320                    
321                }
322    
323    
324                else {
325    
326                    //if the new sequence is a subclass, use it in the return List
327                    //beware - we may need to copy other properties fromold to new
328                    out_sequences.add(newSeq);
329                    outIDs.add(newSeq.getId());
330    
331                }
332    
333    
334            }
335    
336            // ADD BACK any input sequences that werent pulled back from database
337            for (Integer i : in_idHash.keySet()) {
338                if (!outIDs.contains(i)) {
339                    try {
340                        out_sequences.add((DADNASequence) in_idHash.get(i));
341                        outIDs.add(i);
342                    } catch (ClassCastException cce) { }
343                }
344            }
345    
346            return out_sequences;
347    
348        }
349    
350    
351    
352    
353        //***********************************************
354    
355    
356        public class SequenceRowHandler implements DBResultHandler {
357    
358            // the magic strings to be used as property keys for HashMap in Ibatis
359            private final String id = "id";
360            private final String name = "name";
361            private final String length = "length";
362            private final String coordSystemID = "csID";
363            private List<HashMap> rawResults = null;
364    
365            //this may be a subclass according to type
366            private DADNASequence objectResult = null;
367    
368    
369            private List<DADNASequence> listResult = new ArrayList<DADNASequence>();
370    
371            public SequenceRowHandler(List<HashMap> results) {
372                rawResults = results;
373            }
374    
375    
376            @Override
377            public List<DADNASequence> getListResult() {
378                return listResult;
379            }
380    
381            @Override
382            public DADNASequence getObjectResult() {
383                return objectResult;
384            }
385    
386            public void handleResult() throws DAOException {
387    
388                if (rawResults == null || rawResults.isEmpty()) {
389                    return;
390                }
391    
392                for (HashMap map : rawResults) {
393                    handleRow(map);
394                }
395    
396            }
397    
398    
399            private void handleRow(HashMap result) throws DAOException {
400    
401    
402                if (result == null || result.isEmpty()) {
403                    return;
404                }
405    
406                DADNASequence rowSequence = null;
407    
408                rowSequence = this.parseResult(result);
409    
410    
411                if (rowSequence!= null) {
412                    this.objectResult = rowSequence;
413                    this.listResult.add((DADNASequence) rowSequence);
414                }
415    
416            }
417    
418    
419            private DADNASequence parseResult(HashMap result) throws DAOException {
420    
421                if (result == null) {
422                    return null;
423                }
424    
425                DADNASequence pseq = null;
426                Integer length = null;
427                Integer id = null;
428                Integer pcsID = null;
429                String name = null;
430                CoordinateSystem cs = null;
431    
432    
433                pcsID = (Integer) result.get(this.coordSystemID);
434                length = (Integer) result.get(this.length);
435                id = (Integer) result.get(this.id);
436                name = (String) result.get(this.name);
437    
438    
439                if(singleSpecies) {
440                    cs = ssFactory.getDatabase().getCSByID(pcsID);
441                } else {
442                    cs= collFactory.getDatabase().getCSByID(species, pcsID);
443                }
444    
445    
446                if (cs.getType()==EnsemblCoordSystemType.chromosome ) {
447                    pseq = new DAChromosome();
448                } else if (! cs.isSequenceLevel()) {
449                    pseq = new DAAssembledDNASequence();
450                } else {
451                    pseq = new DADNASequence();
452                }
453    
454    
455                pseq.setId(id);
456                pseq.setCoordSystem(cs);
457                pseq.setDBSeqLength(length);
458                pseq.setName(name);
459                pseq.setDaoFactory(daoFactory);
460    
461                //do check for cached chromosomes here
462                if (pseq instanceof DAChromosome)
463                {
464                    pseq = species.getCachedChromosome((DAChromosome)pseq);
465                }
466    
467                return pseq;
468    
469    
470            }
471        }
472    
473    }