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