/* * 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.vamsas; import java.util.Enumeration; import java.util.Hashtable; import java.util.IdentityHashMap; import java.util.Vector; import jalview.bin.Console; import jalview.io.VamsasAppDatastore; import jalview.log.JLoggerLog4j; import jalview.util.MessageManager; import uk.ac.vamsas.client.IClientDocument; import uk.ac.vamsas.client.Vobject; import uk.ac.vamsas.client.VorbaId; import uk.ac.vamsas.objects.core.Entry; import uk.ac.vamsas.objects.core.Provenance; import uk.ac.vamsas.objects.core.Seg; /** * Holds all the common machinery for binding objects to vamsas objects * * @author JimP * */ public abstract class DatastoreItem { /** * */ Entry provEntry = null; IClientDocument cdoc; Hashtable vobj2jv; IdentityHashMap jv2vobj; boolean tojalview = false; /** * shared log instance */ protected static JLoggerLog4j log = JLoggerLog4j .getLogger(DatastoreItem.class); /** * note: this is taken verbatim from jalview.io.VamsasAppDatastore * * @return the Vobject bound to Jalview datamodel object */ protected Vobject getjv2vObj(Object jvobj) { if (jv2vobj.containsKey(jvobj)) { return cdoc.getObject((VorbaId) jv2vobj.get(jvobj)); } if (Console.isDebugEnabled()) { Console.debug( "Returning null VorbaID binding for jalview object " + jvobj); } return null; } /** * * @param vobj * @return Jalview datamodel object bound to the vamsas document object */ protected Object getvObj2jv(uk.ac.vamsas.client.Vobject vobj) { if (vobj2jv == null) return null; VorbaId id = vobj.getVorbaId(); if (id == null) { id = cdoc.registerObject(vobj); Console.debug( "Registering new object and returning null for getvObj2jv"); return null; } if (vobj2jv.containsKey(vobj.getVorbaId())) { return vobj2jv.get(vobj.getVorbaId()); } return null; } /** * note: this is taken verbatim from jalview.io.VamsasAppDatastore with added * call to updateRegistryEntry * * @param jvobj * @param vobj */ protected void bindjvvobj(Object jvobj, uk.ac.vamsas.client.Vobject vobj) { VorbaId id = vobj.getVorbaId(); if (id == null) { id = cdoc.registerObject(vobj); if (id == null || vobj.getVorbaId() == null || cdoc.getObject(id) != vobj) { Console.error("Failed to get id for " + (vobj.isRegisterable() ? "registerable" : "unregisterable") + " object " + vobj); } } if (vobj2jv.containsKey(vobj.getVorbaId()) && !(vobj2jv.get(vobj.getVorbaId())).equals(jvobj)) { Console.debug( "Warning? Overwriting existing vamsas id binding for " + vobj.getVorbaId(), new Exception(MessageManager.getString( "exception.overwriting_vamsas_id_binding"))); } else if (jv2vobj.containsKey(jvobj) && !((VorbaId) jv2vobj.get(jvobj)).equals(vobj.getVorbaId())) { Console.debug( "Warning? Overwriting existing jalview object binding for " + jvobj, new Exception(MessageManager.getString( "exception.overwriting_jalview_id_binding"))); } /* * Cache.error("Attempt to make conflicting object binding! "+vobj+" id " * +vobj.getVorbaId()+" already bound to "+getvObj2jv(vobj)+" and "+jvobj+" * already bound to "+getjv2vObj(jvobj),new Exception("Excessive call to * bindjvvobj")); } */ // we just update the hash's regardless! Console.debug("Binding " + vobj.getVorbaId() + " to " + jvobj); vobj2jv.put(vobj.getVorbaId(), jvobj); // JBPNote - better implementing a hybrid invertible hash. jv2vobj.put(jvobj, vobj.getVorbaId()); if (jvobj == this.jvobj || vobj == this.vobj) { updateRegistryEntry(jvobj, vobj); } } /** * update the vobj and jvobj references and the registry entry for this * datastore object called by bindjvvobj and replacejvobjmapping */ private void updateRegistryEntry(Object jvobj, Vobject vobj) { if (this.jvobj != null && this.vobj != null) { Console.debug("updating dsobj registry. (" + this.getClass().getName() + ")"); } this.jvobj = jvobj; this.vobj = vobj; dsReg.registerDsObj(this); } /** * replaces oldjvobject with newjvobject in the Jalview Object <> VorbaID * binding tables note: originally taken verbatim from * jalview.io.VamsasAppDatastore with added call to updateRegistryEntry * * @param oldjvobject * @param newjvobject * (may be null to forget the oldjvobject's document mapping) * */ protected void replaceJvObjMapping(Object oldjvobject, Object newjvobject) { Object vobject = jv2vobj.remove(oldjvobject); if (vobject == null) { throw new Error(MessageManager.formatMessage( "error.implementation_error_old_jalview_object_not_bound", new String[] { oldjvobject.toString() })); } if (newjvobject != null) { jv2vobj.put(newjvobject, vobject); vobj2jv.put(vobject, newjvobject); updateRegistryEntry(newjvobject, vobj); } } public DatastoreItem() { super(); } public DatastoreItem(VamsasAppDatastore datastore) { this(); initDatastoreItem(datastore); // TODO Auto-generated constructor stub } /** * construct and initialise datastore object and retrieve object bound to * vobj2 and validate it against boundType * * @param datastore2 * @param vobj2 * @param boundType */ public DatastoreItem(VamsasAppDatastore datastore2, Vobject vobj2, Class boundType) { this(datastore2); vobj = vobj2; jvobj = getvObj2jv(vobj2); tojalview = true; if (jvobj != null && !(boundType.isAssignableFrom(jvobj.getClass()))) { throw new Error(MessageManager.formatMessage( "error.implementation_error_vamsas_doc_class_should_bind_to_type", new String[] { vobj.getClass().toString(), boundType.toString(), jvobj.getClass().toString() })); } dsReg.registerDsObj(this); } /** * construct and initialise datastore object and retrieve document object * bound to Jalview object jvobj2 and validate it against boundType * * @param datastore2 * the datastore * @param jvobj2 * the jalview object * @param boundToType * - the document object class that the bound object should be * assignable from */ public DatastoreItem(VamsasAppDatastore datastore2, Object jvobj2, Class boundToType) { this(datastore2); jvobj = jvobj2; tojalview = false; vobj = getjv2vObj(jvobj); if (vobj != null && !(boundToType.isAssignableFrom(vobj.getClass()))) { throw new Error(MessageManager.formatMessage( "error.implementation_error_vamsas_doc_class_should_bind_to_type", new String[] { jvobj2.getClass().toString(), boundToType.toString(), vobj.getClass().toString() })); } dsReg.registerDsObj(this); } /** * create a new vobj to be added to the document for the jalview object jvobj * (jvobj!=null, vobj==null) */ public abstract void addToDocument(); /** * handle a conflict where both an existing vobj has been updated and a local * jalview object has been updated. This method is only called from doSync, * when an incoming update from the vamsas session conflicts with local * modifications made by the Jalview user. (jvobj!=null, vobj!=null) */ public abstract void conflict(); /** * update an existing vobj in the document with the data and settings from * jvobj (jvobj!=null, vobj!=null) */ public abstract void updateToDoc(); /** * update the local jalview object with the data from an existing vobj in the * document (jvobj!=null, vobj!=null) */ public abstract void updateFromDoc(); /** * create a new local jvobj bound to the vobj in the document. (jvobj==null, * vobj!=null) */ public abstract void addFromDocument(); boolean addtodoc = false, conflicted = false, updated = false, addfromdoc = false, success = false; private boolean updatedtodoc; private boolean updatedfromdoc; /** * Sync jalview to document. Enact addToDocument, conflict or update dependent * on existence of a vobj bound to the local jvobj. */ protected void doSync() { dsReg.registerDsObj(this); if (vobj == null) { log.debug("adding new vobject to document."); addtodoc = true; addToDocument(); } else { if (vobj.isUpdated()) { log.debug("Handling update conflict for existing bound vobject."); conflicted = true; conflict(); } else { log.debug("updating existing vobject in document."); updatedtodoc = true; updateToDoc(); } } // no exceptions were encountered... success = true; } /** * Update jalview from document. enact addFromDocument if no local jvobj * exists, or update iff jvobj exists and the vobj.isUpdated() flag is set. */ protected void doJvUpdate() { dsReg.registerDsObj(this); if (jvobj == null) { log.debug("adding new vobject to Jalview from Document"); addfromdoc = true; addFromDocument(); } else { if (vobj.isUpdated()) { log.debug("updating Jalview from existing bound vObject"); updatedfromdoc = true; updateFromDoc(); } } } VamsasAppDatastore datastore = null; /** * object in vamsas document */ protected Vobject vobj = null; /** * local jalview object */ protected Object jvobj = null; protected DatastoreRegistry dsReg; public void initDatastoreItem(VamsasAppDatastore ds) { datastore = ds; dsReg = ds.getDatastoreRegisty(); initDatastoreItem(ds.getProvEntry(), ds.getClientDocument(), ds.getVamsasObjectBinding(), ds.getJvObjectBinding()); } private void initDatastoreItem(Entry provEntry, IClientDocument cdoc, Hashtable vobj2jv, IdentityHashMap jv2vobj) { this.provEntry = provEntry; this.cdoc = cdoc; this.vobj2jv = vobj2jv; this.jv2vobj = jv2vobj; } protected boolean isModifiable(String modifiable) { return modifiable == null; // TODO: USE VAMSAS LIBRARY OBJECT LOCK METHODS) } protected Vector getjv2vObjs(Vector alsq) { Vector vObjs = new Vector(); Enumeration elm = alsq.elements(); while (elm.hasMoreElements()) { vObjs.addElement(getjv2vObj(elm.nextElement())); } return vObjs; } // utility functions /** * get start