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.datasourceaware.core; 023 024import java.util.*; 025import org.biojava3.core.sequence.DNASequence; 026import org.biojava3.core.sequence.ProteinSequence; 027import org.biojava3.core.sequence.RNASequence; 028import org.biojava3.core.sequence.transcription.TranscriptionEngine; 029import org.slf4j.Logger; 030import org.slf4j.LoggerFactory; 031import uk.ac.roslin.ensembl.config.DBConnection; 032import uk.ac.roslin.ensembl.config.EnsemblCoreObjectType; 033import uk.ac.roslin.ensembl.config.ExternalDBType; 034import uk.ac.roslin.ensembl.datasourceaware.DAXRef; 035import uk.ac.roslin.ensembl.exception.DAOException; 036import uk.ac.roslin.ensembl.exception.RangeException; 037import uk.ac.roslin.ensembl.model.Coordinate.Strand; 038import uk.ac.roslin.ensembl.model.*; 039import uk.ac.roslin.ensembl.model.core.ProteinFeature; 040import uk.ac.roslin.ensembl.model.core.Transcript; 041import uk.ac.roslin.ensembl.model.core.Translation; 042import uk.ac.roslin.ensembl.model.core.VegaFeature; 043 044public class DATranslation extends DACoreObject implements Translation, XRefed, VegaFeature { 045 046 DATranscript transcript = null; 047 List<? extends ProteinFeature> proteinFeatures = null; 048 private boolean canonical = false; 049 private DAExon firstExon = null; 050 private Integer firstExonID = null; 051 private DAExon lastExon = null; 052 private Integer lastExonID = null; 053 private Integer firstExonStart = null; 054 private Integer lastExonEnd = null; 055 private Integer transcriptID = null; 056 private DNASequence translatedSequence = null; 057 /** 058 * Each Mapping in this TreeSet has 059 * source: null (implicitly the translated sequence) 060 * sourceCoordinates: the coordinate on the translated sequence - including 061 * any 1 or 2 residue shift due to Exon1 phase issues. 062 * target: the (unprocessed) primaryTranscript specifying this Translation 063 * targetCoordinates: the coordinates on the (unprocessed) pimaryTranscript 064 */ 065 MappingSet translationMappings = null; 066 final static Logger LOGGER = LoggerFactory.getLogger(DATranslation.class); 067 private String vegaProteinID = null; 068 protected Set<DAXRef> xrefs = new HashSet<DAXRef>(); 069 protected HashMap<ExternalDBType, Set<DAXRef>> typedXRefs = new HashMap<ExternalDBType, Set<DAXRef>>(); 070 boolean xrefsInitialized = false; 071 private boolean initialized; 072 private TreeSet<String> synonyms = null; 073 074 /* 075 * Temporarily just a demo function... 076 */ 077 @Override 078 public List<? extends ProteinFeature> getProteinFeatures() { 079 if (proteinFeatures == null) { 080 081 if (this.getId() == null) { 082 return null; 083 } 084 085 try { 086 proteinFeatures = this.getDaoFactory().getProteinFeatureDAO().getProteinFeaturesByTranslationID(this.id); 087 } catch (DAOException dex) { 088 LOGGER.info("failed to get Protein Features", dex); 089 } catch (Exception ex) { 090 LOGGER.info("failed to get Protein Features", ex); 091 } 092 093 } 094 return proteinFeatures; 095 } 096 097 @Override 098 public DATranscript getTranscript() { 099 //v1.15 previously Translations were only instantiated by the MyBatis/DAO mapping 100 //TranslationDAO.getTranslationsForTranscript(Transcript transcript) 101 //and therefor the transcript were set on all translations 102 //now we have the ability to retrieve a transaltion by stableID from a species 103 //so we need to be able to load the transcript for this 104 105 if (transcript!=null) { 106 return transcript; 107 } 108 this.reinitialize(); 109 if (this.transcriptID!=null && this.getDaoFactory()!= null) { 110 try { 111 transcript = (DATranscript) this.getDaoFactory().getTranscriptDAO().getTranscriptByID(this.transcriptID); 112 } catch (DAOException ex) { 113 LOGGER.info("Threw DAOException on trying to get Transcript: "+this.transcriptID, ex); 114 } 115 } 116 117 return transcript; 118 } 119 120 public boolean isInitialized() { 121 return initialized; 122 } 123 124 public void setInitialized(boolean init) { 125 this.initialized = init; 126 } 127 128 void reinitialize() { 129 if (this.isInitialized()) { 130 return; 131 } 132 try { 133 //nb getDaoFactory() will try and make a factory if we have at least species and ensembl version 134 this.getDaoFactory().getTranslationDAO().reInitialize(this); 135 136 } catch (Exception ex) { 137 LOGGER.info("Failed to reinitialize the Gene from the Database (using its stableID: " 138 +this.stableID+").", ex); 139 } finally { 140 //always set this so dont try again 141 this.setInitialized(true); 142 } 143 } 144 145 @Override 146 public void setTranscript(Transcript transcript) { 147 this.transcript = (DATranscript) transcript; 148 } 149 150 @Override 151 public ObjectType getType() { 152 return EnsemblCoreObjectType.translation; 153 } 154 155 /** 156 * Returns whether this Translation is marked as the Canonical Translation for 157 * its transcript. (Prior to Ensembl57 there was a single translation object 158 * for each transcript, which is considered as canonical.) 159 */ 160 public boolean isCanonical() { 161 return canonical; 162 } 163 164 public void setCanonical(boolean canonical) { 165 this.canonical = canonical; 166 } 167 168 /** 169 * Returns the internal database ID of the first Exon for this translation. 170 */ 171 public Integer getFirstExonID() { 172 return firstExonID; 173 } 174 175 public void setFirstExonID(Integer firstExonID) { 176 this.firstExonID = firstExonID; 177 } 178 179 /** 180 * Returns the (relative) position of the translational start in the first exon of this Translation. 181 */ 182 public Integer getFirstExonStart() { 183 return firstExonStart; 184 } 185 186 public void setFirstExonStart(Integer firstExonStart) { 187 this.firstExonStart = firstExonStart; 188 } 189 190 /** 191 * Returns the internal database ID of the last Exon for this translation. 192 */ 193 public Integer getLastExonID() { 194 return lastExonID; 195 } 196 197 public void setLastExonID(Integer lastExonID) { 198 this.lastExonID = lastExonID; 199 } 200 201 @Override 202 public String getStableID() { 203 return stableID; 204 } 205 206 @Override 207 public void setStableID(String stableID) { 208 this.stableID = stableID; 209 } 210 211 /** 212 * Returns the first Exon of this Translation. 213 */ 214 public DAExon getFirstExon() { 215 if (this.firstExon != null) { 216 return this.firstExon; 217 } 218 219 for (DAExon e : this.getTranscript().getExons()) { 220 if (e.getId().equals(this.getFirstExonID())) { 221 this.firstExon = e; 222 } 223 if (e.getId().equals(this.getLastExonID())) { 224 this.lastExon = e; 225 } 226 } 227 return firstExon; 228 } 229 230 /** 231 * Gets the Gene associated with this Translation via the associated Transcript. 232 */ 233 public DAGene getGene() { 234 if (this.getTranscript() != null) { 235 return this.getTranscript().getGene(); 236 } else { 237 return null; 238 } 239 } 240 241 /** 242 * Returns the last Exon of this Translation. 243 */ 244 public DAExon getLastExon() { 245 246 if (this.lastExon != null) { 247 return this.lastExon; 248 } 249 250 for (DAExon e : this.getTranscript().getExons()) { 251 if (e.getId().equals(this.getFirstExonID())) { 252 this.firstExon = e; 253 } 254 if (e.getId().equals(this.getLastExonID())) { 255 this.lastExon = e; 256 } 257 } 258 return lastExon; 259 260 } 261 262 263 /** 264 * Returns the (relative) position of the translational end in the last exon 265 * of this Translation. This is inclusive of the stop codon. 266 */ 267 public Integer getLastExonEnd() { 268 return lastExonEnd; 269 } 270 271 public void setLastExonEnd(Integer lastExonEnd) { 272 this.lastExonEnd = lastExonEnd; 273 } 274 275 /** 276 * Returns a (BioJava) ProteinSequence for this Translation using the specified 277 * Codon Table ID to retrieve the appropriate (BioJava) TranscriptionEngine. 278 */ 279 public ProteinSequence getProteinSequence(Integer codonTable) { 280 /* 281 * By default BioJava uses a Transcription engine singleton that uses 282 * the universal codon table, we can create alternative codon usage 283 * engines from the common IDed tables 284 * 1 - UNIVERSAL 285 * 2 - VERTEBRATE_MITOCHONDRIAL 286 * 3 - YEAST_MITOCHONDRIAL 287 * 4 - MOLD_MITOCHONDRIAL 288 * 5 - INVERTEBRATE_MITOCHONDRIAL 289 * 6 - CILIATE_NUCLEAR 290 * 9 - ECHINODERM_MITOCHONDRIAL 291 * 10 - EUPLOTID_NUCLEAR 292 * 11 - BACTERIAL 293 * 12 - ALTERNATIVE_YEAST_NUCLEAR 294 * 13 - ASCIDIAN_MITOCHONDRIAL 295 * 14 - FLATWORM_MITOCHONDRIAL 296 * 15 - BLEPHARISMA_MACRONUCLEAR 297 * 16 - 2CHLOROPHYCEAN_MITOCHONDRIAL 298 * 21 - TREMATODE_MITOCHONDRIAL 299 * 23 - SCENEDESMUS_MITOCHONDRIAL 300 */ 301 return this.getProteinSequence(this.getRegistry().getTranscriptionEngine(codonTable)); 302 } 303 304 /** 305 * Returns a (BioJava) ProteinSequence for this Translation using the specified (BioJava) 306 * TranscriptionEngine. 307 * 308 */ 309 public ProteinSequence getProteinSequence(TranscriptionEngine trancriptionEngine) { 310 311 if (trancriptionEngine == null) { 312 return null; 313 } 314 315 if (this.translatedSequence == null) { 316 this.translate(); 317 } 318 319 if (this.translatedSequence != null 320 && this.translatedSequence.getLength() > 2) { 321 //vanilla BioJava Translation 322 //a bug in BioJava-core 3.0 which fails to translate some codons with N in, needs shift up to v3.0.3 323 return this.translatedSequence.getRNASequence(trancriptionEngine).getProteinSequence(trancriptionEngine); 324 325 } else { 326 return null; 327 } 328 } 329 330 /** 331 * Returns a (BioJava) ProteinSequence for this Translation. IF possible it will use a 332 * TranscriptionEngine configured to use the Codon table specified by the annotated Chromosome. 333 * Otherwise it will use the default Universal codon table. 334 * 335 */ 336 @Override 337 public ProteinSequence getProteinSequence() { 338 339 Integer codonTable = 1; 340 341 if (this.getTranscript() != null) { 342 343 try { 344 codonTable = this.getTranscript().getTargetSequence().getCodonTableID(); 345 } catch (Exception ex) { 346 } 347 } 348 //if no codon_table attribute has been set for the DNASequence we just use the defualt 349 return this.getProteinSequence(this.getRegistry().getTranscriptionEngine(codonTable)); 350 } 351 352 /** 353 * Convenience method to get the Amino Acid sequence of the protein product of 354 * this translation. Wraps BioJava ProteinSequence functionality. Note that no 355 * terminator (*) is appended. 356 * 357 */ 358 public String getProteinSequenceAsString() { 359 return this.getProteinSequence().getSequenceAsString(); 360 } 361 362 /** 363 * Convenience method to get the Amino Acid sequence of the protein product of 364 * this translation. Wraps BioJava ProteinSequence functionality, using the specified 365 * Codon Table ID to retrieve the appropriate (BioJava) TranscriptionEngine. 366 * Note that no terminator (*) is appended. 367 * @param codonTable 368 * 369 */ 370 public String getProteinSequenceAsString(Integer codonTable) { 371 return this.getProteinSequence(codonTable).getSequenceAsString(); 372 } 373 374 /** 375 * Convenience method to get the Amino Acid sequence of the protein product of 376 * this translation. Wraps BioJava ProteinSequence functionality, using the specified 377 * (BioJava) TranscriptionEngine. Note that no terminator (*) is appended. 378 * @param trancriptionEngine 379 * 380 */ 381 public String getProteinSequenceAsString(TranscriptionEngine trancriptionEngine) { 382 return this.getProteinSequence(trancriptionEngine).getSequenceAsString(); 383 } 384 385 /** 386 * Convenience method to get the Amino Acid sequence of the given range of the 387 * protein product of this translation. Wraps BioJava ProteinSequence functionality. 388 * Note that terminators (*) will be appended for positions beyond the end of the peptide, 389 * but within the translation (i.e. stop codons). 390 * @param start 391 * @param end 392 * @throws RangeException if position does not lie within the peptide and stop codons. 393 * 394 */ 395 public String getProteinSequenceAsString(Integer start, Integer end) { 396 397 org.biojava3.core.sequence.Strand strand = org.biojava3.core.sequence.Strand.POSITIVE; 398 if (start!=null && end !=null && start>end) { 399 //Integers are assigned by value not as pointers 400 Integer temp = end; 401 end = start; 402 start = temp; 403 strand = org.biojava3.core.sequence.Strand.NEGATIVE; 404 } 405 406 if (start==null || start<1 407 || end == null || end < 1 || 3*end > this.getLength()) { 408 throw new RangeException("An amino acid position must lie between 1 and the length of the peptide. "); 409 } 410 411 String stop = ""; 412 413 if (start > this.getProteinSequence().getLength() ) { 414 return GapSequence.getGapString((end-start)+1, '*'); 415 } 416 417 418 for (int i=0; i<end-this.getProteinSequence().getLength();i++) { 419 stop += "*"; 420 } 421 end -= stop.length(); 422 if (org.biojava3.core.sequence.Strand.NEGATIVE.equals(strand)) { 423 return stop+this.getProteinSequence().getSequenceAsString(start,end,strand); 424 } 425 return this.getProteinSequence().getSequenceAsString(start,end,org.biojava3.core.sequence.Strand.POSITIVE)+stop; 426 } 427 428 /** 429 * Convenience method to get the Amino Acid sequence of the given range of the 430 * protein product of this translation. 431 * Wraps BioJava ProteinSequence functionality, using the specified 432 * Codon Table ID to retrieve the appropriate (BioJava) TranscriptionEngine. 433 * For 'start'>'end' the amino acid sequence will be written in reverse. 434 * Note that terminators (*) will be appended for positions beyond the end of the peptide, 435 * but within the translation (i.e. stop codons). 436 * @param start 437 * @param end 438 * @throws RangeException if position does not lie within the peptide 439 * 440 */ 441 public String getProteinSequenceAsString(Integer codonTable, Integer start, Integer end) { 442 443 org.biojava3.core.sequence.Strand strand = org.biojava3.core.sequence.Strand.POSITIVE; 444 if (start!=null && end !=null && start>end) { 445 //Integers are assigned by value not as pointers 446 Integer temp = end; 447 end = start; 448 start = temp; 449 strand = org.biojava3.core.sequence.Strand.NEGATIVE; 450 } 451 452 if (start==null || start<1 453 || end == null || end < 1 || 3*end > this.getLength()) { 454 throw new RangeException("An amino acid position must lie between 1 and the length of the peptide. "); 455 } 456 457 if (start > this.getProteinSequence(codonTable).getLength() ) { 458 return GapSequence.getGapString((end-start)+1, '*'); 459 } 460 String stop = ""; 461 for (int i=0; i<end-this.getProteinSequence(codonTable).getLength();i++) { 462 stop += "*"; 463 } 464 end -= stop.length(); 465 466 if (org.biojava3.core.sequence.Strand.NEGATIVE.equals(strand)) { 467 return stop+this.getProteinSequence(codonTable).getSequenceAsString(start,end,strand); 468 } 469 return this.getProteinSequence(codonTable).getSequenceAsString(start,end,org.biojava3.core.sequence.Strand.POSITIVE)+stop; 470 471 } 472 473 /** 474 * Convenience method to get the Amino Acid sequence of the given range of the 475 * protein product of this translation. 476 * Wraps BioJava ProteinSequence functionality, using the specified 477 * (BioJava) TranscriptionEngine. 478 * For 'start'>'end' the amino acid sequence will be written in reverse. 479 * Note that terminators (*) will be appended for positions beyond the end of the peptide, 480 * but within the translation (i.e. stop codons). 481 * @param start 482 * @param end 483 * @throws RangeException if position does not lie within the peptide 484 * 485 */ 486 public String getProteinSequenceAsString(TranscriptionEngine trancriptionEngine, Integer start, Integer end) { 487 488 org.biojava3.core.sequence.Strand strand = org.biojava3.core.sequence.Strand.POSITIVE; 489 if (start!=null && end !=null && start>end) { 490 //Integers are assigned by value not as pointers 491 Integer temp = end; 492 end = start; 493 start = temp; 494 strand = org.biojava3.core.sequence.Strand.NEGATIVE; 495 } 496 497 if (start==null || start<1 498 || end == null || end < 1 || 3*end > this.getLength()) { 499 throw new RangeException("An amino acid position must lie between 1 and the length of the peptide. "); 500 } 501 502 if (start > this.getProteinSequence(trancriptionEngine).getLength() ) { 503 return GapSequence.getGapString((end-start)+1, '*'); 504 } 505 506 String stop = ""; 507 for (int i=0; i<end-this.getProteinSequence(trancriptionEngine).getLength();i++) { 508 stop += "*"; 509 } 510 end -= stop.length(); 511 512 if (org.biojava3.core.sequence.Strand.NEGATIVE.equals(strand)) { 513 return stop+this.getProteinSequence(trancriptionEngine).getSequenceAsString(start,end,strand); 514 } 515 516 return this.getProteinSequence(trancriptionEngine).getSequenceAsString(start,end,org.biojava3.core.sequence.Strand.POSITIVE)+stop; 517 } 518 519 /** 520 * Returns a String representation of this Translation ( i.e. the DNA Sequence...). 521 * 522 */ 523 public String getTranslatedSequenceAsString() { 524 525 if (translatedSequence == null) { 526 this.translate(); 527 } 528 529 if (translatedSequence != null) { 530 return translatedSequence.getSequenceAsString(); 531 } else { 532 return ""; 533 } 534 } 535 536 /** 537 * Returns a String representation of this Translation for the given range 538 * (i.e. the DNA Sequence...). 539 * @param start 540 * @param stop 541 * 542 * @throws RangeException 543 * @throws IllegalArgumentException 544 */ 545 public String getTranslatedSequenceAsString(Integer start, Integer stop) throws RangeException, IllegalArgumentException { 546 547 if (start == null || start== 0 ) { 548 throw new IllegalArgumentException("Translated sequence begins at +1."); 549 } 550 551 if (translatedSequence == null) { 552 this.translate(); 553 } 554 555 if (translatedSequence != null) { 556 if ( stop > translatedSequence.getLength()) { 557 throw new RangeException("Specified end is beyond ends of translation."); 558 } 559 //the translated sequence object is a BioJava DNASequence object so we call its methods directly 560 return translatedSequence.getSequenceAsString(start,stop,org.biojava3.core.sequence.Strand.POSITIVE); 561 } else { 562 return ""; 563 } 564 } 565 566 /** 567 * Returns the mapped position of a translation (nucleotide) position on the unprocessed 568 * primary transcript that provides this translation. 569 * @param translationBase a nucleotide position on the translated sequence 570 * 571 */ 572 public Integer getPrimaryTranscriptPositionFromBASE(Integer translationBase) { 573 574 Integer result = null; 575 if (translationMappings == null) { 576 this.translate(); 577 } 578 579 if (translationMappings != null && !translationMappings.isEmpty()) { 580 581 if (translationBase<1) { 582 result = translationMappings.first().getTargetCoordinates().getStart()+translationBase; 583 if (result<1 && translationMappings.first().getTargetCoordinates().getStart()>0 ) { 584 result--; 585 } 586 return result; 587 } 588 if (translationBase > translationMappings.last().getSourceCoordinates().getEnd()) { 589 result = translationMappings.last().getTargetCoordinates().getEnd()+ 590 translationBase - translationMappings.last().getSourceCoordinates().getEnd(); 591 return result; 592 } 593 594 for (Mapping m : translationMappings) { 595 if (m.getSourceCoordinates().containsPoint(translationBase)) { 596 Integer offset = translationBase-m.getSourceCoordinates().getStart(); 597 return m.getTargetCoordinates().getStart()+offset; 598 } 599 } 600 } 601 return result; 602 } 603 604 /** 605 * Returns the mapped position of a translation (nucleotide) position on the (spliced) processed 606 * transcript that provides this translation. Querying for upstream or downstream positions 607 * is unreliable, and may return null if falling within an intron. 608 * @param translationBase a nucleotide position on the translated sequence 609 * 610 */ 611 public Integer getProcessedTranscriptPositionFromBASE(Integer translationBase) throws DAOException { 612 613 Integer result = null; 614 Integer primaryT = this.getPrimaryTranscriptPositionFromBASE(translationBase); 615 616 if (primaryT != null && this.getTranscript()!=null) { 617 result = this.getTranscript().convertPrimaryToProcessedTranscriptPosition(primaryT); 618 } 619 620 return result; 621 } 622 623 /** 624 * Returns the mapped chromosomal position of a translation (nucleotide) position. 625 * @param translationBase a nucleotide position on the translated sequence 626 * 627 * @throws DAOException 628 */ 629 public Integer getChromosomePositionFromBASE(Integer translationBase) throws DAOException { 630 631 Integer result = null; 632 Integer primaryT = this.getPrimaryTranscriptPositionFromBASE(translationBase); 633 634 if (primaryT != null) { 635 result = this.getTranscript().convertPrimaryTranscriptPositionToChromosome(primaryT); 636 } 637 638 return result; 639 } 640 641 /** 642 * Returns the mapped coordinates of an amino acid position on the unprocessed 643 * primary transcript that provides this translation. 644 * @param aminoAcidPosition 645 * 646 * @throws RangeException if position does not lie within the peptide 647 */ 648 public Coordinate getPrimaryTranscriptPositionFromAA(Integer aminoAcidPosition) throws RangeException { 649 650 if (aminoAcidPosition==null || aminoAcidPosition<1 || 3*aminoAcidPosition>this.getLength()) { 651 throw new RangeException("An amino acid position must lie between 1 and the length of the peptide. "); 652 } 653 654 Strand strand = null; 655 try { 656 strand = this.getTranscript().getTopLevelTargetCoordinates().getStrand(); 657 } catch (Exception ex) { 658 659 } 660 661 Integer start = getPrimaryTranscriptPositionFromBASE(3*aminoAcidPosition-2); 662 Integer end = getPrimaryTranscriptPositionFromBASE(3*aminoAcidPosition); 663 if (end ==null || start ==null ) { 664 return null; 665 } 666 return new Coordinate(start,end,strand); 667 } 668 669 /** 670 * Returns the mapped coordinates of an amino acid position on the (spliced) processed 671 * transcript that provides this translation. Querying for upstream or downstream positions 672 * is unreliable, and may return null if falling within an intron. 673 * @param aminoAcidPosition 674 * 675 * @throws RangeException if position does not lie within the peptide 676 */ 677 public Coordinate getProcessedTranscriptPositionFromAA(Integer aminoAcidPosition) throws DAOException,RangeException { 678 if (aminoAcidPosition==null || aminoAcidPosition<1 || aminoAcidPosition>3*this.getLength()) { 679 throw new RangeException("An amino acid position must lie between 1 and the length of the peptide. "); 680 } 681 Strand strand = null; 682 try { 683 strand = this.getTranscript().getTopLevelTargetCoordinates().getStrand(); 684 } catch (Exception ex) { 685 686 } 687 Integer start = getProcessedTranscriptPositionFromBASE(3*aminoAcidPosition-2); 688 Integer end = getProcessedTranscriptPositionFromBASE(3*aminoAcidPosition); 689 if (end ==null || start ==null ) { 690 return null; 691 } 692 return new Coordinate(start,end,strand); 693 } 694 695 /** 696 * Returns the mapped chromosomal coordinates of an amino acid position. 697 * @param aminoAcidPosition 698 * 699 * @throws DAOException 700 * @throws RangeException if position does not lie within the peptide 701 */ 702 public Coordinate getChromosomePositionFromAA(Integer aminoAcidPosition) throws DAOException,RangeException { 703 if (aminoAcidPosition==null || aminoAcidPosition<1 || 3*aminoAcidPosition>this.getLength()) { 704 throw new RangeException("An amino acid position must lie between 1 and the length of the peptide. "); 705 } 706 Strand strand = null; 707 try { 708 strand = this.getTranscript().getTopLevelTargetCoordinates().getStrand(); 709 } catch (Exception ex) { 710 711 } 712 Integer start = getChromosomePositionFromBASE(3*aminoAcidPosition-2); 713 Integer end = getChromosomePositionFromBASE(3*aminoAcidPosition); 714 if (end ==null || start ==null ) { 715 return null; 716 } 717 return new Coordinate(start,end,strand); 718 } 719 720 /** 721 * Returns the nucleotide position on this translation sequence for a given 722 * Chromosomal Position 723 * @param chromosomePosition 724 * 725 */ 726 public Integer getBasePositionFromChromosome(Integer chromosomePosition) { 727 728 DATranscript primTranscript = this.getTranscript(); 729 730 if (primTranscript == null) { 731 return null; 732 } 733 734 if (this.translationMappings == null) { 735 this.translate(); 736 } 737 738 if (this.translatedSequence == null 739 || this.translatedSequence.getLength() <1 || translationMappings==null) { 740 return null; 741 } 742 743 Integer primTPos = primTranscript.convertChromosomeToPrimaryTranscriptPosition(chromosomePosition); 744 745 if (primTPos<1 || primTPos>primTranscript.getLength()) { 746 return null; 747 } 748 return getBasePositionFromPrimaryTranscript(primTPos); 749 } 750 751 /** 752 * Returns the nucleotide position on this translation sequence for a given 753 * primary Transcript position 754 * @param primaryTranscriptPosition 755 * 756 */ 757 public Integer getBasePositionFromPrimaryTranscript(Integer primaryTranscriptPosition) { 758 759 if (primaryTranscriptPosition==null || primaryTranscriptPosition==0) { 760 throw new IllegalArgumentException("Zero is not a valid position."); 761 } 762 763 if (this.getTranscript() == null) { 764 return null; 765 } 766 767 if (this.translationMappings == null) { 768 this.translate(); 769 } 770 771 if (this.translatedSequence == null 772 || this.translatedSequence.getLength() <1 || translationMappings==null ) { 773 return null; 774 } 775 776 for (Mapping m: translationMappings) { 777 if (m.getTargetCoordinates().containsPoint(primaryTranscriptPosition)) { 778 Integer offset = primaryTranscriptPosition-m.getTargetCoordinates().getStart(); 779 return m.getSourceCoordinates().getStart()+offset; 780 } 781 } 782 783 return null; 784 } 785 786 /** 787 * Returns the nucleotide position on this translation sequence for a given 788 * processed (spliced) transcript position. 789 * @param processedTranscriptPosition 790 * 791 */ 792 public Integer getBasePositionFromProcessedTranscript(Integer processedTranscriptPosition) { 793 794 DATranscript primTranscript = this.getTranscript(); 795 796 if (primTranscript == null) { 797 return null; 798 } 799 800 if (this.translationMappings == null) { 801 this.translate(); 802 } 803 804 if (this.translatedSequence == null 805 || this.translatedSequence.getLength() <1 || translationMappings==null) { 806 return null; 807 } 808 Integer primTPos = null; 809 810 try { 811 primTPos = primTranscript.convertProcessedToPrimaryTranscriptPosition(processedTranscriptPosition); 812 } catch (DAOException ex) { 813 return null; 814 } 815 816 if (primTPos ==null || primTPos<1 || primTPos>primTranscript.getLength()) { 817 return null; 818 } 819 820 return getBasePositionFromPrimaryTranscript(primTPos); 821 } 822 823 /** 824 * Returns the amino acid position on this translation for a given 825 * Chromosomal Position 826 * @param chromosomePosition 827 * 828 */ 829 public Integer getAAPositionFromChromosome(Integer chromosomePosition) { 830 831 Integer transPosition = this.getBasePositionFromChromosome(chromosomePosition); 832 833 if (transPosition==null || transPosition <1 || transPosition> this.getLength()) { 834 return null; 835 } 836 837 Integer two = 2; 838 Integer three = 3; 839 return (transPosition+two)/three; 840 } 841 842 /** 843 * Returns the amino acid position on this translation for a given 844 * Primary Transcript Position 845 * @param primaryTranscriptPosition 846 * 847 */ 848 public Integer getAAPositionFromPrimaryTranscript(Integer primaryTranscriptPosition) { 849 Integer transPosition = this.getBasePositionFromPrimaryTranscript(primaryTranscriptPosition); 850 851 if (transPosition==null || transPosition <1 || transPosition> this.getLength()) { 852 return null; 853 } 854 855 Integer two = 2; 856 Integer three = 3; 857 return (transPosition+two)/three; 858 } 859 860 /** 861 * Returns the amino acid position on this translation for a given 862 * Processed Transcript Position 863 * @param processedTranscriptPosition 864 * 865 */ 866 public Integer getAAPositionFromProcessedTranscript(Integer processedTranscriptPosition) { 867 Integer transPosition = this.getBasePositionFromProcessedTranscript(processedTranscriptPosition); 868 869 if (transPosition==null || transPosition <1 || transPosition> this.getLength()) { 870 return null; 871 } 872 873 Integer two = 2; 874 Integer three = 3; 875 return (transPosition+two)/three; 876 } 877 878 879 /** 880 * Private method that stitches together the ORF coordinates into a map of 881 * Translation/ORF Coordinate to (unprocessed) primaryTranscript Coordinate, and initializes 882 * a DNASequence object representing this translated sequence. 883 */ 884 private void translate() { 885 886 //note it was easier to stitch together the processedTranscript-->translation map 887 //however this 'lacks' any notion of the introns - so is no good for mapping 888 //back from translation to primaryTranscript 889 890 translationMappings = new MappingSet(); 891 boolean intranslated = false; 892 String seq = ""; 893 894 //If something is wrong and the DNASequence for the Exons cannot be retrieved 895 //the seq is set to GapSequences of lengths based on the exon lengths. 896 897 if (this.getTranscript() == null) { 898 return; 899 } 900 Collection<DAExon> exons = this.getTranscript().getExons(); 901 if (exons == null || exons.isEmpty()) { 902 return; 903 } 904 905 Coordinate topLevelTargetCoordinates = null; 906 try { 907 topLevelTargetCoordinates = this.getTranscript().getTopLevelTargetCoordinates(); 908 } catch (DAOException ex) { 909 translatedSequence = new DNASequence(seq); 910 return; 911 } 912 913 if (topLevelTargetCoordinates==null || topLevelTargetCoordinates.getEnd()==null 914 || topLevelTargetCoordinates.getStart()==null) { 915 translatedSequence = new DNASequence(seq); 916 return; 917 } 918 919 Strand strand = topLevelTargetCoordinates.getStrand(); 920 921 Integer chromosomalStart; 922 if (Strand.REVERSE_STRAND.equals(strand)) { 923 chromosomalStart = topLevelTargetCoordinates.getEnd(); 924 } else { 925 chromosomalStart = topLevelTargetCoordinates.getStart(); 926 } 927 928 Integer transcriptPosition=0; 929 930 for (DAExon ex : exons) { 931 932 if (Strand.REVERSE_STRAND.equals(strand)) { 933 transcriptPosition = chromosomalStart - ex.convertToTargetPosition(1) + 1; 934 } else { 935 transcriptPosition = ex.convertToTargetPosition(1) - chromosomalStart + 1; 936 } 937 938 939 if (!intranslated && ex.getId().equals(this.getFirstExonID())) { 940 941 Coordinate transcript ; 942 Coordinate translation ; 943 944 945 intranslated = true; 946 947 //case of a single exon translation 948 if (ex.getId().equals(this.getLastExonID())) { 949 try { 950// if (Strand.REVERSE_STRAND.equals(strand)) { 951// seq = ex.getSequence().getReverseComplementSequenceAsString( ex.getLength() - this.getLastExonEnd() + 1, ex.getLength()-this.getFirstExonStart() + 1); 952// } else { 953// seq = ex.getSequence().getSequenceAsString(this.getFirstExonStart(), this.getLastExonEnd()); 954// } 955 seq = ex.getSequenceAsString(this.getFirstExonStart(), this.getLastExonEnd()); 956 } catch (Exception e) { 957 seq = GapSequence.getGapString( this.getLastExonEnd()- this.getFirstExonStart()+1); 958 } 959 Mapping m = new Mapping(); 960 m.setTarget(this.getTranscript()); 961 962 //case where we are missing one or two 5'bases for the correct phase 963 if (ex.getPhase() == 1) { 964 seq = "N" + seq; 965 translation = new Coordinate(1+ex.getPhase(), seq.length()+ex.getPhase()); 966 } else if (ex.getPhase() == 2) { 967 seq = "NN" + seq; 968 translation = new Coordinate(1+ex.getPhase(), seq.length()+ex.getPhase()); 969 } else { 970 translation = new Coordinate(1, seq.length()); 971 } 972 transcript = new Coordinate(transcriptPosition+this.getFirstExonStart()-1,transcriptPosition+this.getLastExonEnd()-1); 973 m.setSourceCoordinates(translation); 974 m.setTargetCoordinates(transcript); 975 translationMappings.add(m); 976 977 break; 978 } 979 try { 980// if (Strand.REVERSE_STRAND.equals(strand)) { 981// 982// System.out.println("ex.getSequenceAsString(1,30): "+ex.getSequenceAsString(1,30)); 983// System.out.println("ex.getSequence().getSequenceAsString(1,30): "+ex.getSequence().getSequenceAsString(1,30)); 984// System.out.println("ex.getSequence().getReverseComplementSequenceAsString(1,30): "+ex.getSequence().getReverseComplementSequenceAsString(1,30)); 985// 986// seq = ex.getSequence().getReverseComplementSequenceAsString(1, ex.getLength() - this.getFirstExonStart() + 1); 987// } else { 988// seq = ex.getSequence().getSequenceAsString(this.getFirstExonStart(), ex.getSequence().getLength()); 989// } 990 seq = ex.getSequenceAsString(this.getFirstExonStart(), ex.getLength()); 991 } catch (Exception e) { 992 seq = GapSequence.getGapString( ex.getLength() - this.getFirstExonStart()+1); 993 } 994 Mapping m = new Mapping(); 995 m.setTarget(this.getTranscript()); 996 997 //case where we are missing one or two 5'bases for the correct phase 998 if (ex.getPhase() == 1) { 999 seq = "N" + seq; 1000 //correct the mapping coordinate...by adding the shift 1001 translation = new Coordinate(1+ex.getPhase(),seq.length()+ex.getPhase()); 1002 } else if (ex.getPhase() == 2) { 1003 seq = "NN" + seq; 1004 translation = new Coordinate(1+ex.getPhase(),seq.length()+ex.getPhase()); 1005 } else { 1006 translation = new Coordinate(1,seq.length()); 1007 } 1008 1009 transcript = new Coordinate(transcriptPosition+this.getFirstExonStart()-1,transcriptPosition+ex.getLength()-1); 1010 //transcriptPosition =transcriptPosition+ ex.getLength()-1; 1011 m.setSourceCoordinates(translation); 1012 m.setTargetCoordinates(transcript); 1013 translationMappings.add(m); 1014 1015 continue; 1016 } 1017// else if (!intranslated && !ex.getId().equals(this.getFirstExonID())) { 1018// 1019// 1020// continue; 1021// } 1022 1023 else if (intranslated && !ex.getId().equals(this.getLastExonID())) { 1024 Integer start = seq.length()+1; 1025 try { 1026// if (Strand.REVERSE_STRAND.equals(strand)) { 1027// seq = seq.concat(ex.getSequence().getReverseComplementSequenceAsString()); 1028// } else { 1029// seq = seq.concat(ex.getSequence().getSequenceAsString()); 1030// } 1031 seq = seq.concat(ex.getSequenceAsString()); 1032 } catch (Exception e) { 1033 seq = seq.concat(GapSequence.getGapString( ex.getLength())); 1034 } 1035 Mapping m = new Mapping(); 1036 m.setTarget(this.getTranscript()); 1037 1038 Coordinate translation = new Coordinate(start,seq.length()); 1039 Coordinate transcript = new Coordinate(transcriptPosition,transcriptPosition+ex.getLength()-1); 1040 m.setSourceCoordinates(translation); 1041 m.setTargetCoordinates(transcript); 1042 //transcriptPosition=transcriptPosition+ex.getLength()-1; 1043 translationMappings.add(m); 1044 continue; 1045 } 1046 else if (intranslated && ex.getId().equals(this.getLastExonID())) { 1047 Integer start = seq.length()+1; 1048 try { 1049// if (Strand.REVERSE_STRAND.equals(strand)) { 1050// seq = seq.concat(ex.getSequence().getReverseComplementSequenceAsString(ex.getLength()- this.getLastExonEnd() +1 , ex.getLength())); 1051// } else { 1052// seq = seq.concat(ex.getSequence().getSequenceAsString(1,this.getLastExonEnd())); 1053// } 1054 seq = seq.concat(ex.getSequenceAsString(1,this.getLastExonEnd())); 1055 } catch (Exception e) { 1056 seq = seq.concat(GapSequence.getGapString( this.getLastExonEnd())); 1057 } 1058 Mapping m = new Mapping(); 1059 m.setTarget(this.getTranscript()); 1060 1061 Coordinate translation = new Coordinate(start,seq.length()); 1062 Coordinate transcript = new Coordinate(transcriptPosition,transcriptPosition+this.getLastExonEnd()-1); 1063 m.setSourceCoordinates(translation); 1064 m.setTargetCoordinates(transcript); 1065 translationMappings.add(m); 1066 break; 1067 } 1068 else { 1069 //this must be a 5'UTR 1070 //transcriptPosition += ex.getLength()-1; 1071 } 1072 } 1073 translatedSequence = new DNASequence(seq); 1074 } 1075 1076 /** 1077 * Returns the length of the translated nucleotide sequence, i.e. from first 1078 * nucleotide of the start codon to end of the stop codon. 1079 * 1080 */ 1081 public int getLength() { 1082 if (translatedSequence==null) { 1083 this.translate(); 1084 } 1085 if (translatedSequence!= null) { 1086 return translatedSequence.getLength(); 1087 } 1088 return 0; 1089 } 1090 1091 /** 1092 * Returns a DNASequence object representing the translation. 1093 * 1094 */ 1095 public DNASequence getTranslatedSequence() { 1096 if (this.translationMappings==null) { 1097 this.translate(); 1098 } 1099 return translatedSequence; 1100 } 1101 1102 /** 1103 * Returns the Set of Mappings between coordinates on this Translation and 1104 * the Primary transcript. 1105 * 1106 */ 1107 public MappingSet getTranslationMappings() { 1108 if (this.translationMappings==null) { 1109 this.translate(); 1110 } 1111 return this.translationMappings; 1112 } 1113 1114 /** 1115 * Returns a (BioJava) RNASequence for this Translation using the default (BioJava) 1116 * TranscriptionEngine or one assigned to this Gene/Organism. 1117 * 1118 */ 1119 public RNASequence getRNASequence() { 1120 1121 Integer codonTable = 1; 1122 1123 if (this.getTranscript() != null) { 1124 1125 try { 1126 codonTable = this.getTranscript().getTargetSequence().getCodonTableID(); 1127 } catch (Exception ex) { 1128 } 1129 } 1130 if (this.getRegistry()!=null) { 1131 return this.getRNASequence(this.getRegistry().getTranscriptionEngine(codonTable)); 1132 } 1133 //if no Registry we just use BioJava's fallback default engine 1134 return this.getRNASequence(null); 1135 } 1136 1137 /** 1138 * Returns a (BioJava) RNASequence for this Translation using the specified (BioJava) 1139 * TranscriptionEngine or one assigned to this Gene/Organism. 1140 * 1141 */ 1142 public RNASequence getRNASequence(TranscriptionEngine engine) { 1143 if (this.translatedSequence == null) { 1144 this.translate(); 1145 } 1146 if (this.translatedSequence == null) { 1147 return null; 1148 } 1149 if (engine!=null) { 1150 return this.translatedSequence.getRNASequence(engine); 1151 } 1152 //Fallback on BioJava's default 1153 return this.translatedSequence.getRNASequence(); 1154 } 1155 1156 public String getRNASequenceAsString() { 1157 RNASequence rnaSequence = this.getRNASequence(); 1158 if (rnaSequence!=null) { 1159 return rnaSequence.getSequenceAsString(); 1160 } return ""; 1161 } 1162 1163 public String getRNASequenceAsString(TranscriptionEngine engine) { 1164 RNASequence rnaSequence = this.getRNASequence(engine); 1165 if (rnaSequence!=null) { 1166 return rnaSequence.getSequenceAsString(); 1167 } return ""; 1168 } 1169 1170 public String getRNASequenceAsString(Integer start, Integer stop) { 1171 if (start==null || start<1 || stop==null || stop<1 || stop>this.getLength()) { 1172 throw new RangeException("The specified position must lie between 1 and the length of the translation. "); 1173 } 1174 RNASequence rnaSequence = this.getRNASequence(); 1175 if (rnaSequence!=null) { 1176 return rnaSequence.getSequenceAsString(start,stop,org.biojava3.core.sequence.Strand.POSITIVE); 1177 } return ""; 1178 1179 } 1180 1181 public String getRNASequenceAsString(TranscriptionEngine engine, Integer start, Integer stop) { 1182 if (start==null || start<1 || stop==null || stop<1 || stop>this.getLength()) { 1183 throw new RangeException("The specified position must lie between 1 and the length of the translation. "); 1184 } 1185 RNASequence rnaSequence = this.getRNASequence(engine); 1186 if (rnaSequence!=null) { 1187 return rnaSequence.getSequenceAsString(start,stop,org.biojava3.core.sequence.Strand.POSITIVE); 1188 } return ""; 1189 } 1190 1191 /** 1192 * Returns any curated VegaID for the Translation, forcing lazy load if not set, and defaulting 1193 * to an empty string if absent (e.g. for all the invertebrate species in EnsemblGenomes). 1194 * 1195 */ 1196 @Override 1197 public String getVegaID() { 1198 if (this.vegaProteinID!=null) { 1199 return this.vegaProteinID; 1200 } 1201 List<DAXRef> outList = new ArrayList<DAXRef>(); 1202 1203 if (this.getDaoFactory()!= null 1204 && !this.getDaoFactory().getRegistry().getDatasourceType().equals(DBConnection.DataSource.ENSEMBLDB)) { 1205 this.vegaProteinID=""; 1206 this.addTypedXRefs(ExternalDBType.VegaProtein, outList); 1207 return this.vegaProteinID; 1208 } 1209 1210 //?? 1211 this.reinitialize(); 1212 1213 if (this.vegaProteinID==null ) { 1214 1215 if (this.getDaoFactory()!= null ) { 1216 1217 for (DAXRef dax : this.getAllXRefs()) { 1218 if (dax.getPrimaryAccession()!=null 1219 && dax.getPrimaryAccession().startsWith("OTT") 1220 && dax.getDB()!= null 1221 && (dax.getDB().getDBName().equals(ExternalDBType.VegaProtein.toString()) 1222 || 1223 dax.getDB().getDBName().contains("Vega_translation") 1224 || 1225 dax.getDB().getDBName().contains("vega_translation") ) 1226 ) { 1227 outList.add(dax); 1228 } 1229 } 1230 1231 if (outList.isEmpty()) { 1232 this.vegaProteinID = ""; 1233 this.addTypedXRefs(ExternalDBType.VegaProtein, outList); 1234 return this.vegaProteinID; 1235 } else { 1236 //add the factory to the xref - although we shouldn't need to use it as it is fully initialized 1237 for (DAXRef xr: outList) { 1238 xr.setDaoFactory(this.getDaoFactory()); 1239 } 1240 this.addTypedXRefs(ExternalDBType.VegaProtein, outList); 1241 } 1242 1243 if (outList.size()==1) { 1244 this.vegaProteinID = outList.get(0).getPrimaryAccession().trim(); 1245 return this.vegaProteinID; 1246 } else { 1247 //hopefully all the IDs will be the same - but can't guarantee this! 1248 String pre = "Multiple Vega IDs: {"; 1249 boolean multiple = false; 1250 String out = null; 1251 String firstID = ""; 1252 1253 for (XRef x: outList) { 1254 if (out==null) { 1255 out = x.getPrimaryAccession().trim(); 1256 firstID = x.getPrimaryAccession().trim(); 1257 } else if (!firstID.equals(x.getPrimaryAccession().trim())) { 1258 out = out.concat(", ").concat(x.getPrimaryAccession().trim()); 1259 multiple = true; 1260 } 1261 } 1262 if (!multiple) { 1263 vegaProteinID=out; 1264 } else { 1265 out = out.trim().concat("}"); 1266 vegaProteinID = pre.concat(out); 1267 } 1268 return this.vegaProteinID; 1269 } 1270 } 1271 } 1272 return this.vegaProteinID; 1273 } 1274 1275 @Override 1276 public Set<DAXRef> getVegaXRefs() { 1277 this.getVegaID(); 1278 return this.getXRefs(ExternalDBType.VegaProtein); 1279 } 1280 1281 /** 1282 * Returns preloaded XRefs of given type: Note - does not lazy load these. 1283 * @param type 1284 * 1285 */ 1286 protected Set<DAXRef> getXRefs(ExternalDBType type) { 1287 return typedXRefs.get(type); 1288 } 1289 1290 @Override 1291 public Set<DAXRef> getAllXRefs() { 1292 if (this.xrefsInitialized) { 1293 return xrefs; 1294 } 1295 1296 this.reinitialize(); 1297 1298 if (this.getDaoFactory() != null && this.getId() != null) { 1299 List<DAXRef> result = null; 1300 try { 1301 result = (List<DAXRef>) this.getDaoFactory().getXRefDAO().getAllXRefs(this); 1302 1303 } catch (DAOException ex) { 1304 LOGGER.info("Threw DAOException on trying to get Vega ID for Translation: " + this.getStableID(), ex); 1305 } finally { 1306 this.xrefsInitialized = true; 1307 } 1308 1309 if (result == null || result.isEmpty()) { 1310 return xrefs; 1311 } else { 1312 1313 for (DAXRef xr : result) { 1314 //add the factory to the xref - although we shouldn't need to use it as it is fully initialized 1315 xr.setDaoFactory(this.getDaoFactory()); 1316 /* shouldn't be necessary now */ 1317 //check that we are not creating duplicate External DBs... 1318// ExternalDB db = xr.getDB(); 1319// int originalHashCode = db.originalHashCode(); 1320// db = this.getDaoFactory().getDatabase().validateExternalDB(db); 1321// int checkedHashCode = db.originalHashCode(); 1322// if (originalHashCode-checkedHashCode !=0) { 1323// System.out.println("*** FAILED TO REUSE EXTERNALDB"); 1324// } else { 1325// System.out.println("*** successfully reused externaldb"); 1326// } 1327// xr.setDB(db); 1328 xrefs.add(xr); 1329 } 1330 } 1331 } 1332 return xrefs; 1333 } 1334 1335 protected void addTypedXRefs(ExternalDBType type, Collection<? extends XRef> xrefs) { 1336 if ( this.typedXRefs.get(type)==null) { 1337 this.typedXRefs.put(type, new HashSet<DAXRef>()); 1338 } 1339 this.typedXRefs.get(type).addAll((Collection<DAXRef>)xrefs); 1340 } 1341 1342 public Integer getTranscriptID() { 1343 return transcriptID; 1344 } 1345 1346 public void setTranscriptID(Integer transcriptID) { 1347 this.transcriptID = transcriptID; 1348 } 1349 1350 public void setVegaProteinID(String vegaProteinID) { 1351 this.vegaProteinID = vegaProteinID; 1352 } 1353 1354 @Override 1355 public Integer getId() { 1356 if (id==null || id == 0) { 1357 this.reinitialize(); 1358 } 1359 return id; 1360 } 1361 1362 @Override 1363 public Integer getVersion() { 1364 if (version==null) { 1365 this.reinitialize(); 1366 } 1367 return version; 1368 } 1369 1370 @Override 1371 public Date getModificationDate() { 1372 if (modificationDate==null) { 1373 this.reinitialize(); 1374 } 1375 return modificationDate; 1376 } 1377 1378 @Override 1379 public Date getCreationDate() { 1380 if (creationDate==null) { 1381 this.reinitialize(); 1382 } 1383 return creationDate; 1384 } 1385 1386 @Override 1387 public TreeSet<String> getAllSynonyms() { 1388 if (synonyms!=null) { 1389 return synonyms; 1390 } 1391 this.reinitialize(); 1392 try { 1393 synonyms = this.getDaoFactory().getXRefDAO().getAllSynonyms(this); 1394 } catch (DAOException ex) { 1395 LOGGER.debug("Failed to getAllSynonyms for DAFeature", ex); 1396 } 1397 if (synonyms==null) { 1398 synonyms = new TreeSet<String>(); 1399 } 1400 return synonyms; 1401 } 1402 1403 @Override 1404 public TreeSet<String> getSynonyms(XRef xref) { 1405 return xref.getSynonyms(); 1406 } 1407 1408}