001    /**
002     * Copyright (C) 2011 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.exception.DAOException;
024    import java.util.ArrayList;
025    import java.util.HashMap;
026    import java.util.List;
027    import org.apache.ibatis.session.SqlSession;
028    import org.apache.log4j.Logger;
029    import uk.ac.roslin.ensembl.datasourceaware.core.DAGene;
030    import uk.ac.roslin.ensembl.config.FeatureType;
031    import uk.ac.roslin.ensembl.model.Mapping;
032    import uk.ac.roslin.ensembl.datasourceaware.DAXRef;
033    import uk.ac.roslin.ensembl.datasourceaware.core.DAAssembledDNASequence;
034    import uk.ac.roslin.ensembl.datasourceaware.core.DAChromosome;
035    import uk.ac.roslin.ensembl.datasourceaware.core.DADNASequence;
036    import uk.ac.roslin.ensembl.mapper.handler.DBResultHandler;
037    import uk.ac.roslin.ensembl.mapper.query.FeatureQuery;
038    import uk.ac.roslin.ensembl.model.Coordinate;
039    import uk.ac.roslin.ensembl.model.core.CoreObject;
040    import uk.ac.roslin.ensembl.config.EnsemblCoordSystemType;
041    import uk.ac.roslin.ensembl.dao.coreaccess.TranscriptDAO;
042    import uk.ac.roslin.ensembl.dao.factory.DAOCollectionCoreFactory;
043    import uk.ac.roslin.ensembl.dao.factory.DAOCoreFactory;
044    import uk.ac.roslin.ensembl.dao.factory.DAOSingleSpeciesCoreFactory;
045    import uk.ac.roslin.ensembl.datasourceaware.core.DATranscript;
046    import uk.ac.roslin.ensembl.mapper.core.TranscriptMapper;
047    import uk.ac.roslin.ensembl.model.MappingSet;
048    import uk.ac.roslin.ensembl.model.core.CoordinateSystem;
049    import uk.ac.roslin.ensembl.model.core.Gene;
050    
051    
052    public class DBTranscriptDAO extends DBCoreObjectDAO implements TranscriptDAO {
053    
054        //if the meta table tells us that transcript.build.level is 'toplevel'
055        //we can grab the top ranked CS and use this for all genes
056        //there may be other values than 'toplevel' - i dont know what :)
057        //if the build level isn't annotated we have to get the possible CS levels
058        //from meta_coord and use which ever one is approriate!
059        CoordinateSystem transcriptBuildCS = null;
060        final static Logger LOGGER = Logger.getLogger(DBTranscriptDAO.class);
061    
062    
063        public DBTranscriptDAO() {
064            super();
065        }
066    
067        public DBTranscriptDAO(DAOSingleSpeciesCoreFactory factory) throws DAOException {
068            super(factory);
069    
070            //we want to initialize the GeneDAO so that it knows which COordinate system
071            //it needs to quwery about genes
072    
073            transcriptBuildCS = this.ssFactory.getDatabase().getBuildCoordSystem(FeatureType.transcript.toString());
074            //what if this is null or throws an exception?
075            //if it throws an exception we are probably in some sort of bad factory environment
076            if (transcriptBuildCS==null) {
077                transcriptBuildCS=this.ssFactory.getDatabase().getTopLevelCoordSystem();
078            }
079        }
080    
081        public DBTranscriptDAO(DAOCollectionCoreFactory factory) throws DAOException {
082            super(factory);
083            transcriptBuildCS= this.collFactory.getDatabase().getBuildCoordSystem(species, FeatureType.transcript.toString());
084            //what if this is null  or throw an exception?
085            //if it throws an exception we are probably in some sort of bad factory environment
086            if (transcriptBuildCS==null) {
087                transcriptBuildCS=this.collFactory.getDatabase().getTopLevelCS(species);
088            }
089        }
090    
091        /**
092         * Uses the stableid of an object to fill in missing data 
093         * @param object
094         * @throws DAOException
095         */
096        @Override
097        public void reInitialize(CoreObject object) throws DAOException {
098    
099            if (object == null ||  !( object instanceof DATranscript) ) {
100                throw new DAOException("Object not a DATranscript");
101            }
102    
103            DATranscript transcript = (DATranscript) object;
104    
105            //the DAO method requires a stableID
106            if (transcript.getStableID()==null || transcript.getStableID().isEmpty() ) {
107                return;
108            }
109    
110            DATranscript temp = this.getTranscriptByStableID(transcript.getStableID());
111    
112            transcript.setDisplayXRef(temp.getDisplayXRef());
113            transcript.setBiotype(temp.getBiotype());
114            transcript.setId(temp.getId());
115            transcript.setCreationDate(temp.getCreationDate());
116            transcript.setModificationDate(temp.getModificationDate());
117            transcript.setDescription(temp.getDescription());
118    
119    //        for (Mapping tempMapping :temp.getMappings()) {
120    //
121    //            Mapping tempRevMapping = tempMapping.getReverseMapping();
122    //            if (tempRevMapping != null) {
123    //                tempRevMapping.setTarget(transcript);
124    //            }
125    //            tempMapping.setSource(transcript);
126    //            transcript.addMapping(tempMapping);
127    //
128    //        }
129    
130        }
131    
132        /**
133         * @param id
134         * @return
135         * @throws DAOException
136         */
137        @Override
138        public DATranscript getTranscriptByID(Integer id) throws DAOException {
139            
140            if (id==null) {
141                return null;
142            }
143    
144            FeatureQuery q = new FeatureQuery();
145            q.setFeatureID(id);
146            if (!singleSpecies) {
147                try {
148                    q.setSpeciesID(species.getDBSpeciesID(this.getFactory().getDBVersion()));
149                } catch (Exception e) {
150                    throw new DAOException("No species ID context for this query!", e);
151                }
152            }
153            return this.getTranscript(q);
154        }
155    
156        /**
157         * @param stableID
158         * @return
159         * @throws DAOException
160         */
161        @Override
162        public DATranscript getTranscriptByStableID(String stableID) throws DAOException {
163            if (stableID==null || stableID.isEmpty()  ) {
164                return null;
165            }
166    
167            FeatureQuery q = new FeatureQuery();
168            if (!singleSpecies) {
169                try {
170                    q.setSpeciesID(species.getDBSpeciesID(this.getFactory().getDBVersion()));
171                } catch (Exception e) {
172                    throw new DAOException("No species ID context for this query!", e);
173                }
174            }
175            q.setFeatureStableID(stableID.trim());
176            return this.getTranscript(q);
177        }
178    
179        @Override
180        public List<DATranscript> getTranscriptsForGene(Gene gene) throws DAOException {
181           if (gene==null  || !(gene instanceof DAGene) || gene.getId()==null ) {
182                return null;
183            }
184           
185           DAGene daGene = (DAGene) gene;
186                  
187            FeatureQuery q = new FeatureQuery();
188            if (!singleSpecies) {
189                try {
190                    q.setSpeciesID(species.getDBSpeciesID(this.getFactory().getDBVersion()));
191                } catch (Exception e) {
192                    throw new DAOException("No species ID context for this query!", e);
193                }
194            }
195           
196            q.setGeneID(daGene.getId());
197            
198            return this.getTranscripts(q, daGene);
199    
200        }
201    
202       //*******************************
203    
204        private DATranscript getTranscript(FeatureQuery query) throws DAOException {
205            DATranscript out = null;
206            TranscriptRowHandler handler = null;
207            List<HashMap> result;
208    
209            SqlSession session = null;
210    
211            try {
212                session = this.getFactory().getNewSqlSession();
213                TranscriptMapper mapper = session.getMapper(TranscriptMapper.class);
214                result = mapper.getTranscript(query);
215            } catch (Exception e) {
216                throw new DAOException("Failed to call getTranscript", e);
217            } finally {
218                if (session != null) {
219                    session.close();
220                }
221            }
222    
223            if (result != null && !result.isEmpty()) {
224    
225                handler = new TranscriptRowHandler(result);
226                handler.handleResult();
227                out = handler.getObjectResult();
228            }
229    
230            return out;
231        }
232    
233        private List<DATranscript> getTranscripts(FeatureQuery query, DAGene gene) throws DAOException {
234            List<DATranscript> out = null;
235            TranscriptRowHandler handler = null;
236            List<HashMap> result;
237    
238            SqlSession session = null;
239    
240            try {
241                session = this.getFactory().getNewSqlSession();
242                TranscriptMapper mapper = session.getMapper(TranscriptMapper.class);
243                result = mapper.getTranscript(query);
244            } catch (Exception e) {
245                throw new DAOException("Failed to call getTranscripts", e);
246            } finally {
247                if (session != null) {
248                    session.close();
249                }
250            }
251    
252            if (result != null && !result.isEmpty()) {
253    
254                handler = new TranscriptRowHandler(result,gene);
255                handler.handleResult();
256                out = handler.getListResult();
257            }
258    
259            return out;
260        }
261    
262        //*********************************
263    
264        //as an inner class it has access to the factory etc of the enclosing class
265        public class TranscriptRowHandler implements DBResultHandler {
266    
267            // the magic strings to be used as property keys for HashMap in Ibatis
268            private final String transcript = "transcript";
269            private final String xref = "xref";
270            private final String target = "target";
271            private final String coords = "coords";
272            private final String coordSystemID = "csID";
273    
274            private DADNASequence parentSeq = null;
275            private DATranscript objectResult = null;
276            private List<DATranscript> listResult = new ArrayList<DATranscript>();
277            private List<HashMap> rawResults = null;
278            private DAGene daGene = null;
279    
280            public TranscriptRowHandler(List<HashMap> results, DAGene g) {
281                daGene = g;
282                rawResults = results;
283                try {
284                    MappingSet m = daGene.getTopLevelMappings();
285                    parentSeq = (DADNASequence) m.first().getTarget();
286                } catch (DAOException ex) {
287                        LOGGER.info("DAOException trying to retrieve the Chromosome for the Gene", ex);
288                }
289    
290            }
291    
292            public TranscriptRowHandler(List<HashMap> results) {
293                rawResults = results;
294            }
295    
296            @Override
297            public List<DATranscript> getListResult() {
298                return listResult;
299            }
300    
301            @Override
302            public DATranscript getObjectResult() {
303                return objectResult;
304            }
305    
306            public void handleResult() throws DAOException {
307    
308                if (rawResults == null || rawResults.isEmpty()) {
309                    return;
310                }
311    
312                for (HashMap map : rawResults) {
313                    handleRow(map);
314                }
315    
316            }
317    
318            private void handleRow(HashMap result) throws DAOException {
319    
320                if (result == null || result.isEmpty()) {
321                    return;
322                }
323    
324                DATranscript rowTranscript = this.parseResult(result);
325    
326    
327                if (rowTranscript != null) {
328                    this.objectResult = rowTranscript;
329                    this.listResult.add(rowTranscript);
330                }
331    
332            }
333    
334            private DATranscript parseResult(HashMap result) throws DAOException {
335    
336                if (result == null || result.isEmpty()) {
337                    return null;
338                }
339    
340                DADNASequence pparentSeq = parentSeq;
341                DATranscript ptranscript = null;
342                DADNASequence ptarget = null;
343                Coordinate pcoords = null;
344                DAXRef pxref = null;
345                Integer pcsID = null;
346    
347                ptranscript = (DATranscript) result.get(this.transcript);
348                pcoords = (Coordinate) result.get(this.coords);
349                ptarget = (DADNASequence) result.get(this.target);
350                pxref = (DAXRef) result.get(this.xref);
351                pcsID = (Integer) result.get(this.coordSystemID);
352    
353                if (ptranscript == null
354                        || pcoords == null
355                            || ptarget == null
356                                ) {
357                    return null;
358                }
359    
360                //if we havent got a target DNA for the Gene, we can make and use one
361                //for the transcript, beware - may make >1 identically id'd sequence 
362                //here tho cos not caching
363                if (pparentSeq==null) {
364    
365                    CoordinateSystem targetCS = null;
366    
367                    if (ptarget.getDaoFactory() == null) {
368                            ptarget.setDaoFactory(daoFactory);
369                        }
370    
371                    targetCS = ptarget.getCoordSystem();
372    
373                    if (targetCS == null) {
374                            if (singleSpecies) {
375                                ptarget.setCoordSystem(ssFactory.getDatabase().getCSByID(pcsID));
376                            } else {
377                                ptarget.setCoordSystem(collFactory.getDatabase().getCSByID(species, pcsID));
378                            }
379                            targetCS = ptarget.getCoordSystem();
380                        }
381    
382    
383                     if (targetCS.isSequenceLevel()) {
384                        ptarget.setCoordSystem(targetCS);
385                     } else if (targetCS.getType().equals(EnsemblCoordSystemType.chromosome)) {
386                        ptarget = new DAChromosome((DAOCoreFactory) daoFactory);
387                        ptarget.setId(((DADNASequence) result.get(this.target)).getId());
388                        ptarget.setSpecies(species);
389                        ptarget.setCoordSystem(targetCS);
390    
391                        //loook to see if we have this sequence in cache
392                        ptarget = species.getCachedChromosome((DAChromosome) ptarget);
393    
394                    } else {
395                        ptarget = new DAAssembledDNASequence((DAOCoreFactory) daoFactory);
396                        ptarget.setId(((DADNASequence) result.get(this.target)).getId());
397                        ptarget.setCoordSystem(targetCS);
398    
399                        //not got a cache of assembled sequences yet to check
400                    }
401    
402    
403                } else {
404                    //if the target DNASequence isn't the sequence that the gene is on
405                    //throw this result away
406                    //ultimately will need to modify this to map from alternate CS/sequences
407                    if (!ptarget.getId().equals(pparentSeq.getId())) {
408                        return null;                }
409                }
410    
411                if (ptranscript.getDaoFactory() == null) {
412                    //pgene.setType(FeatureType.transcript);
413                    ptranscript.setDaoFactory(daoFactory);
414                }
415    
416                if (ptranscript.getDisplayXRef() == null) {
417                    pxref = (DAXRef) result.get(this.xref);
418                    if (pxref != null) {
419                        pxref.setDaoFactory(daoFactory);
420                        ptranscript.setDisplayXRef(pxref);
421                    }
422                }
423    
424    
425    
426    
427    
428    //            //check if the transcript object has somehow been returned from a cache and it
429    //            //has a mapping to a seq region with the same id as the parentSeq: if
430    //            //so, swap it for the parentSeq
431    //            for (Mapping m : pgene.getMappings()) {
432    //                if (m.getTarget().getId().equals(pparentSeq.getId())) {
433    //                    if (pparentSeq.getDaoFactory() == null) {
434    //                        pparentSeq.setDaoFactory(daoFactory);
435    //                    }
436    //                    if (pparentSeq.getCoordSystem() == null) {
437    //                        if (singleSpecies) {
438    //                            pparentSeq.setCoordSystem(ssFactory.getDatabase().getCSByID(pcsID));
439    //                        } else {
440    //                            pparentSeq.setCoordSystem(collFactory.getDatabase().getCSByID(species, pcsID));
441    //                        }
442    //                    }
443    //                    //do the switch
444    //                    m.setTarget(pparentSeq);
445    //                    m.setTargetCoordinates(pcoords);
446    //                    Mapping.addReverseMapping(m);
447    //                    return pgene;
448    //                }
449    //            }
450    //
451    //
452                Mapping mapping = new Mapping();
453                mapping.setSource(ptranscript);
454                mapping.setTargetCoordinates(pcoords);
455                mapping.setTarget(pparentSeq);
456    
457                if(ptranscript.addMapping(mapping)) {
458                    Mapping.addReverseMapping(mapping);
459                }
460                if (daGene!=null) {
461                    if (daGene.getCanonicalTranscriptID()!= null
462                            && ptranscript.getId() != null
463                                && daGene.getCanonicalTranscriptID().compareTo(ptranscript.getId())==0) {
464                        ptranscript.setCanonical(true);
465                    }
466                    daGene.addTranscript(ptranscript);
467                    ptranscript.setGene(daGene); 
468                }
469                return ptranscript;
470    
471    
472            }
473    
474        
475        }
476    
477    }