X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fgui%2FJalview2XML.java;h=97dfefd969be3330ac3f3d13594016fa7b741b04;hb=c24267ee9b42f032d0d1a561b6fb05b03d754460;hp=e57e7486e8bc7dafc5b2a77e5f235b1aa9b8a2ab;hpb=10e5f98521859f56139ca49860b2678e78e61da7;p=jalview.git diff --git a/src/jalview/gui/Jalview2XML.java b/src/jalview/gui/Jalview2XML.java index e57e748..97dfefd 100755 --- a/src/jalview/gui/Jalview2XML.java +++ b/src/jalview/gui/Jalview2XML.java @@ -48,10 +48,55 @@ import jalview.structure.StructureSelectionManager; */ public class Jalview2XML { - - Hashtable seqRefIds = null; + /** + * create/return unique hash string for sq + * @param sq + * @return new or existing unique string for sq + */ + String seqHash(SequenceI sq) + { + if (seqsToIds==null) + { + initSeqRefs(); + } + if (seqsToIds.containsKey(sq)) + { + return (String) seqsToIds.get(sq); + } else { + // create sequential key + String key = "sq"+(seqsToIds.size()+1); + seqsToIds.put(sq, key); + return key; + } + } + void clearSeqRefs() + { + seqRefIds.clear(); + seqsToIds.clear(); + } + void initSeqRefs() + { + if (seqsToIds==null) + { + seqsToIds = new IdentityHashMap(); + } + if (seqRefIds==null) + { + seqRefIds = new Hashtable(); + } + } + java.util.IdentityHashMap seqsToIds = null; // SequenceI->key resolution + java.util.Hashtable seqRefIds = null; // key->SequenceI resolution Vector frefedSequence = null; + boolean raiseGUI = true; // whether errors are raised in dialog boxes or not + public Jalview2XML() + { + } + public Jalview2XML(boolean raiseGUI) + { + this.raiseGUI = raiseGUI; + } public void resolveFrefedSequences() { @@ -131,8 +176,8 @@ public class Jalview2XML //NOTE UTF-8 MUST BE USED FOR WRITING UNICODE CHARS //////////////////////////////////////////////////// - PrintWriter out = new PrintWriter(new OutputStreamWriter(jout, - "UTF-8")); + //NOTE ALSO new PrintWriter must be used for each new JarEntry + PrintWriter out = null; Vector shortNames = new Vector(); @@ -177,17 +222,21 @@ public class Jalview2XML { AlignmentPanel apanel = (AlignmentPanel) af.alignPanels .elementAt(ap); + String fileName = apSize == 1 ? shortName : ap + shortName; + if (!fileName.endsWith(".xml")) + { + fileName = fileName + ".xml"; + } - SaveState(apanel, apSize == 1 ? shortName : ap + shortName, - jout, out); + SaveState(apanel, fileName, jout); } } } - - out.close(); + try { jout.flush(); } catch (Exception foo) {}; jout.close(); } catch (Exception ex) { + //TODO: inform user of the problem - they need to know if their data was not saved ! ex.printStackTrace(); } } @@ -201,17 +250,19 @@ public class Jalview2XML int ap, apSize = af.alignPanels.size(); FileOutputStream fos = new FileOutputStream(jarFile); JarOutputStream jout = new JarOutputStream(fos); - PrintWriter out = new PrintWriter(new OutputStreamWriter(jout, - "UTF-8")); for (ap = 0; ap < apSize; ap++) { AlignmentPanel apanel = (AlignmentPanel) af.alignPanels .elementAt(ap); - - SaveState(apanel, apSize == 1 ? fileName : fileName + ap, jout, out); + String jfileName = apSize == 1 ? fileName : fileName + ap; + if (!jfileName.endsWith(".xml")) + { + jfileName = jfileName + ".xml"; + } + SaveState(apanel, jfileName, jout); } - out.close(); + try { jout.flush(); } catch (Exception foo) {}; jout.close(); return true; } catch (Exception ex) @@ -222,22 +273,19 @@ public class Jalview2XML } /** - * DOCUMENT ME! + * create a JalviewModel from an algnment view and marshall it + * to a JarOutputStream * - * @param af DOCUMENT ME! - * @param timeStamp DOCUMENT ME! - * @param fileName DOCUMENT ME! - * @param jout DOCUMENT ME! - * @param out DOCUMENT ME! + * @param ap panel to create jalview model for + * @param fileName name of alignment panel written to output stream + * @param jout jar output stream + * @param out jar entry name */ public JalviewModel SaveState(AlignmentPanel ap, String fileName, - JarOutputStream jout, PrintWriter out) + JarOutputStream jout) { - if (seqRefIds == null) - { - seqRefIds = new Hashtable(); - } - + initSeqRefs(); + Vector userColours = new Vector(); AlignViewport av = ap.av; @@ -282,22 +330,29 @@ public class Jalview2XML JSeq jseq; //SAVE SEQUENCES - int id = 0; + String id = ""; jalview.datamodel.SequenceI jds; for (int i = 0; i < jal.getHeight(); i++) { jds = jal.getSequenceAt(i); - id = jds.hashCode(); - - if (seqRefIds.get(id + "") != null) - { - + 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 + "", jal.getSequenceAt(i)); + seqRefIds.put(id, jds); } jseq = new JSeq(); @@ -305,7 +360,7 @@ public class Jalview2XML jseq.setEnd(jds.getEnd()); jseq.setColour(av.getSequenceColour(jds).getRGB()); - jseq.setId(id); + jseq.setId(id); // jseq id should be a string not a number if (av.hasHiddenRows) { @@ -440,6 +495,7 @@ public class Jalview2XML DataOutputStream dout = new DataOutputStream(jout); dout.write(data, 0, data.length); + dout.flush(); jout.closeEntry(); } } catch (Exception ex) @@ -485,7 +541,7 @@ public class Jalview2XML { AlcodonFrame alc = new AlcodonFrame(); vamsasSet.addAlcodonFrame(alc); - for (int p = 0; p < jac[i].aaWidth; i++) + for (int p = 0; p < jac[i].aaWidth; p++) { Alcodon cmap = new Alcodon(); cmap.setPos1(jac[i].codons[p][0]); @@ -721,7 +777,7 @@ public class Jalview2XML { jalview.datamodel.Sequence seq = (jalview.datamodel.Sequence) sg .getSequenceAt(s); - groups[i].addSeq(seq.hashCode()); + groups[i].addSeq(seqHash(seq)); } } @@ -918,47 +974,47 @@ public class Jalview2XML object.setJalviewModelSequence(jms); object.getVamsasModel().addSequenceSet(vamsasSet); - if (out != null) + if (jout!=null && fileName!=null) { - //We may not want to right the object to disk, + //We may not want to write the object to disk, //eg we can copy the alignViewport to a new view object //using save and then load try { - if (!fileName.endsWith(".xml")) - { - fileName = fileName + ".xml"; - } - JarEntry entry = new JarEntry(fileName); jout.putNextEntry(entry); - - object.marshal(out); + PrintWriter pout = new PrintWriter(new OutputStreamWriter(jout, + "UTF-8")); + org.exolab.castor.xml.Marshaller marshaller = new org.exolab.castor.xml.Marshaller(pout); + marshaller.marshal(object); + pout.flush(); + jout.closeEntry(); } catch (Exception ex) { + // TODO: raise error in GUI if marshalling failed. ex.printStackTrace(); } } return object; } - private Sequence createVamsasSequence(int id, SequenceI jds) + private Sequence createVamsasSequence(String id, SequenceI jds) { return createVamsasSequence(true, id, jds, null); } - private Sequence createVamsasSequence(boolean recurse, int id, + private Sequence createVamsasSequence(boolean recurse, String id, SequenceI jds, SequenceI parentseq) { Sequence vamsasSeq = new Sequence(); - vamsasSeq.setId(id + ""); + vamsasSeq.setId(id); vamsasSeq.setName(jds.getName()); vamsasSeq.setSequence(jds.getSequenceAsString()); vamsasSeq.setDescription(jds.getDescription()); jalview.datamodel.DBRefEntry[] dbrefs = null; if (jds.getDatasetSequence() != null) { - vamsasSeq.setDsseqid(jds.getDatasetSequence().hashCode() + ""); + vamsasSeq.setDsseqid(seqHash(jds.getDatasetSequence())); if (jds.getDatasetSequence().getDBRef() != null) { dbrefs = jds.getDatasetSequence().getDBRef(); @@ -966,9 +1022,10 @@ public class Jalview2XML } else { + vamsasSeq.setDsseqid(id); // so we can tell which sequences really are dataset sequences only dbrefs = jds.getDBRef(); } - if (jds.getDBRef() != null) + if (dbrefs != null) { for (int d = 0; d < dbrefs.length; d++) { @@ -1022,24 +1079,24 @@ public class Jalview2XML && (parentseq != jmp.getTo() || parentseq .getDatasetSequence() != jmp.getTo())) { - mpc.setSequence(createVamsasSequence(false, jmp.getTo() - .hashCode(), jmp.getTo(), jds)); + mpc.setSequence(createVamsasSequence(false, seqHash(jmp.getTo()) + , jmp.getTo(), jds)); } else { - long jmpid = 0; + String jmpid = ""; SequenceI ps = null; if (parentseq != jmp.getTo() && parentseq.getDatasetSequence() != jmp.getTo()) { // chaining dbref rather than a handshaking one - jmpid = (ps = jmp.getTo()).hashCode(); + jmpid = seqHash(ps = jmp.getTo()); } else { - jmpid = (ps = parentseq).hashCode(); + jmpid = seqHash(ps = parentseq); } - mpc.setDseqFor("" + jmpid); + mpc.setDseqFor(jmpid); if (!seqRefIds.containsKey(mpc.getDseqFor())) { jalview.bin.Cache.log.debug("creatign new DseqFor ID"); @@ -1224,9 +1281,22 @@ public class Jalview2XML + ex + "\n"); } catch (Exception ex) { + System.err.println("Parsing as Jalview Version 2 file failed."); + ex.printStackTrace(System.err); + //Is Version 1 Jar file? - af = new Jalview2XML_V1().LoadJalviewAlign(file); + try { + af = new Jalview2XML_V1(raiseGUI).LoadJalviewAlign(file); + } catch (Exception ex2) { + System.err.println("Exception whilst loading as jalviewXMLV1:"); + ex2.printStackTrace(); + af = null; + } + if (Desktop.instance != null) + { + Desktop.instance.stopLoading(); + } if (af != null) { System.out.println("Successfully loaded archive file"); @@ -1252,15 +1322,20 @@ public class Jalview2XML if (errorMessage != null) { final String finalErrorMessage = errorMessage; - javax.swing.SwingUtilities.invokeLater(new Runnable() - { - public void run() + if (raiseGUI) + { + javax.swing.SwingUtilities.invokeLater(new Runnable() + { + public void run() { JOptionPane.showInternalMessageDialog(Desktop.desktop, finalErrorMessage, "Error loading Jalview file", JOptionPane.WARNING_MESSAGE); } }); + } else { + System.err.println("Problem loading Jalview file: "+errorMessage); + } } return af; @@ -1305,6 +1380,7 @@ public class Jalview2XML { out.println(data); } + try { out.flush(); } catch (Exception foo) {}; out.close(); alreadyLoadedPDB.put(pdbId, outFile.getAbsolutePath()); @@ -1339,6 +1415,7 @@ public class Jalview2XML boolean multipleView = false; JSeq[] JSEQ = object.getJalviewModelSequence().getJSeq(); + int vi=0; // counter in vamsasSeq array for (int i = 0; i < JSEQ.length; i++) { String seqId = JSEQ[i].getId() + ""; @@ -1350,14 +1427,15 @@ public class Jalview2XML } else { - jseq = new jalview.datamodel.Sequence(vamsasSeq[i].getName(), - vamsasSeq[i].getSequence()); - jseq.setDescription(vamsasSeq[i].getDescription()); + jseq = new jalview.datamodel.Sequence(vamsasSeq[vi].getName(), + vamsasSeq[vi].getSequence()); + jseq.setDescription(vamsasSeq[vi].getDescription()); jseq.setStart(JSEQ[i].getStart()); jseq.setEnd(JSEQ[i].getEnd()); jseq.setVamsasId(uniqueSetSuffix + seqId); - seqRefIds.put(vamsasSeq[i].getId(), jseq); + seqRefIds.put(vamsasSeq[vi].getId()+"", jseq); tmpseqs.add(jseq); + vi++; } if (JSEQ[i].getHidden()) @@ -1399,7 +1477,6 @@ public class Jalview2XML { // older jalview projects do not have a dataset id. al.setDataset(null); - // addDatasetRef(al.getDataset()); } else { @@ -1440,7 +1517,10 @@ public class Jalview2XML al.getSequenceAt(i).getDatasetSequence().addSequenceFeature(sf); } } - + if (vamsasSeq[i].getDBRefCount() > 0) + { + addDBRefs(al.getSequenceAt(i).getDatasetSequence(), vamsasSeq[i]); + } if (JSEQ[i].getPdbidsCount() > 0) { Pdbids[] ids = JSEQ[i].getPdbids(); @@ -1464,10 +1544,6 @@ public class Jalview2XML al.getSequenceAt(i).getDatasetSequence().addPDBId(entry); } } - if (vamsasSeq[i].getDBRefCount() > 0) - { - addDBRefs(al.getSequenceAt(i).getDatasetSequence(), vamsasSeq[i]); - } } } @@ -1573,9 +1649,14 @@ public class Jalview2XML .getSecondaryStructure() == null || ae[aa] .getSecondaryStructure().length() == 0) ? ' ' : ae[aa] .getSecondaryStructure().charAt(0), ae[aa].getValue() - + ); - + // JBPNote: Consider verifying dataflow for IO of secondary structure annotation read from Stockholm files + // this was added to try to ensure that + //if (anot[ae[aa].getPosition()].secondaryStructure>' ') + //{ + // anot[ae[aa].getPosition()].displayCharacter = ""; + //} anot[ae[aa].getPosition()].colour = new java.awt.Color(ae[aa] .getColour()); } @@ -2070,8 +2151,21 @@ public class Jalview2XML int height = ids[p].getStructureState(s).getHeight(); java.awt.Component comp = null; - - JInternalFrame[] frames = Desktop.desktop.getAllFrames(); + + JInternalFrame[] frames = null; + do { + try { + frames = Desktop.desktop.getAllFrames(); + } + catch (ArrayIndexOutOfBoundsException e) + { + // occasional No such child exceptions are thrown here... + frames = null; + try { + Thread.sleep(10); + } catch (Exception f) {}; + } + } while (frames==null); for (int f = 0; f < frames.length; f++) { if (frames[f] instanceof AppJmol) @@ -2139,80 +2233,114 @@ public class Jalview2XML for (int i = 0, iSize = vamsasSet.getSequenceCount(); i < iSize; i++) { Sequence vamsasSeq = vamsasSet.getSequence(i); - jalview.datamodel.Sequence sq = null; - String sqid = vamsasSeq.getDsseqid(); + ensureJalviewDatasetSequence(vamsasSeq, ds, dseqs); + } + // create a new dataset + if (ds == null) + { + SequenceI[] dsseqs = new SequenceI[dseqs.size()]; + dseqs.copyInto(dsseqs); + ds = new jalview.datamodel.Alignment(dsseqs); + addDatasetRef(vamsasSet.getDatasetId(), ds); + } + // set the dataset for the newly imported alignment. + if (al.getDataset() == null) + { + al.setDataset(ds); + } + } + + + /** + * + * @param vamsasSeq sequence definition to create/merge dataset sequence for + * @param ds dataset alignment + * @param dseqs vector to add new dataset sequence to + */ + private void ensureJalviewDatasetSequence(Sequence vamsasSeq, AlignmentI ds, Vector dseqs) + { + jalview.datamodel.Sequence sq = (jalview.datamodel.Sequence) seqRefIds.get(vamsasSeq.getId()); + jalview.datamodel.SequenceI dsq = null; + if (sq!=null && sq.getDatasetSequence()!=null) + { + dsq = (jalview.datamodel.SequenceI) sq.getDatasetSequence(); + } + + String sqid = vamsasSeq.getDsseqid(); + if (dsq==null) + { + // need to create or add a new dataset sequence reference to this sequence if (sqid != null) { - sq = (jalview.datamodel.Sequence) seqRefIds.get(vamsasSeq - .getDsseqid()); + dsq = (jalview.datamodel.SequenceI) seqRefIds.get(sqid); } - if (sq == null) + // check again + if (dsq == null) { - sq = (jalview.datamodel.Sequence) seqRefIds.get(vamsasSeq.getId()); - jalview.datamodel.SequenceI dsq = sq.createDatasetSequence(); + // make a new dataset sequence + dsq = sq.createDatasetSequence(); if (sqid == null) { // make up a new dataset reference for this sequence - sqid = "" + dsq.hashCode(); + sqid = seqHash(dsq); } - ((SequenceI) dsq).setVamsasId(uniqueSetSuffix + sqid); + dsq.setVamsasId(uniqueSetSuffix + sqid); seqRefIds.put(sqid, dsq); if (ds == null) { - dseqs.addElement(dsq); + if (dseqs!=null) + { + dseqs.addElement(dsq); + } } else { ds.addSequence(dsq); } - + } else { + if (sq!=dsq) + { // make this dataset sequence sq's dataset sequence + sq.setDatasetSequence(dsq); + } } - // TODO: refactor: This is a low-level sequence operation - effectively merging one dataset sequence into another. - // check that dataset sequence really is the union of all references to it - boolean pre = sq.getStart() < sq.getDatasetSequence().getStart(); - boolean post = sq.getEnd() > sq.getDatasetSequence().getEnd(); - if (pre || post) + } + // TODO: refactor this as a merge dataset sequence function + // now check that sq (the dataset sequence) sequence really is the union of all references to it + //boolean pre = sq.getStart() < dsq.getStart(); + //boolean post = sq.getEnd() > dsq.getEnd(); + //if (pre || post) + if (sq!=dsq) + { + StringBuffer sb = new StringBuffer(); + String newres = jalview.analysis.AlignSeq.extractGaps( + jalview.util.Comparison.GapChars, sq.getSequenceAsString()); + if (!newres.equalsIgnoreCase(dsq.getSequenceAsString()) && newres.length()>dsq.getLength()) { - SequenceI dsq = sq.getDatasetSequence(); - StringBuffer sb = new StringBuffer(); - String newres = jalview.analysis.AlignSeq.extractGaps( - jalview.util.Comparison.GapChars, sq.getSequenceAsString()); + // Update with the longer sequence. synchronized (dsq) { - sb.append(dsq.getSequence()); - if (pre) - { - sb.insert(0, newres - .substring(0, dsq.getStart() - sq.getStart())); - dsq.setStart(sq.getStart()); - } - if (post) - { - sb.append(newres.substring(newres.length() - sq.getEnd() - - dsq.getEnd())); - dsq.setEnd(sq.getEnd()); - } - dsq.setSequence(sb.toString()); + /*if (pre) + { + sb.insert(0, newres + .substring(0, dsq.getStart() - sq.getStart())); + dsq.setStart(sq.getStart()); + } + if (post) + { + sb.append(newres.substring(newres.length() - sq.getEnd() + - dsq.getEnd())); + dsq.setEnd(sq.getEnd()); + } + */ + dsq.setSequence(sb.toString()); } + //TODO: merges will never happen if we 'know' we have the real dataset sequence - this should be detected when id==dssid System.err - .println("DEBUG Notice: Merged dataset sequence (" - + (pre ? "prepended" : "") + " " - + (post ? "appended" : "")); + .println("DEBUG Notice: Merged dataset sequence"); // (" + // + (pre ? "prepended" : "") + " " + //+ (post ? "appended" : "")); } } - // create a new dataset - if (ds == null) - { - SequenceI[] dsseqs = new SequenceI[dseqs.size()]; - dseqs.copyInto(dsseqs); - ds = new jalview.datamodel.Alignment(dsseqs); - addDatasetRef(vamsasSet.getDatasetId(), ds); - } - // set the dataset for the newly imported alignment. - if (al.getDataset() == null) - { - al.setDataset(ds); - } } java.util.Hashtable datasetIds = null; @@ -2299,18 +2427,38 @@ public class Jalview2XML else { /** - * make a new sequence and add it to refIds hash + * local sequence definition */ Sequence ms = mc.getSequence(); - jalview.datamodel.Sequence djs = new jalview.datamodel.Sequence(ms + jalview.datamodel.Sequence djs=null; + String sqid = ms.getDsseqid(); + if (sqid!=null && sqid.length()>0) + { + /* + * recover dataset sequence + */ + djs = (jalview.datamodel.Sequence) seqRefIds.get(sqid); + } else { + System.err.println("Warning - making up dataset sequence id for DbRef sequence map reference"); + sqid = ((Object)ms).toString(); // make up a new hascode for undefined dataset sequence hash (unlikely to happen) + } + + if (djs==null) { + /** + * make a new dataset sequence and add it to refIds hash + */ + djs = new jalview.datamodel.Sequence(ms .getName(), ms.getSequence()); - djs.setStart(jmap.getMap().getToLowest()); - djs.setEnd(jmap.getMap().getToHighest()); - djs.setVamsasId(uniqueSetSuffix + ms.getId()); - jmap.setTo(djs); - seqRefIds.put(ms.getId(), djs); + djs.setStart(jmap.getMap().getToLowest()); + djs.setEnd(jmap.getMap().getToHighest()); + djs.setVamsasId(uniqueSetSuffix + sqid); + jmap.setTo(djs); + seqRefIds.put(sqid, djs); + + } jalview.bin.Cache.log.debug("about to recurse on addDBRefs."); addDBRefs(djs, ms); + } } return (jmap); @@ -2320,12 +2468,12 @@ public class Jalview2XML public jalview.gui.AlignmentPanel copyAlignPanel(AlignmentPanel ap, boolean keepSeqRefs) { - jalview.schemabinding.version2.JalviewModel jm = SaveState(ap, null, - null, null); + jalview.schemabinding.version2.JalviewModel jm = + SaveState(ap, null, null); if (!keepSeqRefs) { - seqRefIds.clear(); + clearSeqRefs(); jm.getJalviewModelSequence().getViewport(0).setSequenceSetId(null); } else @@ -2353,4 +2501,16 @@ public class Jalview2XML return af.alignPanel; } + /* (non-Javadoc) + * @see java.lang.Object#finalize() + */ + protected void finalize() throws Throwable + { + // really make sure we have no buried refs left. + clearSeqRefs(); + this.seqRefIds = null; + this.seqsToIds = null; + super.finalize(); + } + }