From: Jim Procter Date: Wed, 7 Sep 2016 11:46:28 +0000 (+0100) Subject: Merge branch 'develop' into bug/JAL-1803_JAL-2157 X-Git-Tag: Release_2_10_0~47^2~4^2 X-Git-Url: http://source.jalview.org/gitweb/?a=commitdiff_plain;h=3f12f4932226512316ec113e600695150431fd0a;hp=a9b2a4dd7dcbb2c86bb247970a8fe1b2ab6dc37d;p=jalview.git Merge branch 'develop' into bug/JAL-1803_JAL-2157 --- 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/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/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;