001/**
002 * Copyright (C) 2010-2015 The Roslin Institute <contact andy.law@roslin.ed.ac.uk>
003 *
004 * This file is part of JEnsembl: a Java API to Ensembl data sources developed by the
005 * Bioinformatics Group at The Roslin Institute, The Royal (Dick) School of
006 * Veterinary Studies, University of Edinburgh.
007 *
008 * Project hosted at: http://jensembl.sourceforge.net
009 *
010 * This is free software: you can redistribute it and/or modify
011 * it under the terms of the GNU General Public License (version 3) as published by
012 * the Free Software Foundation.
013 *
014 * This software is distributed in the hope that it will be useful,
015 * but WITHOUT ANY WARRANTY; without even the implied warranty of
016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
017 * GNU General Public License for more details.
018 *
019 * You should have received a copy of the GNU General Public License
020 * in this software distribution. If not, see: http://opensource.org/licenses/gpl-3.0.html
021 */
022package uk.ac.roslin.ensembl.dao.database.coreaccess;
023
024import java.util.ArrayList;
025import java.util.HashMap;
026import java.util.List;
027import java.util.TreeMap;
028import org.apache.ibatis.session.SqlSession;
029import org.slf4j.Logger;
030import org.slf4j.LoggerFactory;
031import uk.ac.roslin.ensembl.config.AssemblyExceptionType;
032import uk.ac.roslin.ensembl.config.EnsemblCoordSystemType;
033import uk.ac.roslin.ensembl.dao.coreaccess.ChromosomeDAO;
034import uk.ac.roslin.ensembl.dao.factory.DAOCollectionCoreFactory;
035import uk.ac.roslin.ensembl.dao.factory.DAOCoreFactory;
036import uk.ac.roslin.ensembl.dao.factory.DAOSingleSpeciesCoreFactory;
037import uk.ac.roslin.ensembl.datasourceaware.core.DAAssembledDNASequence;
038import uk.ac.roslin.ensembl.datasourceaware.core.DAChromosome;
039import uk.ac.roslin.ensembl.datasourceaware.core.DADNASequence;
040import uk.ac.roslin.ensembl.datasourceaware.core.DAGene;
041import uk.ac.roslin.ensembl.exception.DAOException;
042import uk.ac.roslin.ensembl.mapper.core.ChromosomeMapper;
043import uk.ac.roslin.ensembl.mapper.handler.DBResultHandler;
044import uk.ac.roslin.ensembl.model.Coordinate;
045import uk.ac.roslin.ensembl.model.Mapping;
046import uk.ac.roslin.ensembl.model.core.Chromosome;
047import uk.ac.roslin.ensembl.model.core.CoordinateSystem;
048
049/**
050 *
051 * @author paterson
052 */
053public class DBChromosomeDAO extends DBCoreObjectDAO implements ChromosomeDAO {
054
055    final static Logger LOGGER = LoggerFactory.getLogger(DBChromosomeDAO.class);
056    
057    public DBChromosomeDAO() {
058        super();
059    }
060
061    public DBChromosomeDAO(DAOSingleSpeciesCoreFactory factory) {
062        super(factory);
063    }
064
065    public DBChromosomeDAO(DAOCollectionCoreFactory factory)  {
066        super(factory);
067    }
068
069    @Override
070    public DAChromosome getChromosomeByName(String name) throws DAOException {
071
072        if (name==null || name.isEmpty()) {
073            return null;
074        }
075
076        DAChromosome out = null;
077        String chrName = name;
078        CoordinateSystem chrCS = null;
079
080        if (singleSpecies) {
081            chrCS = ssFactory.getDatabase().getChromosomeLevelCoordSystem();
082        } else {
083            chrCS = collFactory.getDatabase().getChromosomeLevelCS(species);
084        }
085
086        if (chrCS==null || chrCS.getId()==null  ) {
087            throw new DAOException("Failed to call to retrieve the CoordinateSystem for Chromosomes");
088        }
089
090        Integer chrCSID = chrCS.getId();
091
092        HashMap parameters = new HashMap();
093        parameters.put("chrName",chrName);
094        parameters.put("coordSysID", chrCSID);
095
096        SqlSession session = null;
097
098        try {
099            session = this.getFactory().getNewSqlSession();
100            ChromosomeMapper mapper = session.getMapper(ChromosomeMapper.class);
101            out = mapper.getChromosomeByName_CoordSysID(parameters);
102        } catch (Exception e) {
103            throw new DAOException("Failed to call getChromsomeByName_CoordSysID", e);
104        } finally {
105            if (session != null) {
106                session.close();
107            }
108        }
109
110        if (out != null) {
111            out.setDaoFactory(daoFactory);
112            out.setCoordSystem(chrCS);
113            out.setSpecies(species);
114        }
115
116        return out;
117    }
118    
119    @Override
120    public DAAssembledDNASequence getFragmentByName(String name) throws DAOException {
121
122        if (name==null || name.isEmpty()) {
123            return null;
124        }
125
126        DAAssembledDNASequence out = null;
127        String assName = name;
128        CoordinateSystem topCS = null;
129
130        if (singleSpecies) {
131            topCS = ssFactory.getDatabase().getTopLevelCoordSystem();
132        } else {
133            topCS = collFactory.getDatabase().getTopLevelCS(species);
134        }
135
136        if (topCS==null || topCS.getId()==null  ) {
137            throw new DAOException("Failed to call to retrieve the CoordinateSystem for TopLevel");
138        }
139
140        Integer topCSID = topCS.getId();
141
142        HashMap parameters = new HashMap();
143        parameters.put("coordSysID", topCSID);
144
145        parameters.put("assName",assName);
146
147
148        SqlSession session = null;
149
150        try {
151            session = this.getFactory().getNewSqlSession();
152            ChromosomeMapper mapper = session.getMapper(ChromosomeMapper.class);
153            out = mapper.getTopLevelFragmentByName_CoordSysID(parameters);
154        } catch (Exception e) {
155            throw new DAOException("Failed to call getTopLevelFragmentByName_CoordSysID", e);
156        } finally {
157            if (session != null) {
158                session.close();
159            }
160        }
161
162        if (out != null) {
163            out.setDaoFactory(daoFactory);
164            out.setCoordSystem(topCS);
165            out.setSpecies(species);
166        }
167
168        return out;
169    }
170
171    @Override
172    public List<DAChromosome> getChromosomes() throws DAOException {
173
174        List<DAChromosome> out = new ArrayList<DAChromosome>();
175        CoordinateSystem chrCS = null;
176
177        if (singleSpecies) {
178            chrCS = ssFactory.getDatabase().getChromosomeLevelCoordSystem();
179        } else {
180            chrCS = collFactory.getDatabase().getChromosomeLevelCS(species);
181        }
182
183        if (chrCS==null || chrCS.getId()==null  ) {
184            LOGGER.info("Failed to call to retrieve the CoordinateSystem for Chromosomes for: "+species.getShortName());
185            return out;
186        }
187
188        Integer chrCSID = chrCS.getId();
189
190        HashMap parameters = new HashMap();
191        parameters.put("coordSysID", chrCSID);
192
193        SqlSession session = null;
194
195        try {
196            session = this.getFactory().getNewSqlSession();
197            ChromosomeMapper mapper = session.getMapper(ChromosomeMapper.class);
198            out = mapper.getChromosomesByCoordSysID(parameters);
199        } catch (Exception e) {
200            throw new DAOException("Failed to call getChromsomes", e);
201        } finally {
202            if (session != null) {
203                session.close();
204            }
205        }
206        for (DAChromosome c : out) {
207            c.setDaoFactory(daoFactory);
208            c.setCoordSystem(chrCS);
209            c.setSpecies(species);
210        }
211
212        return out;
213    }
214    
215    @Override
216    public List<DAAssembledDNASequence> getFragments() throws DAOException {
217
218        List<DAAssembledDNASequence> out = new ArrayList<DAAssembledDNASequence>();
219        CoordinateSystem topCS = null;
220
221        if (singleSpecies) {
222            topCS = ssFactory.getDatabase().getTopLevelCoordSystem();
223        } else {
224            topCS = collFactory.getDatabase().getTopLevelCS(species);
225        }
226
227        if (topCS==null || topCS.getId()==null  ) {
228            LOGGER.info("Failed to call to retrieve the CoordinateSystem for TopLevel for: "+species.getShortName());
229            return out;
230        }
231
232        Integer topCSID = topCS.getId();
233
234        HashMap parameters = new HashMap();
235        parameters.put("coordSysID", topCSID);
236
237        SqlSession session = null;
238
239        try {
240            session = this.getFactory().getNewSqlSession();
241            ChromosomeMapper mapper = session.getMapper(ChromosomeMapper.class);
242            out = mapper.getTopLevelFragmentsByCoordSysID(parameters);
243        } catch (Exception e) {
244            throw new DAOException("Failed to call getTopLevelFragmentsByCoordSysID", e);
245        } finally {
246            if (session != null) {
247                session.close();
248            }
249        }
250        for (DAAssembledDNASequence c : out) {
251            c.setDaoFactory(daoFactory);
252            c.setCoordSystem(topCS);
253            c.setSpecies(species);
254        }
255
256        return out;
257    }
258    
259    @Override
260    public DAChromosome getSexLinkedChromosome(Chromosome chr) throws DAOException {
261        
262        
263        if (chr == null || chr.getId()==null || this.getFactory()==null ) {
264            throw new DAOException("Invalid call to retrieve sex linked chromosomes");
265        }
266        
267        DAChromosome out = null;
268        
269        CoordinateSystem chrCS = null;
270
271        if (singleSpecies) {
272            chrCS = ssFactory.getDatabase().getChromosomeLevelCoordSystem();
273        } else {
274            chrCS = collFactory.getDatabase().getChromosomeLevelCS(species);
275        }
276
277        if (chrCS==null || chrCS.getId()==null  ) {
278            throw new DAOException("Failed to call to retrieve the CoordinateSystem for Chromosomes");
279        }
280
281        Integer chrCSID = chrCS.getId();
282
283        HashMap parameters = new HashMap();
284        parameters.put("coordSysID", chrCSID);
285        parameters.put("seqID", chr.getId());
286
287        SqlSession session = null;
288
289        String name = null;
290        try {
291            session = this.getFactory().getNewSqlSession();
292            ChromosomeMapper mapper = session.getMapper(ChromosomeMapper.class);
293            name = mapper.getSexLinkedChromosomeName(parameters);
294        } catch (Exception e) {
295            throw new DAOException("Failed to call getSexLinkedChromosomeChromsomes", e);
296        } finally {
297            if (session != null) {
298                session.close();
299            }
300        }
301
302        if (name != null && !name.isEmpty()) {
303             out = this.getSpecies().getChromosomeByName(name, chr.getDBVersion());
304        } 
305
306        return out;
307    }
308    
309    @Override
310    public void setAssemblyExceptions(TreeMap<String, ? extends Chromosome> chrs) throws DAOException {
311        
312        TreeMap<String, DAChromosome> chromosomes = (TreeMap<String, DAChromosome>) chrs;
313        
314        if (chromosomes == null || chromosomes.isEmpty() || this.getFactory()==null ) {
315            throw new DAOException("Invalid call to retrieve assembly exceptions");
316        }
317
318        //Future proofed this to work with multi-speceies collections
319        
320        Integer speciesID;
321        try {
322            DAChromosome chr1 = chromosomes.firstEntry().getValue();
323            speciesID = this.species.getDBSpeciesID(this.getFactory().getDBVersion());
324            if (speciesID==null) {
325                throw new Exception();
326            }
327        } catch (Exception e) {
328            throw new DAOException("Invalid call to retrieve assembly exceptions");
329        }
330        
331        
332        HashMap parameters = new HashMap();
333        parameters.put("speciesID", speciesID);
334
335        List<HashMap> results;
336        
337        SqlSession session = null;
338
339        try {
340            session = this.getFactory().getNewSqlSession();
341            ChromosomeMapper mapper = session.getMapper(ChromosomeMapper.class);
342            results = mapper.getAssemblyExceptions(parameters);
343        } catch (Exception e) {
344            throw new DAOException("Failed to call setAssemblyExceptions", e);
345        } finally {
346            if (session != null) {
347                session.close();
348            }
349        }
350        
351
352        AssemblyExceptionRowHandler handler = null;
353        
354        if (results != null && !results.isEmpty()) {
355            handler = new AssemblyExceptionRowHandler(chromosomes, results);
356            handler.handleResult();
357        }       
358               
359        for (DAChromosome c:chromosomes.values()) {
360            c.setExceptions(true);
361        }
362
363    }
364        
365    //as an inner class it has access to the factory etc of the enclosing class
366    public class AssemblyExceptionRowHandler implements DBResultHandler {
367
368        // the magic strings to be used as property keys for HashMap in Ibatis
369        protected final String type = "type";
370        protected final String target = "target";
371        protected final String target_coords = "target_coords";
372        protected final String source_coords = "source_coords";
373        protected final String targetCSID = "targetCSID";
374        protected final String sourceChrName = "sourceChrName";
375        protected final String sourceChrID = "sourceChrID";
376        
377        private TreeMap<String, DAChromosome> chromosomes = null;
378        private List<HashMap> rawResults = null;
379
380        public AssemblyExceptionRowHandler(TreeMap<String, DAChromosome> chrs , List<HashMap> results) {
381            chromosomes = chrs; 
382            rawResults = results;
383        }
384
385        @Override
386        public List<DAGene> getListResult() {
387            return null;
388        }
389
390        @Override
391        public DAGene getObjectResult() {
392            return null;
393        }
394
395        public void handleResult() throws DAOException {
396            if (chromosomes ==null || chromosomes.isEmpty() 
397                    ||rawResults == null || rawResults.isEmpty()) {
398                return;
399            }
400            for (HashMap map : rawResults) {
401                handleRow(map);
402            }
403        }
404
405        private void handleRow(HashMap result) throws DAOException {
406
407            if (result == null || result.isEmpty()) {
408                return;
409            }
410            
411
412            DAChromosome s_sequence = null;
413            DADNASequence t_sequence = null;
414            String s_name;
415            Integer s_id;
416            Coordinate s_coords = null;
417            Coordinate t_coords = null;
418            Integer t_csID = null;
419            AssemblyExceptionType ae_type = null;
420            
421            
422            
423            s_name = (String) result.get(this.sourceChrName);
424            s_id = (Integer) result.get(this.sourceChrID);
425            
426            s_sequence = this.chromosomes.get(s_name);
427            
428            if (s_sequence==null || !s_sequence.getId().equals(s_id)) {
429                return;
430            }
431            
432            s_coords = (Coordinate) result.get(this.source_coords);
433
434            ae_type = (AssemblyExceptionType) result.get(this.type);   
435            if (ae_type == null) {
436                ae_type = AssemblyExceptionType.UNKNOWN;
437            }
438            
439            t_coords = (Coordinate) result.get(this.target_coords);
440            
441            if ( result.get(this.targetCSID) != null ) {
442                t_csID = (Integer) result.get(this.targetCSID);
443            } else {
444                return;
445            }
446 
447            t_sequence = (DADNASequence) result.get(this.target);
448            if (t_sequence == null) {
449                return;
450            }            
451            
452            CoordinateSystem targetCS  = null;
453
454            if (singleSpecies) {
455                    targetCS = ssFactory.getDatabase().getCSByID(t_csID);
456               } else {
457                    targetCS =collFactory.getDatabase().getCSByID(species, t_csID);
458            }
459
460             //we want to convert the DADNASequence to the correct type if it is an assembly!
461            
462            if (targetCS.isSequenceLevel()) {
463                t_sequence.setCoordSystem(targetCS);
464            } else if (EnsemblCoordSystemType.chromosome.equals(targetCS.getType())) {
465                t_sequence = new DAChromosome((DAOCoreFactory) daoFactory);
466                t_sequence.setId(((DADNASequence) result.get(this.target)).getId());
467                t_sequence.setName(((DADNASequence) result.get(this.target)).getName());
468                t_sequence.setDBSeqLength(((DADNASequence) result.get(this.target)).getDBSeqLength());
469                t_sequence.setSpecies(species);
470                t_sequence.setCoordSystem(targetCS);
471                
472                //look to see if we have this sequence in cache
473                t_sequence = species.getCachedChromosome((DAChromosome) t_sequence);
474
475            } else {
476                t_sequence = new DAAssembledDNASequence((DAOCoreFactory) daoFactory);
477                t_sequence.setId(((DADNASequence) result.get(this.target)).getId());
478                t_sequence.setName(((DADNASequence) result.get(this.target)).getName());
479                t_sequence.setDBSeqLength(((DADNASequence) result.get(this.target)).getDBSeqLength());
480                t_sequence.setCoordSystem(targetCS);
481
482                //look to see if we have this sequence in cache
483                t_sequence = species.getCachedFragment((DAAssembledDNASequence) t_sequence);
484            }
485            
486            if (t_sequence.getDaoFactory() == null) {
487               // pgene.setType(FeatureType.gene);
488                t_sequence.setDaoFactory(daoFactory);
489            }
490
491            Mapping mapping = new Mapping();
492            mapping.setSource(s_sequence);
493            mapping.setSourceCoordinates(s_coords);
494            mapping.setTarget(t_sequence);
495            mapping.setTargetCoordinates(t_coords);
496            
497            s_sequence.addException(ae_type, mapping);
498
499        }
500    }
501    
502}
503
504