4 package org.vamsas.client.simpleclient;
6 import java.util.Hashtable;
7 import java.util.Vector;
9 import org.apache.commons.logging.Log;
10 import org.apache.commons.logging.LogFactory;
11 import org.vamsas.client.IClient;
12 import org.vamsas.client.IClientAppdata;
13 import org.vamsas.client.IClientDocument;
14 import org.vamsas.client.VorbaId;
15 import org.vamsas.client.Vobject;
16 import org.vamsas.objects.core.AppData;
17 import org.vamsas.objects.core.ApplicationData;
18 import org.vamsas.objects.core.User;
19 import org.vamsas.objects.core.VAMSAS;
20 import org.vamsas.objects.core.VamsasDocument;
21 import org.vamsas.objects.utils.AppDataReference;
24 * Maintains a collection of vamsas objects, appdatas and states, and provides api for a SimpleClient's client.
27 public class ClientDocument extends org.vamsas.client.ClientDocument implements IClientDocument {
28 private static Log log = LogFactory.getLog(ClientDocument.class);
29 private VamsasDocument doc;
30 protected SimpleClient sclient;
31 protected VamsasArchive archive = null;
33 * indicate if new data has been incorporated
35 private boolean isModified = false;
37 * Public method for internal use by SimpleClient.
38 * @return true if document has been modified.
40 public boolean isModified() {
45 * prepare Application-side dataset from the vamsas Document archive
46 * @param doc - the dataset
47 * @param docHandler - the sessionFile IO handler
48 * @param Factory - the source of current and new vorbaIds
49 * @param sclient - the simpleclient instance
51 protected ClientDocument(VamsasDocument doc, VamsasArchive docHandler, IdFactory Factory, SimpleClient sclient) {
52 super(Factory.getVorbaIdHash(), Factory);
55 * prepare Application-side dataset from the vamsas Document archive
57 this.sclient = sclient;
65 * @see org.vamsas.client.IClientDocument#getObject(org.vamsas.client.VorbaId)
67 public Vobject getObject(VorbaId id) {
68 // TODO: look up id in document Vobject
69 // retrieve Vobject and return
76 * @see org.vamsas.client.IClientDocument#getObjects(org.vamsas.client.VorbaId[])
78 public Vobject[] getObjects(VorbaId[] ids) {
79 // TODO: getObject in bulk
83 * internal reference to single copy of Document Roots array
85 private VAMSAS[] _VamsasRoots=null;
88 * 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)
89 * @see org.vamsas.client.IClientDocument#getVamsasRoots()
91 public VAMSAS[] getVamsasRoots() {
92 if (_VamsasRoots!=null)
94 VAMSAS[] roots = doc.getVAMSAS();
96 // Make a new one to return to client : TODO: Decide if this is correct
97 _VamsasRoots = new VAMSAS[] { new VAMSAS() };
99 _VamsasRoots = new VAMSAS[roots.length];
100 for (int r=0;r<roots.length; r++)
101 _VamsasRoots[r] = roots[r];
106 private int _contains(VAMSAS root, VAMSAS[] docRoots) {
109 if (docRoots==null || docRoots.length==0)
111 String r_id = root.getId();
112 for (int i=0,j=docRoots.length; i<j; i++)
113 if (docRoots[i]==root || (docRoots[i]!=null && docRoots[i].getId().equals(r_id)))
118 * verify that newr version is really an intact version of the
119 * @param newVersion (may be modified)
121 * @return true if newVersion is a valid root that preserves original references
123 private boolean isValidUpdate(VAMSAS newVersion, final VAMSAS oldVersion) {
125 // ideal - this cascades down the two structures, ensuring that all ID'd objects in one are present in the other.
126 if (oldVersion==newVersion) {
127 // may be a virgin root element.
128 if (!newVersion.isRegistered())
129 _registerObject(newVersion);
130 // Should retrieve original version and compare - unless local hashes can be used to determine if resultSet has been truncated.
131 // just do internal validation for moment.
132 if (newVersion.isValid())
136 // redundant ? if (oldVersion.is__stored_in_document())
137 if (!newVersion.isRegistered())
138 _registerObject(newVersion);
139 if (newVersion.isValid())
145 * merge old and new root vectors
146 * @param newr This array may be written to
148 * @param the client document (usually this) which this root set belongs to.
149 * @return merged vector of vamsas roots
151 private VAMSAS[] _combineRoots(VAMSAS[] newr, final VAMSAS[] original, ClientDocument modflag) {
152 Vector rts = new Vector();
153 boolean modified=false;
154 for (int i=0,j=original.length; i<j; i++) {
155 int k = _contains(original[i], newr);
157 if (isValidUpdate(newr[k], original[i])) {
162 // LATER: try harder to merge ducument roots.
163 log.warn("Couldn't merge new VAMSAS root "+newr[k].getId());
164 newr[k] = null; // LATER: this means we ignore mangled roots. NOT GOOD
168 rts.add(original[i]);
171 // add remaining (new) roots
172 for (int i=0,j=newr.length; i<j; i++) {
178 newr = new VAMSAS[rts.size()];
179 for (int i=0,j=rts.size(); i<j; i++)
180 newr[i] = (VAMSAS) rts.get(i);
182 modflag.isModified = modified;
187 * update the document with new roots.
188 * LATER: decide: this affects the next call to getVamsasRoots()
190 public void setVamsasRoots(VAMSAS[] newroots) {
192 // are we dealing with same array ?
193 if (_VamsasRoots!=newroots) {
196 // extract root objects
197 if (newroots != null) {
198 // check newroots for objects that were present in the old document
199 // check to see if the 'old' objects have been modified
200 // if they have ? we overwrite them with their new version, ensuring that
201 // provenance is updated.
202 // if they haven't ? do nothing ?
204 for (int i = 0, k = newroots.length; i < k; i++) {
205 if (newroots[i].isRegistered()) {
206 // easy - just check if anything has changed and do provenance
207 Vobject oldversion = getObject(newroots[i].getVorbaId());
208 if (oldversion instanceof VAMSAS) {
209 // LATER: appropriate merging behaviour when two clients have improperly modified the same Vobject independently.
210 if (newroots[i].get__last_hash() != newroots[i].hashCode()) {
211 // client has modified this Vobject since last retrieval.
212 if (newroots[i].get__last_hash() != oldversion.get__last_hash()) {
213 // Vobject has been modified by another client since this
215 // last access to document.
220 "SimpleClient error when using setVamsasRoots : The vorbaId for Vobject "
222 + " does not refer to an Vobject of type VAMSAS in the current document!");
225 if (!newroots[i].is__stored_in_document()) {
226 // check if Vobject is modified
227 if (newroots[i].get__last_hash() != newroots[i].hashCode()) {
228 // it is - so we add newroots[i] as a new Vobject, with updated
235 // just add newroots[i] as a new Vobject in the document
236 // - with appropriate provenance.
244 * LATER: decide: this affects the next call to getVamsasRoots()
245 * @see org.vamsas.client.IClientDocument#addVamsasRoot(org.vamsas.objects.core.VAMSAS)
247 public void addVamsasRoot(VAMSAS newroot) {
248 VAMSAS[] newroots = _combineRoots(new VAMSAS[] {newroot}, _VamsasRoots, this);
249 _VamsasRoots = newroots;
255 * @see org.vamsas.client.IClientDocument#registerObjects(org.vamsas.client.Vobject[])
257 public VorbaId[] registerObjects(Vobject[] unregistered) {
258 if (unregistered!=null) {
259 VorbaId ids[] = new VorbaId[unregistered.length];
260 for (int i=0,k=unregistered.length; i<k; i++)
261 if (unregistered[i]!=null) {
262 log.warn("Null Vobject passed to registerObject[] at position "+i);
265 ids[i]=registerObject(unregistered[i]);
272 * @see org.vamsas.client.IClientDocument#registerObject(org.vamsas.client.Vobject)
274 public VorbaId registerObject(Vobject unregistered) {
275 if (unregistered!=null)
276 return _registerObject(unregistered);
277 log.warn("Null Vobject passed to registerObject.");
281 * IClientAppdata instance - if it exists.
283 SimpleClientAppdata scappd = null;
285 * @see org.vamsas.client.IClientDocument#getClientAppdata()
287 public IClientAppdata getClientAppdata() {
289 log.debug("Creating new SimpleClientAppdata instance for "+sclient.getSessionHandle());
290 scappd = new SimpleClientAppdata(this);
292 // LATER: may not need this as a warning message.
293 log.warn("Null appdata object for "+sclient.getSessionHandle());
295 log.debug("Created SimpleClientAppdata successfully.");
298 log.debug("Returning existing SimpleClientAppdata reference.");
303 * @see java.lang.Object#finalize()
305 protected void finalize() throws Throwable {
306 log.debug("Garbage collecting on ClientDocument instance.");
315 * access the vamsas document
316 * @return the session's vamsas document
318 protected VamsasDocument getVamsasDocument() {
322 * returns the read-only IO interface for the vamsas document Jar file
325 protected VamsasArchiveReader getVamsasArchiveReader() {
327 return archive.getOriginalArchiveReader();
328 } catch (Exception e) {
329 log.warn("Unable to create OriginalArchiveReader!", e);