AJAX & Record Locking
by David Perelman-Hall

Listing One

public Page execute(UrlArguments args, Person requester)
{
    recordID = args.getValue("recordID");
recordLock = map.get(recordID); // try to get lock for record
lockOwner = requester; // changes if lock owned by someone else
locked = "unlocked"; // changes based on actual lock state
// Requesting status of lock for a given record
if(request_is_for_lock_status)
{
    if(recordLock != null) 
{
// Since client can continue to poll server, even after session has timed out,
// this will stop the loop from running on the client.
        if(app.userSessionExpired(recordLock.getOwner()))
        {
            locked = "noSession";
        }
        // Record is locked by someone
else
        {
            // Request was from current lock owner
            if(recordLock.getOwner() == requester)
            {
                locked = "owned";
            }
            // request by someone other than owner
            else
            {
                lockOwner = recordLock.getOwner();
                locked = "locked";
            }
        }
    }
}
// Requesting a lock for a given record
else if(request_is_for_lock)
{
    // Record already locked by the current requester
if(recordLock != null  &&
recordLock.getOwner() == requester)
    {
        locked = "owned";
    }
// Record is owned/locked by someone else
    {
        locked = "locked";
        lockOwner = recordLock.getOwner();
    }
    // Not owned or locked already, so lock it
    else if(recordLock == null)
    {
        map.add(recordID,requester);
        locked = "owned";
    }
}
// Else, unlocking
else
{
// Should never get a request to unlock a record which isn't // already locked
Assert(recordLock != null);
map.remove(recordID);
    locked = "unlocked";
}
return PageLockPage(lockOwner, locked);
}


Listing Two

// HttpRequestObject in net namspace
var net = new Object();
net.trimString = function(inString) { return 
   inString.replace( /^\s+/g, "" ).replace( /\s+$/g, "" ); } 
      // belongs in another namespace
net.READYSTATE_UNITITIALIZED=0;
net.READYSTATE_LOADING=1;
net.READYSTATE_LOADED=2;
net.READYSTATE_INTERACTIVE=3;
net.READYSTATE_COMPLETE=4;
net.ContentLoader = function()
{
    this.req = null;
    this.doc = null;
    this.text = null;
    this.url = null;
    this.onload = onload;
    this.onerror = this.defaultError;
}
net.ContentLoader.prototype =
{
    load:function(url)
    {
        if(window.XMLHttpRequest) this.req = new XMLHttpRequest();
        else if(window.ActiveXObject) this.req = 
                               new ActiveXObject('Microsoft.XMLHTTP');
        if(this.req)
        {
            try
            {
               this.setUrl(url);
                var loader = this;
                this.req.onreadystatechange = function() { loader.onReadyStateHandler.call(loader); }
                this.req.open('POST', url, true);
                this.req.send(null);
            }
            catch(err)
            {
                this.onerror.call(this);
            }
        }
    },
    onReadyStateHandler:function()
    {
        var ready = this.req.readyState;
        if(ready == net.READYSTATE_COMPLETE)
        {
            if(this.req.status == 200 || this.req.status == 0)
            {
                this.setText(this.req.responseText);
                this.setXml(this.req.responseXML);
                this.onload.call(this);
            }
            else this.onerror.call(this);
        }
    },
    defaultError:function()
    {
        alert("Error with AJAX communication"
            + "\nURL: " + this.url
            + "\nreadyState: " + this.req.readyState
            + "\nstatus: " + this.req.status
            + "\nheaders: " + this.req.getAllResponseHeaders());
    },
    setResponseHandler:function(handler) { this.onload = handler; },
    setErrorHandler:function(handler) { this.onerror = handler; },
    setUrl:function(url) { this.url = url; },
    getUrl:function() { return this.url; },
    setXml:function(doc) { this.doc = doc; },
    getXml:function() { return this.doc; },
    setText:function(text) { this.text = text; },
    getText:function() { return this.text; }
}

3


