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    package uk.ac.roslin.ensembl.dao.database.compara;
021    
022    import java.util.ArrayList;
023    import java.util.HashMap;
024    import java.util.List;
025    import java.util.TreeMap;
026    import org.apache.ibatis.session.SqlSession;
027    import org.apache.log4j.Logger;
028    import uk.ac.roslin.ensembl.config.EnsemblComparaDivision;
029    import uk.ac.roslin.ensembl.dao.compara.HomologyDAO;
030    import uk.ac.roslin.ensembl.dao.database.DBBaseDAO;
031    import uk.ac.roslin.ensembl.dao.database.DBSpecies;
032    import uk.ac.roslin.ensembl.dao.factory.DAOComparaFactory;
033    import uk.ac.roslin.ensembl.model.MappingSet;
034    import uk.ac.roslin.ensembl.datasourceaware.compara.DAHomologyPairRelationship;
035    import uk.ac.roslin.ensembl.datasourceaware.compara.InverseHomologyPairRelationshipView;
036    import uk.ac.roslin.ensembl.datasourceaware.core.DAChromosome;
037    import uk.ac.roslin.ensembl.datasourceaware.core.DADNASequence;
038    import uk.ac.roslin.ensembl.datasourceaware.core.DAGene;
039    import uk.ac.roslin.ensembl.exception.DAOException;
040    import uk.ac.roslin.ensembl.mapper.compara.HomologyPairMapper;
041    import uk.ac.roslin.ensembl.model.Coordinate;
042    import uk.ac.roslin.ensembl.model.Mapping;
043    import uk.ac.roslin.ensembl.model.compara.HomologyAlignmentProperties;
044    import uk.ac.roslin.ensembl.model.core.Chromosome;
045    import uk.ac.roslin.ensembl.model.core.Gene;
046    import uk.ac.roslin.ensembl.model.core.Species;
047    
048    
049    public class DBHomologyDAO extends DBBaseDAO implements HomologyDAO {
050    
051        final static Logger LOGGER = Logger.getLogger(DBHomologyDAO.class);
052    
053        //If we really want to cache here we will need to use a singleton DBHomologyDAO
054        TreeMap<String, DAGene> localGeneCache = new TreeMap<String, DAGene>();
055    
056        EnsemblComparaDivision comparaDivision;
057    
058        public DBHomologyDAO(DAOComparaFactory factory) throws DAOException {
059            super(factory);
060            comparaDivision = factory.getComparaDivision();
061        }
062    
063        @Override
064        public List<DAHomologyPairRelationship> getHomologiesForGene(Gene g) throws DAOException {
065    
066            DAGene gene = (DAGene) g;
067            
068            //this tests for the field used by mybatis
069            if (gene.getStableID()==null || gene.getStableID().isEmpty()) {
070                throw new DAOException("Failed to get homologies for a gene without a stable EnsemblID");
071            }
072    
073            List<DAHomologyPairRelationship> results = new ArrayList<DAHomologyPairRelationship>();
074            SqlSession session = null;
075    
076            try {
077                session = this.getFactory().getNewSqlSession();
078                HomologyPairMapper mapper = session.getMapper(HomologyPairMapper.class);
079                results = mapper.getHomologiesForGene(g);
080            } catch (Exception e) {
081                throw new DAOException("Failed to call getHomologiesForGene(g) on HomologyDAO", e);
082            } finally {
083                if (session != null) {
084                    session.close();
085                }
086            }
087    
088            //do i want to do this - or to throw an exception to indicate something
089            //has gone wrong with the DB call
090            if (results==null) {
091                return new ArrayList<DAHomologyPairRelationship>();
092            }
093    
094            for (DAHomologyPairRelationship h : results) {
095    
096                Species sp = null;
097                //the DAO must have a factory or it wouldn't get here
098                //and we 'should' always have a registry on a factory
099                //we use this to get the species for the homologous gene (i.e from the registry)
100                //but we can return null here
101                sp = this.getFactory().getRegistry().getSpeciesByAlias(h.getTargetProperties().getSpeciesName());
102    
103                if (sp == null) {
104                    //make a 'dummy species' - this wont have a factory!
105                    sp = new DBSpecies();
106                    ((DBSpecies) sp).setComparaName(h.getTargetProperties().getSpeciesName());
107                }
108    
109                h.setSource(gene);
110    
111                DAGene target = new DAGene();
112                target.setDBVersion( this.getFactory().getDBVersion());
113                target.setStableID(h.getTargetProperties().getGeneID());
114                target.setSpecies(sp);
115    
116                //hopefully there will only be one relationship to a given target gene
117                //but just in case
118                if (localGeneCache.containsKey(target.getStableID())) {
119                    target = localGeneCache.get(target.getStableID());
120                } else {
121                   localGeneCache.put(target.getStableID(),target );
122                }
123    
124    
125                h.setTarget(target);
126    
127                //fill in the sourceProperties that are not filled in by sql
128                //but are needed once we reverse the relationship
129                HomologyAlignmentProperties sourceProperties = h.getSourceProperties();
130    
131    
132                try {
133                    sourceProperties.setSequenceName(
134                            ((DADNASequence)gene.getAnnotationLevelMappings().first().getTarget()).getName());
135                    sourceProperties.setCoords(
136                            gene.getAnnotationLevelMappings().first().getTargetCoordinates());
137                } catch (Exception e) {
138                    LOGGER.warn("Gene "+gene.getHashID()+ " has no annotation level coordinates.");
139                }
140                sourceProperties.setSpeciesName(
141                        (gene.getSpecies()!= null) ? gene.getSpecies().getComparaName() : ""
142                        );
143    
144    //            //reverse the relationship
145    //            DAHomologyPairRelationship reverse = new DAHomologyPairRelationship();
146    //            reverse.setSource(target);
147    //            reverse.setTarget(gene);
148    //            //these arent treversable - use the same type??
149    //            //i.e the type one2many is not necessarily specified the correct way
150    //            reverse.setRelationshipType(h.getRelationshipType());
151    //            reverse.setTargetProperties(h.getSourceProperties());
152    //            reverse.setSourceProperties(h.getTargetProperties());
153    //            reverse.setLastCommonAncestor(h.getLastCommonAncestor());
154    //            reverse.setId(h.getId());
155    //
156    //            //add the reversed relationship
157    //            target.addHomology(comparaDivision, reverse);
158    
159                //this doesnt reverse the direction of the relationship
160                //maybe i do want to do this - and remember that i have to look at
161                //relationships either way
162                target.addHomology(comparaDivision, new InverseHomologyPairRelationshipView(h));
163    
164            }
165            return results;
166        }
167    
168        @Override
169        public HashMap<DADNASequence, MappingSet> getRegionsOfConservedSynteny(Chromosome source, Coordinate range,
170                Species target) throws DAOException {
171    
172            DAChromosome sChr;
173            DBSpecies tSp;
174    
175            if (source==null || target==null) {
176                throw new DAOException("Require a source chromosome and a target species to call getRegionsOfConservedSynteny");
177            }
178    
179            try {
180                sChr = (DAChromosome) source;
181                tSp = (DBSpecies) target;
182            } catch (Exception e) {
183                throw new DAOException("failed to pass valid parameters to get Regions of Conserved Synteny", e);
184            }
185    
186            HashMap<DADNASequence, MappingSet> syntenies = new HashMap<DADNASequence, MappingSet>();
187    
188            if (range == null || range.getStart() == null || range.getEnd() == null) {
189                range = new Coordinate(sChr.getBioBegin(), sChr.getBioEnd(), 1);
190            }
191    
192            List<DAGene> sGenes = sChr.getGenesOnRegion(range);
193    
194            if (sGenes == null || sGenes.isEmpty()) {
195                return syntenies;
196            }
197    
198            for (DAGene g : sGenes) {
199                List<DAHomologyPairRelationship> l = g.getHomologies(this.comparaDivision, tSp);
200    
201                for (DAHomologyPairRelationship hpr : l) {
202                    //force conversion to real mappings, re-using cached chromosomes if appropriate
203                    MappingSet m = null;
204                    try {
205                        //get annotation level mappingsof the target (homologous) gene
206                        //i.e. gene-> chromosome in general?
207                        m = hpr.getTarget().getAnnotationLevelMappings();
208                    } catch (DAOException dAOException) {
209                    }
210                    if (m != null && !m.isEmpty()) {
211                        //probably only one of these?
212                        for (Mapping mp : m) {
213                           DADNASequence dna = (DADNASequence) mp.getTarget();
214                           if (!syntenies.containsKey(dna)) {
215                               //if we are using the gene->chr mappings we need to be sorting on the target coords
216                               //syntenies.put(dna, new MappingSet(Mapping.mappingOnTargetComparator));
217                               //but if we are using the chr->gene mappings we can sort on the source coords (i.e. default comparator)
218                               syntenies.put(dna, new MappingSet());
219                           }
220                           // this adds the mapping hom_gene->chr
221                           //syntenies.get(dna).add(mp);
222                           //but we want the mapping chr->hom_gene
223    
224                           //this method is called within the getReverseMapping method if required!
225                           //Mapping.addReverseMapping(mp);
226                           syntenies.get(dna).add(mp.getReverseMapping());
227                        }
228                    }
229                    // incase there are no mappings for the homologous genes on a chromosome!
230                    else
231                    {
232                        //what do we do
233                    }
234                }
235            }
236            return syntenies;
237        }
238    }