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.compara; 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.EnsemblComparaDivision; 032import uk.ac.roslin.ensembl.dao.compara.HomologyDAO; 033import uk.ac.roslin.ensembl.dao.database.DBBaseDAO; 034import uk.ac.roslin.ensembl.dao.database.DBSpecies; 035import uk.ac.roslin.ensembl.dao.factory.DAOComparaFactory; 036import uk.ac.roslin.ensembl.datasourceaware.compara.DAHomologyPairRelationship; 037import uk.ac.roslin.ensembl.datasourceaware.compara.InverseHomologyPairRelationshipView; 038import uk.ac.roslin.ensembl.datasourceaware.core.DADNASequence; 039import uk.ac.roslin.ensembl.datasourceaware.core.DAGene; 040import uk.ac.roslin.ensembl.exception.DAOException; 041import uk.ac.roslin.ensembl.exception.NonUniqueException; 042import uk.ac.roslin.ensembl.mapper.compara.HomologyPairMapper; 043import uk.ac.roslin.ensembl.model.Coordinate; 044import uk.ac.roslin.ensembl.model.Mapping; 045import uk.ac.roslin.ensembl.model.MappingSet; 046import uk.ac.roslin.ensembl.model.compara.HomologyAlignmentProperties; 047import uk.ac.roslin.ensembl.model.core.DNASequence; 048import uk.ac.roslin.ensembl.model.core.Gene; 049import uk.ac.roslin.ensembl.model.core.Species; 050 051 052public class DBHomologyDAO extends DBBaseDAO implements HomologyDAO { 053 054 final static Logger LOGGER = LoggerFactory.getLogger(DBHomologyDAO.class); 055 056 //If we really want to cache here we will need to use a singleton DBHomologyDAO 057 TreeMap<String, DAGene> localGeneCache = new TreeMap<String, DAGene>(); 058 059 EnsemblComparaDivision comparaDivision; 060 String sourceVersion = ""; 061 062 public DBHomologyDAO(DAOComparaFactory factory) throws DAOException { 063 super(factory); 064 comparaDivision = factory.getComparaDivision(); 065 sourceVersion = this.getFactory().getDBVersion(); 066 } 067 068 /** 069 * Data Access method to retrieve all of the homologies 070 * (i.e. to all species) for a given gene with a stableID. 071 * @param g The query Gene 072 * @return List of HomologyPairRelationships 073 * @throws DAOException 074 */ 075 @Override 076 public List<DAHomologyPairRelationship> getHomologiesForGene(Gene g) throws DAOException { 077 078 DAGene gene = (DAGene) g; 079 080 //this tests for the field used by mybatis 081 if (gene.getStableID()==null || gene.getStableID().isEmpty()) { 082 throw new DAOException("Failed to get homologies for a gene without a stable EnsemblID"); 083 } 084 085 List<DAHomologyPairRelationship> results = new ArrayList<DAHomologyPairRelationship>(); 086 SqlSession session = null; 087 088 try { 089 session = this.getFactory().getNewSqlSession(); 090 HomologyPairMapper mapper = session.getMapper(HomologyPairMapper.class); 091 results = mapper.getHomologiesForGene(g); 092 } catch (Exception e) { 093 throw new DAOException("Failed to call getHomologiesForGene(g) on HomologyDAO", e); 094 } finally { 095 if (session != null) { 096 session.close(); 097 } 098 } 099 100 //do i want to do this - or to throw an exception to indicate something 101 //has gone wrong with the DB call 102 if (results==null) { 103 return new ArrayList<DAHomologyPairRelationship>(); 104 } 105 106 for (DAHomologyPairRelationship h : results) { 107 108 Species sp = null; 109 //the DAO must have a factory or it wouldn't get here 110 //and we 'should' always have a registry on a factory 111 //we use this to get the species for the homologous gene (i.e from the registry) 112 //but we can return null here 113 114 try { 115 sp = this.getFactory().getRegistry().getSpeciesByAlias(h.getTargetProperties().getSpeciesName()); 116 } catch (NonUniqueException ex) { 117 LOGGER.debug(ex.getMessage()); 118 for (Object s : ex.getAllHits()) { 119 LOGGER.debug(((DBSpecies)s).getDatabaseStyleName()); 120 } 121 //not sure what to do here if the name is not unique.... 122 // 123 //continue; 124 } 125 126 if (sp == null) { 127 //make a 'dummy species' - this wont have a factory! 128 sp = new DBSpecies(); 129 ((DBSpecies) sp).setComparaName(sourceVersion, h.getTargetProperties().getSpeciesName()); 130 } 131 132 h.setSource(gene); 133 134 DAGene target = new DAGene(); 135 target.setDBVersion( this.getFactory().getDBVersion()); 136 target.setStableID(h.getTargetProperties().getGeneID()); 137 target.setSpecies(sp); 138 139 //hopefully there will only be one relationship to a given target gene 140 //but just in case 141 if (localGeneCache.containsKey(target.getStableID())) { 142 target = localGeneCache.get(target.getStableID()); 143 } else { 144 localGeneCache.put(target.getStableID(),target ); 145 } 146 147 148 h.setTarget(target); 149 150 //fill in the sourceProperties that are not filled in by sql 151 //but are needed once we reverse the relationship 152 HomologyAlignmentProperties sourceProperties = h.getSourceProperties(); 153 154 155 try { 156 sourceProperties.setSequenceName( 157 ((DADNASequence)gene.getAnnotationLevelMappings().first().getTarget()).getName()); 158 sourceProperties.setCoords( 159 gene.getAnnotationLevelMappings().first().getTargetCoordinates()); 160 } catch (Exception e) { 161 LOGGER.warn("Gene "+gene.getHashID()+ " has no annotation level coordinates."); 162 } 163 sourceProperties.setSpeciesName( 164 (gene.getSpecies()!= null) ? gene.getSpecies().getComparaName(sourceVersion) : "" 165 ); 166 167// //reverse the relationship 168// DAHomologyPairRelationship reverse = new DAHomologyPairRelationship(); 169// reverse.setSource(target); 170// reverse.setTarget(gene); 171// //these arent treversable - use the same type?? 172// //i.e the type one2many is not necessarily specified the correct way 173// reverse.setRelationshipType(h.getRelationshipType()); 174// reverse.setTargetProperties(h.getSourceProperties()); 175// reverse.setSourceProperties(h.getTargetProperties()); 176// reverse.setLastCommonAncestor(h.getLastCommonAncestor()); 177// reverse.setId(h.getId()); 178// 179// //add the reversed relationship 180// target.addHomology(comparaDivision, reverse); 181 182 //this doesnt reverse the direction of the relationship 183 //maybe i do want to do this - and remember that i have to look at 184 //relationships either way 185 target.addHomology(comparaDivision, new InverseHomologyPairRelationshipView(h)); 186 187 } 188 return results; 189 } 190 191 /** 192 * Data Access method to retrieve all of the homologies 193 * in the specified target species for a List of genes with stableIDs. 194 * @param genes theList of query genes 195 * @param target_sp The target Species 196 * @param chrName The target chromosome name 197 * @return List of HomologyPairRelationships 198 * @throws DAOException 199 */ 200 @Override 201 public List<DAHomologyPairRelationship> 202 getHomologiesForGenesBySpecies(List<? extends Gene> genes, Species target_sp, String chrName) 203 throws DAOException { 204 205 206 207 if (genes==null || genes.isEmpty()) { 208 throw new DAOException("Failed to get homologies: No Genes specified"); 209 } 210 211 HashMap<String,DAGene> geneMap = new HashMap<String,DAGene>(); 212 213 if (target_sp==null ) { 214 throw new DAOException("Failed to get homologies: no target Species specified"); 215 } 216 if (target_sp.getComparaName(sourceVersion) == null 217 || target_sp.getComparaName(sourceVersion).isEmpty()) { 218 throw new DAOException("Failed to get homologies: target Species not identified in Compara source"); 219 } 220 221 HashMap<String, Object> query = new HashMap<String, Object>(); 222 223 query.put("targetSpecies", target_sp.getComparaName(sourceVersion)); 224 225 226 for (Gene g : genes) { 227 if (!((DAGene)g).getStableID().isEmpty()) { 228 229 geneMap.put(((DAGene)g).getStableID(), (DAGene) g); 230 } 231 } 232 233 if (geneMap.isEmpty()) { 234 throw new DAOException("Failed to get homologies: No Genes specified"); 235 } 236 237 query.put("geneIDs",new ArrayList(geneMap.keySet()) ); 238 239 if (chrName !=null && !chrName.isEmpty()) { 240 query.put("chrName", chrName); 241 } 242 243 List<DAHomologyPairRelationship> results = new ArrayList<DAHomologyPairRelationship>(); 244 SqlSession session = null; 245 246 try { 247 session = this.getFactory().getNewSqlSession(); 248 HomologyPairMapper mapper = session.getMapper(HomologyPairMapper.class); 249 results = mapper.getHomologiesForGenesBySpecies(query); 250 } catch (Exception e) { 251 throw new DAOException("Failed to call getSpeciesHomologiesForGenes(HashMap) on HomologyDAO", e); 252 } finally { 253 if (session != null) { 254 session.close(); 255 } 256 } 257 258 //do i want to do this - or to throw an exception to indicate something 259 //has gone wrong with the DB call 260 if (results==null) { 261 return new ArrayList<DAHomologyPairRelationship>(); 262 } 263 264 for (DAHomologyPairRelationship h : results) { 265 266 DAGene sourceGene = geneMap.get(h.getSourceProperties().getGeneID()); 267 268 h.setSource(sourceGene); 269 270 DAGene targetGene = new DAGene(); 271 targetGene.setDBVersion( this.getFactory().getDBVersion()); 272 targetGene.setStableID(h.getTargetProperties().getGeneID()); 273 targetGene.setSpecies(target_sp); 274 275 //hopefully there will only be one relationship to a given target gene 276 //but just in case 277 if (localGeneCache.containsKey(targetGene.getStableID())) { 278 targetGene = localGeneCache.get(targetGene.getStableID()); 279 } else { 280 localGeneCache.put(targetGene.getStableID(),targetGene ); 281 } 282 283 284 h.setTarget(targetGene); 285 286 //fill in the sourceProperties that are not filled in by sql 287 //but are needed once we reverse the relationship 288 HomologyAlignmentProperties sourceProperties = h.getSourceProperties(); 289 290 291 try { 292 sourceProperties.setSequenceName( 293 ((DADNASequence)sourceGene.getAnnotationLevelMappings().first().getTarget()).getName()); 294 sourceProperties.setCoords( 295 sourceGene.getAnnotationLevelMappings().first().getTargetCoordinates()); 296 } catch (Exception e) { 297 LOGGER.warn("Gene "+sourceGene.getHashID()+ " has no annotation level coordinates."); 298 } 299 sourceProperties.setSpeciesName( 300 (sourceGene.getSpecies()!= null) ? sourceGene.getSpecies().getComparaName(sourceVersion) : "" 301 ); 302 303// //reverse the relationship 304// DAHomologyPairRelationship reverse = new DAHomologyPairRelationship(); 305// reverse.setSource(target); 306// reverse.setTarget(gene); 307// //these arent treversable - use the same type?? 308// //i.e the type one2many is not necessarily specified the correct way 309// reverse.setRelationshipType(h.getRelationshipType()); 310// reverse.setTargetProperties(h.getSourceProperties()); 311// reverse.setSourceProperties(h.getTargetProperties()); 312// reverse.setLastCommonAncestor(h.getLastCommonAncestor()); 313// reverse.setId(h.getId()); 314// 315// //add the reversed relationship 316// target.addHomology(comparaDivision, reverse); 317 318 //this doesnt reverse the direction of the relationship 319 //maybe i do want to do this - and remember that i have to look at 320 //relationships either way 321 322 //we havent done a complete search for the division for all species 323 //so store result with a specieal key 324 //targetGene.addHomology(comparaDivision, new InverseHomologyPairRelationshipView(h)); 325 sourceGene.addHomology(EnsemblComparaDivision.INCOMPLETE_SEARCH,h); 326 targetGene.addHomology(EnsemblComparaDivision.INCOMPLETE_SEARCH, new InverseHomologyPairRelationshipView(h)); 327 328 } 329 return results; 330 } 331 332 /** 333 * Data Access method to retrieve all of the regions on DNASequences 334 * for the specified target species, holding genes with homologies to genes found 335 * in the given region of the source query sequence. 336 * @param source DNASequence to be queried 337 * @param range Coordinate range of query sequence to be queried 338 * @param target the target species 339 * @return HashMap of Syntenic regions against the set of Mappings holding homologous genes 340 * @throws DAOException 341 */ 342 @Override 343 public HashMap<DADNASequence, MappingSet> getRegionsOfConservedSynteny(DNASequence source, Coordinate range, 344 Species target) throws DAOException { 345 return this.getRegionsOfConservedSynteny(source, range, target, null); 346 } 347 348 /** 349 * Data Access method to retrieve any potential region of 350 * conserved synteny on a given Chromosome/fragment 351 * for the specified target species, holding genes with homologies to genes found 352 * in the given region of the source query sequence. 353 * @param source DNASequence to be queried 354 * @param range Coordinate range of query sequence to be queried 355 * @param target the target species 356 * @param chrName the target chromosome name 357 * @return HashMap of Syntenic regions against the set of Mappings holding homologous genes 358 * @throws DAOException 359 */ 360 @Override 361 public HashMap<DADNASequence, MappingSet> 362 getRegionsOfConservedSynteny(DNASequence source, Coordinate range, Species target, String chrName) 363 throws DAOException { 364 365 DADNASequence sChr; 366 DBSpecies tSp; 367 String tChr; 368 369 if (source==null || target==null) { 370 throw new DAOException("Require a source chromosome and a target species to call getRegionsOfConservedSynteny"); 371 } 372 373 try { 374 sChr = (DADNASequence) source; 375 tSp = (DBSpecies) target; 376 tChr = chrName; 377 } catch (Exception e) { 378 throw new DAOException("failed to pass valid parameters to get Regions of Conserved Synteny", e); 379 } 380 381 HashMap<DADNASequence, MappingSet> syntenies = new HashMap<DADNASequence, MappingSet>(); 382 383 if (range == null || range.getStart() == null || range.getEnd() == null) { 384 range = new Coordinate(sChr.getBioBegin(), sChr.getBioEnd(), 1); 385 } 386 387 List<DAGene> sGenes = sChr.getGenesOnRegion(range); 388 389 if (sGenes == null || sGenes.isEmpty()) { 390 return syntenies; 391 } 392 393 List<DAHomologyPairRelationship> speciesHomologiesForGenes = this.getHomologiesForGenesBySpecies(sGenes, target, tChr); 394 395 //old way recursed through the genes... 396 //for (DAGene g : sGenes) { 397 //List<DAHomologyPairRelationship> l = g.getHomologies(this.comparaDivision, tSp); 398 399 for (DAHomologyPairRelationship hpr : speciesHomologiesForGenes) { 400 //force conversion to real mappings, re-using cached chromosomes if appropriate 401 MappingSet m = null; 402 try { 403 //get annotation level mappingsof the target (homologous) gene 404 //i.e. gene-> chromosome in general? 405 m = hpr.getTarget().getAnnotationLevelMappings(); 406 } catch (DAOException dAOException) { 407 } 408 if (m != null && !m.isEmpty()) { 409 //probably only one of these? 410 for (Mapping mp : m) { 411 DADNASequence dna = (DADNASequence) mp.getTarget(); 412 if (!syntenies.containsKey(dna)) { 413 //if we are using the gene->chr mappings we need to be sorting on the target coords 414 //syntenies.put(dna, new MappingSet(Mapping.mappingOnTargetComparator)); 415 //but if we are using the chr->gene mappings we can sort on the source coords (i.e. default comparator) 416 syntenies.put(dna, new MappingSet()); 417 } 418 // this adds the mapping hom_gene->chr 419 //syntenies.get(dna).add(mp); 420 //but we want the mapping chr->hom_gene 421 422 //this method is called within the getReverseMapping method if required! 423 //Mapping.addReverseMapping(mp); 424 syntenies.get(dna).add(mp.getReverseMapping()); 425 } 426 } 427 // incase there are no mappings for the homologous genes on a chromosome! 428 else 429 { 430 //what do we do 431 } 432 } 433 //} 434 return syntenies; 435 } 436 437}