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