2 * Jalview - A Sequence Alignment Editor and Viewer (Version 2.4)
3 * Copyright (C) 2008 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
21 import jalview.bin.Cache;
22 import jalview.datamodel.AlignmentI;
23 import jalview.datamodel.ColumnSelection;
24 import jalview.datamodel.SequenceGroup;
25 import jalview.datamodel.SequenceI;
26 import jalview.io.VamsasAppDatastore;
27 import jalview.structure.SelectionListener;
28 import jalview.structure.SelectionSource;
29 import jalview.structure.StructureSelectionManager;
30 import jalview.structure.VamsasListener;
32 import java.beans.PropertyChangeEvent;
33 import java.beans.PropertyChangeListener;
35 import java.io.IOException;
36 import java.util.Enumeration;
37 import java.util.Hashtable;
38 import java.util.IdentityHashMap;
39 import java.util.Iterator;
41 import javax.swing.JInternalFrame;
42 import javax.swing.JOptionPane;
44 import uk.ac.vamsas.client.ClientHandle;
45 import uk.ac.vamsas.client.IClient;
46 import uk.ac.vamsas.client.IClientDocument;
47 import uk.ac.vamsas.client.InvalidSessionDocumentException;
48 import uk.ac.vamsas.client.NoDefaultSessionException;
49 import uk.ac.vamsas.client.UserHandle;
50 import uk.ac.vamsas.client.VorbaId;
51 import uk.ac.vamsas.client.picking.IMessageHandler;
52 import uk.ac.vamsas.client.picking.IPickManager;
53 import uk.ac.vamsas.client.picking.Message;
54 import uk.ac.vamsas.client.picking.MouseOverMessage;
55 import uk.ac.vamsas.client.picking.SelectionMessage;
56 import uk.ac.vamsas.objects.core.Entry;
57 import uk.ac.vamsas.objects.core.Input;
58 import uk.ac.vamsas.objects.core.Pos;
59 import uk.ac.vamsas.objects.core.Seg;
65 public class VamsasApplication implements SelectionSource
67 IClient vclient = null;
69 ClientHandle app = null;
71 UserHandle user = null;
73 Desktop jdesktop = null; // our jalview desktop reference
75 // Cache.preferences for vamsas client session arena
76 // preferences for check for default session at startup.
77 // user and organisation stuff.
78 public VamsasApplication(Desktop jdesktop, File sessionPath)
81 // we should create a session URI from the sessionPath and pass it to
82 // the clientFactory - but the vamsas api doesn't cope with that yet.
83 this.jdesktop = jdesktop;
84 initClientSession(null, sessionPath);
87 private static uk.ac.vamsas.client.IClientFactory getClientFactory()
90 return new uk.ac.vamsas.client.simpleclient.SimpleClientFactory();
94 * Start a new vamsas session
98 public VamsasApplication(Desktop jdesktop)
100 this.jdesktop = jdesktop;
101 initClientSession(null, null);
105 * init a connection to the session at the given url
110 public VamsasApplication(Desktop jdesktop, String sessionUrl)
112 this.jdesktop = jdesktop;
113 initClientSession(sessionUrl, null);
117 * @throws IOException
118 * or other if clientfactory instantiation failed.
119 * @return list of current sessions or null if no session exists.
121 public static String[] getSessionList() throws Exception
123 return getClientFactory().getCurrentSessions();
127 * initialise, possibly with either a valid session url or a file for a new
131 * null or a valid session url
132 * @param vamsasDocument
133 * null or a valid vamsas document file
134 * @return false if no vamsas connection was made
136 private boolean initClientSession(String sess, File vamsasDocument)
140 // Only need to tell the library what the application is here
141 app = getJalviewHandle();
142 uk.ac.vamsas.client.IClientFactory clientfactory = getClientFactory();
143 if (vamsasDocument != null)
148 "Implementation Error - cannot import existing vamsas document into an existing session, Yet!");
152 vclient = clientfactory.openAsNewSessionIClient(app,
154 } catch (InvalidSessionDocumentException e)
157 .showInternalMessageDialog(
160 "VAMSAS Document could not be opened as a new session - please choose another",
161 "VAMSAS Document Import Failed",
162 JOptionPane.ERROR_MESSAGE);
168 // join existing or create a new session
171 vclient = clientfactory.getNewSessionIClient(app);
175 vclient = clientfactory.getIClient(app, sess);
178 // set some properties for our VAMSAS interaction
180 user = vclient.getUserHandle();
182 } catch (Exception e)
184 jalview.bin.Cache.log
185 .error("Couldn't instantiate vamsas client !", e);
191 private void setVclientConfig()
199 if (vclient instanceof uk.ac.vamsas.client.simpleclient.SimpleClient)
201 uk.ac.vamsas.client.simpleclient.SimpleClientConfig cfg = ((uk.ac.vamsas.client.simpleclient.SimpleClient) vclient)
202 .getSimpleClientConfig();
203 cfg._validatemergedroots = false;
204 cfg._validateupdatedroots = true; // we may write rubbish otherwise.
210 "Probable SERIOUS VAMSAS client incompatibility - carrying on regardless",
212 } catch (Exception e)
216 "Probable VAMSAS client incompatibility - carrying on regardless",
222 * make the appHandle for Jalview
226 private ClientHandle getJalviewHandle()
228 return new ClientHandle("jalview.bin.Jalview", jalview.bin.Cache
229 .getProperty("VERSION"));
234 * @return true if we are registered in a vamsas session
236 public boolean inSession()
238 return (vclient != null);
242 * called to connect to session inits handlers, does an initial document
245 public void initial_update()
250 "Impementation error! Vamsas Operations when client not initialised and connected.");
252 addDocumentUpdateHandler();
253 addStoreDocumentHandler();
256 .debug("Jalview loading the Vamsas Session for the first time.");
257 dealWithDocumentUpdate(false); // we don't push an update out to the
259 Cache.log.debug("... finished update for the first time.");
263 * Update all windows after a vamsas datamodel change. this could go on the
267 protected void updateJalviewGui()
269 JInternalFrame[] frames = jdesktop.getAllFrames();
279 for (int i = frames.length - 1; i > -1; i--)
281 if (frames[i] instanceof AlignFrame)
283 AlignFrame af = (AlignFrame) frames[i];
284 af.alignPanel.alignmentChanged();
287 } catch (Exception e)
291 "Exception whilst refreshing jalview windows after a vamsas document update.",
296 public void push_update()
298 Thread udthread = new Thread(new Runnable()
303 Cache.log.info("Jalview updating to the Vamsas Session.");
305 dealWithDocumentUpdate(true);
307 * IClientDocument cdoc=null; try { cdoc = vclient.getClientDocument(); }
308 * catch (Exception e) { Cache.log.error("Failed to get client document
309 * for update."); // RAISE A WARNING DIALOG disableGui(false); return; }
310 * updateVamsasDocument(cdoc); updateJalviewGui();
311 * cdoc.setVamsasRoots(cdoc.getVamsasRoots()); // propagate update flags
312 * back vclient.updateDocument(cdoc);
314 Cache.log.info("Jalview finished updating to the Vamsas Session.");
315 // TODO Auto-generated method stub
322 public void end_session()
325 throw new Error("Jalview not connected to Vamsas session.");
326 Cache.log.info("Jalview disconnecting from the Vamsas Session.");
331 vclient.finalizeClient();
332 Cache.log.info("Jalview has left the session.");
337 .warn("JV Client leaving a session that's its not joined yet.");
339 joinedSession = false;
345 } catch (Exception e)
347 Cache.log.error("Vamsas Session finalization threw exceptions!", e);
351 public void updateJalview(IClientDocument cdoc)
353 Cache.log.debug("Jalview updating from sesion document ..");
355 VamsasAppDatastore vds = new VamsasAppDatastore(cdoc, vobj2jv, jv2vobj,
356 baseProvEntry(), alRedoState);
359 vds.updateToJalview();
360 } catch (Exception e)
362 Cache.log.error("Failed to update Jalview from vamsas document.", e);
368 vds.updateJalviewFromAppdata();
369 // Comment this out to repeatedly read in data from JalviewAppData
370 // firstUpdate=false;
372 } catch (Exception e)
375 "Exception when updating Jalview settings from Appdata.", e);
377 Cache.log.debug(".. finished updating from sesion document.");
381 boolean firstUpdate = false;
383 private void ensureJvVamsas()
387 jv2vobj = new IdentityHashMap();
388 vobj2jv = new Hashtable();
389 alRedoState = new Hashtable();
395 * jalview object binding to VorbaIds
397 IdentityHashMap jv2vobj = null;
399 Hashtable vobj2jv = null;
401 Hashtable alRedoState = null;
403 boolean errorsDuringUpdate = false;
405 boolean errorsDuringAppUpdate = false;
408 * update the document accessed through doc. A backup of the current object
413 public void updateVamsasDocument(IClientDocument doc)
416 errorsDuringUpdate = false;
417 errorsDuringAppUpdate = false;
418 backup_objectMapping();
419 VamsasAppDatastore vds = new VamsasAppDatastore(doc, vobj2jv, jv2vobj,
420 baseProvEntry(), alRedoState);
421 // wander through frames
422 JInternalFrame[] frames = Desktop.desktop.getAllFrames();
428 Hashtable skipList = new Hashtable();
429 Hashtable viewset = new Hashtable();
434 for (int i = frames.length - 1; i > -1; i--)
436 if (frames[i] instanceof AlignFrame)
438 AlignFrame af = (AlignFrame) frames[i];
439 if (!viewset.containsKey(af.getViewport().getSequenceSetId()))
441 // update alignment and root from frame.
442 boolean stored = false;
445 stored = vds.storeVAMSAS(af.getViewport(), af.getTitle());
446 } catch (Exception e)
448 errorsDuringUpdate = true;
449 Cache.log.error("Exception synchronizing "
452 + (af.getViewport().viewName == null ? "" : " view "
453 + af.getViewport().viewName)
454 + " to document.", e);
458 { // record skip in skipList
459 skipList.put(af.getViewport().getSequenceSetId(), af);
463 // could try to eliminate sequenceSetId from skiplist ..
464 // (skipList.containsKey(af.getViewport().getSequenceSetId()))
465 // remember sequenceSetId so we can skip all the other views on
467 viewset.put(af.getViewport().getSequenceSetId(), af);
473 // for (int i = frames.length - 1; i > -1; i--)
475 // if (frames[i] instanceof AlignFrame)
477 // AlignFrame af = (AlignFrame) frames[i];
478 Iterator aframes = viewset.values().iterator();
479 while (aframes.hasNext())
481 AlignFrame af = (AlignFrame) aframes.next();
482 // add any AlignedCodonFrame mappings on this alignment to any other.
483 vds.storeSequenceMappings(af.getViewport(), af.getTitle());
485 } catch (Exception e)
487 Cache.log.error("Exception synchronizing Views to Document :", e);
488 errorsDuringUpdate = true;
493 if (viewset.size() > 0)
495 // Alignment views were synchronized, so store their state in the
497 // The skipList ensures we don't write out any alignments not actually
499 vds.setSkipList(skipList);
500 vds.updateJalviewClientAppdata();
502 } catch (Exception e)
504 Cache.log.error("Client Appdata Write exception", e);
505 errorsDuringAppUpdate = true;
510 private Entry baseProvEntry()
512 uk.ac.vamsas.objects.core.Entry pentry = new uk.ac.vamsas.objects.core.Entry();
513 pentry.setUser(user.getFullName());
514 pentry.setApp(app.getClientUrn());
515 pentry.setDate(new java.util.Date());
516 pentry.setAction("created");
521 * do a vamsas document update or update jalview from the vamsas document
524 * true to update from jalview to the vamsas document
526 protected void dealWithDocumentUpdate(boolean fromJalview)
528 // called by update handler for document update.
529 Cache.log.debug("Updating jalview from changed vamsas document.");
533 long time = System.currentTimeMillis();
534 IClientDocument cdoc = vclient.getClientDocument();
535 if (Cache.log.isDebugEnabled())
537 Cache.log.debug("Time taken to get ClientDocument = "
538 + (System.currentTimeMillis() - time));
539 time = System.currentTimeMillis();
543 this.updateVamsasDocument(cdoc);
544 if (Cache.log.isDebugEnabled())
547 .debug("Time taken to update Vamsas Document from jalview\t= "
548 + (System.currentTimeMillis() - time));
549 time = System.currentTimeMillis();
551 cdoc.setVamsasRoots(cdoc.getVamsasRoots());
552 if (Cache.log.isDebugEnabled())
554 Cache.log.debug("Time taken to set Document Roots\t\t= "
555 + (System.currentTimeMillis() - time));
556 time = System.currentTimeMillis();
562 if (Cache.log.isDebugEnabled())
565 .debug("Time taken to update Jalview from vamsas document Roots\t= "
566 + (System.currentTimeMillis() - time));
567 time = System.currentTimeMillis();
571 vclient.updateDocument(cdoc);
572 if (Cache.log.isDebugEnabled())
574 Cache.log.debug("Time taken to update Session Document\t= "
575 + (System.currentTimeMillis() - time));
576 time = System.currentTimeMillis();
579 } catch (Exception ee)
581 System.err.println("Exception whilst updating :");
582 ee.printStackTrace(System.err);
583 // recover object map backup, since its probably corrupted with references
584 // to Vobjects that don't exist anymore.
585 this.recover_objectMappingBackup();
587 Cache.log.debug("Finished updating from document change.");
591 private void addDocumentUpdateHandler()
593 final VamsasApplication client = this;
594 vclient.addDocumentUpdateHandler(new PropertyChangeListener()
596 public void propertyChange(PropertyChangeEvent evt)
598 Cache.log.debug("Dealing with document update event.");
599 client.dealWithDocumentUpdate(false);
600 Cache.log.debug("finished dealing with event.");
603 Cache.log.debug("Added Jalview handler for vamsas document updates.");
606 private void addStoreDocumentHandler()
608 final VamsasApplication client = this;
609 vclient.addVorbaEventHandler(
610 uk.ac.vamsas.client.Events.DOCUMENT_REQUESTTOCLOSE,
611 new PropertyChangeListener()
613 public void propertyChange(PropertyChangeEvent evt)
616 .debug("Asking user if the vamsas session should be stored.");
617 int reply = JOptionPane
618 .showInternalConfirmDialog(
620 "The current VAMSAS session has unsaved data - do you want to save it ?",
621 "VAMSAS Session Shutdown",
622 JOptionPane.YES_NO_OPTION,
623 JOptionPane.QUESTION_MESSAGE);
625 if (reply == JOptionPane.YES_OPTION)
627 Cache.log.debug("Prompting for vamsas store filename.");
628 Desktop.instance.vamsasSave_actionPerformed(null);
629 Cache.log.debug("Finished attempt at storing document.");
632 .debug("finished dealing with REQUESTTOCLOSE event.");
635 Cache.log.debug("Added Jalview handler for vamsas document updates.");
638 public void disableGui(boolean b)
640 Desktop.instance.setVamsasUpdate(b);
643 Hashtable _backup_vobj2jv;
645 IdentityHashMap _backup_jv2vobj;
648 * make a backup of the object mappings (vobj2jv and jv2vobj)
650 public void backup_objectMapping()
652 _backup_vobj2jv = new Hashtable(vobj2jv);
653 _backup_jv2vobj = new IdentityHashMap(jv2vobj);
657 * recover original object mappings from the object mapping backup if document
661 * if backup_objectMapping was not called.
663 public void recover_objectMappingBackup()
665 if (_backup_vobj2jv == null)
668 "IMPLEMENTATION ERROR: Cannot recover vamsas object mappings - no backup was made.");
671 Iterator el = _backup_jv2vobj.entrySet().iterator();
674 java.util.Map.Entry mp = (java.util.Map.Entry) el.next();
675 jv2vobj.put(mp.getKey(), mp.getValue());
677 el = _backup_vobj2jv.entrySet().iterator();
680 java.util.Map.Entry mp = (java.util.Map.Entry) el.next();
681 vobj2jv.put(mp.getKey(), mp.getValue());
685 private boolean joinedSession = false;
687 private VamsasListener picker = null;
689 private SelectionListener selecter;
691 private void startSession()
697 vclient.joinSession();
698 joinedSession = true;
699 } catch (Exception e)
702 Cache.log.error("Failed to join vamsas session.", e);
707 final IPickManager pm = vclient.getPickManager();
708 final StructureSelectionManager ssm = StructureSelectionManager
709 .getStructureSelectionManager();
710 final SelectionSource me = this;
711 pm.registerMessageHandler(new IMessageHandler()
715 public void handleMessage(Message message)
719 // we are not in a session yet.
722 if (message instanceof MouseOverMessage)
724 MouseOverMessage mm = (MouseOverMessage) message;
725 String mstring = mm.getVorbaID() + " " + mm.getPosition();
726 if (last != null && mstring.equals(last))
730 // if (Cache.log.isDebugEnabled())
732 // Cache.log.debug("Received MouseOverMessage "+mm.getVorbaID()+"
733 // "+mm.getPosition());
735 Object jvobj = vobj2jv.get(mm.getVorbaID());
736 if (jvobj != null && jvobj instanceof SequenceI)
739 // Cache.log.debug("Handling Mouse over "+mm.getVorbaID()+"
740 // bound to "+jvobj+" at "+mm.getPosition());
741 // position is character position in aligned sequence
742 ssm.mouseOverVamsasSequence((SequenceI) jvobj, mm
746 if (message instanceof uk.ac.vamsas.client.picking.SelectionMessage)
748 // we only care about AlignmentSequence selections
749 SelectionMessage sm = (SelectionMessage) message;
751 System.err.println("Received\n"+sm.getRawMessage());
752 Object[] jvobjs = sm.getVorbaIDs()==null ? null : new Object[sm.getVorbaIDs().length];
755 // TODO: rationalise : can only clear a selection over a referred to object
756 ssm.sendSelection(null,null,me);
761 for (int o = 0; o < jvobjs.length; o++)
763 jvobjs[o] = vobj2jv.get(sm.getVorbaIDs()[o]);
764 if (jvobjs[o] == null)
766 // can't cope with selections for unmapped objects
771 type = jvobjs[o].getClass();
774 if (type != jvobjs[o].getClass())
777 // discard - can't cope with selections over mixed objects
781 SequenceGroup jselection = null;
782 ColumnSelection colsel = null;
783 if (type == jalview.datamodel.Alignment.class)
785 if (jvobjs.length == 1)
787 // TODO if (sm.isNone())// send a message to select the specified columns over the
794 if (type == jalview.datamodel.Sequence.class)
798 boolean aligned = ((jalview.datamodel.Sequence) jvobjs[0])
799 .getDatasetSequence() != null;
803 jselection = new SequenceGroup();
804 jselection.addSequence(seq =
805 (jalview.datamodel.Sequence) jvobjs[0], false);
806 maxWidth = seq.getLength();
808 for (int c = 1; aligned && jvobjs.length > 1 && c < jvobjs.length; c++)
810 if (((jalview.datamodel.Sequence) jvobjs[c])
811 .getDatasetSequence() == null)
818 jselection.addSequence(
819 seq = (jalview.datamodel.Sequence) jvobjs[c], false);
820 if (maxWidth<seq.getLength())
822 maxWidth = seq.getLength();
830 // if cardinality is greater than one then verify all
831 // sequences are alignment sequences.
832 if (jvobjs.length == 1)
834 // find all instances of this dataset sequence in the
835 // displayed alignments containing the associated range and
841 jselection.setStartRes(0);
842 jselection.setEndRes(maxWidth);
843 // locate the alignment containing the given sequences and
844 // select the associated ranges on them.
845 if (sm.getRanges() != null)
847 int[] prange = uk.ac.vamsas.objects.utils.Range.getBounds(sm.getRanges());
848 boolean rangeset=false;
849 colsel = new ColumnSelection();
850 prange = uk.ac.vamsas.objects.utils.Range.getIntervals(sm.getRanges());
851 for (int p=0;p<prange.length;p+=2)
853 int d = (prange[p]<=prange[p+1]) ? 1 : -1;
856 if (jselection!=null)
858 // set the bounds of the selected area using the first interval.
859 jselection.setStartRes(prange[p]-1);
860 jselection.setEndRes(prange[p+1]-1);
864 // try to join up adjacent columns to make a larger selection
865 // lower and upper bounds
869 if (jselection.getStartRes()>0 && prange[p+l]==jselection.getStartRes())
871 jselection.setStartRes(prange[p+l]-1);
873 if (jselection.getEndRes()<=maxWidth && prange[p+u]==(jselection.getEndRes()+2))
875 jselection.setEndRes(prange[p+u]-1);
878 // mark all the columns in the range.
879 for (int sr=prange[p],er=prange[p+1],de=er+d; sr!=de; sr+=d)
881 colsel.addElement(sr-1);
890 ssm.sendSelection(jselection, colsel, me);
893 for (int c = 0; c < jvobjs.length; c++)
903 picker = new VamsasListener()
905 SequenceI last = null;
909 public void mouseOver(SequenceI seq, int index)
913 if (seq != last || i != index)
915 VorbaId v = (VorbaId) jv2vobj.get(seq);
918 Cache.log.debug("Mouse over " + v.getId() + " bound to "
919 + seq + " at " + index);
922 MouseOverMessage message = new MouseOverMessage(v.getId(),
924 pm.sendMessage(message);
929 selecter = new SelectionListener()
932 public void selection(SequenceGroup seqsel,
933 ColumnSelection colsel, SelectionSource source)
937 Cache.log.warn("Selection listener still active for dead session.");
943 AlignmentI visal=null;
944 if (source instanceof AlignViewport)
946 visal = ((AlignViewport) source).getAlignment();
948 SelectionMessage sm = null;
949 if ((seqsel == null || seqsel.getSize() == 0)
950 && (colsel == null || colsel.getSelected() == null || colsel
951 .getSelected().size() == 0))
953 if (source instanceof AlignViewport)
955 // the empty selection.
956 sm = new SelectionMessage("jalview", new String[] { ((AlignViewport)source).getSequenceSetId()}, null, true);
958 // the empty selection.
959 sm = new SelectionMessage("jalview", null, null, true);
964 String[] vobj = new String[seqsel.getSize()];
966 Enumeration sels = seqsel.getSequences(null).elements();
967 while (sels.hasMoreElements())
969 SequenceI sel = (SequenceI) sels.nextElement();
970 VorbaId v = (VorbaId) jv2vobj.get(sel);
973 vobj[o++] = v.toString();
979 vobj = new String[o];
980 System.arraycopy(t, 0, vobj, 0, o);
984 if (seqsel!=null && colsel != null)
986 // deparse the colsel into positions on the vamsas alignment
989 if (colsel.getSelected()!=null && colsel.getSelected().size()>0 && visal!=null && seqsel.getSize()==visal.getHeight())
991 // gather selected columns outwith the sequence positions too
992 Enumeration cols = colsel.getSelected().elements();
993 while (cols.hasMoreElements())
995 int ival = ((Integer) cols.nextElement()).intValue();
1001 int[] intervals = colsel.getVisibleContigs(seqsel.getStartRes(), seqsel.getEndRes()+1);
1002 for (int iv=0;iv<intervals.length; iv+=2)
1005 s.setStart(intervals[iv]+1); // vamsas indices begin at 1, not zero.
1006 s.setEnd(intervals[iv+1]+1);
1007 s.setInclusive(true);
1012 sm = new SelectionMessage("jalview", vobj, range);
1014 sm.validate(); // debug
1015 Cache.log.debug("Selection Message\n"+sm.getRawMessage());
1021 ssm.addStructureViewerListener(picker); // better method here
1022 ssm.addSelectionListener(selecter);
1023 } catch (Exception e)
1025 Cache.log.error("Failed to init Vamsas Picking", e);