In my case, it was straightforward: the user is considered to be "still editing" if they have a browser window open to the edit page for the object in question; if they navigate away from that page, the system considers their edit session over.

Robert


On Feb 21, 2007, at 2/212:47 AM , Peter Stavrinides wrote:

Hi Robert

I like your idea, "you say that periodic ajax calls are sent to the server to inform of the fact that the user is still editing" how exactly do you track if a user is still editing?

Robert Zeigler wrote:
The main problem with using a session timeout for the lock is that it doesn't allow you to detect events where a user starts to edit an object, does not finish, but remains active in the webapp; the session won't die, and neither will your lock. You have to incorporate time at least to some degree. I implemented similar functionality in an application recently, but used a bit of ajax magic to ensure that the lock was held for exactly as long as it needed to be and no longer (while the user is editing the object, periodic ajax calls are sent to the server to inform of the fact that the user is still editing; if the user saves, the lock is released; if the user moves to a different portion of the webapp without saving or canceling the lock, the lock expires since there are no more ajax calls to keep the lock valid)

Robert

On Feb 21, 2007, at 2/211:56 AM , Peter Stavrinides wrote:

I don't think the benefits justify the effort involved to maintain all those timestamps, its a bit too complex. Perhaps its better to stick to a single table as well... rather write the session id into the database to checkout a customer record.

Allow updates to a customer record if its not checked out, and this way you have no worries about lock expiration etc.

You should maintain an ASO that tracks all active sessions by session id. Once a user queries for a customer record that has been checked out, if the session ID still exists in the ASO, then refuse update access and grant only read access, simple and elegant. Once the user saves successfully release the lock in the database. if a session is interrupted for whatever reason, then using a session timeout of 20 or 30 minutes and a session listener you clean up removing the session ID from the ASO and database... so you are well covered. I am no guru like some of these other guys, but this works for me and its nice and simple... here is a brief implementation outline:

public class ApplicationManager {

/** variable to store the singleton ApplicationManager */
private static final ApplicationManager applicationManagerInstance_ = new ApplicationManager();

/** Hashtable containing visit history objects. <String,Visit> is the sessionid and the Visit Object */ private static ConcurrentHashMap<String,Visit> visitHistory_ = new ConcurrentHashMap<String,Visit>();

/** @return the ApplicationManager instance */
public synchronized static ApplicationManager getInstance(){
return applicationManagerInstance_;
}

}

public class SessionMonitor implements HttpSessionListener {

/** @see javax.servlet.http.HttpSessionListener#sessionDestroyed (javax.servlet.http.HttpSessionEvent) */
public void sessionDestroyed(HttpSessionEvent event) {
String sid = event.getSession().getId();
ApplicationManager manager = ApplicationManager.getInstance();
manager.removeUserSession(sid);
}


Hivemodule.xml:

<contribution configuration-id="tapestry.state.ApplicationObjects">
<state-object name="visit" scope="session">
<create-instance class="application.Visit"/>
</state-object>
</contribution>

<contribution configuration-id="tapestry.state.ApplicationObjects">
<state-object name="ApplicationManager" scope="application">
<create-instance class="application.ApplicationManager"/>
</state-object>
</contribution>

cheers,
Peter

Murray Collingwood wrote:
Wow - what a lot of responses.

First a little more detail - use case (for example):

Take a customer record, a basic record has previously been created and the customer has completed some forms so we are now wanting to complete all of the details about contact information, financial details, key assets, health information, etc, etc. The system relies on a number of classifications which need to be looked up, anyways, editing this record can take upto 20 minutes. The size of this record certainly justifies breaking it up into a number of smaller records stored in separate tables, however the same problem remains because the user wants to see all of this information on 1 (scrollable) web page, we are still holding a lock on the information for the duration of the
request.

Potentially there are maybe 700 people who could be editing this record for different reasons. Accuracy of the information is critical - we don't want
personal details being sent to a neighbour.

The nature of the application means that users will be reviewing a record each year, and if any changes are made they are often made to the same record around the same time of the year - increasing the possibility of two people wanting to
edit the record at the same time.

Besides all of the above, the user has asked for exclusive editing of a record - such that other users can still read the existing record but nobody else can update the record while it is locked. The user understands the concept of networks issues and broken connections and therefore accepts a timeout condition
on the lock of say 20 minutes.

Next, how I will do this:

1. To establish a lock:
a. I need a LOCK table: foreign-key, timestamp, userid
b. In my Session I need a collection of timestamps
c. Create a timestamp value - add it to my collection of timestamps
d. Add a record to the LOCK table using my timestamp value
e. Select from the lock table by foreign-key - if mine is the only record then
read the record and begin editing, the lock was successful

2. Release the lock: (PS This is the difficult bit)
a. Retrieve the LOCK records by foreign-key and userid, hopefully there should
only be one.
b. Check the timestamp value against my Session collection of timestamp values c. If the timestamp is in my collection then save the edited record and delete
my LOCK record
d. If the timestamp is not in my collection then the save has failed - tell the
user gently

3. Dealing with an existing lock:
a. While trying to establish a lock I find 2 LOCK records
b. The latest record is mine, ignore that and look at the earlier record c. Look at the timestamp on the earlier record, if older than 20 minutes then
delete this record and continue as normal
d. Look at the userid on the earlier record, if it is mine then delete it and continue as normal (assumes my browser died, rebooted my computer, whatever, it's very typical for people to go straight back to what they were doing when
their system crashed)
e. If the timestamp is less than 20 minutes old then delete my LOCK record and
report to the user that the record is locked by another user

4. You may want a maintenance process that cleans up broken locks, automatically deleting locks with a timestamp older than 24 hours. You could schedule this
nightly or weekly - it's not critical.


Why the collection of timestamps?

1. It allows the user to use the back button on the browser, either during editing or after editing (if it didn't save correctly the first time).

2. They might need to edit a related record in a different table as part of updating the main record - by storing each timestamp in a session collection we
don't need to maintain these timestamps on our forms.


Why add the lock record first?

To avoid sequence problems like:
a: User 1 looks for lock on id=1 - none found
b: User 2 looks for lock on id=1 - none found
c: User 1 adds a lock record
d: user 2 adds a lock record
Now the worst possible outcome is:
a: User 1 adds a lock record on id=1
b: User 2 adds a lock record on id=1
c: Both users read and find two records with short timestamps - they are both informed the record is in use and to try again later - both records are deleted.


Finally - the weakness:

1. The lock this gives you is only guaranteed for 20 minutes. Once that time is up somebody else can overwrite your lock with their own. It is better to set
this timeout higher rather than lower.

2. You can overwrite your own lock. A user could open two browsers and edit the same record in each, the latter save overwriting the first. Hmmm, I think this
comes under 'user error'.


I think that explains it fairly well.

Cheers
mc



------------------------------------------------------------------- --
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]



--Peter Stavrinides
Albourne Partners (Cyprus) Ltd
Tel: +357 22 750652
If you are not an intended recipient of this e-mail, please notify the sender, delete it and do not read, act upon, print, disclose, copy, retain or redistribute it. Please visit http:// www.albourne.com/email.html for important additional terms relating to this e-mail.


---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]


--
Peter Stavrinides
Albourne Partners (Cyprus) Ltd
Tel: +357 22 750652
If you are not an intended recipient of this e-mail, please notify the sender, delete it and do not read, act upon, print, disclose, copy, retain or redistribute it. Please visit http:// www.albourne.com/email.html for important additional terms relating to this e-mail.


---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]


---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to