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.datasourceaware.core;
022    
023    import java.util.ArrayList;
024    import java.util.HashMap;
025    import java.util.List;
026    import uk.ac.roslin.ensembl.config.EnsemblComparaDivision;
027    import uk.ac.roslin.ensembl.model.Mapping;
028    import uk.ac.roslin.ensembl.model.MappingSet;
029    import uk.ac.roslin.ensembl.model.Coordinate;
030    import uk.ac.roslin.ensembl.model.Coordinate.Strand;
031    import uk.ac.roslin.ensembl.model.Mapping;
032    import uk.ac.roslin.ensembl.model.database.Registry;
033    import uk.ac.roslin.ensembl.model.core.CoordinateSystem;
034    import uk.ac.roslin.ensembl.dao.factory.DAOCoreFactory;
035    import uk.ac.roslin.ensembl.dao.factory.DAOFactory;
036    import uk.ac.roslin.ensembl.exception.DAOException;
037    import uk.ac.roslin.ensembl.model.CoordinateSet;
038    import uk.ac.roslin.ensembl.model.ObjectType;
039    import uk.ac.roslin.ensembl.model.core.CoreObject;
040    import uk.ac.roslin.ensembl.model.core.Species;
041    import uk.ac.roslin.ensembl.config.FeatureType;
042    import uk.ac.roslin.ensembl.dao.factory.DAOComparaFactory;
043    import uk.ac.roslin.ensembl.dao.factory.DAOSpeciesFactory;
044    import uk.ac.roslin.ensembl.model.core.CollectionSpecies;
045    import uk.ac.roslin.ensembl.model.database.CollectionDatabase;
046    import uk.ac.roslin.ensembl.model.database.SingleSpeciesDatabase;
047    
048    /**
049     *
050     * @author paterson
051     */
052    public class DADNASequence extends org.biojava3.core.sequence.DNASequence implements CoreObject, uk.ac.roslin.ensembl.model.core.DNASequence {
053    
054        protected DAOFactory daoFactory = null;
055        protected String schemaVersion = null;
056        protected String dbVersion = null;
057        protected Registry registry = null;
058        protected Integer id = null;
059        protected Integer seqRegionID = null;
060        protected String name = null;
061        protected String dbSpeciesName = null;
062        protected Species species = null;
063        protected Integer DBSeqLength = null;
064        protected CoordinateSystem coordSystem = null;
065        protected MappingSet mappings = new MappingSet();
066        protected HashMap<ObjectType, CoordinateSet> mappedRegions
067                = new HashMap<ObjectType, CoordinateSet>();
068        protected HashMap<ObjectType, MappingSet> objectTypeMappings
069                = new HashMap<ObjectType, MappingSet>();
070        protected HashMap<EnsemblComparaDivision, DAOComparaFactory> comparaFactories
071                = new HashMap<EnsemblComparaDivision, DAOComparaFactory>();
072    
073        public DADNASequence() {
074            super();
075    
076        }
077    
078        public DADNASequence(DAEnsemblDNASequenceReader proxyLoader) {
079            super(proxyLoader);
080            ((DAEnsemblDNASequenceReader) this.getProxySequenceReader()).setParent(this);
081            this.setId(proxyLoader.getSeqRegionID());
082            this.setDBSeqLength(proxyLoader.getLengthInteger());
083        }
084    
085        public DADNASequence(String sequence) {
086            super(new DAEnsemblDNASequenceReader());
087            ((DAEnsemblDNASequenceReader) this.getProxySequenceReader()).setParent(this);
088            ((DAEnsemblDNASequenceReader) this.getProxySequenceReader()).setContents(sequence);
089        }
090    
091        public DADNASequence(DAOCoreFactory factory) {
092            this.setDaoFactory(factory);
093        }
094    
095        public void setSequenceStorage(DAEnsemblDNASequenceReader proxyLoader) {
096            this.setProxySequenceReader(proxyLoader);
097            ((DAEnsemblDNASequenceReader) this.getProxySequenceReader()).setParent(this);
098        }
099    
100        public DAOCoreFactory getDaoFactory() {
101            return (DAOCoreFactory) daoFactory;
102        }
103    
104        public void setDaoFactory(DAOFactory daoFactory) {
105            this.daoFactory = daoFactory;
106            if (this.daoFactory!= null) {
107                this.setSchemaVersion(daoFactory.getEnsemblSchemaVersion());
108                this.setDBVersion(daoFactory.getDBVersion());
109                this.setRegistry((Registry) daoFactory.getRegistry());
110            }
111        }
112    
113        public String getSchemaVersion() {
114                return schemaVersion;
115        }
116    
117        private void setSchemaVersion(String schemaVersion) {
118            this.schemaVersion = schemaVersion;
119        }
120    
121        public String getDBVersion() {
122                return dbVersion;
123        }
124    
125        private void setDBVersion(String dbversion) {
126            this.dbVersion = dbversion;
127        }
128    
129        public Registry getRegistry() {
130                return registry;
131        }
132    
133        public void setRegistry(Registry datasource) {
134            this.registry = datasource;
135        }
136    
137        public Integer getId() {
138            return id;
139        }
140    
141        public void setId(Integer id) {
142            this.id = id;
143        }
144    
145        public String getDBName() {
146            return (daoFactory!= null)?daoFactory.getDatabaseName():null;
147        }
148    
149        public Species getSpecies() {
150            if (species == null && this.daoFactory != null && this.daoFactory instanceof DAOSpeciesFactory) {
151                species = ((DAOSpeciesFactory) this.daoFactory).getSpecies();
152            }
153            return species;
154        }
155    
156        public void setSpecies(Species species) {
157            this.species = species;
158        }
159    
160        public ObjectType getType() {
161            //forces a lazy load so make sure we get CS for all retrieved sequenceIDS in the first query!
162            if (this.getCoordSystem() != null) {
163                return this.getCoordSystem().getType();
164            } else {
165                return null;
166            }
167        }
168    
169        public Integer getDBSeqLength() {
170            if (DBSeqLength == null) {
171                this.lazyLoad();
172            }
173            if (DBSeqLength != null) {
174                return DBSeqLength;
175            } else { return 0;}
176        }
177    
178        public void setDBSeqLength(Integer seqLength) {
179            this.DBSeqLength = seqLength;
180            this.setBioEnd(seqLength);
181        }
182    
183        @Override
184        public Integer getBioEnd() {
185    
186            try {
187                return (super.getBioEnd() != null) ? super.getBioEnd() : this.getDBSeqLength();
188            } catch (NullPointerException e) {
189                return this.getDBSeqLength();
190            }
191        }
192    
193        @Override
194        public int getLength() {
195    
196            try {
197                return super.getLength();
198            } catch (NullPointerException e) {
199                return this.getDBSeqLength();
200            }
201        }
202    
203        public String getName() {
204            if (name == null) {
205                this.lazyLoad();
206            }
207            return name;
208        }
209    
210        public void setName(String name) {
211            this.name = name;
212        }
213    
214        public CoordinateSystem getCoordSystem() {
215    
216            if (coordSystem == null) {
217                this.lazyLoad();
218            }
219    
220            return coordSystem;
221        }
222    
223        public void setCoordSystem(CoordinateSystem coordSystem) {
224            this.coordSystem = coordSystem;
225        }
226    
227        public MappingSet getMappings() {
228            return this.mappings;
229        }
230    
231        //Should Be Private??
232        public MappingSet getMappings(ObjectType targetType) {
233    
234            //need to add lazy load here?
235    
236            if (!this.objectTypeMappings.containsKey(targetType)) {
237                return new MappingSet();
238            } else {
239                return this.objectTypeMappings.get(targetType);
240            }
241        }
242    
243        public Boolean addMapping(Mapping mapping) {
244    
245    //        //check we haven't already added a mapping for an object with this id!
246    //        if (mapping.getTarget() != null) {
247    //
248    //            for (Mapping m : this.mappings) {
249    //                if (m.getTarget() != null && m.getTarget().getId().equals(mapping.getTarget().getId())) {
250    //                    return;
251    //                }
252    //            }
253    //        }
254    
255            //if we fail to add the mapping this will be false
256            if (this.mappings.add((Mapping) mapping)) {
257    
258                ObjectType t = mapping.getTargetType();
259    
260                if (t != null) {
261                    if (!this.objectTypeMappings.containsKey(t)) {
262                        this.objectTypeMappings.put(t, new MappingSet());
263                    }
264    
265                    this.objectTypeMappings.get(t).add((Mapping) mapping);
266                }
267                return true;
268            }
269            return false;
270        }
271    
272        public List<DAGene> getGenesOnRegion(Coordinate coord) throws DAOException {
273    
274            List<DAGene> out = new ArrayList<DAGene>();
275    
276            List<? extends Mapping> mappings = null;
277    
278            //test if we already have got the genes for this coordinate region
279            if (this.mappedRegions.containsKey(FeatureType.gene)
280                    && this.mappedRegions.get(FeatureType.gene).containsCoordinateWithoutGaps(coord)) {
281    
282                //we need a temporary pointer here so we can match the signatures
283                ArrayList<Mapping> theseMappings = new ArrayList<Mapping>();
284    
285                //find and return genes in this region
286                for (Mapping m : this.getMappings(FeatureType.gene)) {
287                    Coordinate c = m.getSourceCoordinates();
288                    if (c.overlaps(coord)) {
289                        theseMappings.add(m);
290                    }
291                }
292                mappings = theseMappings;
293    
294                if (mappings == null || mappings.isEmpty()) {
295                    return out;
296                } else {
297                    //these mappings are seq -> gene
298    
299                    if (coord.getStrand() == null) {
300                        for (Mapping m : mappings) {
301                            out.add((DAGene) m.getTarget());
302                            //already done in the DAO
303                            //this.addMapping(m);
304    
305                        }
306                    } else {
307                        for (Mapping m : mappings) {
308                            if (m.getSourceCoordinates().getStrand().equals(coord.getStrand())) {
309                                out.add((DAGene) m.getTarget());
310                            }
311                            //already done in the DAO
312                            //this.addMapping(m);
313                        }
314                    }
315                }
316                return out;
317    
318            } else {
319    
320                if (this.getDaoFactory() != null && this.getDaoFactory().getGeneDAO() != null) {
321    
322                    mappings = this.getDaoFactory().getGeneDAO().getGeneMappingsOnRegion(this, coord);
323                }
324    
325                if (mappings == null || mappings.isEmpty()) {
326                    return out;
327                } else {
328                    //these mappings ade gene->seq
329                    if (coord.getStrand() == null) {
330                        for (Mapping m : mappings) {
331                            out.add((DAGene) m.getSource());
332                            //already done in the DAO
333                            //this.addMapping(m);
334    
335                        }
336                    } else {
337                        for (Mapping m : mappings) {
338                            if (m.getTargetCoordinates().getStrand().equals(coord.getStrand())) {
339                                out.add((DAGene) m.getSource());
340                            }
341                            //already done in the DAO
342                            //this.addMapping(m);
343                        }
344                    }
345                }
346    
347                //put this region in the sore of mapped regions
348                if (!mappedRegions.containsKey(FeatureType.gene)) {
349                    mappedRegions.put(FeatureType.gene, new CoordinateSet());
350                }
351                this.mappedRegions.get(FeatureType.gene).add(coord);
352                return out;
353            }
354        }
355    
356        public List<DAGene> getGenesOnRegion(Integer start, Integer stop, Strand strand) throws DAOException {
357    
358            Strand s = strand;
359            Integer begin = null;
360            Integer end = null;
361    
362    //        if (s == null) {
363    //            s = Strand.FORWARD_STRAND;
364    //        }
365    
366            if (start != null && stop != null && start.doubleValue() > stop.doubleValue()) {
367                begin = stop;
368                end = start;
369            } else {
370                begin = start;
371                end = stop;
372            }
373    
374            Coordinate coord = new Coordinate(start, stop, strand);
375            return this.getGenesOnRegion(coord);
376    
377        }
378    
379        public List<DAGene> getGenesOnRegion(Integer start, Integer stop) throws DAOException {
380    
381            return this.getGenesOnRegion(start, stop, null);
382        }
383    
384        private void lazyLoad() {
385    
386            if (this.id != null && this.getDaoFactory() != null) {
387                try {
388                    DADNASequence fetchedSeq = (DADNASequence) this.getDaoFactory().getSequenceDAO().getSequenceByID(id);
389                    this.setName(fetchedSeq.getName());
390                    this.setDBSeqLength(fetchedSeq.getDBSeqLength());
391                    this.setCoordSystem(fetchedSeq.getCoordSystem());
392                } catch (Exception ex) {
393                }
394            }
395        }
396    
397        public String getSequenceAsString(Integer begin, Integer end) {
398            if (this.getLength()==0) {
399                return "";
400            }
401            return super.getSequenceAsString(begin, end, org.biojava3.core.sequence.Strand.POSITIVE);
402        }
403    
404        public String getReverseComplementSequenceAsString(Integer begin, Integer end) {
405            if (this.getLength()==0) {
406                return "";
407            }
408            DAEnsemblDNASequenceReader ss = (DAEnsemblDNASequenceReader) getProxySequenceReader();
409            return ss.getReverseComplementSequenceAsString(begin, end);
410        }
411    
412        public String getReverseComplementSequenceAsString() {
413            if (this.getLength()==0) {
414                return "";
415            }
416            return this.getReverseComplementSequenceAsString(this.getBioBegin(), this.getBioEnd());
417        }
418    
419        public HashMap<ObjectType, MappingSet> getObjectTypeMappings() {
420            return objectTypeMappings;
421        }
422    
423        public HashMap<ObjectType, CoordinateSet> getMappedRegions() {
424            return mappedRegions;
425        }
426    
427        public String getHashID() {
428            return
429                    ((this.getDaoFactory()!=null) ? this.getDaoFactory().getDatabaseName() : "NODATABASE")
430    
431                    +"_"
432    
433                    +((this.getType()!=null) ? this.getType().toString() : "NOTYPE")
434    
435                    +"_"
436    
437                    +((this.getId()!=null) ? this.getId().toString() : "NOID");
438        }
439    
440        @Override
441        public String toString() {
442            return ((this.getId()!=null) ? this.getId().toString() : "NOID");
443        }
444    
445        public void clearAllMappings() {
446                mappings.clear();
447                mappedRegions.clear();
448                objectTypeMappings.clear();
449        }
450    
451        public EnsemblComparaDivision getComparaDivision() {
452            if (this.getSpecies()==null) {
453                return null;
454            }
455            return this.getSpecies().getComparaDivision();
456        }
457    
458       public DAOComparaFactory getComparaFactory(EnsemblComparaDivision comparaDivision) {
459    
460            if (comparaFactories.containsKey(comparaDivision)) {
461                return comparaFactories.get(comparaDivision);
462            } else if (this.getDaoFactory() != null) {
463                DAOComparaFactory f = this.getDaoFactory().getComparaFactory(comparaDivision);
464                comparaFactories.put(comparaDivision, f);
465                return f;
466            }
467            return null;
468        }
469    
470        public DAOComparaFactory getComparaFactory() {
471    
472            EnsemblComparaDivision comparaDivision = this.getComparaDivision();
473    
474            if (comparaFactories.containsKey(comparaDivision)) {
475                return comparaFactories.get(comparaDivision);
476            } else if (this.getDaoFactory() != null) {
477                DAOComparaFactory f = this.getDaoFactory().getComparaFactory(comparaDivision);
478                comparaFactories.put(comparaDivision, f);
479                return f;
480            }
481            return null;
482        }
483    
484        public String getAssembly() {
485    
486            if (this.getSpecies() == null || this.getDaoFactory() == null
487                    || this.getDaoFactory().getDatabase() == null) {
488                return null;
489            }
490    
491            try {
492    
493                if (this.getSpecies() instanceof CollectionSpecies) {
494                    return ((CollectionDatabase) this.getDaoFactory().getDatabase()).getAssembly(
495                            (CollectionSpecies) this.getSpecies());
496    
497                } else {
498                    return ((SingleSpeciesDatabase) this.getDaoFactory().getDatabase()).getAssembly();
499    
500                }
501            } catch (Exception e) {
502                return null;
503            }
504    
505        }
506    
507        
508    }