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; 023 024import java.util.*; 025import java.util.Map.Entry; 026import org.apache.ibatis.session.SqlSession; 027import uk.ac.roslin.ensembl.config.EnsemblCoordSystemType; 028import uk.ac.roslin.ensembl.config.EnsemblDBType; 029import uk.ac.roslin.ensembl.config.FeatureType; 030import uk.ac.roslin.ensembl.dao.database.factory.DBDAOSingleSpeciesCoreFactory; 031import uk.ac.roslin.ensembl.dao.database.factory.DBDAOSingleSpeciesFactory; 032import uk.ac.roslin.ensembl.datasourceaware.DAAnalysis; 033import uk.ac.roslin.ensembl.datasourceaware.core.DAAssembledDNASequence; 034import uk.ac.roslin.ensembl.datasourceaware.core.DAChromosome; 035import uk.ac.roslin.ensembl.datasourceaware.core.DACoordinateSystem; 036import uk.ac.roslin.ensembl.exception.ConfigurationException; 037import uk.ac.roslin.ensembl.exception.DAOException; 038import uk.ac.roslin.ensembl.mapper.XRefMapper; 039import uk.ac.roslin.ensembl.model.ExternalDB; 040import uk.ac.roslin.ensembl.model.ObjectType; 041import uk.ac.roslin.ensembl.model.core.CoordinateSystem; 042import uk.ac.roslin.ensembl.model.database.Registry; 043import uk.ac.roslin.ensembl.model.database.SingleSpeciesCoreDatabase; 044 045/** 046 * 047 * @author paterson 048 */ 049public class DBSingleSpeciesCoreDatabase extends DBSingleSpeciesDatabase implements SingleSpeciesCoreDatabase { 050 051 private List<DACoordinateSystem> coordSystems = new ArrayList<DACoordinateSystem>(); 052 private TreeMap<Integer, DACoordinateSystem> rankedCoordSystemsHash = new TreeMap<Integer, DACoordinateSystem>(); 053 private TreeMap<Integer, DACoordinateSystem> idCoordSystemsHash = new TreeMap<Integer, DACoordinateSystem>(); 054 private Integer chromosomeLevelID = null; 055 private Integer sequenceLevelID = null; 056 private Integer topLevelID = null; 057 private DACoordinateSystem chromosomeLevelCS = null; 058 private DACoordinateSystem sequenceLevelCS = null; 059 private DACoordinateSystem topLevelCS = null; 060 private HashMap<FeatureType, String> defaultBuildLevels = new HashMap<FeatureType, String>(); 061 private HashMap<FeatureType, HashMap<DACoordinateSystem, Integer>> featureCSHash = null; 062 private HashMap<DACoordinateSystem, List<FeatureType>> CSFeatureHash = null; 063 private HashMap<Integer,DAAnalysis> analyses = null; 064 /** 065 * A Map of ExternalDB objects on their id (previously used the db_name field in the database 066 * table 'external_db' - but this was not unique due to versioning) 067 */ 068 HashMap<Integer, ExternalDB> externalDBsByID = new HashMap<Integer, ExternalDB>(); 069 //unfortunately names may not be unique - e.g. multiple versions of PFAM 070 HashMap<String, Set<ExternalDB>> externalDBsByName = new HashMap<String, Set<ExternalDB>>(); 071 boolean externalDBsInitialized = false; 072 073 protected String assemblyName = null; 074 protected String assemblyAccession = null; 075 protected String comparaName = null; 076 077 public DBSingleSpeciesCoreDatabase(String db_name, EnsemblDBType type, Registry registry) throws ConfigurationException { 078 super(db_name, type, registry); 079 } 080 081 @Override 082 public DBDAOSingleSpeciesCoreFactory getCoreFactory() { 083 if (this.factory == null) { 084 try { 085 this.factory = DBDAOSingleSpeciesFactory.makeFactory(this); 086 } catch (Exception ex) { 087 } 088 } 089 090 if (this.factory != null) { 091 return (DBDAOSingleSpeciesCoreFactory) this.factory; 092 } else { 093 return null; 094 } 095 } 096 097 private List<DACoordinateSystem> fetchCS() throws DAOException { 098 List<DACoordinateSystem> coords = new ArrayList<DACoordinateSystem>(); 099 //can throw DAOException 100 if ( this.getCoreFactory()!=null) { 101 coords = this.getCoreFactory().getCoordinateSystemDAO(). 102 getCoordinateSystems(); 103 } else { 104 return coords; 105 } 106 return coords; 107 } 108 109 private void setCoordinateSystems(List<DACoordinateSystem> coords) throws DAOException { 110 111 this.coordSystems.clear(); 112 this.coordSystems.addAll(coords); 113 114 //set the ids for the top, chromosome and sequence levels 115 116 for (DACoordinateSystem cs : coordSystems) { 117 118 this.rankedCoordSystemsHash.put(cs.getRank(), cs); 119 this.idCoordSystemsHash.put(cs.getId(), cs); 120 121 } 122 123 for (Entry<Integer, DACoordinateSystem> e : this.rankedCoordSystemsHash.entrySet() ) { 124 if (e.getValue().isDefaultVersion()) { 125 e.getValue().setTopLevel(true); 126 this.topLevelCS = e.getValue(); 127 this.topLevelID = e.getValue().getId(); 128 break; 129 } 130 } 131 132 for (Entry<Integer, DACoordinateSystem> e : this.rankedCoordSystemsHash.entrySet() ) { 133 if (e.getValue().isDefaultVersion() 134 && e.getValue().getType() == EnsemblCoordSystemType.chromosome) { 135 this.chromosomeLevelCS = e.getValue(); 136 this.chromosomeLevelID = e.getValue().getId(); 137 break; 138 } 139 } 140 141 for (Entry<Integer, DACoordinateSystem> e : this.rankedCoordSystemsHash.entrySet() ) { 142 if (e.getValue().isDefaultVersion() 143 && e.getValue().isSequenceLevel()) { 144 this.sequenceLevelCS = e.getValue(); 145 this.sequenceLevelID = e.getValue().getId(); 146 break; 147 } 148 } 149 150 } 151 152 private void lazyLoadCoordinateSystems() throws DAOException { 153 154 this.coordSystems.clear(); 155 156 List<DACoordinateSystem> coords = this.fetchCS(); 157 158 if (!coords.isEmpty()) { 159 this.setCoordinateSystems(coords); 160 } 161 162 //set nil values to prevent repeating lazy load 163 164 if (this.chromosomeLevelID == null) { 165 this.chromosomeLevelID = 0; 166 } 167 if (this.topLevelID == null) { 168 this.topLevelID = 0; 169 } 170 if (this.sequenceLevelID == null) { 171 this.sequenceLevelID = 0; 172 } 173 174 } 175 176 @Override 177 public DACoordinateSystem getCSByID(Integer id) throws DAOException { 178 DACoordinateSystem out = null; 179 if (topLevelID == null && this.coordSystems.isEmpty()) { 180 181 //lazyload can throw DAOException 182 lazyLoadCoordinateSystems(); 183 184 } 185 186 out = this.idCoordSystemsHash.get(id); 187 188 return out; 189 } 190 191 public List<DACoordinateSystem> getCoordinateSystems() throws DAOException { 192 193 if (topLevelID == null && this.coordSystems.isEmpty()) { 194 //lazyload can throw DAOException 195 lazyLoadCoordinateSystems(); 196 } 197 return this.coordSystems; 198 } 199 200 @Override 201 public DACoordinateSystem getTopLevelCoordSystem() throws DAOException { 202 if (topLevelID == null && this.coordSystems.isEmpty()) { 203 //lazyload can throw DAOException 204 lazyLoadCoordinateSystems(); 205 } 206 return topLevelCS; 207 } 208 209 @Override 210 public DACoordinateSystem getChromosomeLevelCoordSystem() throws DAOException { 211 if (chromosomeLevelID == null && this.coordSystems.isEmpty()) { 212 //lazyload can throw DAOException 213 lazyLoadCoordinateSystems(); 214 } 215 return chromosomeLevelCS; 216 } 217 218 @Override 219 public DACoordinateSystem getSequenceLevelCoordSystem() throws DAOException { 220 if (sequenceLevelID == null && this.coordSystems.isEmpty()) { 221 //lazyload can throw DAOException 222 lazyLoadCoordinateSystems(); 223 } 224 return sequenceLevelCS; 225 } 226 227 @Override 228 public DAChromosome getChromosomeByName(String name) throws DAOException { 229 if (this.getCoreFactory()!=null){ 230 return this.getCoreFactory().getChromosomeDAO().getChromosomeByName(name); 231 } else { 232 return null; 233 } 234 235 } 236 237 /** 238 * a Fragment is TopLevelAssembledDNASequence ( where there are no chromosomes ) 239 * @param name 240 * 241 * @throws DAOException 242 */ 243 @Override 244 public DAAssembledDNASequence getFragmentByName(String name) throws DAOException { 245 if (this.getCoreFactory()!=null){ 246 return this.getCoreFactory().getChromosomeDAO().getFragmentByName(name); 247 } else { 248 return null; 249 } 250 251 } 252 253 /** 254 * Note that Chromosomes are not cached by the Database object - but by the Species Object 255 * 256 * @throws DAOException 257 */ 258 @Override 259 public List<DAChromosome> getChromosomes() throws DAOException { 260 if (this.getCoreFactory()!=null){ 261 return this.getCoreFactory().getChromosomeDAO().getChromosomes(); 262 } else { 263 return new ArrayList<DAChromosome>(); 264 } 265 } 266 267 /** 268 * Fragments are TopLevelAssembledDNASequences 269 * 270 * @throws DAOException 271 */ 272 @Override 273 public List<DAAssembledDNASequence> getFragments() throws DAOException { 274 if (this.getCoreFactory()!=null){ 275 return this.getCoreFactory().getChromosomeDAO().getFragments(); 276 } else { 277 return new ArrayList<DAAssembledDNASequence>(); 278 } 279 } 280 281 private void setFeatureCSHash() throws DAOException { 282 283 if (sequenceLevelID == null && this.coordSystems.isEmpty()) { 284 //lazyload can throw DAOException 285 lazyLoadCoordinateSystems(); 286 } 287 288 featureCSHash = new HashMap<FeatureType, HashMap<DACoordinateSystem, Integer>>(); 289 CSFeatureHash = new HashMap<DACoordinateSystem, List<FeatureType>>(); 290 291 for (DACoordinateSystem c : this.coordSystems) { 292 CSFeatureHash.put(c, new ArrayList<FeatureType>()); 293 294 } 295 296 297 if (this.getCoreFactory() != null) { 298 299 try { 300 301 this.getCoreFactory().getCoordinateSystemDAO().setFeatureCS(); 302 303 } catch (DAOException e) { 304 featureCSHash = null; 305 CSFeatureHash = null; 306 throw e; 307 } 308 } 309 310 } 311 312 @Override 313 public Set<DACoordinateSystem> getCSForFeature(ObjectType featureType) throws DAOException { 314 315 if (this.featureCSHash == null) { 316 this.setFeatureCSHash(); 317 } 318 319 320 if (this.featureCSHash != null 321 && this.featureCSHash.containsKey(featureType)) { 322 return this.featureCSHash.get(featureType).keySet(); 323 } else { 324 325 return null; 326 } 327 } 328 329 @Override 330 public List<FeatureType> getFeaturesForCS(CoordinateSystem coordSys) throws DAOException{ 331 332 333 if (this.featureCSHash == null) { 334 this.setFeatureCSHash(); 335 } 336 337 338 if (this.CSFeatureHash != null 339 && this.CSFeatureHash.containsKey(coordSys)) { 340 return this.CSFeatureHash.get(coordSys); 341 } else { 342 return null; 343 } 344 } 345 346 @Override 347 public Integer getMaxLengthForFeature(ObjectType featureType, CoordinateSystem cs) throws DAOException { 348 349 if ( featureType == null || cs == null ) { 350 return null; 351 } 352 353 if (this.featureCSHash == null) { 354 this.setFeatureCSHash(); 355 } 356 357 358 359 if (this.featureCSHash != null 360 && this.featureCSHash.containsKey(featureType) 361 && this.featureCSHash.get(featureType).containsKey(cs)) { 362 return this.featureCSHash.get(featureType).get(cs); 363 } else { 364 return null; 365 } 366 367 } 368 369 @Override 370 public void addFeatureCS(String featureType, Integer csID, Integer maxLength) { 371 372 FeatureType type = null; 373 DACoordinateSystem cs = null; 374 375 type = FeatureType.getFeatureType(featureType); 376 cs = this.idCoordSystemsHash.get(csID); 377 378 if (type == null || cs == null) { 379 return; 380 } else { 381 if (!this.featureCSHash.containsKey(type)) { 382 this.featureCSHash.put(type, new HashMap<DACoordinateSystem, Integer>()); 383 } 384 this.featureCSHash.get(type).put(cs, maxLength); 385 386 this.CSFeatureHash.get(cs).add(type); 387 388 } 389 390 391 } 392 393 @Override 394 public void setBuildLevel(String featureKey, String level) { 395 String temp = featureKey.replace("build.level", ""); 396 397 if (FeatureType.getFeatureType(temp) != null) { 398 this.defaultBuildLevels.put(FeatureType.getFeatureType(temp), level); 399 } 400 } 401 402 @Override 403 public String getBuildLevel(String featureType) throws DAOException{ 404 if (FeatureType.getFeatureType(featureType) != null) { 405 if (defaultBuildLevels.isEmpty()) { 406 this.getRegistry().setSpeciesMetadata(this); 407 } 408 return this.defaultBuildLevels.get(FeatureType.getFeatureType(featureType)); 409 } else { 410 return null; 411 } 412 } 413 414 @Override 415 public DACoordinateSystem getBuildCoordSystem(String featureType) throws DAOException { 416 417 if (FeatureType.getFeatureType(featureType) != null) { 418 if (defaultBuildLevels.isEmpty()) { 419 this.getRegistry().setSpeciesMetadata(this); 420 } 421 String level = this.defaultBuildLevels.get(FeatureType.getFeatureType(featureType)); 422 if (level != null && level.equalsIgnoreCase("toplevel")) { 423 return this.getTopLevelCoordSystem(); 424 } else { 425 return null; 426 } 427 428// //are there other values possible? 429// else if (level.equalsIgnoreCase("chromosomelevel")) { 430// return this.getChromosomeLevelCoordSystem(); 431// } else if (level.equalsIgnoreCase("sequencelevel")) { 432// return this.getSequenceLevelCoordSystem(); 433// } 434 } 435 436 return null; 437 438 } 439 440 //dont really want this public - just for testing 441 public HashMap<FeatureType, String> getBuildLevels() { 442 if (defaultBuildLevels.isEmpty()) { 443 try { 444 445 //is this correct - dont i want to do 446 //this.getRegistry().setCoreDBBuildLevels(this); 447 lazyLoadCoordinateSystems(); 448 } catch (DAOException ex) { 449 450 } 451 } 452 return defaultBuildLevels; 453 } 454 455 /** 456 * Analyses are cached at the Database level 457 * 458 * @throws DAOException 459 */ 460 @Override 461 public HashMap<Integer, DAAnalysis> getAnalyses() throws DAOException { 462 if (analyses!= null) { 463 return analyses; 464 } 465 if (this.getCoreFactory()!=null){ 466 analyses = this.getCoreFactory().getAnalysisDAO().getAnalyses(); 467 } else { 468 analyses = new HashMap<Integer, DAAnalysis>(); 469 } 470 return analyses; 471 } 472 473 /** 474 * Validates a givenExternalDB object, to return a pre-existing version id present. 475 * @param db 476 * 477 */ 478 @Override 479 public ExternalDB validateExternalDB(ExternalDB db) { 480 481 if (db==null) { 482 return null; 483 } 484 485 this.initializeExternalDBs(); 486 487 if (this.externalDBsByID.containsKey(db.getId())) { 488 return this.externalDBsByID.get(db.getId()); 489 } else { 490 this.externalDBsByID.put(db.getId(), db); 491 return db; 492 } 493 } 494 495 @Override 496 public void initializeExternalDBs() { 497 if (this.externalDBsInitialized) { 498 return; 499 } 500 501 List<ExternalDB> result = null; 502 SqlSession session = null; 503 504 try { 505 session = this.getNewSqlSession(); 506 XRefMapper mapper = session.getMapper(XRefMapper.class); 507 result= mapper.getExternalDBs(); 508 } catch (Exception e) { 509 LOGGER.debug("Failed to call getExternalDBs on DBDatabase", e); 510 return; 511 //throw new DAOException("Failed to call getExternalDBs on DBDatabase", e); 512 } finally { 513 if (session != null) { 514 session.close(); 515 } 516 } 517 518 if (result!=null && !result.isEmpty()) { 519 for (ExternalDB d : result) { 520 this.externalDBsByID.put(d.getId(), d); 521 522 if (!this.externalDBsByName.containsKey(d.getDBName())) { 523 this.externalDBsByName.put(d.getDBName(), new HashSet<ExternalDB>()); 524 } 525 this.externalDBsByName.get(d.getDBName()).add(d); 526 } 527 } 528 529 this.externalDBsInitialized = true; 530 } 531 532 @Override 533 public ExternalDB getExternalDB(Integer id) { 534 this.initializeExternalDBs(); 535 return this.externalDBsByID.get(id); 536 } 537 538 @Override 539 public String getAssemblyName() { 540 if (assemblyName == null) { 541 try { 542 this.lazyLoadMetadata(); 543 } catch (DAOException e) { 544 //probably should throw this 545 } 546 } 547 return assemblyName; 548 } 549 550 @Override 551 public String getComparaName() { 552 if (comparaName == null) { 553 try { 554 this.lazyLoadMetadata(); 555 } catch (DAOException e) { 556 //probably should throw this 557 } 558 } 559 return comparaName; 560 } 561 562 @Override 563 public String getAssemblyAccession() { 564 if (assemblyAccession == null) { 565 try { 566 this.lazyLoadMetadata(); 567 } catch (DAOException e) { 568 //probably should throw this 569 } 570 } 571 return assemblyAccession; 572 } 573 574 public void lazyLoadMetadata() throws DAOException { 575 this.getRegistry().setSpeciesMetadata(this); 576 if (assemblyName==null) {assemblyName ="";} 577 if (assemblyAccession==null) {assemblyAccession ="";} 578 if (comparaName==null) {comparaName ="";} 579 } 580 581 @Override 582 public void setAssemblyName(String value) { 583 assemblyName = value; 584 } 585 586 @Override 587 public void setAssemblyAccession(String value) { 588 assemblyAccession = value; 589 } 590 591 @Override 592 public void setComparaName(String value) { 593 comparaName = value; 594 } 595 596 597}