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 uk.ac.roslin.ensembl.model.Mapping; 029import uk.ac.roslin.ensembl.model.MappingSet; 030import uk.ac.roslin.ensembl.dao.coreaccess.AssemblyDAO; 031import uk.ac.roslin.ensembl.datasourceaware.core.DAAssembledDNASequence; 032import uk.ac.roslin.ensembl.datasourceaware.core.DADNASequence; 033import uk.ac.roslin.ensembl.dao.factory.DAOCollectionCoreFactory; 034import uk.ac.roslin.ensembl.dao.factory.DAOSingleSpeciesCoreFactory; 035import uk.ac.roslin.ensembl.datasourceaware.core.DAChromosome; 036import uk.ac.roslin.ensembl.mapper.core.SequenceMapper; 037import uk.ac.roslin.ensembl.exception.DAOException; 038import uk.ac.roslin.ensembl.mapper.handler.DBResultHandler; 039import uk.ac.roslin.ensembl.model.Coordinate; 040import uk.ac.roslin.ensembl.model.core.Chromosome; 041import uk.ac.roslin.ensembl.model.core.CoordinateSystem; 042import uk.ac.roslin.ensembl.model.core.DNASequence; 043 044/** 045 * 046 * @author paterson 047 */ 048public class DBAssemblyDAO extends DBCoreObjectDAO implements AssemblyDAO { 049 050 public DBAssemblyDAO() { 051 super(); 052 } 053 054 public DBAssemblyDAO(DAOSingleSpeciesCoreFactory factory) { 055 super(factory); 056 } 057 058 public DBAssemblyDAO(DAOCollectionCoreFactory factory) { 059 super(factory); 060 } 061 062 @Override 063 public MappingSet getComponentMappingsByStartStop(DNASequence assembledSequence, Integer begin, Integer stop) throws DAOException { 064 065 066 if (assembledSequence == null || begin == null || stop == null 067 || assembledSequence.getId() == null 068 || assembledSequence.getCoordSystem() == null 069 || assembledSequence.getCoordSystem().getId() == null) { 070 throw new DAOException("Invalid parameters passed to getComponentMappingsByStartStopDNASequence assembledSequence, Integer begin, Integer stop "); 071 } 072 073 MappingSet componentMappings = new MappingSet(); 074 List<Mapping> results; 075 DAAssembledDNASequence parent; 076 SqlSession session = null; 077 078 try { 079 parent = (DAAssembledDNASequence) assembledSequence; 080 } catch (ClassCastException e) { 081 throw new DAOException("This sequence is not an assembly!"); 082 } 083 084 Integer start = begin; 085 Integer end = stop; 086 CoordinateSystem seqLevelCS = null; 087 088 Integer seqLevelCoordSysID = null; 089 Integer parentCoordSysID = null; 090 091 try { 092 if (singleSpecies) { 093 seqLevelCS = ssFactory.getDatabase().getSequenceLevelCoordSystem(); 094 } else { 095 seqLevelCS = collFactory.getDatabase().getSequenceLevelCS(species); 096 } 097 098 if (seqLevelCS == null || seqLevelCS.getId() == null) { 099 throw new DAOException("Failed to call to retrieve the CoordinateSystem for Sequences"); 100 } 101 102 seqLevelCoordSysID = seqLevelCS.getId(); 103 parentCoordSysID = parent.getCoordSystem().getId(); 104 105 if (seqLevelCoordSysID.equals(parentCoordSysID)) { 106 //the parent is at sequence level - so dont need a projection 107 //probably prevent this call happening before here 108 throw new DAOException("This sequence is not an assembly!"); 109 } 110 111 Integer seqRegionID = parent.getId(); 112 113 //none of these should be null 114 115 HashMap parameters = new HashMap(); 116 parameters.put("seqRegionID", seqRegionID); 117 parameters.put("start", start); 118 parameters.put("end", end); 119 parameters.put("seqLevelCoordSysID", seqLevelCoordSysID); 120 121 session = this.getFactory().getNewSqlSession(); 122 SequenceMapper mapper = session.getMapper(SequenceMapper.class); 123 124 //this first call just gets sequence levelmappings 125 126 results = mapper.getComponentSequences(parameters); 127 } catch (Exception e) { 128 throw new DAOException("Failed to call getComponentMappingsByStartStop", e); 129 } finally { 130 if (session != null) { 131 session.close(); 132 } 133 } 134 135 if (results == null || results.isEmpty()) { 136 try { 137 138 Integer seqRegionID = parent.getId(); 139 140 //none of these should be null 141 142 HashMap parameters = new HashMap(); 143 parameters.put("seqRegionID", seqRegionID); 144 parameters.put("start", start); 145 parameters.put("end", end); 146 // dont put the sequencelevel CS in as a parameter 147 148 session = this.getFactory().getNewSqlSession(); 149 SequenceMapper mapper = session.getMapper(SequenceMapper.class); 150 151 //this second call gets every level of mappings 152 153 results = mapper.getComponentSequences(parameters); 154 } catch (Exception e) { 155 throw new DAOException("Failed to call getComponentMappingsByStartStop", e); 156 } finally { 157 if (session != null) { 158 session.close(); 159 } 160 } 161 162 } 163 if (results == null || results.isEmpty()) { 164 return componentMappings; 165 } 166 167 // System.out.println("query results: "+results.size()); 168 //int count = 1; 169 170 if (results != null) { 171 for (Mapping mapping : results) { 172 173 mapping.setSource(parent); 174 175 //if the target sequence is not se4quence level we need to change it to 176 // an assembledSequence 177 178 DADNASequence seq = (DADNASequence) mapping.getTarget(); 179 180 if (!seq.getCsID().equals(seqLevelCoordSysID)) { 181 182 DAAssembledDNASequence newseq = new DAAssembledDNASequence(); 183 newseq.setId(seq.getId()); 184 newseq.setName(seq.getName()); 185 newseq.setDBSeqLength(seq.getDBSeqLength()); 186 newseq.setDaoFactory(daoFactory); 187 188 //not adding the Reader cos not at sequence level 189 190 newseq.setCsID(seq.getCsID()); 191 if (singleSpecies) { 192 newseq.setCoordSystem(ssFactory.getDatabase().getCSByID(seq.getCsID())); 193 } else { 194 newseq.setCoordSystem(collFactory.getDatabase().getCSByID(species, seq.getCsID())); 195 } 196 197 //switch 198 mapping.setTarget(newseq); 199 200 } else { 201 //everything returned from this query is a sequence level component 202 seq.setDaoFactory(daoFactory); 203 ((DADNASequence) mapping.getTarget()).setCoordSystem(seqLevelCS); 204 //this is now done by mybatis 205 //((DADNASequence) mapping.getTarget()).setSequenceStorage(mapping.getReader()); 206 } 207 208 //this adds the reverse mapping to the DA DNASequence - 209 //not sure if this is required, or if better stored as another type of relationship 210 211 if (componentMappings.add(mapping)) { 212 Mapping.addReverseMapping(mapping); 213 } 214 } 215 } 216 217 218 return componentMappings; 219 220 } 221 222 @Override 223 public MappingSet getPARMappingsByStartStop(Chromosome chr, Integer begin, Integer stop) throws DAOException { 224 225 if (chr == null || !chr.isPAR() || chr.getId() == null 226 || chr.getCoordSystem() == null 227 || chr.getCoordSystem().getId() == null) { 228 throw new DAOException("Invalid chromosome for getPARMappingsByStartStop"); 229 } 230 231 DAChromosome ychr = (DAChromosome) chr; 232 //i need to get the linked chromsome ( ie X if we are mapping Y) 233 DAChromosome xchr = ychr.getParChromosome(); 234 235 if (xchr == null) { 236 throw new DAOException("No PAR chromosome found for getPARMappingsByStartStop"); 237 } 238 239 240 241 242 Integer start = begin != null ? begin : ychr.getBioBegin(); 243 Integer end = stop != null ? stop : ychr.getBioEnd(); 244 245 246 MappingSet parMappings = new MappingSet(); 247 List<HashMap> results; 248 DAAssembledDNASequence parent; 249 SqlSession session = null; 250 PARMappingHandler handler = null; 251 252 253 CoordinateSystem chrLevelCS = null; 254 255 try { 256 if (singleSpecies) { 257 258 //PARs are mapped at the chromosome level 259 260 chrLevelCS = ssFactory.getDatabase().getChromosomeLevelCoordSystem(); 261 } else { 262 chrLevelCS = collFactory.getDatabase().getSequenceLevelCS(species); 263 } 264 265 if (chrLevelCS == null || chrLevelCS.getId() == null) { 266 throw new DAOException("Failed to call to retrieve the CoordinateSystem for Chromosomes"); 267 } 268 269 Integer chrLevelCoordSysID = chrLevelCS.getId(); 270 Integer parentCoordSysID = ychr.getCoordSystem().getId(); 271 272 Integer seqRegionID = ychr.getId(); 273 274 //none of these should be null 275 276 HashMap parameters = new HashMap(); 277 parameters.put("seqRegionID", seqRegionID); 278 parameters.put("start", start); 279 parameters.put("end", end); 280 parameters.put("parentCoordSysID", parentCoordSysID); 281 parameters.put("chrLevelCoordSysID", chrLevelCoordSysID); 282 283 session = this.getFactory().getNewSqlSession(); 284 SequenceMapper mapper = session.getMapper(SequenceMapper.class); 285 results = mapper.getPARSequences(parameters); 286 } catch (Exception e) { 287 throw new DAOException("Failed to call getPARMappingsByStartStop", e); 288 } finally { 289 if (session != null) { 290 session.close(); 291 } 292 } 293 294 if (results == null || results.isEmpty()) { 295 return parMappings; 296 } 297 298 if (results != null && !results.isEmpty()) { 299 300 handler = new PARMappingHandler(results, ychr, xchr); 301 handler.handleResult(); 302 parMappings.addAll(handler.getListResult()); 303 } 304 305 return parMappings; 306 307 } 308 309 //as an inner class it has access to the factory etc of the enclosing class 310 public class PARMappingHandler implements DBResultHandler { 311 312 // the magic strings to be used as property keys for HashMap in Ibatis 313 private final String componentID = "componentID"; 314 private final String targetCoordinates = "targetCoordinates"; 315 private final String sourceCoordinates = "sourceCoordinates"; 316 private Mapping objectResult = null; 317 private List<Mapping> listResult = new ArrayList<Mapping>(); 318 private List<HashMap> rawResults = null; 319 private DAChromosome sourceChr = null; 320 private DAChromosome targetChr = null; 321 private int targetID = 0; 322 323 public PARMappingHandler(List<HashMap> results, DAChromosome source, DAChromosome target) { 324 sourceChr = source; 325 targetChr = target; 326 rawResults = results; 327 328 targetID = targetChr.getId(); 329 330 } 331 332 @Override 333 public List<Mapping> getListResult() { 334 return listResult; 335 } 336 337 @Override 338 public Mapping getObjectResult() { 339 return objectResult; 340 } 341 342 public void handleResult() throws DAOException { 343 344 if (rawResults == null || rawResults.isEmpty()) { 345 return; 346 } 347 348 for (HashMap map : rawResults) { 349 handleRow(map); 350 } 351 352 } 353 354 private void handleRow(HashMap result) throws DAOException { 355 356 Mapping rowMapping = null; 357 358 rowMapping = this.parseResult(result); 359 360 361 if (rowMapping != null) { 362 this.objectResult = rowMapping; 363 this.listResult.add(rowMapping); 364 } 365 366 367 } 368 369 private Mapping parseResult(HashMap result) throws DAOException { 370 371 if (result == null || result.isEmpty()) { 372 return null; 373 } 374 375 376 Coordinate sCoords = null; 377 Coordinate tCoords = null; 378 Integer tID = null; 379 380 381 tID = (Integer) result.get(this.componentID); 382 sCoords = (Coordinate) result.get(this.sourceCoordinates); 383 tCoords = (Coordinate) result.get(this.targetCoordinates); 384 385 386 if (tID != this.targetID 387 || sCoords == null 388 || tCoords == null) { 389 return null; 390 } 391 392 393 Mapping mapping = new Mapping(); 394 mapping.setSource(this.sourceChr); 395 mapping.setSourceCoordinates(sCoords); 396 mapping.setTarget(this.targetChr); 397 mapping.setTargetCoordinates(tCoords); 398 399 400 401 if (this.sourceChr.addMapping(mapping)) { 402 Mapping.addReverseMapping(mapping); 403 } 404 405 return mapping; 406 407 408 } 409 } 410}