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.List; 026import java.util.HashMap; 027import org.apache.ibatis.session.SqlSession; 028import uk.ac.roslin.ensembl.biojava3.EnsemblDNASequenceReader; 029import uk.ac.roslin.ensembl.dao.coreaccess.DNASequenceDAO; 030import uk.ac.roslin.ensembl.datasourceaware.core.DAAssembledDNASequence; 031import uk.ac.roslin.ensembl.datasourceaware.core.DAChromosome; 032import uk.ac.roslin.ensembl.datasourceaware.core.DADNASequence; 033import uk.ac.roslin.ensembl.mapper.handler.DBResultHandler; 034import uk.ac.roslin.ensembl.mapper.core.SequenceMapper; 035import uk.ac.roslin.ensembl.exception.DAOException; 036import uk.ac.roslin.ensembl.model.core.DNASequence; 037import uk.ac.roslin.ensembl.config.EnsemblCoordSystemType; 038import uk.ac.roslin.ensembl.dao.factory.DAOCollectionCoreFactory; 039import uk.ac.roslin.ensembl.dao.factory.DAOSingleSpeciesCoreFactory; 040import uk.ac.roslin.ensembl.model.core.CoordinateSystem; 041 042/** 043 * 044 * @author paterson 045 */ 046public class DBDNASequenceDAO extends DBCoreObjectDAO implements DNASequenceDAO{ 047 048 public DBDNASequenceDAO() { 049 super(); 050 } 051 052 public DBDNASequenceDAO(DAOSingleSpeciesCoreFactory factory) { 053 super(factory); 054 } 055 056 public DBDNASequenceDAO(DAOCollectionCoreFactory factory) { 057 super(factory); 058 } 059 060 @Override 061 public String getSequenceByStartStop(EnsemblDNASequenceReader reader, Integer start, Integer stop) throws DAOException { 062 063 064 if (reader==null || reader.getSeqRegionID()==null) { 065 throw new DAOException("Invalid parameter handed to getSequenceByStartStop(EnsemblDNASequenceReader reader, Integer start, Integer stop)"); 066 } 067 068 String out = null; 069 070 Integer id = reader.getSeqRegionID(); 071 Integer begin = start; 072 Integer end = stop; 073 074 HashMap parameters = new HashMap(); 075 parameters.put("id", id); 076 077 SqlSession session = null; 078 079 try { 080 session = this.getFactory().getNewSqlSession(); 081 SequenceMapper mapper = session.getMapper(SequenceMapper.class); 082 083 if (stop ==null && start ==null) { 084 out = mapper.getSequence(parameters); 085 } else if (stop==null && start != null) { 086 parameters.put("start", begin); 087 out = mapper.getSequenceStart(parameters); 088 } else { 089 parameters.put("start", begin); 090 parameters.put("stop", end); 091 out = mapper.getSequenceStartStop(parameters); 092 } 093 094 095 096 } catch (Exception e) { 097 throw new DAOException("Failed to call getSequenceByStartStop", e); 098 } finally { 099 if (session != null) { 100 session.close(); 101 } 102 } 103 104 return out; 105 } 106 107 108 @Override 109 public String getFullSequence(EnsemblDNASequenceReader reader) throws DAOException { 110 return this.getSequenceByStartStop(reader, null, null); 111 } 112 113 @Override 114 public DADNASequence getSequenceByID(Integer id) throws DAOException { 115 116 if (id==null ) { 117 throw new DAOException("Invalid parameter handed to getSequenceByID(Integer id)"); 118 } 119 120 DADNASequence seq = null; 121 122 HashMap parameters = new HashMap(); 123 List<HashMap> results = null; 124 parameters.put("id", id); 125 126 SequenceRowHandler handler = null; 127 SqlSession session = null; 128 129 try { 130 session = this.getFactory().getNewSqlSession(); 131 SequenceMapper mapper = session.getMapper(SequenceMapper.class); 132 results = mapper.getSequenceByID(parameters); 133 } catch (Exception e) { 134 throw new DAOException("Failed to call getSequenceByID", e); 135 } finally { 136 if (session != null) { 137 session.close(); 138 } 139 } 140 141 if (results ==null || results.isEmpty()) { 142 return null; 143 } 144 145 handler = new SequenceRowHandler(results); 146 handler.handleResult(); 147 seq = handler.getObjectResult(); 148 149 150 return seq; 151 } 152 153 @Override 154 public DADNASequence getValidatedSequence(DNASequence seq) throws DAOException { 155 156 if (seq==null || seq.getId()==null) { 157 return null; 158 } 159 160 if ( !(seq instanceof DADNASequence) ) { 161 throw new DAOException("Illegal attempt to validate a non DA sequence "); 162 } 163 164 DADNASequence inseq = (DADNASequence) seq; 165 List<HashMap> results = null; 166 167 DADNASequence newSeq = null; 168 169 HashMap parameters = new HashMap(); 170 parameters.put("id", inseq.getId()); 171 172 SequenceRowHandler handler = null; 173 SqlSession session = null; 174 175 try { 176 session = this.getFactory().getNewSqlSession(); 177 SequenceMapper mapper = session.getMapper(SequenceMapper.class); 178 results = mapper.getSequenceByID(parameters); 179 } catch (Exception e) { 180 throw new DAOException("Failed to call getValidatedSequence", e); 181 } finally { 182 if (session != null) { 183 session.close(); 184 } 185 } 186 187 if (results ==null || results.isEmpty()) { 188 //this punts back the original sequence - ie it has not been validated 189 //so would probably be the wrong behavious 190 //return inseq; 191 return null; 192 } 193 194 handler = new SequenceRowHandler(results); 195 handler.handleResult(); 196 newSeq = handler.getObjectResult(); 197 198 if (newSeq==null) { 199 //this punts back the original sequence - ie it has not been validated 200 //so would probably be the wrong behavious 201 //return inseq; 202 return null; 203 } 204 205 //if object is a DAChromosome, that will be the cached version, 206 //so return it 207 if (newSeq instanceof DAChromosome) { 208 return newSeq; 209 } 210 211 //if the objects are same class, re-intitialize the original 212 if (inseq.getClass().equals(newSeq.getClass()) ) { 213 214 inseq.setDBSeqLength(newSeq.getDBSeqLength()); 215 inseq.setCoordSystem(newSeq.getCoordSystem()); 216 inseq.setName(newSeq.getName()); 217 inseq.setAttributes(newSeq.getAttributes()); 218 inseq.setLazyLoaded(true); 219 220 return inseq; 221 222 } 223 //otherwise retrun the new object 224 else { 225 //beware may want to copy some data from inseq to newSeq 226 return newSeq; 227 } 228 229 230 } 231 232 233 @Override 234 public List<? extends DNASequence> getValidatedSequences(List<? extends DNASequence> in_sequences) throws DAOException { 235 236 List<DADNASequence> out_sequences = new ArrayList<DADNASequence>(); 237 238 if (in_sequences==null || in_sequences.isEmpty()) { 239 return out_sequences; 240 } 241 242 List<HashMap> results = null; 243 List<DADNASequence> retrievedSeqs = null; 244 List<Integer> outIDs = new ArrayList(); 245 246 // make a map of the incoming sequences that are to be validated (that have an id) 247 HashMap<Integer, DNASequence> in_idHash = new HashMap<Integer, DNASequence>(); 248 for (DNASequence s: in_sequences ) { 249 if (s.getId()!= null //&& s instanceof DADNASequence 250 ) { 251 in_idHash.put(s.getId(), s); 252 } 253 } 254 255 256 //if we dont have any sequences to validate - return empty list 257 if (in_idHash.isEmpty() || in_idHash.keySet().isEmpty() ) { 258 return out_sequences; 259 } 260 261 List<Integer> in_ids = new ArrayList<Integer>() {}; 262 263 for (Integer i: in_idHash.keySet()) { 264 in_ids.add(i); 265 } 266 267 HashMap parameters = new HashMap(); 268 parameters.put("ids", in_ids); 269 270 SequenceRowHandler handler = null; 271 SqlSession session = null; 272 273 try { 274 session = this.getFactory().getNewSqlSession(); 275 SequenceMapper mapper = session.getMapper(SequenceMapper.class); 276 results = mapper.getSequenceByID(parameters); 277 } catch (Exception e) { 278 throw new DAOException("Failed to call getValidatedSequences", e); 279 } finally { 280 if (session != null) { 281 session.close(); 282 } 283 } 284 285 if (results ==null || results.isEmpty()) { 286 return in_sequences; 287 } 288 289 handler = new SequenceRowHandler(results); 290 handler.handleResult(); 291 retrievedSeqs = handler.getListResult(); 292 293 294 if (retrievedSeqs == null || retrievedSeqs.isEmpty() ) { 295 return in_sequences; 296 } 297 298 299 for (DADNASequence newSeq : retrievedSeqs) { 300 301 //if object is a DAChromosome, that will be the cached version, 302 //so use it 303 if (newSeq instanceof DAChromosome) { 304 out_sequences.add(newSeq); 305 outIDs.add(newSeq.getId()); 306 } 307 308 309 else if (in_idHash.get(newSeq.getId()).getClass().equals(newSeq.getClass())) { 310 311 //if the new sequence is just the same type as the original 312 //just modify the original and use it in the reretruned List 313 in_idHash.get(newSeq.getId()).setDBSeqLength(newSeq.getDBSeqLength()); 314 in_idHash.get(newSeq.getId()).setCoordSystem(newSeq.getCoordSystem()); 315 in_idHash.get(newSeq.getId()).setName(newSeq.getName()); 316 try { 317 ((DADNASequence)in_idHash.get(newSeq.getId())).setAttributes(newSeq.getAttributes()); 318 out_sequences.add((DADNASequence) in_idHash.get(newSeq.getId())); 319 outIDs.add(newSeq.getId()); 320 } catch (ClassCastException cce) { } 321 322 } 323 324 325 else { 326 327 //if the new sequence is a subclass, use it in the return List 328 //beware - we may need to copy other properties fromold to new 329 out_sequences.add(newSeq); 330 outIDs.add(newSeq.getId()); 331 332 } 333 334 335 } 336 337 // ADD BACK any input sequences that werent pulled back from database 338 for (Integer i : in_idHash.keySet()) { 339 if (!outIDs.contains(i)) { 340 try { 341 out_sequences.add((DADNASequence) in_idHash.get(i)); 342 outIDs.add(i); 343 } catch (ClassCastException cce) { } 344 } 345 } 346 347 return out_sequences; 348 349 } 350 351 352 353 354 //*********************************************** 355 356 357 public class SequenceRowHandler implements DBResultHandler { 358 359 // the magic strings to be used as property keys for HashMap in Ibatis 360 private final String id = "id"; 361 private final String name = "name"; 362 private final String length = "length"; 363 private final String coordSystemID = "csID"; 364 private final String attributes = "attributes"; 365 private List<HashMap> rawResults = null; 366 367 //this may be a subclass according to type 368 private DADNASequence objectResult = null; 369 370 371 private List<DADNASequence> listResult = new ArrayList<DADNASequence>(); 372 373 public SequenceRowHandler(List<HashMap> results) { 374 rawResults = results; 375 } 376 377 378 @Override 379 public List<DADNASequence> getListResult() { 380 return listResult; 381 } 382 383 @Override 384 public DADNASequence getObjectResult() { 385 return objectResult; 386 } 387 388 public void handleResult() throws DAOException { 389 390 if (rawResults == null || rawResults.isEmpty()) { 391 return; 392 } 393 394 for (HashMap map : rawResults) { 395 handleRow(map); 396 } 397 398 } 399 400 401 private void handleRow(HashMap result) throws DAOException { 402 403 404 if (result == null || result.isEmpty()) { 405 return; 406 } 407 408 DADNASequence rowSequence = null; 409 410 rowSequence = this.parseResult(result); 411 412 413 if (rowSequence!= null) { 414 this.objectResult = rowSequence; 415 this.listResult.add((DADNASequence) rowSequence); 416 } 417 418 } 419 420 421 private DADNASequence parseResult(HashMap result) throws DAOException { 422 423 if (result == null) { 424 return null; 425 } 426 427 DADNASequence pseq = null; 428 Integer length = null; 429 Integer id = null; 430 Integer pcsID = null; 431 String name = null; 432 CoordinateSystem cs = null; 433 List<HashMap> attribs = null; 434 435 436 pcsID = (Integer) result.get(this.coordSystemID); 437 length = (Integer) result.get(this.length); 438 id = (Integer) result.get(this.id); 439 name = (String) result.get(this.name); 440 attribs = (List<HashMap> ) result.get(this.attributes); 441 442 443 if(singleSpecies) { 444 cs = ssFactory.getDatabase().getCSByID(pcsID); 445 } else { 446 cs= collFactory.getDatabase().getCSByID(species, pcsID); 447 } 448 449 450 if (cs.getType()==EnsemblCoordSystemType.chromosome ) { 451 pseq = new DAChromosome(); 452 } else if (! cs.isSequenceLevel()) { 453 pseq = new DAAssembledDNASequence(); 454 } else { 455 pseq = new DADNASequence(); 456 } 457 458 459 pseq.setId(id); 460 pseq.setCoordSystem(cs); 461 pseq.setDBSeqLength(length); 462 pseq.setName(name); 463 pseq.setDaoFactory(daoFactory); 464 465 if (attribs!=null && !attribs.isEmpty()) { 466 HashMap<String,String> temp = new HashMap<String,String>(); 467 for (HashMap hm: attribs) { 468 temp.put((String) hm.get("key"), (String) hm.get("value")); 469 } 470 pseq.setAttributes(temp); 471 } 472 473 //do check for cached chromosomes here 474 if (pseq instanceof DAChromosome) 475 { 476 pseq = species.getCachedChromosome((DAChromosome)pseq); 477 } 478 479 //look to see if we have this sequence in cache 480 if (pseq instanceof DAAssembledDNASequence) 481 { 482 pseq = species.getCachedFragment((DAAssembledDNASequence) pseq); 483 } 484 485 return pseq; 486 487 488 } 489 } 490 491}