Dr. Dobb's is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Channels ▼
RSS

Web Development

AJAX & Record Locking


Server-Side Components

Because the server code is language independent, I won't detail the server-side implementation. I do examine how the server handles the client's AJAX requests, but more from a higher level using pseudocode. Still, it's important to understand the server's roles.

We develop in Java and have our own homegrown Struts-like framework. In this framework, actions that users take on the Web are delivered through a controlling servlet to the framework as URLs. The path portion of the URL is parsed apart, mapped first to a particular application, and then within that application to an implementation of an action, where the real server-side work is done. This server-side action is a Java type that the framework looks up, instantiates if necessary, and invokes the lifecycle. The lifecycle of a server-side action handles the user request in some way—using the query portion of the URL—to render content that can be used to write a response to a client. The server-side action lifecycle API contains this central method:

public Page execute(UrlArguments args, Person person)


There is an implementation of this interface on the server that responds to the AJAX lock request running in the window.setTimeout loop. Included in the URL arguments is the nature of the client's lock request, whether for obtaining a lock, releasing a lock, or querying the status of a lock—and the ID of the record being used. This server-side component can be handling numerous client requests. There will be a request for every client page, coming in at the rate of the timer in the window.setTimeout loop. If there are only 10 clients and the call is made every 10 seconds per client, the server will be handling 60 requests per minute. Therefore, this code must run quickly, and in our implementation it mostly maintains a hash map from RecordId to RecordLock. Requests to obtain locks insert RecordLocks into the map; requests to free locks remove them; and status requests check for their existence.

Clients can make three kinds of requests of the server:

  • status. Ask if record is locked or not.
  • lock. Request to obtain lock on record.
  • unlock. Request to free lock on record.

A record's status is locked or unlocked. Because all clients make requests for lock status, the owner of a lock is either the current user or someone else. Also, it's possible for a lock owner to let a session time out; say a user locks a record for editing, then goes for a two-hour lunch. To accommodate all these different states, the server sends back one of four state messages to the client:

  • locked. Another user owns the lock on this record.
  • unlocked. No user owns the lock on this record.
  • owned. Current user owns the lock on this record.
  • noSession. Current user's session timed out.

For every lock status request a client makes, the server is given the ID of a record and the person making the request. Requesters may or may not be the owner of the lock. Our applications are configured to hold a map with record IDs as keys and RecordLocks as values, and to track whether a user's session is still valid. The pseudocode in Listing One is the logic of our server-side handling of client lock requests.

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 One


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.