X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fdatamodel%2FSequence.java;h=d7ac7a70bd2845d9d8705bd74e816dfcc0f1cc16;hb=807f5945ffa954c38f07cbf9d2a4ebc22cfe5eb9;hp=bb634665c3f9c11e8b034b50b117b97a4ded2ae2;hpb=141eaf3859dbd8304fe664b37ef81848353406e0;p=jalview.git diff --git a/src/jalview/datamodel/Sequence.java b/src/jalview/datamodel/Sequence.java index bb63466..d7ac7a7 100755 --- a/src/jalview/datamodel/Sequence.java +++ b/src/jalview/datamodel/Sequence.java @@ -22,16 +22,22 @@ package jalview.datamodel; import jalview.analysis.AlignSeq; import jalview.api.DBRefEntryI; +import jalview.datamodel.features.SequenceFeatures; +import jalview.datamodel.features.SequenceFeaturesI; +import jalview.util.Comparison; 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; +import com.stevesoft.pat.Regex; + import fr.orsay.lri.varna.models.rna.RNA; /** @@ -43,6 +49,11 @@ import fr.orsay.lri.varna.models.rna.RNA; */ public class Sequence extends ASequence implements SequenceI { + private static final Regex limitrx = new Regex( + "[/][0-9]{1,}[-][0-9]{1,}$"); + + private static final Regex endrx = new Regex("[0-9]{1,}$"); + SequenceI datasetSequence; String name; @@ -59,8 +70,6 @@ public class Sequence extends ASequence implements SequenceI String vamsasId; - DBRefEntryI sourceDBRef; - DBRefEntry[] dbrefs; RNA rna; @@ -78,8 +87,7 @@ public class Sequence extends ASequence implements SequenceI */ int index = -1; - /** array of sequence features - may not be null for a valid sequence object */ - public SequenceFeature[] sequenceFeatures; + private SequenceFeatures sequenceFeatureStore; /** * Creates a new Sequence object. @@ -96,11 +104,13 @@ public class Sequence extends ASequence implements SequenceI */ public Sequence(String name, String sequence, int start, int end) { + this(); initSeqAndName(name, sequence.toCharArray(), start, end); } public Sequence(String name, char[] sequence, int start, int end) { + this(); initSeqAndName(name, sequence, start, end); } @@ -124,11 +134,6 @@ public class Sequence extends ASequence implements SequenceI checkValidRange(); } - com.stevesoft.pat.Regex limitrx = new com.stevesoft.pat.Regex( - "[/][0-9]{1,}[-][0-9]{1,}$"); - - com.stevesoft.pat.Regex endrx = new com.stevesoft.pat.Regex("[0-9]{1,}$"); - void parseId() { if (name == null) @@ -175,6 +180,14 @@ public class Sequence extends ASequence implements SequenceI } /** + * default constructor + */ + private Sequence() + { + sequenceFeatureStore = new SequenceFeatures(); + } + + /** * Creates a new Sequence object. * * @param name @@ -213,8 +226,8 @@ public class Sequence extends ASequence implements SequenceI */ public Sequence(SequenceI seq, AlignmentAnnotation[] alAnnotation) { + this(); initSeqFrom(seq, alAnnotation); - } /** @@ -230,34 +243,39 @@ public class Sequence extends ASequence implements SequenceI protected void initSeqFrom(SequenceI seq, AlignmentAnnotation[] alAnnotation) { - { - char[] oseq = seq.getSequence(); - initSeqAndName(seq.getName(), Arrays.copyOf(oseq, oseq.length), - seq.getStart(), - seq.getEnd()); - } + char[] oseq = seq.getSequence(); + initSeqAndName(seq.getName(), Arrays.copyOf(oseq, oseq.length), + seq.getStart(), seq.getEnd()); + description = seq.getDescription(); if (seq != datasetSequence) { setDatasetSequence(seq.getDatasetSequence()); } - if (datasetSequence == null && seq.getDBRefs() != null) + + /* + * only copy DBRefs and seqfeatures if we really are a dataset sequence + */ + if (datasetSequence == null) { - // only copy DBRefs and seqfeatures if we really are a dataset sequence - DBRefEntry[] dbr = seq.getDBRefs(); - for (int i = 0; i < dbr.length; i++) - { - addDBRef(new DBRefEntry(dbr[i])); - } - if (seq.getSequenceFeatures() != null) + if (seq.getDBRefs() != null) { - SequenceFeature[] sf = seq.getSequenceFeatures(); - for (int i = 0; i < sf.length; i++) + DBRefEntry[] dbr = seq.getDBRefs(); + for (int i = 0; i < dbr.length; i++) { - addSequenceFeature(new SequenceFeature(sf[i])); + addDBRef(new DBRefEntry(dbr[i])); } } + + /* + * make copies of any sequence features + */ + for (SequenceFeature sf : seq.getSequenceFeatures()) + { + addSequenceFeature(new SequenceFeature(sf)); + } } + if (seq.getAnnotation() != null) { AlignmentAnnotation[] sqann = seq.getAnnotation(); @@ -293,148 +311,89 @@ public class Sequence extends ASequence implements SequenceI } } - @Override - public void setSequenceFeatures(SequenceFeature[] features) + public void setSequenceFeatures(List features) { - if (datasetSequence == null) - { - sequenceFeatures = features; - } - else + if (datasetSequence != null) { - if (datasetSequence.getSequenceFeatures() != features - && datasetSequence.getSequenceFeatures() != null - && datasetSequence.getSequenceFeatures().length > 0) - { - new Exception( - "Warning: JAL-2046 side effect ? Possible implementation error: overwriting dataset sequence features by setting sequence features on alignment") - .printStackTrace(); - } datasetSequence.setSequenceFeatures(features); + return; } + sequenceFeatureStore = new SequenceFeatures(features); } @Override - public synchronized void addSequenceFeature(SequenceFeature sf) + public synchronized boolean addSequenceFeature(SequenceFeature sf) { - if (sequenceFeatures==null && datasetSequence != null) - { - datasetSequence.addSequenceFeature(sf); - return; - } - if (sequenceFeatures == null) + if (sf.getType() == null) { - sequenceFeatures = new SequenceFeature[0]; + System.err.println("SequenceFeature type may not be null: " + + sf.toString()); + return false; } - for (int i = 0; i < sequenceFeatures.length; i++) + if (datasetSequence != null) { - if (sequenceFeatures[i].equals(sf)) - { - return; - } + return datasetSequence.addSequenceFeature(sf); } - SequenceFeature[] temp = new SequenceFeature[sequenceFeatures.length + 1]; - System.arraycopy(sequenceFeatures, 0, temp, 0, sequenceFeatures.length); - temp[sequenceFeatures.length] = sf; - - sequenceFeatures = temp; + return sequenceFeatureStore.add(sf); } @Override public void deleteFeature(SequenceFeature sf) { - if (sequenceFeatures == null) - { - if (datasetSequence!=null) { - datasetSequence.deleteFeature(sf); - } - return; - } - - int index = 0; - for (index = 0; index < sequenceFeatures.length; index++) - { - if (sequenceFeatures[index].equals(sf)) - { - break; - } - } - - if (index == sequenceFeatures.length) - { - return; - } - - int sfLength = sequenceFeatures.length; - if (sfLength < 2) + if (datasetSequence != null) { - sequenceFeatures = null; + datasetSequence.deleteFeature(sf); } else { - SequenceFeature[] temp = new SequenceFeature[sfLength - 1]; - System.arraycopy(sequenceFeatures, 0, temp, 0, index); - - if (index < sfLength) - { - System.arraycopy(sequenceFeatures, index + 1, temp, index, - sequenceFeatures.length - index - 1); - } - - sequenceFeatures = temp; + sequenceFeatureStore.delete(sf); } } /** - * Returns the sequence features (if any), looking first on the sequence, then - * on its dataset sequence, and so on until a non-null value is found (or - * none). This supports retrieval of sequence features stored on the sequence - * (as in the applet) or on the dataset sequence (as in the Desktop version). + * {@inheritDoc} * * @return */ @Override - public SequenceFeature[] getSequenceFeatures() + public List getSequenceFeatures() { - SequenceFeature[] features = sequenceFeatures; - - SequenceI seq = this; - int count = 0; // failsafe against loop in sequence.datasetsequence... - while (features == null && seq.getDatasetSequence() != null - && count++ < 10) + if (datasetSequence != null) { - seq = seq.getDatasetSequence(); - features = ((Sequence) seq).sequenceFeatures; + return datasetSequence.getSequenceFeatures(); } - return features; + return sequenceFeatureStore.getAllFeatures(); } @Override - public void addPDBId(PDBEntry entry) + public SequenceFeaturesI getFeatures() + { + return datasetSequence != null ? datasetSequence.getFeatures() + : sequenceFeatureStore; + } + + @Override + public boolean addPDBId(PDBEntry entry) { if (pdbIds == null) { pdbIds = new Vector(); + pdbIds.add(entry); + return true; } - if (pdbIds.contains(entry)) - { - updatePDBEntry(pdbIds.get(pdbIds.indexOf(entry)), entry); - } - else - { - pdbIds.addElement(entry); - } - } - private static void updatePDBEntry(PDBEntry oldEntry, PDBEntry newEntry) - { - if (newEntry.getFile() != null) + for (PDBEntry pdbe : pdbIds) { - oldEntry.setFile(newEntry.getFile()); + if (pdbe.updateFrom(entry)) + { + return false; + } } + pdbIds.addElement(entry); + return true; } /** @@ -949,7 +908,17 @@ public class Sequence extends ASequence implements SequenceI @Override public void setDBRefs(DBRefEntry[] dbref) { + if (dbrefs == null && datasetSequence != null + && this != datasetSequence) + { + datasetSequence.setDBRefs(dbref); + return; + } dbrefs = dbref; + if (dbrefs != null) + { + DBRefUtils.ensurePrimaries(this); + } } @Override @@ -966,7 +935,12 @@ public class Sequence extends ASequence implements SequenceI @Override public void addDBRef(DBRefEntry entry) { - // TODO add to dataset sequence instead if there is one? + if (datasetSequence != null) + { + datasetSequence.addDBRef(entry); + return; + } + if (dbrefs == null) { dbrefs = new DBRefEntry[0]; @@ -994,12 +968,23 @@ public class Sequence extends ASequence implements SequenceI temp[temp.length - 1] = entry; dbrefs = temp; + + DBRefUtils.ensurePrimaries(this); } @Override public void setDatasetSequence(SequenceI seq) { - // TODO check for circular reference before setting? + if (seq == this) + { + throw new IllegalArgumentException( + "Implementation Error: self reference passed to SequenceI.setDatasetSequence"); + } + if (seq != null && seq.getDatasetSequence() != null) + { + throw new IllegalArgumentException( + "Implementation error: cascading dataset sequences are not allowed."); + } datasetSequence = seq; } @@ -1072,7 +1057,7 @@ public class Sequence extends ASequence implements SequenceI @Override public SequenceI deriveSequence() { - Sequence seq=null; + Sequence seq = null; if (datasetSequence == null) { if (isValidDatasetSequence()) @@ -1086,7 +1071,7 @@ public class Sequence extends ASequence implements SequenceI else { // Create a new, valid dataset sequence - createDatasetSequence(); + createDatasetSequence(); } } return new Sequence(this); @@ -1096,6 +1081,10 @@ public class Sequence extends ASequence implements SequenceI private long _seqhash = 0; + /** + * Answers false if the sequence is more than 85% nucleotide (ACGTU), else + * true + */ @Override public boolean isProtein() { @@ -1106,7 +1095,7 @@ public class Sequence extends ASequence implements SequenceI if (_seqhash != sequence.hashCode()) { _seqhash = sequence.hashCode(); - _isNa=jalview.util.Comparison.isNucleotide(new SequenceI[] { this }); + _isNa = Comparison.isNucleotide(this); } return !_isNa; }; @@ -1129,10 +1118,10 @@ public class Sequence extends ASequence implements SequenceI dsseq.setDescription(description); // move features and database references onto dataset sequence - dsseq.sequenceFeatures = sequenceFeatures; - sequenceFeatures=null; + dsseq.sequenceFeatureStore = sequenceFeatureStore; + sequenceFeatureStore = null; dsseq.dbrefs = dbrefs; - dbrefs=null; + dbrefs = null; // TODO: search and replace any references to this sequence with // references to the dataset sequence in Mappings on dbref dsseq.pdbIds = pdbIds; @@ -1189,11 +1178,11 @@ public class Sequence extends ASequence implements SequenceI return null; } - Vector subset = new Vector(); - Enumeration e = annotation.elements(); + Vector subset = new Vector(); + Enumeration e = annotation.elements(); while (e.hasMoreElements()) { - AlignmentAnnotation ann = (AlignmentAnnotation) e.nextElement(); + AlignmentAnnotation ann = e.nextElement(); if (ann.label != null && ann.label.equals(label)) { subset.addElement(ann); @@ -1208,7 +1197,7 @@ public class Sequence extends ASequence implements SequenceI e = subset.elements(); while (e.hasMoreElements()) { - anns[i++] = (AlignmentAnnotation) e.nextElement(); + anns[i++] = e.nextElement(); } subset.removeAllElements(); return anns; @@ -1226,46 +1215,22 @@ public class Sequence extends ASequence implements SequenceI { return false; } - Vector newpdb = new Vector(); - for (int i = 0; i < dbrefs.length; i++) - { - if (DBRefSource.PDB.equals(dbrefs[i].getSource())) - { - PDBEntry pdbe = new PDBEntry(); - pdbe.setId(dbrefs[i].getAccessionId()); - if (pdbIds == null || pdbIds.size() == 0) - { - newpdb.addElement(pdbe); - } - else - { - Enumeration en = pdbIds.elements(); - boolean matched = false; - while (!matched && en.hasMoreElements()) - { - PDBEntry anentry = (PDBEntry) en.nextElement(); - if (anentry.getId().equals(pdbe.getId())) - { - matched = true; - } - } - if (!matched) - { - newpdb.addElement(pdbe); - } - } - } - } - if (newpdb.size() > 0) + boolean added = false; + for (DBRefEntry dbr : dbrefs) { - Enumeration en = newpdb.elements(); - while (en.hasMoreElements()) + if (DBRefSource.PDB.equals(dbr.getSource())) { - addPDBId((PDBEntry) en.nextElement()); + /* + * 'Add' any PDB dbrefs as a PDBEntry - add is only performed if the + * PDB id is not already present in a 'matching' PDBEntry + * Constructor parses out a chain code if appended to the accession id + * (a fudge used to 'store' the chain code in the DBRef) + */ + PDBEntry pdbe = new PDBEntry(dbr); + added |= addPDBId(pdbe); } - return true; } - return false; + return added; } @Override @@ -1285,12 +1250,12 @@ public class Sequence extends ASequence implements SequenceI if (entry.getSequenceFeatures() != null) { - SequenceFeature[] sfs = entry.getSequenceFeatures(); - for (int si = 0; si < sfs.length; si++) + List sfs = entry.getSequenceFeatures(); + for (SequenceFeature feature : sfs) { - SequenceFeature sf[] = (mp != null) ? mp.locateFeature(sfs[si]) - : new SequenceFeature[] { new SequenceFeature(sfs[si]) }; - if (sf != null && sf.length > 0) + SequenceFeature sf[] = (mp != null) ? mp.locateFeature(feature) + : new SequenceFeature[] { new SequenceFeature(feature) }; + if (sf != null) { for (int sfi = 0; sfi < sf.length; sfi++) { @@ -1303,10 +1268,10 @@ public class Sequence extends ASequence implements SequenceI // transfer PDB entries if (entry.getAllPDBEntries() != null) { - Enumeration e = entry.getAllPDBEntries().elements(); + Enumeration e = entry.getAllPDBEntries().elements(); while (e.hasMoreElements()) { - PDBEntry pdb = (PDBEntry) e.nextElement(); + PDBEntry pdb = e.nextElement(); addPDBId(pdb); } } @@ -1414,25 +1379,24 @@ public class Sequence extends ASequence implements SequenceI return null; } - @Override public List getPrimaryDBRefs() { - if (datasetSequence!=null) + if (datasetSequence != null) { return datasetSequence.getPrimaryDBRefs(); } - if (dbrefs==null || dbrefs.length==0) + if (dbrefs == null || dbrefs.length == 0) { - return Arrays.asList(new DBRefEntry[0]); + return Collections.emptyList(); } synchronized (dbrefs) { List primaries = new ArrayList(); - DBRefEntry tmp[] = new DBRefEntry[1], res[] = null; + DBRefEntry[] tmp = new DBRefEntry[1]; for (DBRefEntry ref : dbrefs) { - if (!ref.isPrimary()) + if (!ref.isPrimaryCandidate()) { continue; } @@ -1451,13 +1415,12 @@ public class Sequence extends ASequence implements SequenceI { // PDB dbrefs imply there should be a PDBEntry associated // TODO: tighten PDB dbrefs - // formally imply Jalview has actually downlaoded and + // 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.getType() != null - && pdbentry.getType().equalsIgnoreCase("PDB")) + if (pdbentry != null && pdbentry.getFile() != null) { primaries.add(ref); } @@ -1465,7 +1428,7 @@ public class Sequence extends ASequence implements SequenceI } // check standard protein or dna sources tmp[0] = ref; - res = DBRefUtils.selectDbRefs(!isProtein(), tmp); + DBRefEntry[] res = DBRefUtils.selectDbRefs(!isProtein(), tmp); if (res != null && res[0] == tmp[0]) { primaries.add(ref); @@ -1476,4 +1439,17 @@ public class Sequence extends ASequence implements SequenceI } } + /** + * {@inheritDoc} + */ + @Override + public List findFeatures(int from, int to, + String... types) + { + if (datasetSequence != null) + { + return datasetSequence.findFeatures(from, to, types); + } + return sequenceFeatureStore.findFeatures(from, to, types); + } }