import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
-import org.vamsas.objects.core.ApplicationData;
-import org.vamsas.objects.core.User;
-import org.vamsas.objects.core.VAMSAS;
-import org.vamsas.objects.core.VamsasDocument;
-import org.vamsas.objects.utils.AppDataReference;
-import org.vamsas.test.objects.Core;
import uk.ac.vamsas.client.ClientHandle;
import uk.ac.vamsas.client.IClientAppdata;
import uk.ac.vamsas.client.UserHandle;
import uk.ac.vamsas.client.Vobject;
import uk.ac.vamsas.client.VorbaId;
+import uk.ac.vamsas.objects.core.ApplicationData;
+import uk.ac.vamsas.objects.core.User;
+import uk.ac.vamsas.objects.core.VAMSAS;
+import uk.ac.vamsas.objects.core.VamsasDocument;
+import uk.ac.vamsas.objects.utils.AppDataReference;
+import uk.ac.vamsas.test.objects.Core;
/**
- * Maintains a collection of vamsas objects, appdatas and states, and provides api for a SimpleClient's client.
+ * Maintains a collection of vamsas objects, appdatas and states,
+ * and provides api for a SimpleClient's client.
+ * TODO: test and migrate ArchiveClient.getAppData methods to here and retest in ExampleApplication
* @author jimp
*/
public class ClientDocument extends uk.ac.vamsas.client.ClientDocument implements IClientDocument {
private static Log log = LogFactory.getLog(ClientDocument.class);
private VamsasDocument doc;
protected SimpleClient sclient;
- protected VamsasArchive archive = null;
+ protected VamsasArchive iohandler = null;
/**
* indicate if new data has been incorporated
*/
public boolean isModified() {
return isModified;
}
- private Vector updatedObjects=null;
/**
*
- * prepare Application-side dataset from the vamsas Document archive
+ * prepare Application-side dataset from the vamsas Document iohandler
* @param doc - the dataset
* @param docHandler - the sessionFile IO handler
* @param Factory - the source of current and new vorbaIds
/**
- * prepare Application-side dataset from the vamsas Document archive
+ * prepare Application-side dataset from the vamsas Document iohandler
*/
this.sclient = sclient;
- archive = docHandler;
+ iohandler = docHandler;
this.doc = doc;
- updatedObjects=null; /// TODO: correct this line
+ _VamsasRoots=doc.getVAMSAS();
}
/*
* internal reference to single copy of Document Roots array
*/
private VAMSAS[] _VamsasRoots=null;
- /*
+ /**
+ * set if the client has corrupted the Vamsas Document structure somehow.
+ * if this is set the document will never be written back to the session unless the corruption is fixed.
+ */
+ private boolean invalidModification=false;
+
+ protected void updateDocumentRoots() {
+ if (doc==null) {
+ log.error("updateDocumentRoots called on null document. Probably an implementation error.");
+ return;
+ }
+ if (isModified) {
+ if (_VamsasRoots!=null) {
+ doc.setVAMSAS(_VamsasRoots);
+ _VamsasRoots=null;
+ }
+ }
+ }
+/*
* (non-Javadoc)
* LATER: currently there is only one Vector of roots ever passed to client - decide if this is correct (means this is not thread safe and may behave unexpectedly)
* @see uk.ac.vamsas.client.IClientDocument#getVamsasRoots()
log.debug("Null document for getVamsasRoots(), returning null");
return null;
}
- if (archive==null) {
+ if (iohandler==null) {
// LATER: decide on read-only status of ClientDocument object
log.warn("getVamsasRoots() called on possibly read-only document.");
}
if (roots == null) {
// Make a new one to return to client to get filled.
_VamsasRoots = new VAMSAS[] { new VAMSAS() };
+ registerObject(_VamsasRoots[0]);
// Do provenance now. just in case.
doc.getProvenance().addEntry(sclient.getProvenanceEntry("Created new document root [id="+_VamsasRoots[0].getId()+"]"));
doc.addVAMSAS(_VamsasRoots[0]);
return -1;
if (docRoots==null || docRoots.length==0)
return -1;
- String r_id = root.getId();
+ VorbaId d_id=null,r_id = root.getVorbaId();
for (int i=0,j=docRoots.length; i<j; i++)
- if (docRoots[i]==root || (docRoots[i]!=null && docRoots[i].getId().equals(r_id)))
+ if (docRoots[i]==root || (docRoots[i]!=null && (d_id=docRoots[i].getVorbaId())!=null) && d_id.equals(r_id))
return i;
return -1;
}
+
/**
* verify that newr version is really an intact version of the
* @param newVersion (may be modified)
* @param oldVersion
+ * @param modflag
* @return true if newVersion is a valid root that preserves original references
*/
- private boolean isValidUpdate(VAMSAS newVersion, final VAMSAS oldVersion) {
+ private boolean isValidUpdate(VAMSAS newVersion, final VAMSAS oldVersion, ClientDocument modflag) {
// ideal - this cascades down the two structures, ensuring that all ID'd objects in one are present in the other.
if (oldVersion==newVersion) {
// may be a virgin root element.
if (!newVersion.isRegistered())
- _registerObject(newVersion);
- // Should retrieve original version and compare - unless local hashes can be used to determine if resultSet has been truncated.
+ {
+ _registerObject(newVersion); // TODO: check - this call hasn't been tested. (seems to work now)
+ modflag.isModified=true;
+ }
+ // TODO: Should attempt to repair document if client app has deleted/broken bits of it
+ if (oldVersion.is__stored_in_document()) {
+ // retrieve compare hashCodes to detect update.
+ if (oldVersion.get__last_hash()!=oldVersion.hashCode())
+ {
+ log.debug("Modified hashcode for vamsas root "+oldVersion.getVorbaId());
+ modflag.isModified = true;
+ } else {
+ log.debug("Unmodified vamsas root "+oldVersion.getVorbaId());
+ }
+ }
// just do internal validation for moment.
- if (newVersion.isValid())
+ try {
+ if (getSimpleClientConfig().validateUpdatedRoots())
+ {
+ newVersion.validate();
+ }
return true;
+ }
+ catch (Exception e)
+ {
+ log.error("Validation Exception for new vamsas root :"+newVersion.getVorbaId(),e);
+ modflag.invalidModification=true;
+ }
return false;
} else {
// redundant ? if (oldVersion.is__stored_in_document())
if (!newVersion.isRegistered())
+ {
_registerObject(newVersion);
- if (newVersion.isValid())
+ modflag.isModified=true;
+ }
+ try {
+ if (getSimpleClientConfig().validateMergedRoots())
+ {
+ newVersion.validate();
+ }
+ modflag.isModified=true;
return true;
+ }
+ catch (Exception e)
+ {
+ log.error("Validation Exception for new vamsas root :"+newVersion.getVorbaId(),e);
+ }
}
return false;
/**
- * LATER isValidUpdate : Ideally. we efficiently walk down, comparing hashes, to deal with merging and verifying provenance for objects
+ * LATER: MUCH LATER! - not needed for simple case and this routine shouldn't live in this class anymore
+ * isValidUpdate : Ideally. we efficiently walk down, comparing hashes, to deal with merging and verifying provenance for objects
// extract root objects
if (newroots != null) {
}
}*/
}
+ private SimpleClientConfig getSimpleClientConfig() {
+ return sclient.getSimpleClientConfig();
+}
/**
* merge old and new root vectors
* @param newr This array may be written to
*/
private VAMSAS[] _combineRoots(VAMSAS[] newr, final VAMSAS[] original, ClientDocument modflag) {
Vector rts = new Vector();
- boolean modified=false;
for (int i=0,j=original.length; i<j; i++) {
int k = _contains(original[i], newr);
if (k>-1) {
- if (isValidUpdate(newr[k], original[i])) {
- modified=true;
+ if (isValidUpdate(newr[k], original[i], modflag)) {
+ // set by isValidUpdate if the hashcodes were really different from last store
rts.add(newr[k]);
newr[k]=null;
} else {
for (int i=0,j=newr.length; i<j; i++) {
if (newr[i]!=null) {
rts.add(newr[i]);
- modified=true;
+ modflag.isModified=true;
}
}
newr = new VAMSAS[rts.size()];
for (int i=0,j=rts.size(); i<j; i++)
newr[i] = (VAMSAS) rts.get(i);
- if (modflag!=null)
- modflag.isModified = modified;
return newr;
}
/* (non-Javadoc)
* LATER: decide: this affects the next call to getVamsasRoots()
- * @see uk.ac.vamsas.client.IClientDocument#addVamsasRoot(org.vamsas.objects.core.VAMSAS)
+ * @see uk.ac.vamsas.client.IClientDocument#addVamsasRoot(uk.ac.vamsas.objects.core.VAMSAS)
*/
public void addVamsasRoot(VAMSAS newroot) {
if (doc==null) {
log.debug("addVamsasRoots called on null document.");
return;
}
- VAMSAS[] newroots = _combineRoots(new VAMSAS[] {newroot}, _VamsasRoots, this);
+ VAMSAS[] newroots = _combineRoots(new VAMSAS[] {newroot}, getVamsasRoots(), this);
_VamsasRoots = newroots;
}
log.warn("registerObjects called for null vamsasObjects hasharray.");
return null;
}
+ if (iohandler==null) {
+ log.warn("registerObjects called for read only document.");
+ return null;
+ }
+
if (unregistered!=null) {
VorbaId id = _registerObject(unregistered);
log.debug("Registered object - total of "+vamsasObjects.size()+" ids.");
* @see uk.ac.vamsas.client.IClientDocument#getClientAppdata()
*/
public IClientAppdata getClientAppdata() {
+ // TODO: getClientAppdata not tested in ArchiveClient mockup
+ log.error("TODO: TEST Client Appdata access methods");
if (doc==null) {
log.warn("getClientAppdata called on null document.");
return null;
* @return
*/
protected VamsasArchiveReader getVamsasArchiveReader() {
+ if (iohandler==null) {
+ log.error("Near fatal. Null VamsasArchive iohandler so can't get VamsasArchiveReader");
+ return null;
+ }
try {
- return archive.getOriginalArchiveReader();
+ log.info("TODO: test getVamsasArchiveReader");
+ return iohandler.getOriginalArchiveReader();
} catch (Exception e) {
log.warn("Unable to create OriginalArchiveReader!", e);
}
return null;
}
+ /**
+ * called by vamsas api to write updated document to session
+ * @return true if update was successful
+ * @throws java.io.IOException
+ */
protected boolean updateSessionDocument() throws java.io.IOException {
boolean docupdate = true; // 'non-serious' problems below set this false
if (doc==null) {
log.warn("updateSessionDocument called on null document.");
throw new java.io.IOException("Document is closed.");
}
- if (archive==null) {
- log.warn("updateSessionDocument called document archive handler.");
+ if (iohandler==null) {
+ log.warn("updateSessionDocument called on null document iohandler handler.");
throw new java.io.IOException("Document is closed.");
}
// update the VamsasDocument structure with any new appData's.
// try to update the sessionFile
log.debug("Attempting to update session "+sclient.session.getSessionUrn());
- if (scappd.isModified()) {
+ if (scappd!=null && scappd.isModified()) {
ClientHandle client = sclient.client;
UserHandle user = sclient.user;
scappd.closeForWriting();
scappd.appsGlobal.setDataReference(AppDataReference.uniqueAppDataReference(doc, sclient.client.getClientUrn()));
}
// LATER: use a switch to decide if the data should be written as a reference or as an embedded data chunk
- scappd.updateAnAppdataEntry(archive, scappd.appsGlobal, scappd.newAppData);
+ scappd.updateAnAppdataEntry(iohandler, scappd.appsGlobal, scappd.newAppData);
log.debug("...Successfully updated Global Appdata Entry.");
}
if (scappd.newUserData!=null && scappd.newUserData.sessionFile.exists()) {
}
appd.setDataReference(AppDataReference.uniqueAppDataReference(doc, sclient.client.getClientUrn()+safe_username));
}
- scappd.updateAnAppdataEntry(archive, scappd.usersData, scappd.newUserData);
+ scappd.updateAnAppdataEntry(iohandler, scappd.usersData, scappd.newUserData);
log.debug("...Successfully updated user AppData entry.");
}
}
+ try {
+ if (iohandler.transferRemainingAppDatas())
+ log.debug("Remaining appdatas were transferred.");
+ else
+ log.debug("No remaining appdatas were transferred. (Correct?)");
+ } catch (Exception e) {
+ log.error("While transferring remaining AppDatas", e);
+ }
log.debug("Updating Document...");
- // now update the document.
+ // now update the document. - this was basically the doUpdate method in test.ArchiveClient
+ updateDocumentRoots();
try {
- archive.putVamsasDocument(doc);
+ iohandler.putVamsasDocument(doc);
log.debug("Successfully written document entry.");
}
catch (Exception e) {
log.error("Marshalling error for vamsas document.",e);
docupdate = false; // pass on the (probable) object validation error
}
- if (archive.transferRemainingAppDatas())
- log.debug("Remaining appdatas were transferred.");
- else
- log.debug("No remaining appdatas were transferred. (Correct?)");
- archive.closeArchive();
+ iohandler.closeArchive();
+ iohandler=null; // so this method cannot be called again for this instance
log.debug("...successully finished and closed.");
return docupdate; // no errors ?
}
doc = null;
}
// disengage from client
- if (sclient!=null)
+ if (sclient!=null && sclient.cdocument==this)
sclient.cdocument = null;
sclient=null;
super.finalize();
}
public Vector getUpdatedObjects() {
- return updatedObjects;
+ // TODO: WALK through the document objects calling the update mechanism for each one, or just pass this vector back to client ?return updatedObjects;
+ return null;
+ }
+ /**
+ * if this is set the document will never be written back to the session unless the corruption is fixed.
+ * @return the invalidModification
+ */
+ public boolean isInvalidModification() {
+ return invalidModification;
+ }
+ /**
+ * set if the client has corrupted the Vamsas Document structure somehow.
+ * if this is set the document will never be written back to the session unless the corruption is fixed.
+ * @param invalidModification the invalidModification to set
+ */
+ public void setInvalidModification(boolean invalidModification) {
+ this.invalidModification = invalidModification;
}
}