From: gmungoc Date: Mon, 12 Sep 2016 08:12:09 +0000 (+0100) Subject: Merge branch 'develop' of https://source.jalview.org/git/jalview.git into develop X-Git-Tag: Release_2_10_0~45^2~3 X-Git-Url: http://source.jalview.org/gitweb/?a=commitdiff_plain;h=2f0ce1f46c5bb22e1db18c27e68b09516958c84d;hp=d6a7a52ed783274ebf338417af48cd931cfba60e;p=jalview.git Merge branch 'develop' of https://source.jalview.org/git/jalview.git into develop --- diff --git a/build.xml b/build.xml index a8b8928..7feacfb 100755 --- a/build.xml +++ b/build.xml @@ -302,7 +302,7 @@ - + @@ -616,16 +616,16 @@ - - + + - - - + + + @@ -642,7 +642,7 @@ - + @@ -654,14 +654,14 @@ - + - - + + + + + + + + diff --git a/examples/exampleFeatures.txt b/examples/exampleFeatures.txt index 689cd43..c0098a9 100755 --- a/examples/exampleFeatures.txt +++ b/examples/exampleFeatures.txt @@ -26,11 +26,11 @@ BETA-TURN-IIL 8b5b50 ST-MOTIF ac25a1 STARTGROUP uniprot +Pfam family FER_CAPAA -1 0 0 Pfam Iron-sulfur (2Fe-2S) FER_CAPAA -1 39 39 METAL Iron-sulfur (2Fe-2S) FER_CAPAA -1 44 44 METAL Iron-sulfur (2Fe-2S) FER_CAPAA -1 47 47 METAL Iron-sulfur (2Fe-2S) FER_CAPAA -1 77 77 METAL -Pfam family FER_CAPAA -1 0 0 Pfam Fer2 Status: True Positive Pfam 8_8 FER_CAPAA -1 8 83 Pfam Ferredoxin_fold Status: True Positive FER_CAPAA -1 3 93 Cath Iron-sulfur (2Fe-2S) FER_CAPAN -1 86 86 METAL diff --git a/help/helpTOC.xml b/help/helpTOC.xml index f5b28f7..a6145c1 100755 --- a/help/helpTOC.xml +++ b/help/helpTOC.xml @@ -107,7 +107,7 @@ - + diff --git a/help/html/calculations/treeviewer.html b/help/html/calculations/treeviewer.html index b45f8fe..c91fe1b 100755 --- a/help/html/calculations/treeviewer.html +++ b/help/html/calculations/treeviewer.html @@ -120,7 +120,7 @@
  • Associate Leaves with ...

    Only visible when there are multiple views of the same alignment to show and edit which alignment views are associated with the leaves of the displayed tree. diff --git a/help/html/features/uniprotqueryfields.html b/help/html/features/uniprotqueryfields.html index 376180a..eaee308 100644 --- a/help/html/features/uniprotqueryfields.html +++ b/help/html/features/uniprotqueryfields.html @@ -27,9 +27,13 @@

    UniProtKB query fields

    -

    Supported query fields for searching specific data in UniProtKB (see also query syntax).

    +

    + Supported query fields for searching specific data in UniProtKB (see + also query + syntax). +

    - +
    diff --git a/help/html/features/uniprotsequencefetcher.html b/help/html/features/uniprotsequencefetcher.html index 77f7b60..ed7cbb7 100644 --- a/help/html/features/uniprotsequencefetcher.html +++ b/help/html/features/uniprotsequencefetcher.html @@ -67,8 +67,8 @@ mnt_mouse).
    Hitting Return or OK will automatically fetch those IDs, like the default Sequence Fetcher interface. -
  • Complex queries with the UniProt query - Syntax The text box also allows complex queries to be entered. +
  • Complex queries with the UniProt query + Syntax The text box also allows complex queries to be entered. The table below provides a brief overview of the supported syntax (see query fields for UniProtKB): diff --git a/help/html/features/viewingpdbs.html b/help/html/features/viewingpdbs.html index e62b2a7..edb3762 100755 --- a/help/html/features/viewingpdbs.html +++ b/help/html/features/viewingpdbs.html @@ -46,7 +46,7 @@
  • Selecting Structures
    You can select - the structures to you want to open and view by selecting them with + the structures that you want to open and view by selecting them with the mouse and keyboard.
    By default, if structures were discovered, then some will already be selected according to the criteria shown in the drop-down menu. The default criteria is @@ -112,9 +112,8 @@ retrieved with this service are derived directly from the PDB 3D structure data, which can be viewed in the same way above. Secondary structure and temperature factor annotation can also be added.
    -

    -

    - Retrieving sequences from the PDB
    Jalview + +
    Jalview will also read PDB files directly - either in PDB format, or mmCIF. Simply load in the file as you would an alignment file. The sequences of any protein or nucleotide chains @@ -161,7 +160,7 @@ wwwPDB. If you prefer (for any reason) to download data as PDB files instead, then first close Jalview, and add the following line to your .jalview_properties file:
    - DEFAULT_STRUCTURE_FORMAT=PDB + PDB_DOWNLOAD_FORMAT=PDB
    When this setting is configured, Jalview will only request PDB format files from EMBL-EBI's PDBe.
    mmCIF format file support was added in Jalview 2.10. diff --git a/help/html/na/index.html b/help/html/na/index.html index de2741b..22ea27e 100644 --- a/help/html/na/index.html +++ b/help/html/na/index.html @@ -79,7 +79,7 @@ td { the alignment will have a secondary structure line shown below it, and a number of additional options become available:

      -
    • RNA +
    • RNA Helix colouring - highlights columns of alignment involved in particular RNA helices, Uses the first displayed secondary structure annotation.
    • diff --git a/help/html/webServices/proteinDisorder.html b/help/html/webServices/proteinDisorder.html index 57e6698..2c98139 100644 --- a/help/html/webServices/proteinDisorder.html +++ b/help/html/webServices/proteinDisorder.html @@ -40,7 +40,7 @@ >sequence features and sequence associated alignment annotation rows. Features display is controlled from - the Feature Settings + the Feature Settings dialog box. Clicking on the ID for a disorder prediction annotation row will highlight or select (if double clicked) the associated sequence for that row. You can also use the Sequence diff --git a/help/html/whatsNew.html b/help/html/whatsNew.html index a74e5b7..407eca3 100755 --- a/help/html/whatsNew.html +++ b/help/html/whatsNew.html @@ -27,8 +27,9 @@ What's new ?

      - Jalview 2.10 is the next major release in the Jalview 2 series. Full details are in the - Jalview 2.10 Release Notes, but the highlights are below. + Jalview 2.10 is the next major release in the Jalview 2 series. Full + details are in the Jalview + 2.10 Release Notes, but the highlights are below.

      Highlights in Jalview 2.10 diff --git a/src/jalview/analysis/AlignmentUtils.java b/src/jalview/analysis/AlignmentUtils.java index d1cd5a3..ea330d8 100644 --- a/src/jalview/analysis/AlignmentUtils.java +++ b/src/jalview/analysis/AlignmentUtils.java @@ -22,7 +22,6 @@ package jalview.analysis; import static jalview.io.gff.GffConstants.CLINICAL_SIGNIFICANCE; -import jalview.api.DBRefEntryI; import jalview.datamodel.AlignedCodon; import jalview.datamodel.AlignedCodonFrame; import jalview.datamodel.AlignedCodonFrame.SequenceToSequenceMapping; @@ -1689,11 +1688,20 @@ public class AlignmentUtils * didn't find mapped CDS sequence - construct it and add * its dataset sequence to the dataset */ - cdsSeq = makeCdsSequence(dnaSeq.getDatasetSequence(), aMapping); - SequenceI cdsSeqDss = cdsSeq.createDatasetSequence(); + cdsSeq = makeCdsSequence(dnaSeq.getDatasetSequence(), aMapping, + dataset).deriveSequence(); + // cdsSeq has a name constructed as CDS| + // will be either the accession for the coding sequence, + // marked in the /via/ dbref to the protein product accession + // or it will be the original nucleotide accession. + SequenceI cdsSeqDss = cdsSeq.getDatasetSequence(); + cdsSeqs.add(cdsSeq); + if (!dataset.getSequences().contains(cdsSeqDss)) { + // check if this sequence is a newly created one + // so needs adding to the dataset dataset.addSequence(cdsSeqDss); } @@ -1705,7 +1713,8 @@ public class AlignmentUtils MapList cdsToProteinMap = new MapList(cdsRange, mapList.getToRanges(), mapList.getFromRatio(), mapList.getToRatio()); AlignedCodonFrame cdsToProteinMapping = new AlignedCodonFrame(); - cdsToProteinMapping.addMap(cdsSeq, proteinProduct, cdsToProteinMap); + cdsToProteinMapping.addMap(cdsSeqDss, proteinProduct, + cdsToProteinMap); /* * guard against duplicating the mapping if repeating this action @@ -1715,23 +1724,8 @@ public class AlignmentUtils mappings.add(cdsToProteinMapping); } - /* - * copy protein's dbrefs to CDS sequence - * this enables Get Cross-References from CDS alignment - */ - DBRefEntry[] proteinRefs = DBRefUtils.selectDbRefs(false, - proteinProduct.getDBRefs()); - if (proteinRefs != null) - { - for (DBRefEntry ref : proteinRefs) - { - DBRefEntry cdsToProteinRef = new DBRefEntry(ref); - cdsToProteinRef.setMap(new Mapping(proteinProduct, - cdsToProteinMap)); - cdsSeqDss.addDBRef(cdsToProteinRef); - } - } - + propagateDBRefsToCDS(cdsSeqDss, dnaSeq.getDatasetSequence(), + proteinProduct, aMapping); /* * add another mapping from original 'from' range to CDS */ @@ -1739,7 +1733,7 @@ public class AlignmentUtils MapList dnaToCdsMap = new MapList(mapList.getFromRanges(), cdsRange, 1, 1); - dnaToCdsMapping.addMap(dnaSeq.getDatasetSequence(), cdsSeq, + dnaToCdsMapping.addMap(dnaSeq.getDatasetSequence(), cdsSeqDss, dnaToCdsMap); if (!mappings.contains(dnaToCdsMapping)) { @@ -1753,12 +1747,37 @@ public class AlignmentUtils * same source and accession, so need a different accession for * the CDS from the dna sequence */ - DBRefEntryI dnaRef = dnaDss.getSourceDBRef(); - if (dnaRef != null) + + // specific use case: + // Genomic contig ENSCHR:1, contains coding regions for ENSG01, + // ENSG02, ENSG03, with transcripts and products similarly named. + // cannot add distinct dbrefs mapping location on ENSCHR:1 to ENSG01 + + // JBPNote: ?? can't actually create an example that demonstrates we + // need to + // synthesize an xref. + + for (DBRefEntry primRef : dnaDss.getPrimaryDBRefs()) { + // creates a complementary cross-reference to the source sequence's + // primary reference. + + DBRefEntry cdsCrossRef = new DBRefEntry(primRef.getSource(), + primRef.getSource() + ":" + primRef.getVersion(), + primRef.getAccessionId()); + cdsCrossRef + .setMap(new Mapping(dnaDss, new MapList(dnaToCdsMap))); + cdsSeqDss.addDBRef(cdsCrossRef); + + // problem here is that the cross-reference is synthesized - + // cdsSeq.getName() may be like 'CDS|dnaaccession' or + // 'CDS|emblcdsacc' // assuming cds version same as dna ?!? - DBRefEntry proteinToCdsRef = new DBRefEntry(dnaRef.getSource(), - dnaRef.getVersion(), cdsSeq.getName()); + + DBRefEntry proteinToCdsRef = new DBRefEntry( + primRef.getSource(), primRef.getVersion(), + cdsSeq.getName()); + // proteinToCdsRef.setMap(new Mapping(cdsSeqDss, cdsToProteinMap .getInverse())); proteinProduct.addDBRef(proteinToCdsRef); @@ -1864,9 +1883,14 @@ public class AlignmentUtils * * @param seq * @param mapping + * @param dataset + * - existing dataset. We check for sequences that look like the CDS + * we are about to construct, if one exists already, then we will + * just return that one. * @return CDS sequence (as a dataset sequence) */ - static SequenceI makeCdsSequence(SequenceI seq, Mapping mapping) + static SequenceI makeCdsSequence(SequenceI seq, Mapping mapping, + AlignmentI dataset) { char[] seqChars = seq.getSequence(); List fromRanges = mapping.getMap().getFromRanges(); @@ -1893,7 +1917,7 @@ public class AlignmentUtils } } } - + /* * assign 'from id' held in the mapping if set (e.g. EMBL protein_id), * else generate a sequence name @@ -1901,12 +1925,124 @@ public class AlignmentUtils String mapFromId = mapping.getMappedFromId(); String seqId = "CDS|" + (mapFromId != null ? mapFromId : seq.getName()); SequenceI newSeq = new Sequence(seqId, newSeqChars, 1, newPos); + if (dataset != null) + { + SequenceI[] matches = dataset.findSequenceMatch(newSeq.getName()); + if (matches != null) + { + boolean matched = false; + for (SequenceI mtch : matches) + { + if (mtch.getStart() != newSeq.getStart()) + { + continue; + } + if (mtch.getEnd() != newSeq.getEnd()) + { + continue; + } + if (!Arrays.equals(mtch.getSequence(), newSeq.getSequence())) + { + continue; + } + if (!matched) + { + matched = true; + newSeq = mtch; + } + else + { + System.err + .println("JAL-2154 regression: warning - found (and ignnored a duplicate CDS sequence):" + + mtch.toString()); + } + } + } + } // newSeq.setDescription(mapFromId); return newSeq; } /** + * add any DBRefEntrys to cdsSeq from contig that have a Mapping congruent to + * the given mapping. + * + * @param cdsSeq + * @param contig + * @param mapping + * @return list of DBRefEntrys added. + */ + public static List propagateDBRefsToCDS(SequenceI cdsSeq, + SequenceI contig, SequenceI proteinProduct, Mapping mapping) + { + + // gather direct refs from contig congrent with mapping + List direct = new ArrayList(); + HashSet directSources = new HashSet(); + if (contig.getDBRefs() != null) + { + for (DBRefEntry dbr : contig.getDBRefs()) + { + if (dbr.hasMap() && dbr.getMap().getMap().isTripletMap()) + { + MapList map = dbr.getMap().getMap(); + // check if map is the CDS mapping + if (mapping.getMap().equals(map)) + { + direct.add(dbr); + directSources.add(dbr.getSource()); + } + } + } + } + DBRefEntry[] onSource = DBRefUtils.selectRefs( + proteinProduct.getDBRefs(), + directSources.toArray(new String[0])); + List propagated = new ArrayList(); + + // and generate appropriate mappings + for (DBRefEntry cdsref : direct) + { + // clone maplist and mapping + MapList cdsposmap = new MapList(Arrays.asList(new int[][] { new int[] + { cdsSeq.getStart(), cdsSeq.getEnd() } }), cdsref.getMap().getMap() + .getToRanges(), 3, 1); + Mapping cdsmap = new Mapping(cdsref.getMap().getTo(), cdsref.getMap() + .getMap()); + + // create dbref + DBRefEntry newref = new DBRefEntry(cdsref.getSource(), + cdsref.getVersion(), cdsref.getAccessionId(), new Mapping( + cdsmap.getTo(), cdsposmap)); + + // and see if we can map to the protein product for this mapping. + // onSource is the filtered set of accessions on protein that we are + // tranferring, so we assume accession is the same. + if (cdsmap.getTo() == null && onSource != null) + { + List sourceRefs = DBRefUtils.searchRefs(onSource, + cdsref.getAccessionId()); + if (sourceRefs != null) + { + for (DBRefEntry srcref : sourceRefs) + { + if (srcref.getSource().equalsIgnoreCase(cdsref.getSource())) + { + // we have found a complementary dbref on the protein product, so + // update mapping's getTo + newref.getMap().setTo(proteinProduct); + } + } + } + } + cdsSeq.addDBRef(newref); + propagated.add(newref); + } + return propagated; + } + + /** * Transfers co-located features on 'fromSeq' to 'toSeq', adjusting the * feature start/end ranges, optionally omitting specified feature types. * Returns the number of features copied. @@ -2513,7 +2649,7 @@ public class AlignmentUtils { AlignmentI copy = new Alignment(new Alignment(seqs)); copy.setDataset(dataset); - + boolean isProtein = !copy.isNucleotide(); SequenceIdMatcher matcher = new SequenceIdMatcher(seqs); if (xrefs != null) { @@ -2524,7 +2660,8 @@ public class AlignmentUtils { for (DBRefEntry dbref : dbrefs) { - if (dbref.getMap() == null || dbref.getMap().getTo() == null) + if (dbref.getMap() == null || dbref.getMap().getTo() == null + || dbref.getMap().getTo().isProtein() != isProtein) { continue; } diff --git a/src/jalview/analysis/CrossRef.java b/src/jalview/analysis/CrossRef.java index 288d60e..1295b46 100644 --- a/src/jalview/analysis/CrossRef.java +++ b/src/jalview/analysis/CrossRef.java @@ -222,6 +222,9 @@ public class CrossRef boolean found = false; DBRefEntry[] xrfs = DBRefUtils .selectDbRefs(!fromDna, dss.getDBRefs()); + // ENST & ENSP comes in to both Protein and nucleotide, so we need to + // filter them + // out later. if ((xrfs == null || xrfs.length == 0) && dataset != null) { /* @@ -249,11 +252,15 @@ public class CrossRef List sourceRefs = DBRefUtils.searchRefsForSource(xrfs, source); Iterator refIterator = sourceRefs.iterator(); + // At this point, if we are retrieving Ensembl, we still don't filter out + // ENST when looking for protein crossrefs. while (refIterator.hasNext()) { DBRefEntry xref = refIterator.next(); found = false; - if (xref.hasMap()) + // we're only interested in coding cross-references, not + // locus->transcript + if (xref.hasMap() && xref.getMap().getMap().isTripletMap()) { SequenceI mappedTo = xref.getMap().getTo(); if (mappedTo != null) @@ -271,20 +278,45 @@ public class CrossRef * but findInDataset() matches ENSP when looking for Uniprot... */ SequenceI matchInDataset = findInDataset(xref); + if (matchInDataset != null && xref.getMap().getTo() != null + && matchInDataset != xref.getMap().getTo()) + { + System.err + .println("Implementation problem (reopen JAL-2154): CrossRef.findInDataset seems to have recovered a different sequence than the one explicitly mapped for xref." + + "Found:" + + matchInDataset + + "\nExpected:" + + xref.getMap().getTo() + + "\nFor xref:" + + xref); + } /*matcher.findIdMatch(mappedTo);*/ if (matchInDataset != null) { if (!rseqs.contains(matchInDataset)) { rseqs.add(matchInDataset); + // need to try harder to only add unique mappings + if (xref.getMap().getMap().isTripletMap() + && dataset.getMapping(seq, matchInDataset) == null + && cf.getMappingBetween(seq, matchInDataset) == null) + { + // materialise a mapping for highlighting between these sequences + if (fromDna) + { + cf.addMap(dss, matchInDataset, xref.getMap().getMap(), xref.getMap().getMappedFromId()); + } else { + cf.addMap(matchInDataset, dss, xref.getMap().getMap().getInverse(), xref.getMap().getMappedFromId()); + } + } } refIterator.remove(); continue; } + // TODO: need to determine if this should be a deriveSequence SequenceI rsq = new Sequence(mappedTo); rseqs.add(rsq); - if (xref.getMap().getMap().getFromRatio() != xref.getMap() - .getMap().getToRatio()) + if (xref.getMap().getMap().isTripletMap()) { // get sense of map correct for adding to product alignment. if (fromDna) @@ -307,7 +339,9 @@ public class CrossRef { SequenceI matchedSeq = matcher.findIdMatch(xref.getSource() + "|" + xref.getAccessionId()); - if (matchedSeq != null) + // if there was a match, check it's at least the right type of + // molecule! + if (matchedSeq != null && matchedSeq.isProtein() == fromDna) { if (constructMapping(seq, matchedSeq, xref, cf, fromDna)) { @@ -356,6 +390,37 @@ public class CrossRef SequenceI[] retrieved = null; SequenceI dss = seq.getDatasetSequence() == null ? seq : seq .getDatasetSequence(); + // first filter in case we are retrieving crossrefs that have already been + // retrieved. this happens for cases where a database record doesn't yield + // protein products for CDS + DBRefEntry[] dbrSourceSet = sourceRefs.toArray(new DBRefEntry[0]); + for (SequenceI sq : dataset.getSequences()) + { + boolean dupeFound = false; + // !fromDna means we are looking only for nucleotide sequences, not + // protein + if (sq.isProtein() == fromDna) + { + for (DBRefEntry dbr : sq.getPrimaryDBRefs()) + { + for (DBRefEntry found : DBRefUtils.searchRefs(dbrSourceSet, dbr)) + { + sourceRefs.remove(found); + dupeFound = true; + } + } + } + if (dupeFound) + { + dbrSourceSet = sourceRefs.toArray(new DBRefEntry[0]); + } + } + if (sourceRefs.size() == 0) + { + // no more work to do! We already had all requested sequence records in + // the dataset. + return; + } try { retrieved = sftch.getSequences(sourceRefs, !fromDna); @@ -413,7 +478,11 @@ public class CrossRef } else { - matcher.add(map.getTo()); + if (dataset.findIndex(map.getTo()) == -1) + { + dataset.addSequence(map.getTo()); + matcher.add(map.getTo()); + } } try { @@ -483,8 +552,11 @@ public class CrossRef } retrievedSequence.updatePDBIds(); rseqs.add(retrievedDss); - dataset.addSequence(retrievedDss); - matcher.add(retrievedDss); + if (dataset.findIndex(retrievedDss) == -1) + { + dataset.addSequence(retrievedDss); + matcher.add(retrievedDss); + } } } } @@ -662,24 +734,28 @@ public class CrossRef DBRefEntry xref, AlignedCodonFrame mappings, boolean fromDna) { MapList mapping = null; - + SequenceI dsmapFrom = mapFrom.getDatasetSequence() == null ? mapFrom + : mapFrom.getDatasetSequence(); + SequenceI dsmapTo = mapTo.getDatasetSequence() == null ? mapTo + : mapTo.getDatasetSequence(); /* - * look for a reverse mapping, if found make its inverse + * look for a reverse mapping, if found make its inverse. + * Note - we do this on dataset sequences only. */ - if (mapTo.getDBRefs() != null) + if (dsmapTo.getDBRefs() != null) { - for (DBRefEntry dbref : mapTo.getDBRefs()) + for (DBRefEntry dbref : dsmapTo.getDBRefs()) { String name = dbref.getSource() + "|" + dbref.getAccessionId(); - if (dbref.hasMap() && mapFrom.getName().startsWith(name)) + if (dbref.hasMap() && dsmapFrom.getName().startsWith(name)) { /* * looks like we've found a map from 'mapTo' to 'mapFrom' * - invert it to make the mapping the other way */ MapList reverse = dbref.getMap().getMap().getInverse(); - xref.setMap(new Mapping(mapTo, reverse)); - mappings.addMap(mapFrom, mapTo, reverse); + xref.setMap(new Mapping(dsmapTo, reverse)); + mappings.addMap(mapFrom, dsmapTo, reverse); return true; } } @@ -706,14 +782,16 @@ public class CrossRef /* * and add a reverse DbRef with the inverse mapping */ - if (mapFrom.getDatasetSequence() != null - && mapFrom.getDatasetSequence().getSourceDBRef() != null) - { - DBRefEntry dbref = new DBRefEntry(mapFrom.getDatasetSequence() - .getSourceDBRef()); - dbref.setMap(new Mapping(mapFrom.getDatasetSequence(), mapping - .getInverse())); - mapTo.addDBRef(dbref); + if (mapFrom.getDatasetSequence() != null && false) + // && mapFrom.getDatasetSequence().getSourceDBRef() != null) + { + // possible need to search primary references... except, why doesn't xref + // == getSourceDBRef ?? + // DBRefEntry dbref = new DBRefEntry(mapFrom.getDatasetSequence() + // .getSourceDBRef()); + // dbref.setMap(new Mapping(mapFrom.getDatasetSequence(), mapping + // .getInverse())); + // mapTo.addDBRef(dbref); } if (fromDna) @@ -789,8 +867,8 @@ public class CrossRef *

    * @return true if relationship found and sequence added. */ - boolean searchDataset(boolean fromDna, SequenceI fromSeq, - DBRefEntry xrf, List foundSeqs, AlignedCodonFrame mappings, + boolean searchDataset(boolean fromDna, SequenceI fromSeq, DBRefEntry xrf, + List foundSeqs, AlignedCodonFrame mappings, boolean direct) { boolean found = false; @@ -851,37 +929,38 @@ public class CrossRef // } if (!cands.isEmpty()) { - if (!foundSeqs.contains(nxt)) + if (foundSeqs.contains(nxt)) { - found = true; - foundSeqs.add(nxt); - if (mappings != null && !direct) + continue; + } + found = true; + foundSeqs.add(nxt); + if (mappings != null && !direct) + { + /* + * if the matched sequence has mapped dbrefs to + * protein product / cdna, add equivalent mappings to + * our source sequence + */ + for (DBRefEntry candidate : cands) { - /* - * if the matched sequence has mapped dbrefs to - * protein product / cdna, add equivalent mappings to - * our source sequence - */ - for (DBRefEntry candidate : cands) + Mapping mapping = candidate.getMap(); + if (mapping != null) { - Mapping mapping = candidate.getMap(); - if (mapping != null) + MapList map = mapping.getMap(); + if (mapping.getTo() != null + && map.getFromRatio() != map.getToRatio()) { - MapList map = mapping.getMap(); - if (mapping.getTo() != null - && map.getFromRatio() != map.getToRatio()) + /* + * add a mapping, as from dna to peptide sequence + */ + if (map.getFromRatio() == 3) { - /* - * add a mapping, as from dna to peptide sequence - */ - if (map.getFromRatio() == 3) - { - mappings.addMap(nxt, fromSeq, map); - } - else - { - mappings.addMap(nxt, fromSeq, map.getInverse()); - } + mappings.addMap(nxt, fromSeq, map); + } + else + { + mappings.addMap(nxt, fromSeq, map.getInverse()); } } } diff --git a/src/jalview/api/DBRefEntryI.java b/src/jalview/api/DBRefEntryI.java index 32245b3..52ee381 100644 --- a/src/jalview/api/DBRefEntryI.java +++ b/src/jalview/api/DBRefEntryI.java @@ -70,4 +70,25 @@ public interface DBRefEntryI * @return */ public boolean updateFrom(DBRefEntryI otherEntry); + + /** + * Answers true if the ref looks like a primary (direct) database reference.
    + * The only way a dbref's mappings can be fully verified is via the local + * sequence frame, so rather than use isPrimaryCandidate directly, please use + * SequenceI.getPrimaryDbRefs().
    + * Primary references indicate the local sequence data directly corresponds + * with the database record. All other references are secondary. Direct + * references indicate that part or all of the local sequence data can be + * mapped with another sequence, enabling annotation transfer. + * Cross-references indicate the local sequence data can be corresponded to + * some other linear coordinate system via a transformation.
    + * This method is also sufficient to distinguish direct DBRefEntry mappings + * from other relationships - e.g. coding relationships (imply a 1:3/3:1 + * mapping), but not transcript relationships, which imply a (possibly + * non-contiguous) 1:1 mapping. + * + * @return true if this reference provides a primary accession for the + * associated sequence object + */ + public boolean isPrimaryCandidate(); } diff --git a/src/jalview/bin/Cache.java b/src/jalview/bin/Cache.java index df71ccc..508e8a7 100755 --- a/src/jalview/bin/Cache.java +++ b/src/jalview/bin/Cache.java @@ -232,7 +232,7 @@ public class Cache /** * Allowed values are PDB or mmCIF */ - private final static String DEFAULT_STRUCTURE_FORMAT = PDBEntry.Type.MMCIF + private final static String PDB_DOWNLOAD_FORMAT = PDBEntry.Type.MMCIF .toString(); private final static String DEFAULT_PDB_FILE_PARSER = StructureImportSettings.StructureParser.JMOL_PARSER @@ -445,7 +445,7 @@ public class Cache StructureImportSettings.setDefaultStructureFileFormat(jalview.bin.Cache .getDefault( - "DEFAULT_STRUCTURE_FORMAT", DEFAULT_STRUCTURE_FORMAT)); +"PDB_DOWNLOAD_FORMAT", PDB_DOWNLOAD_FORMAT)); StructureImportSettings .setDefaultPDBFileParser(jalview.bin.Cache.getDefault( "DEFAULT_PDB_FILE_PARSER", DEFAULT_PDB_FILE_PARSER)); diff --git a/src/jalview/datamodel/Alignment.java b/src/jalview/datamodel/Alignment.java index 32bb761..2f64759 100755 --- a/src/jalview/datamodel/Alignment.java +++ b/src/jalview/datamodel/Alignment.java @@ -21,6 +21,7 @@ package jalview.datamodel; import jalview.analysis.AlignmentUtils; +import jalview.datamodel.AlignedCodonFrame.SequenceToSequenceMapping; import jalview.io.FastaFile; import jalview.util.Comparison; import jalview.util.MessageManager; @@ -225,18 +226,21 @@ public class Alignment implements AlignmentI { if (dataset != null) { + // maintain dataset integrity - if (snew.getDatasetSequence() != null) - { - getDataset().addSequence(snew.getDatasetSequence()); - } - else + SequenceI dsseq = snew.getDatasetSequence(); + if (dsseq == null) { // derive new sequence SequenceI adding = snew.deriveSequence(); - getDataset().addSequence(adding.getDatasetSequence()); snew = adding; + dsseq = snew.getDatasetSequence(); } + if (getDataset().findIndex(dsseq) == -1) + { + getDataset().addSequence(dsseq); + } + } if (sequences == null) { @@ -255,18 +259,22 @@ public class Alignment implements AlignmentI } } - /** - * Adds a sequence to the alignment. Recalculates maxLength and size. - * - * @param snew - */ @Override - public void setSequenceAt(int i, SequenceI snew) + public SequenceI replaceSequenceAt(int i, SequenceI snew) { synchronized (sequences) { - deleteSequence(i); - sequences.set(i, snew); + if (sequences.size() > i) + { + return sequences.set(i, snew); + + } + else + { + sequences.add(snew); + hiddenSequences.adjustHeightSequenceAdded(); + } + return null; } } @@ -1029,6 +1037,62 @@ public class Alignment implements AlignmentI } /** + * add dataset sequences to seq for currentSeq and any sequences it references + */ + private void resolveAndAddDatasetSeq(SequenceI currentSeq, + Set seqs, boolean createDatasetSequence) + { + if (currentSeq.getDatasetSequence() != null) + { + currentSeq = currentSeq.getDatasetSequence(); + } + else + { + if (createDatasetSequence) + { + currentSeq = currentSeq.createDatasetSequence(); + } + } + if (seqs.contains(currentSeq)) + { + return; + } + List toProcess = new ArrayList(); + toProcess.add(currentSeq); + while (toProcess.size() > 0) + { + // use a queue ? + SequenceI curDs = toProcess.remove(0); + if (seqs.contains(curDs)) + { + continue; + } + seqs.add(curDs); + // iterate over database references, making sure we add forward referenced + // sequences + if (curDs.getDBRefs() != null) + { + for (DBRefEntry dbr : curDs.getDBRefs()) + { + if (dbr.getMap() != null && dbr.getMap().getTo() != null) + { + if (dbr.getMap().getTo().getDatasetSequence() != null) + { + throw new Error("Implementation error: Map.getTo() for dbref" + + dbr + " is not a dataset sequence."); + // TODO: if this happens, could also rewrite the reference to + // point to new dataset sequence + } + // we recurse to add all forward references to dataset sequences via + // DBRefs/etc + toProcess.add(dbr.getMap().getTo()); + } + } + } + } + } + + /** * Creates a new dataset for this alignment. Can only be done once - if * dataset is not null this will not be performed. */ @@ -1038,22 +1102,32 @@ public class Alignment implements AlignmentI { return; } - SequenceI[] seqs = new SequenceI[getHeight()]; - SequenceI currentSeq; + // try to avoid using SequenceI.equals at this stage, it will be expensive + Set seqs = new jalview.util.LinkedIdentityHashSet(); + for (int i = 0; i < getHeight(); i++) { - currentSeq = getSequenceAt(i); - if (currentSeq.getDatasetSequence() != null) - { - seqs[i] = currentSeq.getDatasetSequence(); - } - else + SequenceI currentSeq = getSequenceAt(i); + resolveAndAddDatasetSeq(currentSeq, seqs, true); + } + + // verify all mappings are in dataset + for (AlignedCodonFrame cf : codonFrameList) + { + for (SequenceToSequenceMapping ssm : cf.getMappings()) { - seqs[i] = currentSeq.createDatasetSequence(); + if (!seqs.contains(ssm.getFromSeq())) + { + resolveAndAddDatasetSeq(ssm.getFromSeq(), seqs, false); + } + if (!seqs.contains(ssm.getMapping().getTo())) + { + resolveAndAddDatasetSeq(ssm.getMapping().getTo(), seqs, false); + } } } - - dataset = new Alignment(seqs); + // finally construct dataset + dataset = new Alignment(seqs.toArray(new SequenceI[seqs.size()])); // move mappings to the dataset alignment dataset.codonFrameList = this.codonFrameList; this.codonFrameList = null; diff --git a/src/jalview/datamodel/AlignmentI.java b/src/jalview/datamodel/AlignmentI.java index f1db4c0..1d37fa6 100755 --- a/src/jalview/datamodel/AlignmentI.java +++ b/src/jalview/datamodel/AlignmentI.java @@ -108,11 +108,14 @@ public interface AlignmentI extends AnnotatedCollectionI * Used to set a particular index of the alignment with the given sequence. * * @param i - * Index of sequence to be updated. + * Index of sequence to be updated. if i>length, sequence will be + * added to end, with no intervening positions. * @param seq - * New sequence to be inserted. + * New sequence to be inserted. The existing sequence at position i + * will be replaced. + * @return existing sequence (or null if i>current length) */ - void setSequenceAt(int i, SequenceI seq); + SequenceI replaceSequenceAt(int i, SequenceI seq); /** * Deletes a sequence from the alignment diff --git a/src/jalview/datamodel/DBRefEntry.java b/src/jalview/datamodel/DBRefEntry.java index a641b1b..ec6dcf8 100755 --- a/src/jalview/datamodel/DBRefEntry.java +++ b/src/jalview/datamodel/DBRefEntry.java @@ -22,9 +22,13 @@ package jalview.datamodel; import jalview.api.DBRefEntryI; +import java.util.Arrays; +import java.util.List; + public class DBRefEntry implements DBRefEntryI { String source = "", version = "", accessionId = ""; + /** * maps from associated sequence to the database sequence's coordinate system */ @@ -35,7 +39,6 @@ public class DBRefEntry implements DBRefEntryI } - public DBRefEntry(String source, String version, String accessionId) { this(source, version, accessionId, null); @@ -138,7 +141,8 @@ public class DBRefEntry implements DBRefEntryI String otherAccession = other.getAccessionId(); if ((accessionId == null && otherAccession != null) || (accessionId != null && otherAccession == null) - || (accessionId != null && !accessionId.equalsIgnoreCase(otherAccession))) + || (accessionId != null && !accessionId + .equalsIgnoreCase(otherAccession))) { return false; } @@ -148,7 +152,7 @@ public class DBRefEntry implements DBRefEntryI * otherwise the versions have to match */ String otherVersion = other.getVersion(); - + if ((version == null || version.equals("0") || version.endsWith(":0")) && otherVersion != null) { @@ -223,28 +227,24 @@ public class DBRefEntry implements DBRefEntryI return accessionId; } - @Override public void setAccessionId(String accessionId) { this.accessionId = accessionId; } - @Override public void setSource(String source) { this.source = source; } - @Override public void setVersion(String version) { this.version = version; } - @Override public Mapping getMap() { @@ -280,4 +280,56 @@ public class DBRefEntry implements DBRefEntryI { return getSrcAccString(); } + + @Override + public boolean isPrimaryCandidate() + { + /* + * if a map is present, unless it is 1:1 and has no SequenceI mate, it cannot be a primary reference. + */ + if (map != null) + { + if (map.getTo() != null) + { + return false; + } + if (map.getMap().getFromRatio() != map.getMap().getToRatio() + || map.getMap().getFromRatio() != 1) + { + return false; + } + // check map is between identical single contiguous ranges + List fromRanges = map.getMap().getFromRanges(); + List toRanges = map.getMap().getToRanges(); + if (fromRanges.size() != 1 || toRanges.size() != 1) + { + return false; + } + if (fromRanges.get(0)[0] != toRanges.get(0)[0] + || fromRanges.get(0)[1] != toRanges.get(0)[1]) + { + return false; + } + } + if (version == null) + { + // no version string implies the reference has not been verified at all. + return false; + } + // tricky - this test really needs to search the sequence's set of dbrefs to + // see if there is a primary reference that derived this reference. + String ucv = version.toUpperCase(); + for (String primsrc : Arrays.asList(DBRefSource.allSources())) + { + if (ucv.startsWith(primsrc.toUpperCase())) + { + // by convention, many secondary references inherit the primary + // reference's + // source string as a prefix for any version information from the + // secondary reference. + return false; + } + } + return true; + } } diff --git a/src/jalview/datamodel/DBRefSource.java b/src/jalview/datamodel/DBRefSource.java index fba9211..0ac14e5 100755 --- a/src/jalview/datamodel/DBRefSource.java +++ b/src/jalview/datamodel/DBRefSource.java @@ -20,6 +20,10 @@ */ package jalview.datamodel; +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.List; + /** * Defines internal constants for unambiguous annotation of DbRefEntry source * strings and describing the data retrieved from external database sources (see @@ -36,12 +40,12 @@ public class DBRefSource /** * UNIPROT Accession Number */ - public static String UNIPROT = "UNIPROT"; + public static final String UNIPROT = "UNIPROT"; /** * UNIPROT Entry Name */ - public static String UP_NAME = "UNIPROT_NAME".toUpperCase(); + public static final String UP_NAME = "UNIPROT_NAME".toUpperCase(); /** * Uniprot Knowledgebase/TrEMBL as served from EMBL protein products. @@ -54,27 +58,27 @@ public class DBRefSource /** * PDB Entry Code */ - public static String PDB = "PDB"; + public static final String PDB = "PDB"; /** * EMBL ID */ - public static String EMBL = "EMBL"; + public static final String EMBL = "EMBL"; /** * EMBLCDS ID */ - public static String EMBLCDS = "EMBLCDS"; + public static final String EMBLCDS = "EMBLCDS"; /** * PFAM ID */ - public static String PFAM = "PFAM"; + public static final String PFAM = "PFAM"; /** * RFAM ID */ - public static String RFAM = "RFAM"; + public static final String RFAM = "RFAM"; /** * GeneDB ID @@ -96,6 +100,25 @@ public class DBRefSource public static final String[] CODINGDBS = { EMBLCDS, GENEDB, ENSEMBL }; - public static final String[] PROTEINDBS = { UNIPROT, PDB, UNIPROTKB, + public static final String[] PROTEINDBS = { UNIPROT, UNIPROTKB, EMBLCDSProduct, ENSEMBL }; // Ensembl ENSP* entries are protein + + public static String[] allSources() + { + List src = new ArrayList(); + for (Field f : DBRefSource.class.getFields()) + { + if (String.class.equals(f.getType())) + { + try + { + src.add((String) f.get(null)); + } catch (Exception x) + { + x.printStackTrace(); + } + } + } + return src.toArray(new String[0]); + } } diff --git a/src/jalview/datamodel/PDBEntry.java b/src/jalview/datamodel/PDBEntry.java index 1c7df49..1c1d192 100755 --- a/src/jalview/datamodel/PDBEntry.java +++ b/src/jalview/datamodel/PDBEntry.java @@ -30,13 +30,69 @@ public class PDBEntry private String id; - private String chainCode; - public enum Type { - PDB, MMCIF, FILE + PDB, MMCIF, FILE; + /** + * case insensitive matching for Type enum + * + * @param value + * @return + */ + public static Type getType(String value) + { + for (Type t : Type.values()) + { + if (t.toString().equalsIgnoreCase(value)) + { + return t; + } + } + return null; + } + + /** + * case insensitive equivalence for strings resolving to PDBEntry type + * + * @param t + * @return + */ + public boolean matches(String t) + { + return (this.toString().equalsIgnoreCase(t)); + } } + public final class ChainId + { + String chainId; + + public ChainId(String chainId) + { + this.chainId = chainId; + } + + @Override + public String toString() + { + return chainId; + } + + @Override + public boolean equals(Object o){ + if (o==null) + { + return false; + } + return chainId.equalsIgnoreCase(o.toString()); + } + } + + /** + * constant for storing chain code in properties table + */ + private static final String CHAIN_ID = "chain_code"; + Hashtable properties; /* @@ -60,9 +116,6 @@ public class PDBEntry .equals(type))) && (id == o.id || (id != null && o.id != null && o.id .equalsIgnoreCase(id))) - && (chainCode == o.chainCode || (chainCode != null - && o.chainCode != null && o.chainCode - .equalsIgnoreCase(chainCode))) && (properties == o.properties || (properties != null && o.properties != null && properties .equals(o.properties))); @@ -91,9 +144,9 @@ public class PDBEntry String filePath) { this.id = pdbId; - this.chainCode = chain; this.type = type == null ? null : type.toString(); this.file = filePath; + setChainCode(chain); } /** @@ -106,7 +159,6 @@ public class PDBEntry file = entry.file; type = entry.type; id = entry.id; - chainCode = entry.chainCode; if (entry.properties != null) { properties = (Hashtable) entry.properties.clone(); @@ -158,14 +210,34 @@ public class PDBEntry return properties; } + /** + * + * @return null or a string for associated chain IDs + */ public String getChainCode() { - return chainCode; + return (properties == null || properties.get(CHAIN_ID) == null) ? null + : properties.get(CHAIN_ID).toString(); } public void setChainCode(String chainCode) { - this.chainCode = chainCode; + if (properties == null) + { + if (chainCode == null) + { + // nothing to do. + return; + } + properties = new Hashtable(); + } + if (chainCode == null) + { + properties.remove(CHAIN_ID); + return; + } + // update property for non-null chainCode + properties.put(CHAIN_ID, new ChainId(chainCode)); } @Override @@ -173,4 +245,54 @@ public class PDBEntry { return id; } + + /** + * update entry with details from another entry concerning the same PDB + * ID/file spec. + * + * @param newEntry + * @return true if modifications were made + */ + public boolean updateFrom(PDBEntry newEntry) + { + boolean modified = false; + + if (getFile() == null) + { + // update file and type of file + modified |= newEntry.getFile() != null; + setFile(newEntry.getFile()); + } + if (newEntry.getType() != null && newEntry.getFile() != null + && newEntry.getFile().equals(getFile())) + { + setType(newEntry.getType()); + } + if (getChainCode() == null + || (getChainCode() != null && getChainCode().length() == 0 && newEntry + .getChainCode() != null)) + { + modified |= getChainCode() == null + || !newEntry.getChainCode().equals(getChainCode()); + setChainCode(newEntry.getChainCode()); + } + if (newEntry.getProperty() != null) + { + if (properties == null) + { + properties = new Hashtable(); + } + // TODO: getProperty -> Map + for (Object p : newEntry.getProperty().keySet()) + { + if (properties.get(p) == null + || !properties.get(p).equals(newEntry.getProperty().get(p))) + { + modified = true; + } + properties.put(p, newEntry.getProperty().get(p)); + } + } + return modified; + } } diff --git a/src/jalview/datamodel/Sequence.java b/src/jalview/datamodel/Sequence.java index a857712..4f626a4 100755 --- a/src/jalview/datamodel/Sequence.java +++ b/src/jalview/datamodel/Sequence.java @@ -22,10 +22,13 @@ package jalview.datamodel; import jalview.analysis.AlignSeq; import jalview.api.DBRefEntryI; +import jalview.util.DBRefUtils; +import jalview.util.MapList; import jalview.util.StringUtils; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.Enumeration; import java.util.List; import java.util.Vector; @@ -57,8 +60,6 @@ public class Sequence extends ASequence implements SequenceI String vamsasId; - DBRefEntryI sourceDBRef; - DBRefEntry[] dbrefs; RNA rna; @@ -235,8 +236,6 @@ public class Sequence extends ASequence implements SequenceI seq.getEnd()); } description = seq.getDescription(); - sourceDBRef = seq.getSourceDBRef() == null ? null : new DBRefEntry( - seq.getSourceDBRef()); if (seq != datasetSequence) { setDatasetSequence(seq.getDatasetSequence()); @@ -307,8 +306,9 @@ public class Sequence extends ASequence implements SequenceI && datasetSequence.getSequenceFeatures() != null && datasetSequence.getSequenceFeatures().length > 0) { - System.err - .println("Warning: JAL-2046 side effect ? Possible implementation error: overwriting dataset sequence features by setting sequence features on alignment"); + new Exception( + "Warning: JAL-2046 side effect ? Possible implementation error: overwriting dataset sequence features by setting sequence features on alignment") + .printStackTrace(); } datasetSequence.setSequenceFeatures(features); } @@ -418,22 +418,66 @@ public class Sequence extends ASequence implements SequenceI { pdbIds = new Vector(); } - if (pdbIds.contains(entry)) - { - updatePDBEntry(pdbIds.get(pdbIds.indexOf(entry)), entry); - } - else + if (!updatedPDBEntry(pdbIds, entry)) { pdbIds.addElement(entry); } } - private static void updatePDBEntry(PDBEntry oldEntry, PDBEntry newEntry) + private static boolean updatedPDBEntry(List entries, + PDBEntry newEntry) { - if (newEntry.getFile() != null) + for (PDBEntry xtant : entries) { - oldEntry.setFile(newEntry.getFile()); + if (xtant.getFile() != null && newEntry.getFile() != null + && !xtant.getFile().equals(newEntry.getFile())) + { + // different structure data, so leave alone. + continue; + } + // loop through to check whether we can find a matching ID + + // either exact + if (!xtant.getId().equals(newEntry.getId())) + { + /* TODO: support stemming to group PDB IDs. + // or stemming, with exactly one alphanumeric character difference + if (xtant.getId().length() < newEntry.getId().length()) + { + if (!newEntry.getId().startsWith(xtant.getId())) + { + continue; + } + // newEntry may be chain specific PDBEntry + // TODO: copy/update details from newEntry to xtant + } + else + { + if (!xtant.getId().startsWith(newEntry.getId())) + { + continue; + } + // xtant may be chain specific PDBEntry + // TODO: copy/update missing details from newEntry + }*/ + continue; + } + if (xtant.getChainCode() != null && xtant.getChainCode().length() > 0 + && newEntry.getChainCode() != null + && !newEntry.getChainCode().equals(xtant.getChainCode())) + { + // don't overwrite - multiple chain mappings for a sequence yield + // multiple PDBEntries + // each with different chaincode + continue; + } + + xtant.updateFrom(newEntry); + + return true; } + // if we got to the end of the loop, nothing was updated. + return false; } /** @@ -1394,12 +1438,15 @@ public class Sequence extends ASequence implements SequenceI @Override public PDBEntry getPDBEntry(String pdbIdStr) { - if (getDatasetSequence() == null - || getDatasetSequence().getAllPDBEntries() == null) + if (getDatasetSequence() != null) + { + return getDatasetSequence().getPDBEntry(pdbIdStr); + } + if (pdbIds == null) { return null; } - List entries = getDatasetSequence().getAllPDBEntries(); + List entries = getAllPDBEntries(); for (PDBEntry entry : entries) { if (entry.getId().equalsIgnoreCase(pdbIdStr)) @@ -1410,16 +1457,65 @@ public class Sequence extends ASequence implements SequenceI return null; } - @Override - public void setSourceDBRef(DBRefEntryI dbRef) - { - this.sourceDBRef = dbRef; - } @Override - public DBRefEntryI getSourceDBRef() + public List getPrimaryDBRefs() { - return this.sourceDBRef; + if (datasetSequence!=null) + { + return datasetSequence.getPrimaryDBRefs(); + } + if (dbrefs==null || dbrefs.length==0) + { + return Collections.emptyList(); + } + synchronized (dbrefs) + { + List primaries = new ArrayList(); + DBRefEntry[] tmp = new DBRefEntry[1]; + for (DBRefEntry ref : dbrefs) + { + if (!ref.isPrimaryCandidate()) + { + continue; + } + if (ref.hasMap()) + { + MapList mp = ref.getMap().getMap(); + if (mp.getFromLowest() > start || mp.getFromHighest() < end) + { + // map only involves a subsequence, so cannot be primary + continue; + } + } + // whilst it looks like it is a primary ref, we also sanity check type + if (DBRefUtils.getCanonicalName(DBRefSource.PDB).equals( + DBRefUtils.getCanonicalName(ref.getSource()))) + { + // PDB dbrefs imply there should be a PDBEntry associated + // TODO: tighten PDB dbrefs + // formally imply Jalview has actually downloaded and + // parsed the pdb file. That means there should be a cached file + // handle on the PDBEntry, and a real mapping between sequence and + // extracted sequence from PDB file + PDBEntry pdbentry = getPDBEntry(ref.getAccessionId()); + if (pdbentry != null && pdbentry.getFile() != null) + { + primaries.add(ref); + } + continue; + } + // check standard protein or dna sources + tmp[0] = ref; + DBRefEntry[] res = DBRefUtils.selectDbRefs(!isProtein(), tmp); + if (res != null && res[0] == tmp[0]) + { + primaries.add(ref); + continue; + } + } + return primaries; + } } } diff --git a/src/jalview/datamodel/SequenceI.java b/src/jalview/datamodel/SequenceI.java index 45a767c..55c59db 100755 --- a/src/jalview/datamodel/SequenceI.java +++ b/src/jalview/datamodel/SequenceI.java @@ -20,8 +20,6 @@ */ package jalview.datamodel; -import jalview.api.DBRefEntryI; - import java.util.List; import java.util.Vector; @@ -291,7 +289,12 @@ public interface SequenceI extends ASequenceI public Vector getAllPDBEntries(); /** - * add entry to the vector of PDBIds, if it isn't in the list already + * add entry to the *normalised* vector of PDBIds. + * + * If a PDBEntry is passed with an entry.getID() string, as one already in the + * list, or one is added that appears to be the same but has a chain ID + * appended, then the existing PDBEntry will be updated with the new + * attributes. * * @param entry */ @@ -443,21 +446,14 @@ public interface SequenceI extends ASequenceI */ public PDBEntry getPDBEntry(String pdbId); - /** - * Set the distinct source database, and accession number from which a - * sequence and its start-end data were derived from. This is very important - * for SIFTS mappings and must be set prior to performing SIFTS mapping. - * - * @param dbRef - * the source dbRef for the sequence - */ - public void setSourceDBRef(DBRefEntryI dbRef); /** - * Get the distinct source database, and accession number from which a - * sequence and its start-end data were derived from. + * Get all primary database/accessions for this sequence's data. These + * DBRefEntry are expected to resolve to a valid record in the associated + * external database, either directly or via a provided 1:1 Mapping. * - * @return + * @return just the primary references (if any) for this sequence, or an empty + * list */ - public DBRefEntryI getSourceDBRef(); + public List getPrimaryDBRefs(); } diff --git a/src/jalview/datamodel/xdb/embl/EmblEntry.java b/src/jalview/datamodel/xdb/embl/EmblEntry.java index 06e929d..3ba36ca 100644 --- a/src/jalview/datamodel/xdb/embl/EmblEntry.java +++ b/src/jalview/datamodel/xdb/embl/EmblEntry.java @@ -195,7 +195,6 @@ public class EmblEntry DBRefEntry retrievedref = new DBRefEntry(sourceDb, getSequenceVersion(), accession); dna.addDBRef(retrievedref); - dna.setSourceDBRef(retrievedref); // add map to indicate the sequence is a valid coordinate frame for the // dbref retrievedref.setMap(new Mapping(null, new int[] { 1, dna.getLength() }, @@ -504,7 +503,6 @@ public class EmblEntry dnaToProteinMapping.setTo(proteinSeq); dnaToProteinMapping.setMappedFromId(proteinId); proteinSeq.addDBRef(proteinDbRef); - proteinSeq.setSourceDBRef(proteinDbRef); ref.setMap(dnaToProteinMapping); } hasUniprotDbref = true; @@ -549,7 +547,6 @@ public class EmblEntry DBRefSource.EMBLCDSProduct, getSequenceVersion(), proteinId); } product.addDBRef(proteinToEmblProteinRef); - product.setSourceDBRef(proteinToEmblProteinRef); if (dnaToProteinMapping != null && dnaToProteinMapping.getTo() != null) diff --git a/src/jalview/ext/ensembl/EnsemblGene.java b/src/jalview/ext/ensembl/EnsemblGene.java index b4d2783..50e1032 100644 --- a/src/jalview/ext/ensembl/EnsemblGene.java +++ b/src/jalview/ext/ensembl/EnsemblGene.java @@ -174,7 +174,8 @@ public class EnsemblGene extends EnsemblSeqProxy */ else { - List ids = new EnsemblSymbol(getDomain()).getIds(acc); + List ids = new EnsemblSymbol(getDomain(), getDbSource(), + getDbVersion()).getIds(acc); for (String geneId : ids) { if (!geneIds.contains(geneId)) @@ -196,7 +197,8 @@ public class EnsemblGene extends EnsemblSeqProxy */ protected String getGeneIdentifiersForName(String query) { - List ids = new EnsemblSymbol(getDomain()).getIds(query); + List ids = new EnsemblSymbol(getDomain(), getDbSource(), + getDbVersion()).getIds(query); if (ids != null) { for (String id : ids) diff --git a/src/jalview/ext/ensembl/EnsemblSeqProxy.java b/src/jalview/ext/ensembl/EnsemblSeqProxy.java index cc002e1..5fccedd 100644 --- a/src/jalview/ext/ensembl/EnsemblSeqProxy.java +++ b/src/jalview/ext/ensembl/EnsemblSeqProxy.java @@ -276,8 +276,7 @@ public abstract class EnsemblSeqProxy extends EnsemblRestClient { // clunky: ensure Uniprot xref if we have one is on mapped sequence SequenceI ds = proteinSeq.getDatasetSequence(); - ds.setSourceDBRef(proteinSeq.getSourceDBRef()); - + // TODO: Verify ensp primary ref is on proteinSeq.getDatasetSequence() Mapping map = new Mapping(ds, mapList); DBRefEntry dbr = new DBRefEntry(getDbSource(), getEnsemblDataVersion(), proteinSeq.getName(), map); @@ -309,7 +308,8 @@ public abstract class EnsemblSeqProxy extends EnsemblRestClient seq = seq.getDatasetSequence(); } - EnsemblXref xrefFetcher = new EnsemblXref(getDomain()); + EnsemblXref xrefFetcher = new EnsemblXref(getDomain(), getDbSource(), + getEnsemblDataVersion()); List xrefs = xrefFetcher.getCrossReferences(seq.getName()); for (DBRefEntry xref : xrefs) { @@ -322,7 +322,6 @@ public abstract class EnsemblSeqProxy extends EnsemblRestClient DBRefEntry self = new DBRefEntry(getDbSource(), getEnsemblDataVersion(), seq.getName()); seq.addDBRef(self); - seq.setSourceDBRef(self); } /** @@ -382,7 +381,7 @@ public abstract class EnsemblSeqProxy extends EnsemblRestClient { DBRefEntry dbref = DBRefUtils.parseToDbRef(sq, getDbSource(), getEnsemblDataVersion(), name); - sq.setSourceDBRef(dbref); + sq.addDBRef(dbref); } } if (alignment == null) diff --git a/src/jalview/ext/ensembl/EnsemblSymbol.java b/src/jalview/ext/ensembl/EnsemblSymbol.java index 1c47f11..b8c8c54 100644 --- a/src/jalview/ext/ensembl/EnsemblSymbol.java +++ b/src/jalview/ext/ensembl/EnsemblSymbol.java @@ -25,11 +25,13 @@ public class EnsemblSymbol extends EnsemblXref /** * Constructor given the target domain to fetch data from * - * @param d + * @param domain + * @param dbName + * @param dbVersion */ - public EnsemblSymbol(String d) + public EnsemblSymbol(String domain, String dbName, String dbVersion) { - super(d); + super(domain, dbName, dbVersion); } /** diff --git a/src/jalview/ext/ensembl/EnsemblXref.java b/src/jalview/ext/ensembl/EnsemblXref.java index fa86865..313572f 100644 --- a/src/jalview/ext/ensembl/EnsemblXref.java +++ b/src/jalview/ext/ensembl/EnsemblXref.java @@ -29,20 +29,25 @@ class EnsemblXref extends EnsemblRestClient private static final String GO_GENE_ONTOLOGY = "GO"; + private String dbName = "ENSEMBL (xref)"; + /** * Constructor given the target domain to fetch data from * * @param d */ - public EnsemblXref(String d) + public EnsemblXref(String d, String dbSource, String version) { super(d); + dbName = dbSource; + xrefVersion = dbSource + ":" + version; + } @Override public String getDbName() { - return "ENSEMBL (xref)"; + return dbName; } @Override @@ -152,7 +157,7 @@ class EnsemblXref extends EnsemblRestClient if (dbName != null && id != null) { dbName = DBRefUtils.getCanonicalName(dbName); - DBRefEntry dbref = new DBRefEntry(dbName, "0", id); + DBRefEntry dbref = new DBRefEntry(dbName, getXRefVersion(), id); result.add(dbref); } } @@ -163,6 +168,18 @@ class EnsemblXref extends EnsemblRestClient return result; } + private String xrefVersion = "ENSEMBL:0"; + + /** + * version string for Xrefs - for 2.10, hardwired for ENSEMBL:0 + * + * @return + */ + public String getXRefVersion() + { + return xrefVersion; + } + /** * Returns the URL for the REST endpoint to fetch all cross-references for an * identifier. Note this may return protein cross-references for nucleotide. diff --git a/src/jalview/ext/jmol/JmolParser.java b/src/jalview/ext/jmol/JmolParser.java index 7c3ff42..7836d24 100644 --- a/src/jalview/ext/jmol/JmolParser.java +++ b/src/jalview/ext/jmol/JmolParser.java @@ -22,6 +22,7 @@ package jalview.ext.jmol; import jalview.datamodel.AlignmentAnnotation; import jalview.datamodel.Annotation; +import jalview.datamodel.PDBEntry; import jalview.datamodel.SequenceI; import jalview.io.FileParse; import jalview.io.StructureFile; @@ -97,6 +98,18 @@ public class JmolParser extends StructureFile implements JmolStatusListener */ if (jmolModel.ms.mc > 0) { + // ideally we do this + // try + // { + // setStructureFileType(jmolModel.evalString("show _fileType")); + // } catch (Exception q) + // { + // } + // ; + // instead, we distinguish .cif from non-.cif by filename + setStructureFileType(getDataName().toLowerCase().endsWith(".cif") ? PDBEntry.Type.MMCIF + .toString() : "PDB"); + transformJmolModelToJalview(jmolModel.ms); } } diff --git a/src/jalview/gui/AlignFrame.java b/src/jalview/gui/AlignFrame.java index e8e7da3..1848595 100644 --- a/src/jalview/gui/AlignFrame.java +++ b/src/jalview/gui/AlignFrame.java @@ -32,7 +32,6 @@ import jalview.api.AlignViewControllerI; import jalview.api.AlignViewportI; import jalview.api.AlignmentViewPanel; import jalview.api.FeatureSettingsControllerI; -import jalview.api.FeatureSettingsModelI; import jalview.api.SplitContainerI; import jalview.api.ViewStyleI; import jalview.api.analysis.ScoreModelI; @@ -54,7 +53,6 @@ import jalview.datamodel.AlignmentI; import jalview.datamodel.AlignmentOrder; import jalview.datamodel.AlignmentView; import jalview.datamodel.ColumnSelection; -import jalview.datamodel.DBRefSource; import jalview.datamodel.HiddenSequences; import jalview.datamodel.PDBEntry; import jalview.datamodel.SeqCigar; @@ -74,7 +72,6 @@ import jalview.io.JalviewFileView; import jalview.io.JnetAnnotationMaker; import jalview.io.NewickFile; import jalview.io.TCoffeeScoreFile; -import jalview.io.gff.SequenceOntologyI; import jalview.jbgui.GAlignFrame; import jalview.schemes.Blosum62ColourScheme; import jalview.schemes.BuriedColourScheme; @@ -94,12 +91,10 @@ import jalview.schemes.TaylorColourScheme; import jalview.schemes.TurnColourScheme; import jalview.schemes.UserColourScheme; import jalview.schemes.ZappoColourScheme; -import jalview.structure.StructureSelectionManager; import jalview.util.MessageManager; import jalview.viewmodel.AlignmentViewport; import jalview.ws.DBRefFetcher; import jalview.ws.DBRefFetcher.FetchFinishedListenerI; -import jalview.ws.SequenceFetcher; import jalview.ws.jws1.Discoverer; import jalview.ws.jws2.Jws2Discoverer; import jalview.ws.jws2.jabaws2.Jws2Instance; @@ -4643,14 +4638,21 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, { SequenceI[] seqs = viewport.getAlignment().getSequencesArray(); AlignmentI dataset = viewport.getAlignment().getDataset(); + + showProducts.removeAll(); + final boolean dna = viewport.getAlignment().isNucleotide(); + + if (seqs == null || seqs.length == 0) + { + // nothing to see here. + return false; + } + boolean showp = false; try { - showProducts.removeAll(); - final boolean dna = viewport.getAlignment().isNucleotide(); - List ptypes = (seqs == null || seqs.length == 0) ? null - : new CrossRef(seqs, dataset) - .findXrefSourcesForSequences(dna); + List ptypes = new CrossRef(seqs, dataset) + .findXrefSourcesForSequences(dna); for (final String source : ptypes) { @@ -4693,236 +4695,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, protected void showProductsFor(final SequenceI[] sel, final boolean _odna, final String source) { - Runnable foo = new Runnable() - { - - @Override - public void run() - { - final long sttime = System.currentTimeMillis(); - AlignFrame.this.setProgressBar(MessageManager.formatMessage( - "status.searching_for_sequences_from", - new Object[] { source }), sttime); - try - { - AlignmentI alignment = AlignFrame.this.getViewport() - .getAlignment(); - AlignmentI dataset = alignment.getDataset() == null ? alignment - : alignment.getDataset(); - boolean dna = alignment.isNucleotide(); - if (_odna != dna) - { - System.err - .println("Conflict: showProducts for alignment originally " - + "thought to be " - + (_odna ? "DNA" : "Protein") - + " now searching for " - + (dna ? "DNA" : "Protein") + " Context."); - } - AlignmentI xrefs = new CrossRef(sel, dataset).findXrefSequences( - source, dna); - if (xrefs == null) - { - return; - } - /* - * get display scheme (if any) to apply to features - */ - FeatureSettingsModelI featureColourScheme = new SequenceFetcher() - .getFeatureColourScheme(source); - - AlignmentI xrefsAlignment = makeCrossReferencesAlignment(dataset, - xrefs); - if (!dna) - { - xrefsAlignment = AlignmentUtils.makeCdsAlignment( - xrefsAlignment.getSequencesArray(), dataset, sel); - xrefsAlignment.alignAs(alignment); - } - - /* - * If we are opening a splitframe, make a copy of this alignment (sharing the same dataset - * sequences). If we are DNA, drop introns and update mappings - */ - AlignmentI copyAlignment = null; - - if (Cache.getDefault(Preferences.ENABLE_SPLIT_FRAME, true)) - { - boolean copyAlignmentIsAligned = false; - if (dna) - { - copyAlignment = AlignmentUtils.makeCdsAlignment(sel, dataset, - xrefsAlignment.getSequencesArray()); - if (copyAlignment.getHeight() == 0) - { - JOptionPane.showMessageDialog(AlignFrame.this, - MessageManager.getString("label.cant_map_cds"), - MessageManager.getString("label.operation_failed"), - JOptionPane.OK_OPTION); - System.err.println("Failed to make CDS alignment"); - } - - /* - * pending getting Embl transcripts to 'align', - * we are only doing this for Ensembl - */ - // TODO proper criteria for 'can align as cdna' - if (DBRefSource.ENSEMBL.equalsIgnoreCase(source) - || AlignmentUtils.looksLikeEnsembl(alignment)) - { - copyAlignment.alignAs(alignment); - copyAlignmentIsAligned = true; - } - } - else - { - copyAlignment = AlignmentUtils.makeCopyAlignment(sel, - xrefs.getSequencesArray(), dataset); - } - copyAlignment.setGapCharacter(AlignFrame.this.viewport - .getGapCharacter()); - - StructureSelectionManager ssm = StructureSelectionManager - .getStructureSelectionManager(Desktop.instance); - - /* - * register any new mappings for sequence mouseover etc - * (will not duplicate any previously registered mappings) - */ - ssm.registerMappings(dataset.getCodonFrames()); - - if (copyAlignment.getHeight() <= 0) - { - System.err.println("No Sequences generated for xRef type " - + source); - return; - } - /* - * align protein to dna - */ - if (dna && copyAlignmentIsAligned) - { - xrefsAlignment.alignAs(copyAlignment); - } - else - { - /* - * align cdna to protein - currently only if - * fetching and aligning Ensembl transcripts! - */ - // TODO: generalise for other sources of locus/transcript/cds data - if (dna && DBRefSource.ENSEMBL.equalsIgnoreCase(source)) - { - copyAlignment.alignAs(xrefsAlignment); - } - } - } - /* - * build AlignFrame(s) according to available alignment data - */ - AlignFrame newFrame = new AlignFrame(xrefsAlignment, - DEFAULT_WIDTH, DEFAULT_HEIGHT); - if (Cache.getDefault("HIDE_INTRONS", true)) - { - newFrame.hideFeatureColumns(SequenceOntologyI.EXON, false); - } - String newtitle = String.format("%s %s %s", - dna ? MessageManager.getString("label.proteins") - : MessageManager.getString("label.nucleotides"), - MessageManager.getString("label.for"), getTitle()); - newFrame.setTitle(newtitle); - - if (copyAlignment == null) - { - /* - * split frame display is turned off in preferences file - */ - Desktop.addInternalFrame(newFrame, newtitle, DEFAULT_WIDTH, - DEFAULT_HEIGHT); - return; // via finally clause - } - AlignFrame copyThis = new AlignFrame(copyAlignment, - AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT); - copyThis.setTitle(AlignFrame.this.getTitle()); - - boolean showSequenceFeatures = viewport.isShowSequenceFeatures(); - newFrame.setShowSeqFeatures(showSequenceFeatures); - copyThis.setShowSeqFeatures(showSequenceFeatures); - FeatureRenderer myFeatureStyling = alignPanel.getSeqPanel().seqCanvas - .getFeatureRenderer(); - - /* - * copy feature rendering settings to split frame - */ - newFrame.alignPanel.getSeqPanel().seqCanvas.getFeatureRenderer() - .transferSettings(myFeatureStyling); - copyThis.alignPanel.getSeqPanel().seqCanvas.getFeatureRenderer() - .transferSettings(myFeatureStyling); - - /* - * apply 'database source' feature configuration - * if any was found - */ - // TODO is this the feature colouring for the original - // alignment or the fetched xrefs? either could be Ensembl - newFrame.getViewport().applyFeaturesStyle(featureColourScheme); - copyThis.getViewport().applyFeaturesStyle(featureColourScheme); - - SplitFrame sf = new SplitFrame(dna ? copyThis : newFrame, - dna ? newFrame : copyThis); - newFrame.setVisible(true); - copyThis.setVisible(true); - String linkedTitle = MessageManager - .getString("label.linked_view_title"); - Desktop.addInternalFrame(sf, linkedTitle, -1, -1); - sf.adjustDivider(); - } catch (OutOfMemoryError e) - { - new OOMWarning("whilst fetching crossreferences", e); - } catch (Throwable e) - { - Cache.log.error("Error when finding crossreferences", e); - } finally - { - AlignFrame.this.setProgressBar(MessageManager.formatMessage( - "status.finished_searching_for_sequences_from", - new Object[] { source }), sttime); - } - } - - /** - * Makes an alignment containing the given sequences, and adds them to the - * given dataset, which is also set as the dataset for the new alignment - * - * TODO: refactor to DatasetI method - * - * @param dataset - * @param seqs - * @return - */ - protected AlignmentI makeCrossReferencesAlignment(AlignmentI dataset, - AlignmentI seqs) - { - SequenceI[] sprods = new SequenceI[seqs.getHeight()]; - for (int s = 0; s < sprods.length; s++) - { - sprods[s] = (seqs.getSequenceAt(s)).deriveSequence(); - if (dataset.getSequences() == null - || !dataset.getSequences().contains( - sprods[s].getDatasetSequence())) - { - dataset.addSequence(sprods[s].getDatasetSequence()); - } - sprods[s].updatePDBIds(); - } - Alignment al = new Alignment(sprods); - al.setDataset(dataset); - return al; - } - - }; - Thread frunner = new Thread(foo); - frunner.start(); + new Thread(CrossRefAction.showProductsFor(sel, _odna, source, this)) + .start(); } /** diff --git a/src/jalview/gui/ChimeraViewFrame.java b/src/jalview/gui/ChimeraViewFrame.java index f2244d5..592f56c 100644 --- a/src/jalview/gui/ChimeraViewFrame.java +++ b/src/jalview/gui/ChimeraViewFrame.java @@ -249,6 +249,7 @@ public class ChimeraViewFrame extends StructureViewerBase SequenceI[][] seqs) { createProgressBar(); + // FIXME extractChains needs pdbentries to match IDs to PDBEntry(s) on seqs String[][] chains = extractChains(seqs); jmb = new JalviewChimeraBindingModel(this, ap.getStructureSelectionManager(), pdbentrys, seqs, chains, @@ -303,6 +304,9 @@ public class ChimeraViewFrame extends StructureViewerBase .getAllPDBEntries(); if (pdbrefs != null && pdbrefs.size() > 0) { + // FIXME: SequenceI.PDBEntry[0] chain mapping used for + // ChimeraViewFrame. Is this even used ??? + chain = pdbrefs.get(0).getChainCode(); } } @@ -728,6 +732,7 @@ public class ChimeraViewFrame extends StructureViewerBase */ private String fetchPdbFile(PDBEntry processingEntry) throws Exception { + // FIXME: this is duplicated code with Jmol frame ? String filePath = null; Pdb pdbclient = new Pdb(); AlignmentI pdbseq = null; diff --git a/src/jalview/gui/CrossRefAction.java b/src/jalview/gui/CrossRefAction.java new file mode 100644 index 0000000..32af226 --- /dev/null +++ b/src/jalview/gui/CrossRefAction.java @@ -0,0 +1,312 @@ +/* + * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$) + * Copyright (C) $$Year-Rel$$ The Jalview Authors + * + * This file is part of Jalview. + * + * Jalview is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 + * of the License, or (at your option) any later version. + * + * Jalview is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Jalview. If not, see . + * The Jalview Authors are detailed in the 'AUTHORS' file. + */ +package jalview.gui; + +import jalview.analysis.AlignmentUtils; +import jalview.analysis.CrossRef; +import jalview.api.AlignmentViewPanel; +import jalview.api.FeatureSettingsModelI; +import jalview.bin.Cache; +import jalview.datamodel.Alignment; +import jalview.datamodel.AlignmentI; +import jalview.datamodel.DBRefSource; +import jalview.datamodel.SequenceI; +import jalview.io.gff.SequenceOntologyI; +import jalview.structure.StructureSelectionManager; +import jalview.util.MessageManager; +import jalview.ws.SequenceFetcher; + +import java.util.ArrayList; +import java.util.List; + +import javax.swing.JOptionPane; + +/** + * Factory constructor and runnable for discovering and displaying + * cross-references for a set of aligned sequences + * + * @author jprocter + * + */ +public class CrossRefAction implements Runnable +{ + private AlignFrame alignFrame; + + private SequenceI[] sel; + + private boolean _odna; + + private String source; + + List xrefViews = new ArrayList(); + + public List getXrefViews() + { + return xrefViews; + } + + @Override + public void run() + { + final long sttime = System.currentTimeMillis(); + alignFrame.setProgressBar( + MessageManager.formatMessage( + "status.searching_for_sequences_from", + new Object[] { source }), sttime); + try + { + AlignmentI alignment = alignFrame.getViewport().getAlignment(); + AlignmentI dataset = alignment.getDataset() == null ? alignment + : alignment.getDataset(); + boolean dna = alignment.isNucleotide(); + if (_odna != dna) + { + System.err + .println("Conflict: showProducts for alignment originally " + + "thought to be " + (_odna ? "DNA" : "Protein") + + " now searching for " + (dna ? "DNA" : "Protein") + + " Context."); + } + AlignmentI xrefs = new CrossRef(sel, dataset).findXrefSequences( + source, dna); + if (xrefs == null) + { + return; + } + /* + * get display scheme (if any) to apply to features + */ + FeatureSettingsModelI featureColourScheme = new SequenceFetcher() + .getFeatureColourScheme(source); + + AlignmentI xrefsAlignment = makeCrossReferencesAlignment(dataset, + xrefs); + if (!dna) + { + xrefsAlignment = AlignmentUtils.makeCdsAlignment( + xrefsAlignment.getSequencesArray(), dataset, sel); + xrefsAlignment.alignAs(alignment); + } + + /* + * If we are opening a splitframe, make a copy of this alignment (sharing the same dataset + * sequences). If we are DNA, drop introns and update mappings + */ + AlignmentI copyAlignment = null; + + if (Cache.getDefault(Preferences.ENABLE_SPLIT_FRAME, true)) + { + boolean copyAlignmentIsAligned = false; + if (dna) + { + copyAlignment = AlignmentUtils.makeCdsAlignment(sel, dataset, + xrefsAlignment.getSequencesArray()); + if (copyAlignment.getHeight() == 0) + { + JOptionPane.showMessageDialog(alignFrame, + MessageManager.getString("label.cant_map_cds"), + MessageManager.getString("label.operation_failed"), + JOptionPane.OK_OPTION); + System.err.println("Failed to make CDS alignment"); + } + + /* + * pending getting Embl transcripts to 'align', + * we are only doing this for Ensembl + */ + // TODO proper criteria for 'can align as cdna' + if (DBRefSource.ENSEMBL.equalsIgnoreCase(source) + || AlignmentUtils.looksLikeEnsembl(alignment)) + { + copyAlignment.alignAs(alignment); + copyAlignmentIsAligned = true; + } + } + else + { + copyAlignment = AlignmentUtils.makeCopyAlignment(sel, + xrefs.getSequencesArray(), dataset); + } + copyAlignment + .setGapCharacter(alignFrame.viewport.getGapCharacter()); + + StructureSelectionManager ssm = StructureSelectionManager + .getStructureSelectionManager(Desktop.instance); + + /* + * register any new mappings for sequence mouseover etc + * (will not duplicate any previously registered mappings) + */ + ssm.registerMappings(dataset.getCodonFrames()); + + if (copyAlignment.getHeight() <= 0) + { + System.err.println("No Sequences generated for xRef type " + + source); + return; + } + /* + * align protein to dna + */ + if (dna && copyAlignmentIsAligned) + { + xrefsAlignment.alignAs(copyAlignment); + } + else + { + /* + * align cdna to protein - currently only if + * fetching and aligning Ensembl transcripts! + */ + // TODO: generalise for other sources of locus/transcript/cds data + if (dna && DBRefSource.ENSEMBL.equalsIgnoreCase(source)) + { + copyAlignment.alignAs(xrefsAlignment); + } + } + } + /* + * build AlignFrame(s) according to available alignment data + */ + AlignFrame newFrame = new AlignFrame(xrefsAlignment, + AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT); + if (Cache.getDefault("HIDE_INTRONS", true)) + { + newFrame.hideFeatureColumns(SequenceOntologyI.EXON, false); + } + String newtitle = String.format("%s %s %s", + dna ? MessageManager.getString("label.proteins") + : MessageManager.getString("label.nucleotides"), + MessageManager.getString("label.for"), alignFrame.getTitle()); + newFrame.setTitle(newtitle); + + if (copyAlignment == null) + { + /* + * split frame display is turned off in preferences file + */ + Desktop.addInternalFrame(newFrame, newtitle, + AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT); + xrefViews.add(newFrame.alignPanel); + return; // via finally clause + } + AlignFrame copyThis = new AlignFrame(copyAlignment, + AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT); + copyThis.setTitle(alignFrame.getTitle()); + + boolean showSequenceFeatures = alignFrame.getViewport() + .isShowSequenceFeatures(); + newFrame.setShowSeqFeatures(showSequenceFeatures); + copyThis.setShowSeqFeatures(showSequenceFeatures); + FeatureRenderer myFeatureStyling = alignFrame.alignPanel + .getSeqPanel().seqCanvas.getFeatureRenderer(); + + /* + * copy feature rendering settings to split frame + */ + newFrame.alignPanel.getSeqPanel().seqCanvas.getFeatureRenderer() + .transferSettings(myFeatureStyling); + copyThis.alignPanel.getSeqPanel().seqCanvas.getFeatureRenderer() + .transferSettings(myFeatureStyling); + + /* + * apply 'database source' feature configuration + * if any was found + */ + // TODO is this the feature colouring for the original + // alignment or the fetched xrefs? either could be Ensembl + newFrame.getViewport().applyFeaturesStyle(featureColourScheme); + copyThis.getViewport().applyFeaturesStyle(featureColourScheme); + + SplitFrame sf = new SplitFrame(dna ? copyThis : newFrame, + dna ? newFrame : copyThis); + newFrame.setVisible(true); + copyThis.setVisible(true); + String linkedTitle = MessageManager + .getString("label.linked_view_title"); + Desktop.addInternalFrame(sf, linkedTitle, -1, -1); + sf.adjustDivider(); + + // finally add the top, then bottom frame to the view list + xrefViews.add(dna ? copyThis.alignPanel : newFrame.alignPanel); + xrefViews.add(!dna ? copyThis.alignPanel : newFrame.alignPanel); + + } catch (OutOfMemoryError e) + { + new OOMWarning("whilst fetching crossreferences", e); + } catch (Throwable e) + { + Cache.log.error("Error when finding crossreferences", e); + } finally + { + alignFrame.setProgressBar(MessageManager.formatMessage( + "status.finished_searching_for_sequences_from", + new Object[] { source }), sttime); + } + } + + /** + * Makes an alignment containing the given sequences, and adds them to the + * given dataset, which is also set as the dataset for the new alignment + * + * TODO: refactor to DatasetI method + * + * @param dataset + * @param seqs + * @return + */ + protected AlignmentI makeCrossReferencesAlignment(AlignmentI dataset, + AlignmentI seqs) + { + SequenceI[] sprods = new SequenceI[seqs.getHeight()]; + for (int s = 0; s < sprods.length; s++) + { + sprods[s] = (seqs.getSequenceAt(s)).deriveSequence(); + if (dataset.getSequences() == null + || !dataset.getSequences().contains( + sprods[s].getDatasetSequence())) + { + dataset.addSequence(sprods[s].getDatasetSequence()); + } + sprods[s].updatePDBIds(); + } + Alignment al = new Alignment(sprods); + al.setDataset(dataset); + return al; + } + + public CrossRefAction(AlignFrame alignFrame, SequenceI[] sel, + boolean _odna, String source) + { + this.alignFrame = alignFrame; + this.sel = sel; + this._odna = _odna; + this.source = source; + } + + public static CrossRefAction showProductsFor(final SequenceI[] sel, + final boolean _odna, final String source, + final AlignFrame alignFrame) + { + return new CrossRefAction(alignFrame, sel, _odna, source); + } + +} diff --git a/src/jalview/gui/Jalview2XML.java b/src/jalview/gui/Jalview2XML.java index 68245b6..a9ff3b8 100644 --- a/src/jalview/gui/Jalview2XML.java +++ b/src/jalview/gui/Jalview2XML.java @@ -365,6 +365,12 @@ public class Jalview2XML public jalview.datamodel.Mapping mp = _jmap; @Override + public boolean isResolvable() + { + return super.isResolvable() && mp.getTo() != null; + }; + + @Override boolean resolve() { SequenceI seq = getSrefDatasetSeq(); @@ -787,37 +793,42 @@ public class Jalview2XML JSeq jseq; Set calcIdSet = new HashSet(); - + // record the set of vamsas sequence XML POJO we create. + HashMap vamsasSetIds = new HashMap(); // SAVE SEQUENCES for (final SequenceI jds : rjal.getSequences()) { final SequenceI jdatasq = jds.getDatasetSequence() == null ? jds : jds.getDatasetSequence(); String id = seqHash(jds); - - if (seqRefIds.get(id) != null) - { - // This happens for two reasons: 1. multiple views are being serialised. - // 2. the hashCode has collided with another sequence's code. This DOES - // HAPPEN! (PF00072.15.stk does this) - // JBPNote: Uncomment to debug writing out of files that do not read - // back in due to ArrayOutOfBoundExceptions. - // System.err.println("vamsasSeq backref: "+id+""); - // System.err.println(jds.getName()+" - // "+jds.getStart()+"-"+jds.getEnd()+" "+jds.getSequenceAsString()); - // System.err.println("Hashcode: "+seqHash(jds)); - // SequenceI rsq = (SequenceI) seqRefIds.get(id + ""); - // System.err.println(rsq.getName()+" - // "+rsq.getStart()+"-"+rsq.getEnd()+" "+rsq.getSequenceAsString()); - // System.err.println("Hashcode: "+seqHash(rsq)); - } - else - { - vamsasSeq = createVamsasSequence(id, jds); - vamsasSet.addSequence(vamsasSeq); - seqRefIds.put(id, jds); + if (vamsasSetIds.get(id) == null) + { + if (seqRefIds.get(id) != null && !storeDS) + { + // This happens for two reasons: 1. multiple views are being + // serialised. + // 2. the hashCode has collided with another sequence's code. This + // DOES + // HAPPEN! (PF00072.15.stk does this) + // JBPNote: Uncomment to debug writing out of files that do not read + // back in due to ArrayOutOfBoundExceptions. + // System.err.println("vamsasSeq backref: "+id+""); + // System.err.println(jds.getName()+" + // "+jds.getStart()+"-"+jds.getEnd()+" "+jds.getSequenceAsString()); + // System.err.println("Hashcode: "+seqHash(jds)); + // SequenceI rsq = (SequenceI) seqRefIds.get(id + ""); + // System.err.println(rsq.getName()+" + // "+rsq.getStart()+"-"+rsq.getEnd()+" "+rsq.getSequenceAsString()); + // System.err.println("Hashcode: "+seqHash(rsq)); + } + else + { + vamsasSeq = createVamsasSequence(id, jds); + vamsasSet.addSequence(vamsasSeq); + vamsasSetIds.put(id, vamsasSeq); + seqRefIds.put(id, jds); + } } - jseq = new JSeq(); jseq.setStart(jds.getStart()); jseq.setEnd(jds.getEnd()); @@ -2649,14 +2660,16 @@ public class Jalview2XML * @param pdbId * @return */ - String loadPDBFile(jarInputStreamProvider jprovider, String pdbId) + String loadPDBFile(jarInputStreamProvider jprovider, String pdbId, + String origFile) { if (alreadyLoadedPDB.containsKey(pdbId)) { return alreadyLoadedPDB.get(pdbId).toString(); } - String tempFile = copyJarEntry(jprovider, pdbId, "jalview_pdb"); + String tempFile = copyJarEntry(jprovider, pdbId, "jalview_pdb", + origFile); if (tempFile != null) { alreadyLoadedPDB.put(pdbId, tempFile); @@ -2673,14 +2686,26 @@ public class Jalview2XML * @param prefix * a prefix for the temporary file name, must be at least three * characters long + * @param origFile + * null or original file - so new file can be given the same suffix + * as the old one * @return */ protected String copyJarEntry(jarInputStreamProvider jprovider, - String jarEntryName, String prefix) + String jarEntryName, String prefix, String origFile) { BufferedReader in = null; PrintWriter out = null; - + String suffix = ".tmp"; + if (origFile == null) + { + origFile = jarEntryName; + } + int sfpos = origFile.lastIndexOf("."); + if (sfpos > -1 && sfpos < (origFile.length() - 3)) + { + suffix = "." + origFile.substring(sfpos + 1); + } try { JarInputStream jin = jprovider.getJarInputStream(); @@ -2698,7 +2723,7 @@ public class Jalview2XML if (entry != null) { in = new BufferedReader(new InputStreamReader(jin, UTF_8)); - File outFile = File.createTempFile(prefix, ".tmp"); + File outFile = File.createTempFile(prefix, suffix); outFile.deleteOnExit(); out = new PrintWriter(new FileOutputStream(outFile)); String data; @@ -2808,15 +2833,28 @@ public class Jalview2XML { System.err .println("Warning JAL-2154 regression: updating start/end for sequence " - + tmpSeq.toString()); + + tmpSeq.toString() + " to " + jseqs[i]); } } else { incompleteSeqs.remove(seqId); } + if (vamsasSeq.length > vi && vamsasSeq[vi].getId().equals(seqId)) + { + // most likely we are reading a dataset XML document so + // update from vamsasSeq section of XML for this sequence + tmpSeq.setName(vamsasSeq[vi].getName()); + tmpSeq.setDescription(vamsasSeq[vi].getDescription()); + tmpSeq.setSequence(vamsasSeq[vi].getSequence()); + vi++; + } + else + { + // reading multiple views, so vamsasSeq set is a subset of JSeq + multipleView = true; + } tmpSeq.setStart(jseqs[i].getStart()); tmpSeq.setEnd(jseqs[i].getEnd()); tmpseqs.add(tmpSeq); - multipleView = true; } else { @@ -2905,6 +2943,12 @@ public class Jalview2XML { // load sequence features, database references and any associated PDB // structures for the alignment + // + // prior to 2.10, this part would only be executed the first time a + // sequence was encountered, but not afterwards. + // now, for 2.10 projects, this is also done if the xml doc includes + // dataset sequences not actually present in any particular view. + // for (int i = 0; i < vamsasSeq.length; i++) { if (jseqs[i].getFeaturesCount() > 0) @@ -2931,13 +2975,17 @@ public class Jalview2XML } } - - al.getSequenceAt(i).getDatasetSequence().addSequenceFeature(sf); + // adds feature to datasequence's feature set (since Jalview 2.10) + al.getSequenceAt(i).addSequenceFeature(sf); } } if (vamsasSeq[i].getDBRefCount() > 0) { - addDBRefs(al.getSequenceAt(i).getDatasetSequence(), vamsasSeq[i]); + // adds dbrefs to datasequence's set (since Jalview 2.10) + addDBRefs( + al.getSequenceAt(i).getDatasetSequence() == null ? al.getSequenceAt(i) + : al.getSequenceAt(i).getDatasetSequence(), + vamsasSeq[i]); } if (jseqs[i].getPdbidsCount() > 0) { @@ -2948,9 +2996,9 @@ public class Jalview2XML entry.setId(ids[p].getId()); if (ids[p].getType() != null) { - if (ids[p].getType().equalsIgnoreCase("PDB")) + if (PDBEntry.Type.getType(ids[p].getType()) != null) { - entry.setType(PDBEntry.Type.PDB); + entry.setType(PDBEntry.Type.getType(ids[p].getType())); } else { @@ -2961,16 +3009,36 @@ public class Jalview2XML { if (!pdbloaded.containsKey(ids[p].getFile())) { - entry.setFile(loadPDBFile(jprovider, ids[p].getId())); + entry.setFile(loadPDBFile(jprovider, ids[p].getId(), + ids[p].getFile())); } else { entry.setFile(pdbloaded.get(ids[p].getId()).toString()); } } + if (ids[p].getPdbentryItem() != null) + { + entry.setProperty(new Hashtable()); + for (PdbentryItem item : ids[p].getPdbentryItem()) + { + for (Property pr : item.getProperty()) + { + entry.getProperty().put(pr.getName(), pr.getValue()); + } + } + } StructureSelectionManager.getStructureSelectionManager( Desktop.instance).registerPDBEntry(entry); - al.getSequenceAt(i).getDatasetSequence().addPDBId(entry); + // adds PDBEntry to datasequence's set (since Jalview 2.10) + if (al.getSequenceAt(i).getDatasetSequence() != null) + { + al.getSequenceAt(i).getDatasetSequence().addPDBId(entry); + } + else + { + al.getSequenceAt(i).addPDBId(entry); + } } } } @@ -2999,16 +3067,16 @@ public class Jalview2XML if (maps[m].getMapping() != null) { mapping = addMapping(maps[m].getMapping()); - } - if (dnaseq != null && mapping.getTo() != null) - { - cf.addMap(dnaseq, mapping.getTo(), mapping.getMap()); - } - else - { - // defer to later - frefedSequence.add(newAlcodMapRef(maps[m].getDnasq(), cf, - mapping)); + if (dnaseq != null && mapping.getTo() != null) + { + cf.addMap(dnaseq, mapping.getTo(), mapping.getMap()); + } + else + { + // defer to later + frefedSequence.add(newAlcodMapRef(maps[m].getDnasq(), cf, + mapping)); + } } } al.addCodonFrame(cf); @@ -3512,7 +3580,7 @@ public class Jalview2XML String rnaTitle = ss.getTitle(); String sessionState = ss.getViewerState(); String tempStateFile = copyJarEntry(jprovider, sessionState, - "varna"); + "varna", null); RnaModel rna = new RnaModel(rnaTitle, ann, seq, null, gapped); appVarna.addModelSession(rna, rnaTitle, tempStateFile); } @@ -3687,7 +3755,8 @@ public class Jalview2XML // Originally : ids[p].getFile() // : TODO: verify external PDB file recovery still works in normal // jalview project load - jpdb.setFile(loadPDBFile(jprovider, ids[p].getId())); + jpdb.setFile(loadPDBFile(jprovider, ids[p].getId(), + ids[p].getFile())); jpdb.setId(ids[p].getId()); int x = structureState.getXpos(); @@ -3698,7 +3767,8 @@ public class Jalview2XML // Probably don't need to do this anymore... // Desktop.desktop.getComponentAt(x, y); // TODO: NOW: check that this recovers the PDB file correctly. - String pdbFile = loadPDBFile(jprovider, ids[p].getId()); + String pdbFile = loadPDBFile(jprovider, ids[p].getId(), + ids[p].getFile()); jalview.datamodel.SequenceI seq = seqRefIds.get(jseqs[i] .getId() + ""); if (sviewid == null) @@ -3858,7 +3928,7 @@ public class Jalview2XML */ String viewerJarEntryName = getViewerJarEntryName(data.getViewId()); chimeraSessionFile = copyJarEntry(jprovider, viewerJarEntryName, - "chimera"); + "chimera", null); Set> fileData = data.getFileData() .entrySet(); @@ -4898,7 +4968,7 @@ public class Jalview2XML for (int i = 0, iSize = vamsasSet.getSequenceCount(); i < iSize; i++) { Sequence vamsasSeq = vamsasSet.getSequence(i); - ensureJalviewDatasetSequence(vamsasSeq, ds, dseqs, ignoreUnrefed); + ensureJalviewDatasetSequence(vamsasSeq, ds, dseqs, ignoreUnrefed, i); } // create a new dataset if (ds == null) @@ -4925,18 +4995,29 @@ public class Jalview2XML * dataset alignment * @param dseqs * vector to add new dataset sequence to + * @param ignoreUnrefed + * - when true, don't create new sequences from vamsasSeq if it's id + * doesn't already have an asssociated Jalview sequence. + * @param vseqpos + * - used to reorder the sequence in the alignment according to the + * vamsasSeq array ordering, to preserve ordering of dataset */ private void ensureJalviewDatasetSequence(Sequence vamsasSeq, - AlignmentI ds, Vector dseqs, boolean ignoreUnrefed) + AlignmentI ds, Vector dseqs, boolean ignoreUnrefed, int vseqpos) { // JBP TODO: Check this is called for AlCodonFrames to support recovery of // xRef Codon Maps SequenceI sq = seqRefIds.get(vamsasSeq.getId()); + boolean reorder = false; SequenceI dsq = null; if (sq != null && sq.getDatasetSequence() != null) { dsq = sq.getDatasetSequence(); } + else + { + reorder = true; + } if (sq == null && ignoreUnrefed) { return; @@ -5032,6 +5113,35 @@ public class Jalview2XML // + (post ? "appended" : "")); } } + else + { + // sequence refs are identical. We may need to update the existing dataset + // alignment with this one, though. + if (ds != null && dseqs == null) + { + int opos = ds.findIndex(dsq); + SequenceI tseq = null; + if (opos != -1 && vseqpos != opos) + { + // remove from old position + ds.deleteSequence(dsq); + } + if (vseqpos < ds.getHeight()) + { + if (vseqpos != opos) + { + // save sequence at destination position + tseq = ds.getSequenceAt(vseqpos); + ds.replaceSequenceAt(vseqpos, dsq); + ds.addSequence(tseq); + } + } + else + { + ds.addSequence(dsq); + } + } + } } /* diff --git a/src/jalview/gui/SequenceFetcher.java b/src/jalview/gui/SequenceFetcher.java index afe6754..5d4ea68 100755 --- a/src/jalview/gui/SequenceFetcher.java +++ b/src/jalview/gui/SequenceFetcher.java @@ -43,6 +43,7 @@ import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.Iterator; import java.util.List; @@ -200,8 +201,19 @@ public class SequenceFetcher extends JPanel implements Runnable private IProgressIndicator progressIndicator; + private volatile boolean _isConstructing = false; + + private List newAlframes = null; + public SequenceFetcher(IProgressIndicator guiIndic) { + this(guiIndic, null, null); + } + + public SequenceFetcher(IProgressIndicator guiIndic, + final String selectedDb, final String queryString) + { + this._isConstructing=true; this.progressIndicator = guiIndic; final SequenceFetcher us = this; // launch initialiser thread @@ -213,7 +225,8 @@ public class SequenceFetcher extends JPanel implements Runnable { if (getSequenceFetcherSingleton(progressIndicator) != null) { - us.initGui(progressIndicator); + us.initGui(progressIndicator, selectedDb, queryString); + us._isConstructing=false; } else { @@ -239,6 +252,26 @@ public class SequenceFetcher extends JPanel implements Runnable }); sf.start(); } + /** + * blocking call which creates a new sequence fetcher panel, configures it and presses the OK button with the given database and query. + * @param database + * @param query + */ + public static List fetchAndShow(String database, String query) + { + final SequenceFetcher sf = new SequenceFetcher(Desktop.instance, database, query); + while (sf._isConstructing) + { + try { Thread.sleep(50); + } catch (Exception q) + { + return Collections.emptyList(); + } + } + sf.newAlframes = new ArrayList(); + sf.run(); + return sf.newAlframes; + } private class DatabaseAuthority extends DefaultMutableTreeNode { @@ -249,13 +282,59 @@ public class SequenceFetcher extends JPanel implements Runnable { }; + + /** + * initialise the database and query for this fetcher panel + * + * @param selectedDb + * - string that should correspond to a sequence fetcher + * @param queryString + * - string that will be entered in the query dialog + * @return true if UI was configured with valid database and query string + */ + protected boolean setInitialQuery(String selectedDb, String queryString) + { + if (selectedDb == null || selectedDb.trim().length() == 0) + { + return false; + } + try + { + List sp = sfetch.getSourceProxy(selectedDb); + for (DbSourceProxy sourcep : sp) + { + if (sourcep.getTier() == 0) + { + database.selection = Arrays + .asList(new DbSourceProxy[] { sourcep }); + break; + } + } + if (database.selection == null || database.selection.size() == 0) + { + System.err.println("Ignoring fetch parameter db='" + selectedDb + + "'"); + return false; + } + textArea.setText(queryString); + } catch (Exception q) + { + System.err.println("Ignoring fetch parameter db='" + selectedDb + + "' and query='" + queryString + "'"); + return false; + } + return true; + } /** * called by thread spawned by constructor * * @param guiWindow + * @param queryString + * @param selectedDb */ - private void initGui(IProgressIndicator guiWindow) + private void initGui(IProgressIndicator guiWindow, String selectedDb, + String queryString) { this.guiWindow = guiWindow; if (guiWindow instanceof AlignFrame) @@ -266,6 +345,16 @@ public class SequenceFetcher extends JPanel implements Runnable try { jbInit(); + /* + * configure the UI with any query parameters we were called with + */ + if (!setInitialQuery(selectedDb, queryString)) + { + /* + * none provided, so show the database chooser + */ + database.waitForInput(); + } } catch (Exception ex) { ex.printStackTrace(); @@ -419,11 +508,6 @@ public class SequenceFetcher extends JPanel implements Runnable this.add(jPanel3, java.awt.BorderLayout.CENTER); this.add(jPanel2, java.awt.BorderLayout.NORTH); jScrollPane1.getViewport().add(textArea); - - /* - * open the database tree - */ - database.waitForInput(); } private void pdbSourceAction() @@ -936,7 +1020,10 @@ public class SequenceFetcher extends JPanel implements Runnable { af.hideFeatureColumns(SequenceOntologyI.EXON, false); } - + if (newAlframes != null) + { + newAlframes.add(af); + } Desktop.addInternalFrame(af, title, AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT); diff --git a/src/jalview/gui/StructureChooser.java b/src/jalview/gui/StructureChooser.java index 13fa460..33c7ff3 100644 --- a/src/jalview/gui/StructureChooser.java +++ b/src/jalview/gui/StructureChooser.java @@ -33,6 +33,7 @@ import jalview.fts.core.FTSRestRequest; import jalview.fts.core.FTSRestResponse; import jalview.fts.service.pdb.PDBFTSRestClient; import jalview.jbgui.GStructureChooser; +import jalview.structure.StructureMapping; import jalview.structure.StructureSelectionManager; import jalview.util.MessageManager; import jalview.ws.DBRefFetcher; @@ -865,9 +866,28 @@ public class StructureChooser extends GStructureChooser implements if (SiftsSettings.isMapWithSifts()) { ArrayList seqsWithoutSourceDBRef = new ArrayList(); + int p = 0; + // TODO: skip PDBEntry:Sequence pairs where PDBEntry doesn't look like a + // real PDB ID. For moment, we can also safely do this if there is already + // a known mapping between the PDBEntry and the sequence. for (SequenceI seq : sequences) { - if (seq.getSourceDBRef() == null && seq.getDBRefs() == null) + PDBEntry pdbe = pdbEntriesToView[p++]; + if (pdbe != null && pdbe.getFile() != null) + { + StructureMapping[] smm = ssm.getMapping(pdbe.getFile()); + if (smm != null && smm.length > 0) + { + for (StructureMapping sm : smm) + { + if (sm.getSequence() == seq) + { + continue; + } + } + } + } + if (seq.getPrimaryDBRefs().size() == 0) { seqsWithoutSourceDBRef.add(seq); continue; diff --git a/src/jalview/io/StructureFile.java b/src/jalview/io/StructureFile.java index fc0e207..4a6a1c2 100644 --- a/src/jalview/io/StructureFile.java +++ b/src/jalview/io/StructureFile.java @@ -99,7 +99,7 @@ public abstract class StructureFile extends AlignFile pdbSequence.setName(getId() + "|" + pdbSequence.getName()); PDBEntry entry = new PDBEntry(); entry.setId(getId()); - entry.setType(this.dbRefType); + entry.setType(getStructureFileType()); entry.setProperty(new Hashtable()); if (chain.id != null) { @@ -117,7 +117,9 @@ public abstract class StructureFile extends AlignFile DBRefEntry sourceDBRef = new DBRefEntry(); sourceDBRef.setAccessionId(getId()); sourceDBRef.setSource(DBRefSource.PDB); - pdbSequence.setSourceDBRef(sourceDBRef); + // TODO: specify version for 'PDB' database ref if it is read from a file. + // TODO: decide if jalview.io should be creating primary refs! + sourceDBRef.setVersion(""); pdbSequence.addPDBId(entry); pdbSequence.addDBRef(sourceDBRef); SequenceI chainseq = pdbSequence; @@ -135,6 +137,26 @@ public abstract class StructureFile extends AlignFile return chainseq; } + /** + * filetype of structure file - default is PDB + */ + String structureFileType = PDBEntry.Type.PDB.toString(); + + protected void setStructureFileType(String structureFileType) + { + this.structureFileType = structureFileType; + } + + /** + * filetype of last file processed + * + * @return + */ + public String getStructureFileType() + { + return structureFileType; + } + @SuppressWarnings({ "unchecked", "rawtypes" }) protected void processPdbFileWithAnnotate3d(List rna) throws Exception @@ -407,7 +429,7 @@ public abstract class StructureFile extends AlignFile public void setDbRefType(String dbRefType) { - this.dbRefType = Type.valueOf(dbRefType); + this.dbRefType = Type.getType(dbRefType); } public void setDbRefType(Type dbRefType) diff --git a/src/jalview/structure/StructureSelectionManager.java b/src/jalview/structure/StructureSelectionManager.java index be042e6..c27289c 100644 --- a/src/jalview/structure/StructureSelectionManager.java +++ b/src/jalview/structure/StructureSelectionManager.java @@ -428,6 +428,12 @@ public class StructureSelectionManager { boolean infChain = true; final SequenceI seq = sequenceArray[s]; + SequenceI ds = seq; + while (ds.getDatasetSequence() != null) + { + ds = ds.getDatasetSequence(); + } + if (targetChainIds != null && targetChainIds[s] != null) { infChain = false; @@ -502,7 +508,7 @@ public class StructureSelectionManager } ArrayList seqToStrucMapping = new ArrayList(); - if (isMapUsingSIFTs) + if (isMapUsingSIFTs && seq.isProtein()) { setProgressBar(null); setProgressBar(MessageManager @@ -518,8 +524,11 @@ public class StructureSelectionManager pdb, maxChain, sqmpping, maxAlignseq); seqToStrucMapping.add(siftsMapping); maxChain.makeExactMapping(maxAlignseq, seq); - maxChain.transferRESNUMFeatures(seq, null); + maxChain.transferRESNUMFeatures(seq, null);// FIXME: is this + // "IEA:SIFTS" ? maxChain.transferResidueAnnotation(siftsMapping, sqmpping); + ds.addPDBId(maxChain.sequence.getAllPDBEntries().get(0)); + } catch (SiftsException e) { // fall back to NW alignment @@ -527,6 +536,11 @@ public class StructureSelectionManager StructureMapping nwMapping = getNWMappings(seq, pdbFile, targetChainId, maxChain, pdb, maxAlignseq); seqToStrucMapping.add(nwMapping); + maxChain.makeExactMapping(maxAlignseq, seq); + maxChain.transferRESNUMFeatures(seq, null); // FIXME: is this + // "IEA:Jalview" ? + maxChain.transferResidueAnnotation(nwMapping, sqmpping); + ds.addPDBId(maxChain.sequence.getAllPDBEntries().get(0)); } } else @@ -549,15 +563,21 @@ public class StructureSelectionManager { seqToStrucMapping.addAll(foundSiftsMappings); maxChain.makeExactMapping(maxAlignseq, seq); - maxChain.transferRESNUMFeatures(seq, null); + maxChain.transferRESNUMFeatures(seq, null);// FIXME: is this + // "IEA:SIFTS" ? maxChain.transferResidueAnnotation(foundSiftsMappings.get(0), sqmpping); + ds.addPDBId(sqmpping.getTo().getAllPDBEntries().get(0)); } else { StructureMapping nwMapping = getNWMappings(seq, pdbFile, maxChainId, maxChain, pdb, maxAlignseq); seqToStrucMapping.add(nwMapping); + maxChain.transferRESNUMFeatures(seq, null); // FIXME: is this + // "IEA:Jalview" ? + maxChain.transferResidueAnnotation(nwMapping, sqmpping); + ds.addPDBId(maxChain.sequence.getAllPDBEntries().get(0)); } } } @@ -566,8 +586,11 @@ public class StructureSelectionManager setProgressBar(null); setProgressBar(MessageManager .getString("status.obtaining_mapping_with_nw_alignment")); - seqToStrucMapping.add(getNWMappings(seq, pdbFile, maxChainId, - maxChain, pdb, maxAlignseq)); + StructureMapping nwMapping = getNWMappings(seq, pdbFile, + maxChainId, maxChain, pdb, maxAlignseq); + seqToStrucMapping.add(nwMapping); + ds.addPDBId(maxChain.sequence.getAllPDBEntries().get(0)); + } if (forStructureView) @@ -585,6 +608,20 @@ public class StructureSelectionManager return "cif".equalsIgnoreCase(fileExt); } + /** + * retrieve a mapping for seq from SIFTs using associated DBRefEntry for + * uniprot or PDB + * + * @param seq + * @param pdbFile + * @param targetChainId + * @param pdb + * @param maxChain + * @param sqmpping + * @param maxAlignseq + * @return + * @throws SiftsException + */ private StructureMapping getStructureMapping(SequenceI seq, String pdbFile, String targetChainId, StructureFile pdb, PDBChain maxChain, jalview.datamodel.Mapping sqmpping, diff --git a/src/jalview/util/DBRefUtils.java b/src/jalview/util/DBRefUtils.java index d5d0cf5..405f6e6 100755 --- a/src/jalview/util/DBRefUtils.java +++ b/src/jalview/util/DBRefUtils.java @@ -31,6 +31,7 @@ import java.util.HashSet; import java.util.Hashtable; import java.util.List; import java.util.Map; +import java.util.Set; import com.stevesoft.pat.Regex; @@ -59,6 +60,18 @@ public class DBRefUtils canonicalSourceNameLookup.put("pdb", DBRefSource.PDB); canonicalSourceNameLookup.put("ensembl", DBRefSource.ENSEMBL); + // Ensembl Gn and Tr are for Ensembl genomic and transcript IDs as served + // from ENA. + canonicalSourceNameLookup.put("ensembl-tr", DBRefSource.ENSEMBL); + canonicalSourceNameLookup.put("ensembl-gn", DBRefSource.ENSEMBL); + + // Make sure we have lowercase entries for all canonical string lookups + Set keys = canonicalSourceNameLookup.keySet(); + for (String k : keys) + { + canonicalSourceNameLookup.put(k.toLowerCase(), + canonicalSourceNameLookup.get(k)); + } dasCoordinateSystemsLookup.put("pdbresnum", DBRefSource.PDB); dasCoordinateSystemsLookup.put("uniprot", DBRefSource.UNIPROT); @@ -235,7 +248,8 @@ public class DBRefUtils public boolean matches(DBRefEntry refa, DBRefEntry refb) { if (refa.getSource() == null - || refb.getSource().equals(refa.getSource())) + || DBRefUtils.getCanonicalName(refb.getSource()).equals( + DBRefUtils.getCanonicalName(refa.getSource()))) { if (refa.getVersion() == null || refb.getVersion().equals(refa.getVersion())) @@ -266,7 +280,7 @@ public class DBRefUtils @Override public boolean matches(DBRefEntry refa, DBRefEntry refb) { - if (nullOrEqual(refa.getSource(), refb.getSource()) + if (nullOrEqualSource(refa.getSource(), refb.getSource()) && nullOrEqual(refa.getVersion(), refb.getVersion()) && nullOrEqual(refa.getAccessionId(), refb.getAccessionId()) && nullOrEqual(refa.getMap(), refb.getMap())) @@ -288,7 +302,8 @@ public class DBRefUtils public boolean matches(DBRefEntry refa, DBRefEntry refb) { if (refa.getSource() != null && refb.getSource() != null - && refb.getSource().equals(refa.getSource())) + && DBRefUtils.getCanonicalName(refb.getSource()).equals( + DBRefUtils.getCanonicalName(refa.getSource()))) { // We dont care about version if (refa.getAccessionId() != null && refb.getAccessionId() != null @@ -319,7 +334,8 @@ public class DBRefUtils public boolean matches(DBRefEntry refa, DBRefEntry refb) { if (refa.getSource() != null && refb.getSource() != null - && refb.getSource().equals(refa.getSource())) + && DBRefUtils.getCanonicalName(refb.getSource()).equals( + DBRefUtils.getCanonicalName(refa.getSource()))) { // We dont care about version if (refa.getAccessionId() != null && refb.getAccessionId() != null @@ -355,7 +371,8 @@ public class DBRefUtils public boolean matches(DBRefEntry refa, DBRefEntry refb) { if (refa.getSource() != null && refb.getSource() != null - && refb.getSource().equals(refa.getSource())) + && DBRefUtils.getCanonicalName(refb.getSource()).equals( + DBRefUtils.getCanonicalName(refa.getSource()))) { // We dont care about version // if ((refa.getVersion()==null || refb.getVersion()==null) @@ -394,7 +411,8 @@ public class DBRefUtils public boolean matches(DBRefEntry refa, DBRefEntry refb) { if (refa.getSource() != null && refb.getSource() != null - && refb.getSource().equals(refa.getSource())) + && DBRefUtils.getCanonicalName(refb.getSource()).equals( + DBRefUtils.getCanonicalName(refa.getSource()))) { // We dont care about version @@ -521,7 +539,28 @@ public class DBRefUtils { return true; } - return (o1 == null ? o2.equals(o1) : o1.equals(o2)); + return o1.equals(o2); + } + + /** + * canonicalise source string before comparing. null is always wildcard + * + * @param o1 + * - null or source string to compare + * @param o2 + * - null or source string to compare + * @return true if either o1 or o2 are null, or o1 equals o2 under + * DBRefUtils.getCanonicalName + * (o1).equals(DBRefUtils.getCanonicalName(o2)) + */ + public static boolean nullOrEqualSource(String o1, String o2) + { + if (o1 == null || o2 == null) + { + return true; + } + return DBRefUtils.getCanonicalName(o1).equals( + DBRefUtils.getCanonicalName(o2)); } /** diff --git a/src/jalview/util/LinkedIdentityHashSet.java b/src/jalview/util/LinkedIdentityHashSet.java new file mode 100644 index 0000000..bce540f --- /dev/null +++ b/src/jalview/util/LinkedIdentityHashSet.java @@ -0,0 +1,143 @@ +/* + * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$) + * Copyright (C) $$Year-Rel$$ The Jalview Authors + * + * This file is part of Jalview. + * + * Jalview is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 + * of the License, or (at your option) any later version. + * + * Jalview is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Jalview. If not, see . + * The Jalview Authors are detailed in the 'AUTHORS' file. + */ +package jalview.util; + +import java.util.AbstractSet; +import java.util.Iterator; +import java.util.LinkedHashMap; + +/** + * Order preserving Set based on System.identityHashCode() for an object, which + * also supports Object->index lookup. + * + * @author Jim Procter (2016) based on Evgeniy Dorofeev's response: via + * https://stackoverflow.com/questions/17276658/linkedidentityhashset + * + */ +public class LinkedIdentityHashSet extends AbstractSet +{ + LinkedHashMap set = new LinkedHashMap(); + + static class IdentityWrapper + { + Object obj; + + public int p; + + IdentityWrapper(Object obj, int p) + { + this.obj = obj; + this.p = p; + } + + @Override + public boolean equals(Object obj) + { + return this.obj == obj; + } + + @Override + public int hashCode() + { + return System.identityHashCode(obj); + } + } + + @Override + public boolean add(E e) + { + IdentityWrapper el = (new IdentityWrapper(e, set.size())); + // Map.putIfAbsent() from Java 8 + // return set.putIfAbsent(el, el) == null; + return putIfAbsent(el, el) == null; + } + + /** + * If the specified key is not already associated with a value (or is mapped + * to null) associates it with the given value and returns null, else returns + * the current value. + * + * Method added for Java 7 (can remove for Java 8) + * + * @param key + * @param value + * @return + * @see https + * ://docs.oracle.com/javase/8/docs/api/java/util/Map.html#putIfAbsent + * -K-V- + */ + private IdentityWrapper putIfAbsent(IdentityWrapper key, + IdentityWrapper value) + { + IdentityWrapper v = set.get(key); + if (v == null) + { + v = set.put(key, value); + } + return v; + } + + @Override + public Iterator iterator() + { + return new Iterator() + { + final Iterator se = set.keySet().iterator(); + + @Override + public boolean hasNext() + { + return se.hasNext(); + } + + @SuppressWarnings("unchecked") + @Override + public E next() + { + return (E) se.next().obj; + } + + @Override + public void remove() + { + // Java 8 default behaviour + throw new UnsupportedOperationException(); + } + }; + } + + @Override + public int size() + { + return set.size(); + } + + /** + * Lookup the index for e in the set + * + * @param e + * @return position of e in the set when it was added. + */ + public int indexOf(E e) + { + return set.get(e).p; + } +} diff --git a/src/jalview/util/MapList.java b/src/jalview/util/MapList.java index cae968e..dc5bee8 100644 --- a/src/jalview/util/MapList.java +++ b/src/jalview/util/MapList.java @@ -1103,4 +1103,14 @@ public class MapList return forwardStrand; } + /** + * + * @return true if from, or to is a three to 1 mapping + */ + public boolean isTripletMap() + { + return (toRatio == 3 && fromRatio == 1) + || (fromRatio == 3 && toRatio == 1); + } + } diff --git a/src/jalview/util/MappingUtils.java b/src/jalview/util/MappingUtils.java index 515ff51..da83338 100644 --- a/src/jalview/util/MappingUtils.java +++ b/src/jalview/util/MappingUtils.java @@ -757,9 +757,19 @@ public final class MappingUtils return findMappingsForSequenceAndOthers(sequence, mappings, null); } + /** + * Returns a list of any mappings that are from or to the given (aligned or + * dataset) sequence, optionally limited to mappings involving one of a given + * list of sequences. + * + * @param sequence + * @param mappings + * @param filterList + * @return + */ public static List findMappingsForSequenceAndOthers( SequenceI sequence, List mappings, - AlignmentI alignment) + List filterList) { List result = new ArrayList(); if (sequence == null || mappings == null) @@ -770,14 +780,14 @@ public final class MappingUtils { if (mapping.involvesSequence(sequence)) { - if (alignment != null) + if (filterList != null) { - for (SequenceI otherseq : alignment.getSequences()) + for (SequenceI otherseq : filterList) { + SequenceI otherDataset = otherseq.getDatasetSequence(); if (otherseq == sequence - || (otherseq.getDatasetSequence() != null && (otherseq - .getDatasetSequence() == sequence || otherseq - .getDatasetSequence() == sequence + || otherseq == sequence.getDatasetSequence() + || (otherDataset != null && (otherDataset == sequence || otherDataset == sequence .getDatasetSequence()))) { // skip sequences in subset which directly relate to sequence diff --git a/src/jalview/viewmodel/AlignmentViewport.java b/src/jalview/viewmodel/AlignmentViewport.java index bd55668..97f2e1c 100644 --- a/src/jalview/viewmodel/AlignmentViewport.java +++ b/src/jalview/viewmodel/AlignmentViewport.java @@ -2730,7 +2730,7 @@ public abstract class AlignmentViewport implements AlignViewportI, } seqMappings = MappingUtils .findMappingsForSequenceAndOthers(sequence, mappings, - getCodingComplement().getAlignment()); + getCodingComplement().getAlignment().getSequences()); if (!seqMappings.isEmpty()) { break; diff --git a/src/jalview/ws/DBRefFetcher.java b/src/jalview/ws/DBRefFetcher.java index 3ba0e34..ca403c5 100644 --- a/src/jalview/ws/DBRefFetcher.java +++ b/src/jalview/ws/DBRefFetcher.java @@ -176,6 +176,9 @@ public class DBRefFetcher implements Runnable srces.addAll(srcesfordb); } } + // append the PDB data source, since it is 'special', catering for both + // nucleotide and protein + srces.addAll(sfetcher.getSourceProxy(DBRefSource.PDB)); // append the selected sequence sources to the default dbs srces.addAll(selsources); @@ -622,33 +625,43 @@ public class DBRefFetcher implements Runnable final int sequenceStart = sequence.getStart(); if (absStart == -1) { - // Is local sequence contained in dataset sequence? + // couldn't find local sequence in sequence from database, so check if + // the database sequence is a subsequence of local sequence absStart = nonGapped.indexOf(entrySeq); if (absStart == -1) - { // verification failed. + { + // verification failed. couldn't find any relationship between + // entrySeq and local sequence messages.append(sequence.getName() + " SEQUENCE NOT %100 MATCH \n"); continue; } + /* + * found match for the whole of the database sequence within the local + * sequence's reference frame. + */ transferred = true; sbuffer.append(sequence.getName() + " HAS " + absStart + " PREFIXED RESIDUES COMPARED TO " + dbSource + "\n"); - // - // + " - ANY SEQUENCE FEATURES" - // + " HAVE BEEN ADJUSTED ACCORDINGLY \n"); - // absStart = 0; - // create valid mapping between matching region of local sequence and - // the mapped sequence + + /* + * So create a mapping to the external entry from the matching region of + * the local sequence, and leave local start/end untouched. + */ mp = new Mapping(null, new int[] { sequenceStart + absStart, sequenceStart + absStart + entrySeq.length() - 1 }, new int[] { entry.getStart(), entry.getStart() + entrySeq.length() - 1 }, 1, 1); - updateRefFrame = false; // mapping is based on current start/end so - // don't modify start and end + updateRefFrame = false; } else { + /* + * found a match for the local sequence within sequence from + * the external database + */ transferred = true; + // update start and end of local sequence to place it in entry's // reference frame. // apply identity map map from whole of local sequence to matching @@ -660,10 +673,14 @@ public class DBRefFetcher implements Runnable // absStart+sequence.getStart()+entrySeq.length()-1}, // new int[] { entry.getStart(), entry.getEnd() }, 1, 1); // relocate local features for updated start + if (updateRefFrame) { if (sequence.getSequenceFeatures() != null) { + /* + * relocate existing sequence features by offset + */ SequenceFeature[] sf = sequence.getSequenceFeatures(); int start = sequenceStart; int end = sequence.getEnd(); @@ -686,7 +703,7 @@ public class DBRefFetcher implements Runnable System.out.println("Adding dbrefs to " + sequence.getName() + " from " + dbSource + " sequence : " + entry.getName()); sequence.transferAnnotation(entry, mp); - // unknownSequences.remove(sequence); + absStart += entry.getStart(); int absEnd = absStart + nonGapped.length() - 1; if (!trimDatasetSeqs) diff --git a/src/jalview/ws/dbsources/Pdb.java b/src/jalview/ws/dbsources/Pdb.java index 61c5c04..04c23a2 100644 --- a/src/jalview/ws/dbsources/Pdb.java +++ b/src/jalview/ws/dbsources/Pdb.java @@ -173,6 +173,8 @@ public class Pdb extends EbiFileRetrievedProxy || chid.trim().equals(chain.trim()) || (chain .trim().length() == 0 && chid.equals("_"))))) { + // FIXME seems to result in 'PDB|1QIP|1qip|A' - 1QIP is redundant. + // TODO: suggest simplify naming to 1qip|A as default name defined pdbcs.setName(jalview.datamodel.DBRefSource.PDB + "|" + id + "|" + pdbcs.getName()); // Might need to add more metadata to the PDBEntry object diff --git a/src/jalview/ws/dbsources/Uniprot.java b/src/jalview/ws/dbsources/Uniprot.java index 8cc0ce4..81b4caf 100644 --- a/src/jalview/ws/dbsources/Uniprot.java +++ b/src/jalview/ws/dbsources/Uniprot.java @@ -205,10 +205,10 @@ public class Uniprot extends DbSourceProxyImpl { DBRefEntry dbRef = new DBRefEntry(DBRefSource.UNIPROT, dbVersion, accessionId); + + // mark dbRef as a primary reference for this sequence dbRefs.add(dbRef); } - sequence.setSourceDBRef((dbRefs != null && dbRefs.size() > 0) ? dbRefs - .get(0) : null); Vector onlyPdbEntries = new Vector(); for (PDBEntry pdb : entry.getDbReference()) diff --git a/src/jalview/ws/sifts/SiftsClient.java b/src/jalview/ws/sifts/SiftsClient.java index 6c94723..f20954e 100644 --- a/src/jalview/ws/sifts/SiftsClient.java +++ b/src/jalview/ws/sifts/SiftsClient.java @@ -29,6 +29,7 @@ import jalview.datamodel.SequenceI; import jalview.io.StructureFile; import jalview.schemes.ResidueProperties; import jalview.structure.StructureMapping; +import jalview.util.DBRefUtils; import jalview.util.Format; import jalview.xml.binding.sifts.Entry; import jalview.xml.binding.sifts.Entry.Entity; @@ -323,41 +324,29 @@ public class SiftsClient implements SiftsClientI public DBRefEntryI getValidSourceDBRef(SequenceI seq) throws SiftsException { - DBRefEntryI sourceDBRef = null; - sourceDBRef = seq.getSourceDBRef(); - if (sourceDBRef != null && isValidDBRefEntry(sourceDBRef)) + List dbRefs = seq.getPrimaryDBRefs(); + if (dbRefs == null || dbRefs.size() < 1) { - return sourceDBRef; + throw new SiftsException( + "Source DBRef could not be determined. DBRefs might not have been retrieved."); } - else + + for (DBRefEntry dbRef : dbRefs) { - DBRefEntry[] dbRefs = seq.getDBRefs(); - if (dbRefs == null || dbRefs.length < 1) + if (dbRef == null || dbRef.getAccessionId() == null + || dbRef.getSource() == null) { - throw new SiftsException( - "Source DBRef could not be determined. DBRefs might not have been retrieved."); + continue; } - - for (DBRefEntryI dbRef : dbRefs) + String canonicalSource = DBRefUtils.getCanonicalName(dbRef + .getSource()); + if (isValidDBRefEntry(dbRef) + && (canonicalSource.equalsIgnoreCase(DBRefSource.UNIPROT) || canonicalSource + .equalsIgnoreCase(DBRefSource.PDB))) { - if (dbRef == null || dbRef.getAccessionId() == null - || dbRef.getSource() == null) - { - continue; - } - if (isFoundInSiftsEntry(dbRef.getAccessionId()) - && (dbRef.getSource().equalsIgnoreCase(DBRefSource.UNIPROT) || dbRef - .getSource().equalsIgnoreCase(DBRefSource.PDB))) - { - seq.setSourceDBRef(dbRef); - return dbRef; - } + return dbRef; } } - if (sourceDBRef != null && isValidDBRefEntry(sourceDBRef)) - { - return sourceDBRef; - } throw new SiftsException("Could not get source DB Ref"); } @@ -440,7 +429,7 @@ public class SiftsClient implements SiftsClientI String originalSeq = AlignSeq.extractGaps( jalview.util.Comparison.GapChars, seq.getSequenceAsString()); HashMap mapping = new HashMap(); - DBRefEntryI sourceDBRef = seq.getSourceDBRef(); + DBRefEntryI sourceDBRef; sourceDBRef = getValidSourceDBRef(seq); // TODO ensure sequence start/end is in the same coordinate system and // consistent with the choosen sourceDBRef diff --git a/test/jalview/analysis/AlignmentUtilsTests.java b/test/jalview/analysis/AlignmentUtilsTests.java index a856231..ddd38e7 100644 --- a/test/jalview/analysis/AlignmentUtilsTests.java +++ b/test/jalview/analysis/AlignmentUtilsTests.java @@ -994,29 +994,44 @@ public class AlignmentUtilsTests /* * need a sourceDbRef if we are to construct dbrefs to the CDS - * sequence + * sequence from the dna contig sequences */ DBRefEntry dbref = new DBRefEntry("ENSEMBL", "0", "dna1"); - dna1.getDatasetSequence().setSourceDBRef(dbref); + dna1.getDatasetSequence().addDBRef(dbref); + org.testng.Assert.assertEquals(dbref, dna1.getPrimaryDBRefs().get(0)); dbref = new DBRefEntry("ENSEMBL", "0", "dna2"); - dna2.getDatasetSequence().setSourceDBRef(dbref); + dna2.getDatasetSequence().addDBRef(dbref); + org.testng.Assert.assertEquals(dbref, dna2.getPrimaryDBRefs().get(0)); /* * CDS sequences are 'discovered' from dna-to-protein mappings on the alignment * dataset (e.g. added from dbrefs by CrossRef.findXrefSequences) */ - MapList map = new MapList(new int[] { 4, 6, 10, 12 }, + MapList mapfordna1 = new MapList(new int[] { 4, 6, 10, 12 }, new int[] { 1, 2 }, 3, 1); AlignedCodonFrame acf = new AlignedCodonFrame(); - acf.addMap(dna1.getDatasetSequence(), pep1.getDatasetSequence(), map); + acf.addMap(dna1.getDatasetSequence(), pep1.getDatasetSequence(), + mapfordna1); dna.addCodonFrame(acf); - map = new MapList(new int[] { 1, 3, 7, 9, 13, 15 }, new int[] { 1, 3 }, + MapList mapfordna2 = new MapList(new int[] { 1, 3, 7, 9, 13, 15 }, + new int[] { 1, 3 }, 3, 1); acf = new AlignedCodonFrame(); - acf.addMap(dna2.getDatasetSequence(), pep2.getDatasetSequence(), map); + acf.addMap(dna2.getDatasetSequence(), pep2.getDatasetSequence(), + mapfordna2); dna.addCodonFrame(acf); /* + * In this case, mappings originally came from matching Uniprot accessions - so need an xref on dna involving those regions. These are normally constructed from CDS annotation + */ + DBRefEntry dna1xref = new DBRefEntry("UNIPROT", "ENSEMBL", "pep1", + new Mapping(mapfordna1)); + dna1.getDatasetSequence().addDBRef(dna1xref); + DBRefEntry dna2xref = new DBRefEntry("UNIPROT", "ENSEMBL", "pep2", + new Mapping(mapfordna2)); + dna2.getDatasetSequence().addDBRef(dna2xref); + + /* * execute method under test: */ AlignmentI cds = AlignmentUtils.makeCdsAlignment(new SequenceI[] { @@ -1042,11 +1057,12 @@ public class AlignmentUtilsTests * verify CDS has a dbref with mapping to peptide */ assertNotNull(cds1Dss.getDBRefs()); - assertEquals(1, cds1Dss.getDBRefs().length); + assertEquals(2, cds1Dss.getDBRefs().length); dbref = cds1Dss.getDBRefs()[0]; - assertEquals("UNIPROT", dbref.getSource()); - assertEquals("0", dbref.getVersion()); - assertEquals("pep1", dbref.getAccessionId()); + assertEquals(dna1xref.getSource(), dbref.getSource()); + // version is via ensembl's primary ref + assertEquals(dna1xref.getVersion(), dbref.getVersion()); + assertEquals(dna1xref.getAccessionId(), dbref.getAccessionId()); assertNotNull(dbref.getMap()); assertSame(pep1.getDatasetSequence(), dbref.getMap().getTo()); MapList cdsMapping = new MapList(new int[] { 1, 6 }, @@ -1057,6 +1073,7 @@ public class AlignmentUtilsTests * verify peptide has added a dbref with reverse mapping to CDS */ assertNotNull(pep1.getDBRefs()); + // FIXME pep1.getDBRefs() is 1 - is that the correct behaviour ? assertEquals(2, pep1.getDBRefs().length); dbref = pep1.getDBRefs()[1]; assertEquals("ENSEMBL", dbref.getSource()); diff --git a/test/jalview/analysis/CrossRefTest.java b/test/jalview/analysis/CrossRefTest.java index 62bcae8..24ddb34 100644 --- a/test/jalview/analysis/CrossRefTest.java +++ b/test/jalview/analysis/CrossRefTest.java @@ -80,12 +80,11 @@ public class CrossRefTest * Just the protein refs: */ found = DBRefUtils.selectDbRefs(false, refs); - assertEquals(5, found.length); + assertEquals(4, found.length); assertSame(ref1, found[0]); assertSame(ref2, found[1]); - assertSame(ref3, found[2]); - assertSame(ref4, found[3]); - assertSame(ref9, found[4]); + assertSame(ref4, found[2]); + assertSame(ref9, found[3]); } /** diff --git a/test/jalview/datamodel/AlignmentTest.java b/test/jalview/datamodel/AlignmentTest.java index b75ef50..7ad9436 100644 --- a/test/jalview/datamodel/AlignmentTest.java +++ b/test/jalview/datamodel/AlignmentTest.java @@ -27,6 +27,7 @@ import static org.testng.AssertJUnit.assertNull; import static org.testng.AssertJUnit.assertSame; import static org.testng.AssertJUnit.assertTrue; +import jalview.datamodel.AlignedCodonFrame.SequenceToSequenceMapping; import jalview.io.AppletFormatAdapter; import jalview.io.FormatAdapter; import jalview.util.MapList; @@ -37,6 +38,7 @@ import java.util.Arrays; import java.util.Iterator; import java.util.List; +import org.testng.Assert; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; @@ -101,6 +103,460 @@ public class AlignmentTest return a; } + /** + * assert wrapper: tests all references in the given alignment are consistent + * + * @param alignment + */ + public static void assertAlignmentDatasetRefs(AlignmentI alignment) + { + verifyAlignmentDatasetRefs(alignment, true, null); + } + + /** + * assert wrapper: tests all references in the given alignment are consistent + * + * @param alignment + * @param message + * - prefixed to any assert failed messages + */ + public static void assertAlignmentDatasetRefs(AlignmentI alignment, + String message) + { + verifyAlignmentDatasetRefs(alignment, true, message); + } + + /** + * verify sequence and dataset references are properly contained within + * dataset + * + * @param alignment + * - the alignmentI object to verify (either alignment or dataset) + * @param raiseAssert + * - when set, testng assertions are raised. + * @param message + * - null or a string message to prepend to the assert failed messages. + * @return true if alignment references were in order, otherwise false. + */ + public static boolean verifyAlignmentDatasetRefs(AlignmentI alignment, + boolean raiseAssert, String message) + { + if (message==null) { message = ""; } + if (alignment == null) + { + if (raiseAssert) + { + Assert.fail(message+"Alignment for verification was null."); + } + return false; + } + if (alignment.getDataset() != null) + { + AlignmentI dataset = alignment.getDataset(); + // check all alignment sequences have their dataset within the dataset + for (SequenceI seq : alignment.getSequences()) + { + SequenceI seqds = seq.getDatasetSequence(); + if (seqds.getDatasetSequence() != null) + { + if (raiseAssert) + { + Assert.fail(message+" Alignment contained a sequence who's dataset sequence has a second dataset reference."); + } + return false; + } + if (dataset.findIndex(seqds) == -1) + { + if (raiseAssert) + { + Assert.fail(message+" Alignment contained a sequence who's dataset sequence was not in the dataset."); + } + return false; + } + } + return verifyAlignmentDatasetRefs(alignment.getDataset(), raiseAssert, message); + } + else + { + int dsp = -1; + // verify all dataset sequences + for (SequenceI seqds : alignment.getSequences()) + { + dsp++; + if (seqds.getDatasetSequence() != null) + { + if (raiseAssert) + { + Assert.fail(message+" Dataset contained a sequence with non-null dataset reference (ie not a dataset sequence!)"); + } + return false; + } + int foundp = alignment.findIndex(seqds); + if (foundp != dsp) + { + if (raiseAssert) + { + Assert.fail(message + + " Dataset sequence array contains a reference at " + + dsp + " to a sequence first seen at " + foundp + " (" + + seqds.toString() + ")"); + } + return false; + } + if (seqds.getDBRefs() != null) + { + for (DBRefEntry dbr : seqds.getDBRefs()) + { + if (dbr.getMap() != null) + { + SequenceI seqdbrmapto = dbr.getMap().getTo(); + if (seqdbrmapto != null) + { + if (seqdbrmapto.getDatasetSequence() != null) + { + if (raiseAssert) + { + Assert.fail(message+" DBRefEntry for sequence in alignment had map to sequence which was not a dataset sequence"); + } + return false; + + } + if (alignment.findIndex(dbr.getMap().getTo()) == -1) + { + if (raiseAssert) + { + Assert.fail(message+" DBRefEntry for sequence in alignment had map to sequence not in dataset"); + } + return false; + } + } + } + } + } + } + // finally, verify codonmappings involve only dataset sequences. + if (alignment.getCodonFrames() != null) + { + for (AlignedCodonFrame alc : alignment.getCodonFrames()) + { + for (SequenceToSequenceMapping ssm : alc.getMappings()) + { + if (ssm.getFromSeq().getDatasetSequence() != null) + { + if (raiseAssert) + { + Assert.fail(message+" CodonFrame-SSM-FromSeq is not a dataset sequence"); + } + return false; + } + if (alignment.findIndex(ssm.getFromSeq()) == -1) + { + + if (raiseAssert) + { + Assert.fail(message+" CodonFrame-SSM-FromSeq is not contained in dataset"); + } + return false; + } + if (ssm.getMapping().getTo().getDatasetSequence() != null) + { + if (raiseAssert) + { + Assert.fail(message+" CodonFrame-SSM-Mapping-ToSeq is not a dataset sequence"); + } + return false; + } + if (alignment.findIndex(ssm.getMapping().getTo()) == -1) + { + + if (raiseAssert) + { + Assert.fail(message+" CodonFrame-SSM-Mapping-ToSeq is not contained in dataset"); + } + return false; + } + } + } + } + } + return true; // all relationships verified! + } + + /** + * call verifyAlignmentDatasetRefs with and without assertion raising enabled, + * to check expected pass/fail actually occurs in both conditions + * + * @param al + * @param expected + * @param msg + */ + private void assertVerifyAlignment(AlignmentI al, boolean expected, + String msg) + { + if (expected) + { + try + { + + Assert.assertTrue(verifyAlignmentDatasetRefs(al, true, null), + "Valid test alignment failed when raiseAsserts enabled:" + + msg); + } catch (AssertionError ae) + { + ae.printStackTrace(); + Assert.fail( + "Valid test alignment raised assertion errors when raiseAsserts enabled: " + + msg, ae); + } + // also check validation passes with asserts disabled + Assert.assertTrue(verifyAlignmentDatasetRefs(al, false, null), + "Valid test alignment tested false when raiseAsserts disabled:" + + msg); + } + else + { + boolean assertRaised = false; + try + { + verifyAlignmentDatasetRefs(al, true, null); + } catch (AssertionError ae) + { + // expected behaviour + assertRaised = true; + } + if (!assertRaised) + { + Assert.fail("Invalid test alignment passed when raiseAsserts enabled:" + + msg); + } + // also check validation passes with asserts disabled + Assert.assertFalse(verifyAlignmentDatasetRefs(al, false, null), + "Invalid test alignment tested true when raiseAsserts disabled:" + + msg); + } + } + @Test(groups = { "Functional" }) + public void testVerifyAlignmentDatasetRefs() + { + SequenceI sq1 = new Sequence("sq1", "ASFDD"), sq2 = new Sequence("sq2", + "TTTTTT"); + + // construct simple valid alignment dataset + Alignment al = new Alignment(new SequenceI[] { + sq1, sq2 }); + // expect this to pass + assertVerifyAlignment(al, true, "Simple valid alignment didn't verify"); + + // check test for sequence->datasetSequence validity + sq1.setDatasetSequence(sq2); + assertVerifyAlignment( + al, + false, + "didn't detect dataset sequence with a dataset sequence reference."); + + sq1.setDatasetSequence(null); + assertVerifyAlignment( + al, + true, + "didn't reinstate validity after nulling dataset sequence dataset reference"); + + // now create dataset and check again + al.createDatasetAlignment(); + assertNotNull(al.getDataset()); + + assertVerifyAlignment(al, true, + "verify failed after createDatasetAlignment"); + + // create a dbref on sq1 with a sequence ref to sq2 + DBRefEntry dbrs1tos2 = new DBRefEntry("UNIPROT", "1", "Q111111"); + dbrs1tos2.setMap(new Mapping(sq2.getDatasetSequence(), + new int[] { 1, 5 }, new int[] { 2, 6 }, 1, 1)); + sq1.getDatasetSequence().addDBRef(dbrs1tos2); + assertVerifyAlignment(al, true, + "verify failed after addition of valid DBRefEntry/map"); + // now create a dbref on a new sequence which maps to another sequence + // outside of the dataset + SequenceI sqout = new Sequence("sqout", "ututututucagcagcag"), sqnew = new Sequence( + "sqnew", "EEERRR"); + DBRefEntry sqnewsqout = new DBRefEntry("ENAFOO", "1", "R000001"); + sqnewsqout.setMap(new Mapping(sqout, new int[] { 1, 6 }, new int[] { 1, + 18 }, 1, 3)); + al.getDataset().addSequence(sqnew); + + assertVerifyAlignment(al, true, + "verify failed after addition of new sequence to dataset"); + // now start checking exception conditions + sqnew.addDBRef(sqnewsqout); + assertVerifyAlignment( + al, + false, + "verify passed when a dbref with map to sequence outside of dataset was added"); + // make the verify pass by adding the outsider back in + al.getDataset().addSequence(sqout); + assertVerifyAlignment(al, true, + "verify should have passed after adding dbref->to sequence in to dataset"); + // and now the same for a codon mapping... + SequenceI sqanotherout = new Sequence("sqanotherout", + "aggtutaggcagcagcag"); + + AlignedCodonFrame alc = new AlignedCodonFrame(); + alc.addMap(sqanotherout, sqnew, new MapList(new int[] { 1, 6 }, + new int[] { 1, 18 }, 3, 1)); + + al.addCodonFrame(alc); + Assert.assertEquals(al.getDataset().getCodonFrames().size(), 1); + + assertVerifyAlignment( + al, + false, + "verify passed when alCodonFrame mapping to sequence outside of dataset was added"); + // make the verify pass by adding the outsider back in + al.getDataset().addSequence(sqanotherout); + assertVerifyAlignment( + al, + true, + "verify should have passed once all sequences involved in alCodonFrame were added to dataset"); + al.getDataset().addSequence(sqanotherout); + assertVerifyAlignment(al, false, + "verify should have failed when a sequence was added twice to the dataset"); + al.getDataset().deleteSequence(sqanotherout); + assertVerifyAlignment(al, true, + "verify should have passed after duplicate entry for sequence was removed"); + } + + /** + * checks that the sequence data for an alignment's dataset is non-redundant. + * Fails if there are sequences with same id, sequence, start, and. + */ + + public static void assertDatasetIsNormalised(AlignmentI al) + { + assertDatasetIsNormalised(al, null); + } + + /** + * checks that the sequence data for an alignment's dataset is non-redundant. + * Fails if there are sequences with same id, sequence, start, and. + * + * @param al + * - alignment to verify + * @param message + * - null or message prepended to exception message. + */ + public static void assertDatasetIsNormalised(AlignmentI al, String message) + { + if (al.getDataset()!=null) + { + assertDatasetIsNormalised(al.getDataset(), message); + return; + } + /* + * look for pairs of sequences with same ID, start, end, and sequence + */ + List seqSet = al.getSequences(); + for (int p=0;p primRefs = Arrays.asList(new DBRefEntry[] { pdb1pdb, + pdb2pdb }); + + sq.getDatasetSequence().addDBRef(pdb1pdb); + sq.getDatasetSequence().addDBRef(pdb2pdb); sq.getDatasetSequence().addDBRef( - new DBRefEntry("PDB", "version1", "1Tst")); - sq.getDatasetSequence().addDBRef( - new DBRefEntry("PDB", "version2", "2Tst")); - sq.getDatasetSequence().addDBRef( - new DBRefEntry("PDB", "version3", "3Tst")); + new DBRefEntry("PDB", "version3", "3PDB")); sq.getDatasetSequence().addDBRef( - new DBRefEntry("PDB", "version4", "4Tst")); - - sq.getDatasetSequence().addPDBId( - new PDBEntry("1PDB", "A", Type.PDB, "filePath/test1")); - sq.getDatasetSequence().addPDBId( - new PDBEntry("1PDB", "B", Type.PDB, "filePath/test1")); + new DBRefEntry("PDB", "version4", "4PDB")); + + PDBEntry pdbe1a=new PDBEntry("1PDB", "A", Type.PDB, "filePath/test1"); + PDBEntry pdbe1b = new PDBEntry("1PDB", "B", Type.PDB, "filePath/test1"); + PDBEntry pdbe2a=new PDBEntry("2PDB", "A", Type.MMCIF, "filePath/test2"); + PDBEntry pdbe2b = new PDBEntry("2PDB", "B", Type.MMCIF, "filePath/test2"); sq.getDatasetSequence().addPDBId( - new PDBEntry("2PDB", "A", Type.MMCIF, "filePath/test2")); + pdbe1a); sq.getDatasetSequence().addPDBId( - new PDBEntry("2PDB", "B", Type.MMCIF, "filePath/test2")); + pdbe1b); + sq.getDatasetSequence().addPDBId(pdbe2a); + sq.getDatasetSequence().addPDBId(pdbe2b); + /* + * test we added pdb entries to the dataset sequence + */ + Assert.assertEquals(sq.getDatasetSequence().getAllPDBEntries(), Arrays + .asList(new PDBEntry[] { pdbe1a, pdbe1b, pdbe2a, pdbe2b }), + "PDB Entries were not found on dataset sequence."); + + /* + * we should recover a pdb entry that is on the dataset sequence via PDBEntry + */ + Assert.assertEquals(pdbe1a, + sq.getDatasetSequence().getPDBEntry("1PDB"), + "PDB Entry '1PDB' not found on dataset sequence via getPDBEntry."); ArrayList annotsList = new ArrayList(); System.out.println(">>>>>> " + sq.getSequenceAsString().length()); annotsList.add(new Annotation("A", "A", 'X', 0.1f)); @@ -479,7 +500,7 @@ public class SequenceTest new AlignmentAnnotation("Test annot", "Test annot description", annots)); Assert.assertEquals(sq.getDescription(), "Test sequence description.."); - Assert.assertEquals(sq.getDBRefs().length, 4); + Assert.assertEquals(sq.getDBRefs().length, 5); Assert.assertEquals(sq.getAllPDBEntries().size(), 4); Assert.assertNotNull(sq.getAnnotation()); Assert.assertEquals(sq.getAnnotation()[0].annotations.length, 2); @@ -492,7 +513,7 @@ public class SequenceTest Assert.assertEquals(derived.getDescription(), "Test sequence description.."); - Assert.assertEquals(derived.getDBRefs().length, 4); + Assert.assertEquals(derived.getDBRefs().length, 4); // come from dataset Assert.assertEquals(derived.getAllPDBEntries().size(), 4); Assert.assertNotNull(derived.getAnnotation()); Assert.assertEquals(derived.getAnnotation()[0].annotations.length, 2); @@ -510,6 +531,17 @@ public class SequenceTest assertNotNull(sq.getSequenceFeatures()); assertArrayEquals(sq.getSequenceFeatures(), derived.getSequenceFeatures()); + + /* + * verify we have primary db refs *just* for PDB IDs with associated + * PDBEntry objects + */ + + assertEquals(primRefs, sq.getPrimaryDBRefs()); + assertEquals(primRefs, sq.getDatasetSequence().getPrimaryDBRefs()); + + assertEquals(sq.getPrimaryDBRefs(), derived.getPrimaryDBRefs()); + } /** @@ -734,4 +766,122 @@ public class SequenceTest assertSame(dbref3, sq.getDBRefs()[2]); assertEquals("3", dbref2.getVersion()); } + + @Test(groups = { "Functional" }) + public void testGetPrimaryDBRefs_peptide() + { + SequenceI sq = new Sequence("aseq", "ASDFKYLMQPRST", 10, 22); + + // no dbrefs + List primaryDBRefs = sq.getPrimaryDBRefs(); + assertTrue(primaryDBRefs.isEmpty()); + + // empty dbrefs + sq.setDBRefs(new DBRefEntry[] {}); + primaryDBRefs = sq.getPrimaryDBRefs(); + assertTrue(primaryDBRefs.isEmpty()); + + // primary - uniprot + DBRefEntry upentry1 = new DBRefEntry("UNIPROT", "0", "Q04760"); + sq.addDBRef(upentry1); + + // primary - uniprot with congruent map + DBRefEntry upentry2 = new DBRefEntry("UNIPROT", "0", "Q04762"); + upentry2.setMap(new Mapping(null, new MapList(new int[] { 10, 22 }, + new int[] { 10, 22 }, 1, 1))); + sq.addDBRef(upentry2); + + // primary - uniprot with map of enclosing sequence + DBRefEntry upentry3 = new DBRefEntry("UNIPROT", "0", "Q04763"); + upentry3.setMap(new Mapping(null, new MapList(new int[] { 8, 24 }, + new int[] { 8, 24 }, 1, 1))); + sq.addDBRef(upentry3); + + // not primary - uniprot with map of sub-sequence (5') + DBRefEntry upentry4 = new DBRefEntry("UNIPROT", "0", "Q04764"); + upentry4.setMap(new Mapping(null, new MapList(new int[] { 10, 18 }, + new int[] { 10, 18 }, 1, 1))); + sq.addDBRef(upentry4); + + // not primary - uniprot with map that overlaps 3' + DBRefEntry upentry5 = new DBRefEntry("UNIPROT", "0", "Q04765"); + upentry5.setMap(new Mapping(null, new MapList(new int[] { 12, 22 }, + new int[] { 12, 22 }, 1, 1))); + sq.addDBRef(upentry5); + + // not primary - uniprot with map to different coordinates frame + DBRefEntry upentry6 = new DBRefEntry("UNIPROT", "0", "Q04766"); + upentry6.setMap(new Mapping(null, new MapList(new int[] { 12, 18 }, + new int[] { 112, 118 }, 1, 1))); + sq.addDBRef(upentry6); + + // not primary - dbref to 'non-core' database + DBRefEntry upentry7 = new DBRefEntry("Pfam", "0", "PF00903"); + sq.addDBRef(upentry7); + + // primary - type is PDB + DBRefEntry pdbentry = new DBRefEntry("PDB", "0", "1qip"); + sq.addDBRef(pdbentry); + + // not primary - PDBEntry has no file + sq.addDBRef(new DBRefEntry("PDB", "0", "1AAA")); + + // not primary - no PDBEntry + sq.addDBRef(new DBRefEntry("PDB", "0", "1DDD")); + + // add corroborating PDB entry for primary DBref - + // needs to have a file as well as matching ID + // note PDB ID is not treated as case sensitive + sq.addPDBId(new PDBEntry("1QIP", null, Type.PDB, new File("/blah") + .toString())); + + // not valid DBRef - no file.. + sq.addPDBId(new PDBEntry("1AAA", null, null, null)); + + primaryDBRefs = sq.getPrimaryDBRefs(); + assertEquals(4, primaryDBRefs.size()); + assertTrue("Couldn't find simple primary reference (UNIPROT)", + primaryDBRefs.contains(upentry1)); + assertTrue("Couldn't find mapped primary reference (UNIPROT)", + primaryDBRefs.contains(upentry2)); + assertTrue("Couldn't find mapped context reference (UNIPROT)", + primaryDBRefs.contains(upentry3)); + assertTrue("Couldn't find expected PDB primary reference", + primaryDBRefs.contains(pdbentry)); + } + + @Test(groups = { "Functional" }) + public void testGetPrimaryDBRefs_nucleotide() + { + SequenceI sq = new Sequence("aseq", "TGATCACTCGACTAGCATCAGCATA", 10, 34); + + // primary - Ensembl + DBRefEntry dbr1 = new DBRefEntry("ENSEMBL", "0", "ENSG1234"); + sq.addDBRef(dbr1); + + // not primary - Ensembl 'transcript' mapping of sub-sequence + DBRefEntry dbr2 = new DBRefEntry("ENSEMBL", "0", "ENST1234"); + dbr2.setMap(new Mapping(null, new MapList(new int[] { 15, 25 }, + new int[] { 1, 11 }, 1, 1))); + sq.addDBRef(dbr2); + + // primary - EMBL with congruent map + DBRefEntry dbr3 = new DBRefEntry("EMBL", "0", "J1234"); + dbr3.setMap(new Mapping(null, new MapList(new int[] { 10, 34 }, + new int[] { 10, 34 }, 1, 1))); + sq.addDBRef(dbr3); + + // not primary - to non-core database + DBRefEntry dbr4 = new DBRefEntry("CCDS", "0", "J1234"); + sq.addDBRef(dbr4); + + // not primary - to protein + DBRefEntry dbr5 = new DBRefEntry("UNIPROT", "0", "Q87654"); + sq.addDBRef(dbr5); + + List primaryDBRefs = sq.getPrimaryDBRefs(); + assertEquals(2, primaryDBRefs.size()); + assertTrue(primaryDBRefs.contains(dbr1)); + assertTrue(primaryDBRefs.contains(dbr3)); + } } diff --git a/test/jalview/datamodel/xdb/embl/EmblEntryTest.java b/test/jalview/datamodel/xdb/embl/EmblEntryTest.java index 4b71417..abe5099 100644 --- a/test/jalview/datamodel/xdb/embl/EmblEntryTest.java +++ b/test/jalview/datamodel/xdb/embl/EmblEntryTest.java @@ -128,6 +128,7 @@ public class EmblEntryTest assertEquals(5, dbrefs.length); assertEquals(DBRefSource.EMBL, dbrefs[0].getSource()); assertEquals("CAA30420.1", dbrefs[0].getAccessionId()); + // TODO: verify getPrimaryDBRefs() for peptide products assertEquals(cds1Map.getInverse(), dbrefs[0].getMap().getMap()); assertEquals(DBRefSource.EMBLCDS, dbrefs[1].getSource()); assertEquals("CAA30420.1", dbrefs[1].getAccessionId()); diff --git a/test/jalview/ext/ensembl/EnsemblXrefTest.java b/test/jalview/ext/ensembl/EnsemblXrefTest.java index 1dc9b8d..df1c1ad 100644 --- a/test/jalview/ext/ensembl/EnsemblXrefTest.java +++ b/test/jalview/ext/ensembl/EnsemblXrefTest.java @@ -1,6 +1,7 @@ package jalview.ext.ensembl; import static org.testng.AssertJUnit.assertEquals; +import static org.testng.AssertJUnit.assertFalse; import jalview.datamodel.DBRefEntry; @@ -24,8 +25,11 @@ public class EnsemblXrefTest @Test(groups = "Functional") public void testGetCrossReferences() { + String dbName = "ENSEMBL"; + String dbVers = "0.6.2b1"; System.out.println(JSON); - EnsemblXref testee = new EnsemblXref("http://rest.ensembl.org") + EnsemblXref testee = new EnsemblXref("http://rest.ensembl.org", dbName, + dbVers) { @Override protected BufferedReader getHttpResponse(URL url, List ids) @@ -40,8 +44,12 @@ public class EnsemblXrefTest assertEquals(2, dbrefs.size()); assertEquals("CCDS", dbrefs.get(0).getSource()); assertEquals("CCDS5863", dbrefs.get(0).getAccessionId()); + assertFalse(dbrefs.get(0).isPrimaryCandidate()); + assertEquals(dbName + ":" + dbVers, dbrefs.get(0).getVersion()); // Uniprot name should get converted to Jalview canonical form assertEquals("UNIPROT", dbrefs.get(1).getSource()); assertEquals("P15056", dbrefs.get(1).getAccessionId()); + assertEquals(dbName + ":" + dbVers, dbrefs.get(1).getVersion()); + assertFalse(dbrefs.get(1).isPrimaryCandidate()); } } diff --git a/test/jalview/gui/AlignViewportTest.java b/test/jalview/gui/AlignViewportTest.java index 2b72914..eff3fdc 100644 --- a/test/jalview/gui/AlignViewportTest.java +++ b/test/jalview/gui/AlignViewportTest.java @@ -74,6 +74,7 @@ public class AlignViewportTest @Test(groups = { "Functional" }) public void testCollateForPdb() { + // JBP: What behaviour is this supposed to test ? /* * Set up sequence pdb ids */ diff --git a/test/jalview/io/AnnotatedPDBFileInputTest.java b/test/jalview/io/AnnotatedPDBFileInputTest.java index d3d9ff8..e03f7a1 100644 --- a/test/jalview/io/AnnotatedPDBFileInputTest.java +++ b/test/jalview/io/AnnotatedPDBFileInputTest.java @@ -221,8 +221,8 @@ public class AnnotatedPDBFileInputTest sq = sq.getDatasetSequence(); } assertNotNull(sq.getAllPDBEntries()); - assertEquals("Expected only one PDB ID", - sq.getAllPDBEntries().size(), 1); + assertEquals("Expected only one PDB ID", 1, sq.getAllPDBEntries() + .size()); for (PDBEntry pdbentry : sq.getAllPDBEntries()) { System.err.println("PDB Entry " + pdbentry.getId() + " " diff --git a/test/jalview/io/CrossRef2xmlTests.java b/test/jalview/io/CrossRef2xmlTests.java new file mode 100644 index 0000000..2063c88 --- /dev/null +++ b/test/jalview/io/CrossRef2xmlTests.java @@ -0,0 +1,575 @@ +/* + * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$) + * Copyright (C) $$Year-Rel$$ The Jalview Authors + * + * This file is part of Jalview. + * + * Jalview is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 + * of the License, or (at your option) any later version. + * + * Jalview is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Jalview. If not, see . + * The Jalview Authors are detailed in the 'AUTHORS' file. + */ +package jalview.io; + +import jalview.analysis.CrossRef; +import jalview.api.AlignmentViewPanel; +import jalview.datamodel.AlignedCodonFrame; +import jalview.datamodel.AlignmentI; +import jalview.datamodel.AlignmentTest; +import jalview.datamodel.SequenceI; +import jalview.gui.AlignFrame; +import jalview.gui.CrossRefAction; +import jalview.gui.Desktop; +import jalview.gui.Jalview2XML; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +import org.testng.Assert; +import org.testng.annotations.Test; + +@Test(singleThreaded = true) +public class CrossRef2xmlTests extends Jalview2xmlBase +{ + + /** + * test store and recovery of all reachable cross refs from all reachable + * crossrefs for one or more fetched db refs. Currently, this test has a known + * failure case. + * + * @throws Exception + */ + @Test(groups = { "Operational" }, enabled = true) + public void testRetrieveAndShowCrossref() throws Exception + { + + List failedDBRetr = new ArrayList(); + List failedXrefMenuItems = new ArrayList(); + List failedProjectRecoveries = new ArrayList(); + + // for every set of db queries + // retrieve db query + // verify presence of expected xrefs + // show xrefs - verify expected type of frame is shown for each xref + // show xrefs again + // - verify original -> xref -> xref(original) recovers frame containing at + // least the first retrieved sequence + // store + // 1. whole project + // 2. individual frames + // 3. load each one back and verify + // . aligned sequences (.toString() ) + // . xrefs (.toString() ) + // . codonframes + // + // + HashMap dbtoviewBit = new HashMap(); + List keyseq = new ArrayList(); + HashMap savedProjects = new HashMap(); + + for (String[] did : new String[][] { { "ENSEMBL", "ENSG00000157764" }, + { "UNIPROT", "P01731" } }) + { + // pass counters - 0 - first pass, 1 means retrieve project rather than + // perform action + int pass1 = 0, pass2 = 0, pass3 = 0; + // each do loop performs two iterations in the first outer loop pass, but + // only performs one iteration on the second outer loop + // ie. pass 1 = 0 {pass 2= 0 { pass 3 = 0,1 }, pass 2=1 { pass 3 = 0 }}, 1 + // { pass 2 = 0 { pass 3 = 0 } } + do + { + String first = did[0] + " " + did[1]; + AlignFrame af = null; + boolean dna; + AlignmentI retral; + AlignmentI dataset; + SequenceI[] seqs; + List ptypes = null; + if (pass1 == 0) + { + // retrieve dbref + + List afs = jalview.gui.SequenceFetcher.fetchAndShow( + did[0], did[1]); + if (afs.size() == 0) + { + failedDBRetr.add("Didn't retrieve " + first); + break; + } + keyseq.add(first); + af = afs.get(0); + + // verify references for retrieved data + AlignmentTest.assertAlignmentDatasetRefs(af.getViewport() + .getAlignment(), "Pass (" + pass1 + "," + pass2 + "," + + pass3 + "): Fetch " + first + ":"); + assertDatasetIsNormalisedKnownDefect(af.getViewport() + .getAlignment(), "Pass (" + pass1 + "," + pass2 + "," + + pass3 + "): Fetch " + first + ":"); + dna = af.getViewport().getAlignment().isNucleotide(); + retral = af.getViewport().getAlignment(); + dataset = retral.getDataset(); + seqs = retral.getSequencesArray(); + + } + else + { + Desktop.instance.closeAll_actionPerformed(null); + // recover stored project + af = new FileLoader(false).LoadFileWaitTillLoaded(savedProjects + .get(first).toString(), FormatAdapter.FILE); + System.out.println("Recovered view for '" + first + "' from '" + + savedProjects.get(first).toString() + "'"); + dna = af.getViewport().getAlignment().isNucleotide(); + retral = af.getViewport().getAlignment(); + dataset = retral.getDataset(); + seqs = retral.getSequencesArray(); + + // verify references for recovered data + AlignmentTest.assertAlignmentDatasetRefs(af.getViewport() + .getAlignment(), "Pass (" + pass1 + "," + pass2 + "," + + pass3 + "): Recover " + first + ":"); + assertDatasetIsNormalisedKnownDefect(af.getViewport() + .getAlignment(), "Pass (" + pass1 + "," + pass2 + "," + + pass3 + "): Recover " + first + ":"); + + } + + // store project on first pass, compare next pass + stringify(dbtoviewBit, savedProjects, first, af.alignPanel); + + ptypes = (seqs == null || seqs.length == 0) ? null : new CrossRef( + seqs, dataset).findXrefSourcesForSequences(dna); + + // start of pass2: retrieve each cross-ref for fetched or restored + // project. + do // first cross ref and recover crossref loop + { + + for (String db : ptypes) + { + // counter for splitframe views retrieved via crossref + int firstcr_ap = 0; + // build next key so we an retrieve all views + String nextxref = first + " -> " + db + "{" + firstcr_ap + "}"; + // perform crossref action, or retrieve stored project + List cra_views = new ArrayList(); + CrossRefAction cra = null; + + if (pass2 == 0) + { // retrieve and show cross-refs in this thread + cra = new CrossRefAction(af, seqs, dna, db); + cra.run(); + if (cra.getXrefViews().size() == 0) + { + failedXrefMenuItems.add("No crossrefs retrieved for " + + first + " -> " + db); + continue; + } + cra_views = cra.getXrefViews(); + assertNucleotide(cra_views.get(0), + "Nucleotide panel included proteins for " + first + + " -> " + db); + assertProtein(cra_views.get(1), + "Protein panel included nucleotides for " + first + + " -> " + db); + } + else + { + Desktop.instance.closeAll_actionPerformed(null); + pass3 = 0; + // recover stored project + File storedProject = savedProjects.get(nextxref); + if (storedProject == null) + { + failedProjectRecoveries.add("Failed to store a view for '" + + nextxref + "'"); + continue; + } + + // recover stored project + AlignFrame af2 = new FileLoader(false) + .LoadFileWaitTillLoaded(savedProjects.get(nextxref) + .toString(), FormatAdapter.FILE); + System.out.println("Recovered view for '" + nextxref + + "' from '" + savedProjects.get(nextxref).toString() + + "'"); + // gymnastics to recover the alignPanel/Complementary alignPanel + if (af2.getViewport().isNucleotide()) + { + // top view, then bottom + cra_views.add(af2.getViewport().getAlignPanel()); + cra_views.add(((jalview.gui.AlignViewport) af2 + .getViewport().getCodingComplement()) + .getAlignPanel()); + + } + else + { + // bottom view, then top + cra_views.add(((jalview.gui.AlignViewport) af2 + .getViewport().getCodingComplement()) + .getAlignPanel()); + cra_views.add(af2.getViewport().getAlignPanel()); + + } + } + HashMap> xrptypes = new HashMap>(); + // first save/verify views. + for (AlignmentViewPanel avp : cra_views) + { + nextxref = first + " -> " + db + "{" + firstcr_ap++ + "}"; + // verify references for this panel + AlignmentTest.assertAlignmentDatasetRefs(avp.getAlignment(), + "Pass (" + pass1 + "," + pass2 + "," + pass3 + + "): before start of pass3: " + nextxref + + ":"); + assertDatasetIsNormalisedKnownDefect(avp.getAlignment(), + "Pass (" + pass1 + "," + pass2 + "," + pass3 + + "): before start of pass3: " + nextxref + + ":"); + + SequenceI[] xrseqs = avp.getAlignment().getSequencesArray(); + + List _xrptypes = (seqs == null || seqs.length == 0) ? null + : new CrossRef(xrseqs, dataset) + .findXrefSourcesForSequences(avp + .getAlignViewport().isNucleotide()); + + stringify(dbtoviewBit, savedProjects, nextxref, avp); + xrptypes.put(nextxref, _xrptypes); + + } + + // now do the second xref pass starting from either saved or just + // recovered split pane, in sequence + do // retrieve second set of cross refs or recover and verify + { + firstcr_ap = 0; + for (AlignmentViewPanel avp : cra_views) + { + nextxref = first + " -> " + db + "{" + firstcr_ap++ + "}"; + for (String xrefdb : xrptypes.get(nextxref)) + { + List cra_views2 = new ArrayList(); + int q = 0; + String nextnextxref = nextxref + + " -> " + xrefdb + "{" + q + "}"; + + if (pass3 == 0) + { + + SequenceI[] xrseqs = avp.getAlignment() + .getSequencesArray(); + AlignFrame nextaf = Desktop.getAlignFrameFor(avp + .getAlignViewport()); + + cra = new CrossRefAction(nextaf, xrseqs, avp + .getAlignViewport().isNucleotide(), xrefdb); + cra.run(); + if (cra.getXrefViews().size() == 0) + { + failedXrefMenuItems + .add("No crossrefs retrieved for '" + + nextxref + "' to " + xrefdb + " via '" + + nextaf.getTitle() + "'"); + continue; + } + cra_views2 = cra.getXrefViews(); + assertNucleotide(cra_views2.get(0), + "Nucleotide panel included proteins for '" + + nextxref + "' to " + xrefdb + + " via '" + nextaf.getTitle() + "'"); + assertProtein(cra_views2.get(1), + "Protein panel included nucleotides for '" + + nextxref + "' to " + xrefdb + + " via '" + nextaf.getTitle() + "'"); + + } + else + { + Desktop.instance.closeAll_actionPerformed(null); + // recover stored project + File storedProject = savedProjects.get(nextnextxref); + if (storedProject == null) + { + failedProjectRecoveries + .add("Failed to store a view for '" + + nextnextxref + "'"); + continue; + } + AlignFrame af2 = new FileLoader(false) + .LoadFileWaitTillLoaded( + savedProjects.get(nextnextxref) + .toString(), FormatAdapter.FILE); + System.out.println("Recovered view for '" + + nextnextxref + "' from '" + + savedProjects.get(nextnextxref).toString() + + "'"); + // gymnastics to recover the alignPanel/Complementary + // alignPanel + if (af2.getViewport().isNucleotide()) + { + // top view, then bottom + cra_views2.add(af2.getViewport().getAlignPanel()); + cra_views2.add(((jalview.gui.AlignViewport) af2 + .getViewport().getCodingComplement()) + .getAlignPanel()); + + } + else + { + // bottom view, then top + cra_views2.add(((jalview.gui.AlignViewport) af2 + .getViewport().getCodingComplement()) + .getAlignPanel()); + cra_views2.add(af2.getViewport().getAlignPanel()); + } + Assert.assertEquals(cra_views2.size(), 2); + Assert.assertNotNull(cra_views2.get(0)); + Assert.assertNotNull(cra_views2.get(1)); + } + + for (AlignmentViewPanel nextavp : cra_views2) + { + nextnextxref = nextxref + + " -> " + xrefdb + "{" + q++ + "}"; + + // verify references for this panel + AlignmentTest.assertAlignmentDatasetRefs( + nextavp.getAlignment(), "" + "Pass (" + pass1 + + "," + pass2 + "): For " + + nextnextxref + ":"); + assertDatasetIsNormalisedKnownDefect( + nextavp.getAlignment(), "" + "Pass (" + pass1 + + "," + pass2 + "): For " + + nextnextxref + ":"); + + stringify(dbtoviewBit, savedProjects, nextnextxref, + nextavp); + keyseq.add(nextnextxref); + } + } // end of loop around showing all xrefdb for crossrf2 + + } // end of loop around all viewpanels from crossrf1 + } while (pass2 == 2 && pass3++ < 2); + // fetchdb->crossref1->crossref-2->verify for xrefs we + // either loop twice when pass2=0, or just once when pass2=1 + // (recovered project from previous crossref) + + } // end of loop over db-xrefs for crossref-2 + + // fetchdb-->crossref1 + // for each xref we try to retrieve xref, store and verify when + // pass1=0, or just retrieve and verify when pass1=1 + } while (pass1 == 1 && pass2++ < 2); + // fetchdb + // for each ref we + // loop twice: first, do the retrieve, second recover from saved project + + // increment pass counters, so we repeat traversal starting from the + // oldest saved project first. + if (pass1 == 0) + { + // verify stored projects for first set of cross references + pass1 = 1; + // and verify cross-references retrieved from stored projects + pass2 = 0; + pass3 = 0; + } + else + { + pass1++; + } + } while (pass1 < 3); + } + if (failedXrefMenuItems.size() > 0) + { + for (String s : failedXrefMenuItems) + { + System.err.println(s); + } + Assert.fail("Faulty xref menu (" + failedXrefMenuItems.size() + + " counts)"); + } + if (failedProjectRecoveries.size() > 0) + { + + for (String s : failedProjectRecoveries) + { + System.err.println(s); + } + Assert.fail("Didn't recover projects for some retrievals (did they retrieve ?) (" + + failedProjectRecoveries.size() + " counts)"); + } + if (failedDBRetr.size() > 0) + { + for (String s : failedProjectRecoveries) + { + System.err.println(s); + } + Assert.fail("Didn't retrieve some db refs for checking cross-refs (" + + failedDBRetr.size() + " counts)"); + } + } + + /** + * wrapper to trap known defect for AH002001 testcase + * + * @param alignment + * @param string + */ + private void assertDatasetIsNormalisedKnownDefect(AlignmentI al, + String message) + { + try + { + AlignmentTest.assertDatasetIsNormalised(al, message); + } catch (AssertionError ae) + { + if (!ae.getMessage().endsWith("EMBL|AH002001")) + { + throw ae; + } + else + { + System.out + .println("Ignored exception for known defect: JAL-2179 : " + + message); + } + + } + } + + private void assertProtein(AlignmentViewPanel alignmentViewPanel, + String message) + { + assertType(true, alignmentViewPanel, message); + } + + private void assertNucleotide(AlignmentViewPanel alignmentViewPanel, + String message) + { + assertType(false, alignmentViewPanel, message); + } + + private void assertType(boolean expectProtein, + AlignmentViewPanel alignmentViewPanel, String message) + { + List nonType = new ArrayList(); + for (SequenceI sq : alignmentViewPanel.getAlignViewport() + .getAlignment() + .getSequences()) + { + if (sq.isProtein() != expectProtein) + { + nonType.add(sq); + } + } + if (nonType.size() > 0) + { + Assert.fail(message + " [ " + + (expectProtein ? "nucleotides were " : "proteins were ") + + nonType.toString() + + " ]"); + } + } + + /** + * first time called, record strings derived from alignment and + * alignedcodonframes, and save view to a project file. Second time called, + * compare strings to existing ones. org.testng.Assert.assertTrue on + * stringmatch + * + * @param dbtoviewBit + * map between xrefpath and view string + * @param savedProjects + * - map from xrefpath to saved project filename (createTempFile) + * @param xrefpath + * - xrefpath - unique ID for this context (composed of sequence of + * db-fetch/cross-ref actions preceeding state) + * @param avp + * - viewpanel to store (for viewpanels in splitframe, the same + * project should be written for both panels, only one needs + * recovering for comparison on the next stringify call, but each + * viewpanel needs to be called with a distinct xrefpath to ensure + * each one's strings are compared) + */ + private void stringify(HashMap dbtoviewBit, + HashMap savedProjects, String xrefpath, + AlignmentViewPanel avp) + { + if (savedProjects != null) + { + if (savedProjects.get(xrefpath) == null) + { + // write a project file for this view. On the second pass, this will be + // recovered and cross-references verified + try + { + File prfile = File.createTempFile("crossRefTest", ".jvp"); + AlignFrame af = Desktop.getAlignFrameFor(avp.getAlignViewport()); + new Jalview2XML(false).saveAlignment(af, prfile.toString(), + af.getTitle()); + System.out.println("Written view from '" + xrefpath + "' as '" + + prfile.getAbsolutePath() + "'"); + savedProjects.put(xrefpath, prfile); + } catch (IOException q) + { + Assert.fail("Unexpected IO Exception", q); + } + } + else + { + System.out.println("Stringify check on view from '" + xrefpath + + "' [ possibly retrieved from '" + + savedProjects.get(xrefpath).getAbsolutePath() + "' ]"); + + } + } + + StringBuilder sbr = new StringBuilder(); + sbr.append(avp.getAlignment().toString()); + sbr.append("\n"); + sbr.append(""); + sbr.append("\n"); + sbr.append(avp.getAlignment().getDataset()); + sbr.append("\n"); + sbr.append(""); + sbr.append("\n"); + int p = 0; + if (avp.getAlignment().getCodonFrames() != null) + { + for (AlignedCodonFrame ac : avp.getAlignment().getCodonFrames()) + { + sbr.append(""); + sbr.append("\n"); + sbr.append(ac.toString()); + sbr.append("\n"); + } + } + String dbt = dbtoviewBit.get(xrefpath); + if (dbt == null) + { + dbtoviewBit.put(xrefpath, sbr.toString()); + } + else + { + Assert.assertEquals(sbr.toString(), dbt, "stringify mismatch for " + + xrefpath); + } + } +} diff --git a/test/jalview/io/Jalview2xmlBase.java b/test/jalview/io/Jalview2xmlBase.java new file mode 100644 index 0000000..379fd68 --- /dev/null +++ b/test/jalview/io/Jalview2xmlBase.java @@ -0,0 +1,76 @@ +package jalview.io; + +import jalview.bin.Cache; +import jalview.bin.Jalview; +import jalview.datamodel.AlignmentAnnotation; +import jalview.datamodel.SequenceI; +import jalview.gui.Desktop; + +import java.util.Date; + +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.BeforeTest; + +public class Jalview2xmlBase +{ + + /** + * @throws java.lang.Exception + */ + @BeforeClass(alwaysRun = true) + public static void setUpBeforeClass() throws Exception + { + /* + * use read-only test properties file + */ + Cache.loadProperties("test/jalview/io/testProps.jvprops"); + + /* + * set news feed last read to a future time to ensure no + * 'unread' news item is displayed + */ + Date oneHourFromNow = new Date(System.currentTimeMillis() + 3600 * 1000); + Cache.setDateProperty("JALVIEW_NEWS_RSS_LASTMODIFIED", oneHourFromNow); + + Jalview.main(new String[] {}); + } + + /** + * @throws java.lang.Exception + */ + @AfterClass(alwaysRun = true) + public static void tearDownAfterClass() throws Exception + { + jalview.gui.Desktop.instance.closeAll_actionPerformed(null); + } + + @BeforeTest(alwaysRun = true) + public static void clearDesktop() + { + if (Desktop.instance != null && Desktop.getAlignFrames() != null) + { + Desktop.instance.closeAll_actionPerformed(null); + } + } + + public int countDsAnn(jalview.viewmodel.AlignmentViewport avp) + { + int numdsann = 0; + for (SequenceI sq : avp.getAlignment().getDataset().getSequences()) + { + if (sq.getAnnotation() != null) + { + for (AlignmentAnnotation dssa : sq.getAnnotation()) + { + if (dssa.isValidStruc()) + { + numdsann++; + } + } + } + } + return numdsann; + } + +} diff --git a/test/jalview/io/Jalview2xmlTests.java b/test/jalview/io/Jalview2xmlTests.java index 784f3dd..3d53234 100644 --- a/test/jalview/io/Jalview2xmlTests.java +++ b/test/jalview/io/Jalview2xmlTests.java @@ -29,12 +29,11 @@ import static org.testng.AssertJUnit.assertTrue; import jalview.api.AlignViewportI; import jalview.api.AlignmentViewPanel; import jalview.api.ViewStyleI; -import jalview.bin.Cache; -import jalview.bin.Jalview; import jalview.datamodel.AlignmentAnnotation; import jalview.datamodel.AlignmentI; import jalview.datamodel.HiddenSequences; import jalview.datamodel.PDBEntry; +import jalview.datamodel.PDBEntry.Type; import jalview.datamodel.SequenceCollectionI; import jalview.datamodel.SequenceGroup; import jalview.datamodel.SequenceI; @@ -44,84 +43,34 @@ import jalview.gui.Desktop; import jalview.gui.Jalview2XML; import jalview.schemes.AnnotationColourGradient; import jalview.schemes.ColourSchemeI; +import jalview.schemes.ColourSchemeProperty; +import jalview.schemes.TCoffeeColourScheme; import jalview.structure.StructureImportSettings; import jalview.viewmodel.AlignmentViewport; import java.io.File; import java.util.ArrayList; -import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import org.testng.Assert; import org.testng.AssertJUnit; -import org.testng.annotations.AfterClass; -import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; @Test(singleThreaded = true) -public class Jalview2xmlTests +public class Jalview2xmlTests extends Jalview2xmlBase { - /** - * @throws java.lang.Exception - */ - @BeforeClass(alwaysRun = true) - public static void setUpBeforeClass() throws Exception - { - /* - * use read-only test properties file - */ - Cache.loadProperties("test/jalview/io/testProps.jvprops"); - - /* - * set news feed last read to a future time to ensure no - * 'unread' news item is displayed - */ - Date oneHourFromNow = new Date(System.currentTimeMillis() + 3600 * 1000); - Cache.setDateProperty("JALVIEW_NEWS_RSS_LASTMODIFIED", oneHourFromNow); - - Jalview.main(new String[] {}); - } - - /** - * @throws java.lang.Exception - */ - @AfterClass(alwaysRun = true) - public static void tearDownAfterClass() throws Exception - { - Desktop.instance.closeAll_actionPerformed(null); - } - - int countDsAnn(jalview.viewmodel.AlignmentViewport avp) - { - int numdsann = 0; - for (SequenceI sq : avp.getAlignment().getDataset().getSequences()) - { - if (sq.getAnnotation() != null) - { - for (AlignmentAnnotation dssa : sq.getAnnotation()) - { - if (dssa.isValidStruc()) - { - numdsann++; - } - } - } - } - return numdsann; - } - @Test(groups = { "Functional" }) public void testRNAStructureRecovery() throws Exception { String inFile = "examples/RF00031_folded.stk"; String tfile = File.createTempFile("JalviewTest", ".jvp") .getAbsolutePath(); - AlignFrame af = new jalview.io.FileLoader().LoadFileWaitTillLoaded( - inFile, FormatAdapter.FILE); - assertTrue("Didn't read input file " + inFile, af != null); + AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(inFile, + FormatAdapter.FILE); + assertNotNull("Didn't read input file " + inFile, af); int olddsann = countDsAnn(af.getViewport()); assertTrue("Didn't find any dataset annotations", olddsann > 0); af.rnahelicesColour_actionPerformed(null); @@ -132,9 +81,8 @@ public class Jalview2xmlTests af.saveAlignment(tfile, "Jalview")); af.closeMenuItem_actionPerformed(true); af = null; - af = new jalview.io.FileLoader().LoadFileWaitTillLoaded(tfile, - FormatAdapter.FILE); - assertTrue("Failed to import new project", af != null); + af = new FileLoader().LoadFileWaitTillLoaded(tfile, FormatAdapter.FILE); + assertNotNull("Failed to import new project", af); int newdsann = countDsAnn(af.getViewport()); assertTrue( "Differing numbers of dataset sequence annotation\nOriginally " @@ -154,32 +102,26 @@ public class Jalview2xmlTests String inFile = "examples/uniref50.fa", inAnnot = "examples/uniref50.score_ascii"; String tfile = File.createTempFile("JalviewTest", ".jvp") .getAbsolutePath(); - AlignFrame af = new jalview.io.FileLoader().LoadFileWaitTillLoaded( - inFile, FormatAdapter.FILE); - assertTrue("Didn't read input file " + inFile, af != null); + AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(inFile, + FormatAdapter.FILE); + assertNotNull("Didn't read input file " + inFile, af); af.loadJalviewDataFile(inAnnot, FormatAdapter.FILE, null, null); - assertTrue( - "Didn't set T-coffee colourscheme", - af.getViewport().getGlobalColourScheme().getClass() - .equals(jalview.schemes.TCoffeeColourScheme.class)); - assertTrue( - "Recognise T-Coffee score from string", + assertSame("Didn't set T-coffee colourscheme", af.getViewport() + .getGlobalColourScheme().getClass(), TCoffeeColourScheme.class); + assertNotNull("Recognise T-Coffee score from string", jalview.schemes.ColourSchemeProperty.getColour(af.getViewport() - .getAlignment(), - jalview.schemes.ColourSchemeProperty.getColourName(af - .getViewport().getGlobalColourScheme())) != null); + .getAlignment(), ColourSchemeProperty.getColourName(af + .getViewport().getGlobalColourScheme()))); assertTrue("Failed to store as a project.", af.saveAlignment(tfile, "Jalview")); af.closeMenuItem_actionPerformed(true); af = null; - af = new jalview.io.FileLoader().LoadFileWaitTillLoaded(tfile, - FormatAdapter.FILE); - assertTrue("Failed to import new project", af != null); - assertTrue( - "Didn't set T-coffee colourscheme for imported project.", - af.getViewport().getGlobalColourScheme().getClass() - .equals(jalview.schemes.TCoffeeColourScheme.class)); + af = new FileLoader().LoadFileWaitTillLoaded(tfile, FormatAdapter.FILE); + assertNotNull("Failed to import new project", af); + assertSame("Didn't set T-coffee colourscheme for imported project.", af + .getViewport().getGlobalColourScheme().getClass(), + TCoffeeColourScheme.class); System.out .println("T-Coffee score shading successfully recovered from project."); } @@ -190,19 +132,19 @@ public class Jalview2xmlTests String inFile = "examples/uniref50.fa", inAnnot = "examples/testdata/uniref50_iupred.jva"; String tfile = File.createTempFile("JalviewTest", ".jvp") .getAbsolutePath(); - AlignFrame af = new jalview.io.FileLoader().LoadFileWaitTillLoaded( - inFile, FormatAdapter.FILE); - assertTrue("Didn't read input file " + inFile, af != null); + AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(inFile, + FormatAdapter.FILE); + assertNotNull("Didn't read input file " + inFile, af); af.loadJalviewDataFile(inAnnot, FormatAdapter.FILE, null, null); AlignmentAnnotation[] aa = af.getViewport().getAlignment() .getSequenceAt(0).getAnnotation("IUPredWS (Short)"); assertTrue( "Didn't find any IUPred annotation to use to shade alignment.", aa != null && aa.length > 0); - AnnotationColourGradient cs = new jalview.schemes.AnnotationColourGradient( - aa[0], null, AnnotationColourGradient.ABOVE_THRESHOLD); - AnnotationColourGradient gcs = new jalview.schemes.AnnotationColourGradient( - aa[0], null, AnnotationColourGradient.BELOW_THRESHOLD); + AnnotationColourGradient cs = new AnnotationColourGradient(aa[0], null, + AnnotationColourGradient.ABOVE_THRESHOLD); + AnnotationColourGradient gcs = new AnnotationColourGradient(aa[0], + null, AnnotationColourGradient.BELOW_THRESHOLD); cs.setSeqAssociated(true); gcs.setSeqAssociated(true); af.changeColour(cs); @@ -218,16 +160,15 @@ public class Jalview2xmlTests af.saveAlignment(tfile, "Jalview")); af.closeMenuItem_actionPerformed(true); af = null; - af = new jalview.io.FileLoader().LoadFileWaitTillLoaded(tfile, - FormatAdapter.FILE); - assertTrue("Failed to import new project", af != null); + af = new FileLoader().LoadFileWaitTillLoaded(tfile, FormatAdapter.FILE); + assertNotNull("Failed to import new project", af); // check for group and alignment colourschemes ColourSchemeI _rcs = af.getViewport().getGlobalColourScheme(); ColourSchemeI _rgcs = af.getViewport().getAlignment().getGroups() .get(0).cs; - assertTrue("Didn't recover global colourscheme", _rcs != null); + assertNotNull("Didn't recover global colourscheme", _rcs); assertTrue("Didn't recover annotation colour global scheme", _rcs instanceof AnnotationColourGradient); AnnotationColourGradient __rcs = (AnnotationColourGradient) _rcs; @@ -249,7 +190,7 @@ public class Jalview2xmlTests System.out .println("Per sequence colourscheme (Background) successfully applied and recovered."); - assertTrue("Didn't recover group colourscheme", _rgcs != null); + assertNotNull("Didn't recover group colourscheme", _rgcs); assertTrue("Didn't recover annotation colour group colourscheme", _rgcs instanceof AnnotationColourGradient); __rcs = (AnnotationColourGradient) _rgcs; @@ -275,9 +216,9 @@ public class Jalview2xmlTests { int origCount = Desktop.getAlignFrames() == null ? 0 : Desktop .getAlignFrames().length; - AlignFrame af = new jalview.io.FileLoader().LoadFileWaitTillLoaded( + AlignFrame af = new FileLoader().LoadFileWaitTillLoaded( "examples/exampleFile_2_7.jar", FormatAdapter.FILE); - assertTrue("Didn't read in the example file correctly.", af != null); + assertNotNull("Didn't read in the example file correctly.", af); assertTrue("Didn't gather the views in the example file.", Desktop.getAlignFrames().length == 1 + origCount); @@ -286,14 +227,11 @@ public class Jalview2xmlTests @Test(groups = { "Functional" }) public void viewRefPdbAnnotation() throws Exception { - // TODO: Make this pass without setting StructureParser.JALVIEW_PARSER - // StructureImportSettings - // .setDefaultPDBFileParser(StructureParser.JALVIEW_PARSER); StructureImportSettings.setProcessSecondaryStructure(true); StructureImportSettings.setVisibleChainAnnotation(true); - AlignFrame af = new jalview.io.FileLoader().LoadFileWaitTillLoaded( + AlignFrame af = new FileLoader().LoadFileWaitTillLoaded( "examples/exampleFile_2_7.jar", FormatAdapter.FILE); - assertTrue("Didn't read in the example file correctly.", af != null); + assertNotNull("Didn't read in the example file correctly.", af); AlignmentViewPanel sps = null; for (AlignmentViewPanel ap : af.alignPanel.alignFrame.getAlignPanels()) { @@ -303,8 +241,7 @@ public class Jalview2xmlTests break; } } - assertTrue("Couldn't find the structure view", sps != null); - SequenceI sq = sps.getAlignment().findName("1A70|"); + assertNotNull("Couldn't find the structure view", sps); AlignmentAnnotation refan = null; for (AlignmentAnnotation ra : sps.getAlignment() .getAlignmentAnnotation()) @@ -315,10 +252,13 @@ public class Jalview2xmlTests break; } } - assertTrue("Annotation secondary structure not found.", refan != null); - assertTrue("Couldn't find 1a70 null chain", sq != null); + assertNotNull("Annotation secondary structure not found.", refan); + SequenceI sq = sps.getAlignment().findName("1A70|"); + assertNotNull("Couldn't find 1a70 null chain", sq); // compare the manually added temperature factor annotation // to the track automatically transferred from the pdb structure on load + assertNotNull("1a70 has no annotation", sq.getDatasetSequence() + .getAnnotation()); for (AlignmentAnnotation ala : sq.getDatasetSequence().getAnnotation()) { AlignmentAnnotation alaa; @@ -350,9 +290,9 @@ public class Jalview2xmlTests @Test(groups = { "Functional" }) public void testCopyViewSettings() throws Exception { - AlignFrame af = new jalview.io.FileLoader().LoadFileWaitTillLoaded( + AlignFrame af = new FileLoader().LoadFileWaitTillLoaded( "examples/exampleFile_2_7.jar", FormatAdapter.FILE); - assertTrue("Didn't read in the example file correctly.", af != null); + assertNotNull("Didn't read in the example file correctly.", af); AlignmentViewPanel sps = null, groups = null; for (AlignmentViewPanel ap : af.alignPanel.alignFrame.getAlignPanels()) { @@ -365,8 +305,8 @@ public class Jalview2xmlTests groups = ap; } } - assertTrue("Couldn't find the structure view", sps != null); - assertTrue("Couldn't find the MAFFT view", groups != null); + assertNotNull("Couldn't find the structure view", sps); + assertNotNull("Couldn't find the MAFFT view", groups); ViewStyleI structureStyle = sps.getAlignViewport().getViewStyle(); ViewStyleI groupStyle = groups.getAlignViewport().getViewStyle(); @@ -390,9 +330,8 @@ public class Jalview2xmlTests { Desktop.instance.closeAll_actionPerformed(null); - AlignFrame af = new jalview.io.FileLoader().LoadFileWaitTillLoaded( + AlignFrame af = new FileLoader().LoadFileWaitTillLoaded( "examples/exampleFile_2_7.jar", FormatAdapter.FILE); - assertTrue("Didn't read in the example file correctly.", af != null); Assert.assertEquals(Desktop.getAlignFrames().length, 1); String afid = af.getViewport().getSequenceSetId(); @@ -423,8 +362,8 @@ public class Jalview2xmlTests { Assert.assertEquals(Desktop.getAlignFrames().length, 0); } - af = new jalview.io.FileLoader().LoadFileWaitTillLoaded( - tfile.getAbsolutePath(), FormatAdapter.FILE); + af = new FileLoader().LoadFileWaitTillLoaded(tfile.getAbsolutePath(), + FormatAdapter.FILE); Assert.assertNotNull(af); Assert.assertEquals( Desktop.getAlignFrames().length, @@ -446,7 +385,7 @@ public class Jalview2xmlTests Desktop.instance.closeAll_actionPerformed(null); AlignFrame af = new FileLoader().LoadFileWaitTillLoaded( "examples/exampleFile_2_7.jar", FormatAdapter.FILE); - assertTrue("Didn't read in the example file correctly.", af != null); + assertNotNull("Didn't read in the example file correctly.", af); String afid = af.getViewport().getSequenceSetId(); // remember reference sequence for each panel @@ -488,8 +427,8 @@ public class Jalview2xmlTests Assert.assertEquals(Desktop.getAlignFrames().length, 0); } - af = new FileLoader().LoadFileWaitTillLoaded( - tfile.getAbsolutePath(), FormatAdapter.FILE); + af = new FileLoader().LoadFileWaitTillLoaded(tfile.getAbsolutePath(), + FormatAdapter.FILE); afid = af.getViewport().getSequenceSetId(); for (AlignmentViewPanel ap : Desktop.getAlignmentPanels(afid)) @@ -579,18 +518,18 @@ public class Jalview2xmlTests Desktop.instance.closeAll_actionPerformed(null); AlignFrame af = new FileLoader().LoadFileWaitTillLoaded( "examples/uniref50.fa", FormatAdapter.FILE); - assertTrue("Didn't read in the example file correctly.", af != null); + assertNotNull("Didn't read in the example file correctly.", af); String afid = af.getViewport().getSequenceSetId(); // make a second view of the alignment af.newView_actionPerformed(null); - + /* * remember representative and hidden sequences marked * on each panel */ Map repSeqs = new HashMap(); Map> hiddenSeqNames = new HashMap>(); - + /* * mark sequence 2, 3, 4.. in panels 1, 2, 3... * as reference sequence for itself and the preceding sequence @@ -607,7 +546,7 @@ public class Jalview2xmlTests repSeqs.put(ap.getViewName(), repSeq); List hiddenNames = new ArrayList(); hiddenSeqNames.put(ap.getViewName(), hiddenNames); - + /* * have rep sequence represent itself and the one before it * this hides the group (except for the rep seq) @@ -631,7 +570,8 @@ public class Jalview2xmlTests assertTrue(sg.getSequences().contains(repSeq)); assertTrue(sg.getSequences().contains(precedingSeq)); assertTrue("alignment has groups", alignment.getGroups().isEmpty()); - Map hiddenRepSeqsMap = av.getHiddenRepSequences(); + Map hiddenRepSeqsMap = av + .getHiddenRepSequences(); assertNotNull(hiddenRepSeqsMap); assertEquals(1, hiddenRepSeqsMap.size()); assertSame(sg, hiddenRepSeqsMap.get(repSeq)); @@ -642,8 +582,7 @@ public class Jalview2xmlTests n++; } File tfile = File - .createTempFile("testStoreAndRecoverGroupReps", - ".jvp"); + .createTempFile("testStoreAndRecoverGroupReps", ".jvp"); try { new Jalview2XML(false).saveState(tfile); @@ -656,11 +595,11 @@ public class Jalview2xmlTests { Assert.assertEquals(Desktop.getAlignFrames().length, 0); } - - af = new FileLoader().LoadFileWaitTillLoaded( - tfile.getAbsolutePath(), FormatAdapter.FILE); + + af = new FileLoader().LoadFileWaitTillLoaded(tfile.getAbsolutePath(), + FormatAdapter.FILE); afid = af.getViewport().getSequenceSetId(); - + for (AlignmentViewPanel ap : Desktop.getAlignmentPanels(afid)) { String viewName = ap.getViewName(); @@ -684,8 +623,7 @@ public class Jalview2xmlTests HiddenSequences hs = alignment.getHiddenSequences(); assertEquals( "wrong number of restored hidden sequences in " - + ap.getViewName(), - hidden.size(), hs.getSize()); + + ap.getViewName(), hidden.size(), hs.getSize()); } } @@ -701,7 +639,7 @@ public class Jalview2xmlTests String exampleFile = "examples/3W5V.pdb"; AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(exampleFile, FormatAdapter.FILE); - assertTrue("Didn't read in the example file correctly.", af != null); + assertNotNull("Didn't read in the example file correctly.", af); String afid = af.getViewport().getSequenceSetId(); AlignmentPanel[] alignPanels = Desktop.getAlignmentPanels(afid); @@ -721,18 +659,18 @@ public class Jalview2xmlTests Assert.assertNotNull(seqs[2].getDatasetSequence()); Assert.assertNotNull(seqs[3].getDatasetSequence()); PDBEntry[] pdbEntries = new PDBEntry[4]; - pdbEntries[0] = new PDBEntry("3W5V", "A", null, testFile); - pdbEntries[1] = new PDBEntry("3W5V", "B", null, testFile); - pdbEntries[2] = new PDBEntry("3W5V", "C", null, testFile); - pdbEntries[3] = new PDBEntry("3W5V", "D", null, testFile); - Assert.assertTrue(seqs[0].getDatasetSequence().getAllPDBEntries() - .get(0).equals(pdbEntries[0])); - Assert.assertTrue(seqs[1].getDatasetSequence().getAllPDBEntries() - .get(0).equals(pdbEntries[1])); - Assert.assertTrue(seqs[2].getDatasetSequence().getAllPDBEntries() - .get(0).equals(pdbEntries[2])); - Assert.assertTrue(seqs[3].getDatasetSequence().getAllPDBEntries() - .get(0).equals(pdbEntries[3])); + pdbEntries[0] = new PDBEntry("3W5V", "A", Type.PDB, testFile); + pdbEntries[1] = new PDBEntry("3W5V", "B", Type.PDB, testFile); + pdbEntries[2] = new PDBEntry("3W5V", "C", Type.PDB, testFile); + pdbEntries[3] = new PDBEntry("3W5V", "D", Type.PDB, testFile); + Assert.assertEquals(seqs[0].getDatasetSequence().getAllPDBEntries() + .get(0), pdbEntries[0]); + Assert.assertEquals(seqs[1].getDatasetSequence().getAllPDBEntries() + .get(0), pdbEntries[1]); + Assert.assertEquals(seqs[2].getDatasetSequence().getAllPDBEntries() + .get(0), pdbEntries[2]); + Assert.assertEquals(seqs[3].getDatasetSequence().getAllPDBEntries() + .get(0), pdbEntries[3]); File tfile = File.createTempFile("testStoreAndRecoverPDBEntry", ".jvp"); try @@ -767,13 +705,19 @@ public class Jalview2xmlTests // The Asserts below are expected to fail until the PDB chainCode is // recoverable from a Jalview projects - Assert.assertTrue(rseqs[0].getDatasetSequence().getAllPDBEntries() - .get(0).equals(pdbEntries[0])); - Assert.assertTrue(rseqs[1].getDatasetSequence().getAllPDBEntries() - .get(0).equals(pdbEntries[1])); - Assert.assertTrue(rseqs[2].getDatasetSequence().getAllPDBEntries() - .get(0).equals(pdbEntries[2])); - Assert.assertTrue(rseqs[3].getDatasetSequence().getAllPDBEntries() - .get(0).equals(pdbEntries[3])); + for (int chain = 0; chain < 4; chain++) + { + PDBEntry recov = rseqs[chain].getDatasetSequence().getAllPDBEntries() + .get(0); + PDBEntry expected = pdbEntries[chain]; + Assert.assertEquals(recov.getId(), expected.getId(), + "Mismatch PDB ID"); + Assert.assertEquals(recov.getChainCode(), expected.getChainCode(), + "Mismatch PDB ID"); + Assert.assertEquals(recov.getType(), expected.getType(), + "Mismatch PDBEntry 'Type'"); + Assert.assertNotNull(recov.getFile(), + "Recovered PDBEntry should have a non-null file entry"); + } } } diff --git a/test/jalview/io/testProps_nodas.jvprops b/test/jalview/io/testProps_nodas.jvprops new file mode 100644 index 0000000..da95549 --- /dev/null +++ b/test/jalview/io/testProps_nodas.jvprops @@ -0,0 +1,83 @@ +#---JalviewX Properties File--- +#Fri Apr 25 09:54:25 BST 2014 +SCREEN_Y=768 +SCREEN_X=936 +SHOW_WSDISCOVERY_ERRORS=true +LATEST_VERSION=2.8.0b1 +SHOW_CONSERVATION=true +JALVIEW_RSS_WINDOW_SCREEN_WIDTH=550 +JAVA_CONSOLE_SCREEN_WIDTH=450 +LAST_DIRECTORY=/Volumes/Data/Users/jimp/Documents/testing/Jalview/examples +ID_ITALICS=true +SORT_ALIGNMENT=No sort +SHOW_IDENTITY=true +WSMENU_BYHOST=false +SEQUENCE_LINKS=EMBL-EBI Search|http\://www.ebi.ac.uk/ebisearch/search.ebi?db\=allebi&query\=$SEQUENCE_ID$ +SHOW_FULLSCREEN=false +RECENT_URL=http\://www.jalview.org/examples/exampleFile_2_7.jar +FONT_NAME=SansSerif +BLC_JVSUFFIX=true +VERSION_CHECK=false +YEAR=2011 +SHOW_DBREFS_TOOLTIP=true +MSF_JVSUFFIX=true +SCREENGEOMETRY_HEIGHT=1600 +JAVA_CONSOLE_SCREEN_Y=475 +JAVA_CONSOLE_SCREEN_X=830 +PFAM_JVSUFFIX=true +PIR_JVSUFFIX=true +STARTUP_FILE=http\://www.jalview.org/examples/exampleFile_2_3.jar +JAVA_CONSOLE_SCREEN_HEIGHT=162 +PIR_MODELLER=false +GAP_SYMBOL=- +SHOW_QUALITY=true +SHOW_GROUP_CONSERVATION=false +SHOW_JWS2_SERVICES=true +SHOW_NPFEATS_TOOLTIP=true +FONT_STYLE=plain +ANTI_ALIAS=false +SORT_BY_TREE=false +RSBS_SERVICES=|Multi-Harmony|Analysis|Sequence Harmony and Multi-Relief (Brandt et al. 2010)|hseparable,gapCharacter\='-',returns\='ANNOTATION'|?tool\=jalview|http\://zeus.few.vu.nl/programs/shmrwww/index.php?tool\=jalview&groups\=$PARTITION\:min\='2',minsize\='2',sep\=' '$&ali_file\=$ALIGNMENT\:format\='FASTA',writeasfile$ +AUTHORFNAMES=Jim Procter, Andrew Waterhouse, Jan Engelhardt, Lauren Lui, Michele Clamp, James Cuff, Steve Searle, David Martin & Geoff Barton +JALVIEW_RSS_WINDOW_SCREEN_HEIGHT=328 +SHOW_GROUP_CONSENSUS=false +SHOW_CONSENSUS_HISTOGRAM=true +SHOW_OVERVIEW=false +AUTHORS=J Procter, AM Waterhouse, LM Lui, J Engelhardt, G Barton, M Clamp, S Searle +FIGURE_AUTOIDWIDTH=false +SCREEN_WIDTH=900 +ANNOTATIONCOLOUR_MIN=ffc800 +SHOW_STARTUP_FILE=false +RECENT_FILE=examples/uniref50.fa\t/Volumes/Data/Users/jimp/Documents/testing/Jalview/examples/RF00031_folded.stk\t/Volumes/Data/Users/jimp/bs_ig_mult.out +DEFAULT_FILE_FORMAT=FASTA +SHOW_JAVA_CONSOLE=false +VERSION=2.8b1 +FIGURE_USERIDWIDTH= +WSMENU_BYTYPE=false +DEFAULT_COLOUR=None +NOQUESTIONNAIRES=true +JALVIEW_NEWS_RSS_LASTMODIFIED=Apr 23, 2014 2\:53\:26 PM +BUILD_DATE=01 November 2013 +PILEUP_JVSUFFIX=true +SHOW_CONSENSUS_LOGO=false +SCREENGEOMETRY_WIDTH=2560 +SHOW_ANNOTATIONS=true +JALVIEW_RSS_WINDOW_SCREEN_Y=0 +USAGESTATS=false +JALVIEW_RSS_WINDOW_SCREEN_X=0 +SHOW_UNCONSERVED=false +SHOW_JVSUFFIX=true +SCREEN_HEIGHT=650 +ANNOTATIONCOLOUR_MAX=ff0000 +AUTO_CALC_CONSENSUS=true +FASTA_JVSUFFIX=true +DAS_ACTIVE_SOURCE= +JWS2HOSTURLS=http\://www.compbio.dundee.ac.uk/jabaws +PAD_GAPS=false +CLUSTAL_JVSUFFIX=true +SHOW_ENFIN_SERVICES=true +FONT_SIZE=10 +RIGHT_ALIGN_IDS=false +USE_PROXY=false +WRAP_ALIGNMENT=false +DAS_REGISTRY_URL=http\://www.nowhere/ diff --git a/test/jalview/util/DBRefUtilsTest.java b/test/jalview/util/DBRefUtilsTest.java index 96935ce..5e0683e 100644 --- a/test/jalview/util/DBRefUtilsTest.java +++ b/test/jalview/util/DBRefUtilsTest.java @@ -158,6 +158,9 @@ public class DBRefUtilsTest SequenceI seq = new Sequence("Seq1", "ABCD"); DBRefEntry ref = DBRefUtils.parseToDbRef(seq, "pdb", "1.2", "1WRI A; 7-80;"); + // TODO: correct PDBEntry and PDB DBRef accessions need to be generated for + // PDB ref in Stockholm + DBRefEntry[] refs = seq.getDBRefs(); assertEquals(1, refs.length); assertSame(ref, refs[0]); diff --git a/test/jalview/util/MappingUtilsTest.java b/test/jalview/util/MappingUtilsTest.java index 7e28579..d131ed2 100644 --- a/test/jalview/util/MappingUtilsTest.java +++ b/test/jalview/util/MappingUtilsTest.java @@ -708,7 +708,7 @@ public class MappingUtilsTest * subselect the mapping search */ @Test(groups = { "Functional" }) - public void testFindMappingsBetweenSequenceAndOthers() + public void testFindMappingsForSequenceAndOthers() { SequenceI seq1 = new Sequence("Seq1", "ABC"); SequenceI seq2 = new Sequence("Seq2", "ABC"); @@ -720,7 +720,7 @@ public class MappingUtilsTest seq4.createDatasetSequence(); /* - * Create mappings from seq1 to seq2, seq2 to seq1, seq3 to seq1 + * Create mappings from seq1 to seq2, seq2 to seq1, seq3 to seq1, seq3 to seq4 */ AlignedCodonFrame acf1 = new AlignedCodonFrame(); MapList map = new MapList(new int[] { 1, 3 }, new int[] { 1, 3 }, 1, 1); @@ -729,23 +729,54 @@ public class MappingUtilsTest acf2.addMap(seq2.getDatasetSequence(), seq1.getDatasetSequence(), map); AlignedCodonFrame acf3 = new AlignedCodonFrame(); acf3.addMap(seq3.getDatasetSequence(), seq1.getDatasetSequence(), map); + AlignedCodonFrame acf4 = new AlignedCodonFrame(); + acf4.addMap(seq3.getDatasetSequence(), seq4.getDatasetSequence(), map); List mappings = new ArrayList(); mappings.add(acf1); mappings.add(acf2); mappings.add(acf3); + mappings.add(acf4); /* - * Seq1 has three mappings + * test for null args */ List result = MappingUtils - .findMappingsForSequenceAndOthers(seq1, mappings, - new Alignment(new SequenceI[] { seq1, seq2 })); + .findMappingsForSequenceAndOthers(null, mappings, + Arrays.asList(new SequenceI[] { seq1, seq2 })); + assertTrue(result.isEmpty()); + + result = MappingUtils.findMappingsForSequenceAndOthers(seq1, null, + Arrays.asList(new SequenceI[] { seq1, seq2 })); + assertTrue(result.isEmpty()); + + /* + * Seq1 has three mappings, but filter argument will only accept + * those to seq2 + */ + result = MappingUtils.findMappingsForSequenceAndOthers( + seq1, + mappings, + Arrays.asList(new SequenceI[] { seq1, seq2, + seq1.getDatasetSequence() })); + assertEquals(2, result.size()); assertTrue(result.contains(acf1)); assertTrue(result.contains(acf2)); assertFalse("Did not expect to find mapping acf3 - subselect failed", result.contains(acf3)); - assertEquals(2, result.size()); + assertFalse( + "Did not expect to find mapping acf4 - doesn't involve sequence", + result.contains(acf4)); + + /* + * and verify the no filter case + */ + result = MappingUtils.findMappingsForSequenceAndOthers(seq1, mappings, + null); + assertEquals(3, result.size()); + assertTrue(result.contains(acf1)); + assertTrue(result.contains(acf2)); + assertTrue(result.contains(acf3)); } @Test(groups = { "Functional" }) diff --git a/test/jalview/ws/PDBSequenceFetcherTest.java b/test/jalview/ws/PDBSequenceFetcherTest.java index fda0198..c1d1144 100644 --- a/test/jalview/ws/PDBSequenceFetcherTest.java +++ b/test/jalview/ws/PDBSequenceFetcherTest.java @@ -64,7 +64,7 @@ public class PDBSequenceFetcherTest { Cache.applicationProperties.setProperty("STRUCT_FROM_PDB", Boolean.TRUE.toString()); - Cache.applicationProperties.setProperty("DEFAULT_STRUCTURE_FORMAT", + Cache.applicationProperties.setProperty("PDB_DOWNLOAD_FORMAT", "PDB"); List sps = sf.getSourceProxy("PDB"); AlignmentI response = sps.get(0).getSequenceRecords("2GIS"); diff --git a/test/jalview/ws/seqfetcher/DbRefFetcherTest.java b/test/jalview/ws/seqfetcher/DbRefFetcherTest.java index b3c7e10..59bf445 100644 --- a/test/jalview/ws/seqfetcher/DbRefFetcherTest.java +++ b/test/jalview/ws/seqfetcher/DbRefFetcherTest.java @@ -37,6 +37,7 @@ import jalview.ws.dbsources.Pdb; import jalview.ws.dbsources.Uniprot; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import org.testng.annotations.AfterClass; @@ -75,7 +76,9 @@ public class DbRefFetcherTest @Test(groups = { "Functional" }) public void testStandardProtDbs() { - String[] defdb = DBRefSource.PROTEINDBS; + List defdb = new ArrayList(); + defdb.addAll(Arrays.asList(DBRefSource.PROTEINDBS)); + defdb.add(DBRefSource.PDB); List srces = new ArrayList(); SequenceFetcher sfetcher = new SequenceFetcher(); boolean pdbFound = false; diff --git a/utils/HelpLinksChecker.java b/utils/HelpLinksChecker.java index 1ad5322..a0853a9 100644 --- a/utils/HelpLinksChecker.java +++ b/utils/HelpLinksChecker.java @@ -34,6 +34,8 @@ public class HelpLinksChecker private int anchorRefCount = 0; + private int invalidAnchorRefCount = 0; + private int externalHrefCount = 0; private int invalidMapUrlCount = 0; @@ -83,7 +85,7 @@ public class HelpLinksChecker void checkLinks(String helpDirectoryPath) throws IOException { System.out.println("Checking help file links"); - File helpFolder = new File(helpDirectoryPath); + File helpFolder = new File(helpDirectoryPath).getCanonicalFile(); if (!helpFolder.exists()) { System.out.println("Can't find " + helpDirectoryPath); @@ -192,6 +194,8 @@ public class HelpLinksChecker internalHrefCount, anchorRefCount)); System.out.println(invalidInternalHrefCount + " invalid internal href links"); + System.out.println(invalidAnchorRefCount + + " invalid internal anchor links"); System.out.println(externalHrefCount + " external href links"); if (internetAvailable) { @@ -203,7 +207,11 @@ public class HelpLinksChecker System.out .println("External links not verified as internet not available"); } - + if (invalidInternalHrefCount > 0 || invalidExternalHrefCount > 0 + || invalidImageCount > 0 || invalidAnchorRefCount > 0) + { + System.exit(1); + } } /** @@ -269,6 +277,7 @@ public class HelpLinksChecker System.out.println(String.format( "Invalid anchor: %s at line %d of %s", anchor, lineNo, getPath(htmlFile))); + invalidAnchorRefCount++; } } }
  • Field Example