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 }