I am working on a project that is in transition from proof-of-concept to something worthy of a pilot project. One of the key improvements for this phase of development is to move away from the current "persistence" mechanism, which uses a hash table held in memory and periodically dumped to a file, to a more traditional database back-end.
The application itself is designed with ReSTful principles in mind. It uses Jersey to provide access to resources and jQuery to present these resources to the user and enable basic interactions (create, update, delete). Pretty straight-forward.
I have used JPA and Hibernate successfully in the past for persisting server-side state in a relational database, so it seemed a natural choice in this case. With a few minor changes to the model entities, I was able to get basic read, create, and delete operations working in reasonable time. However, the update operation has proved more difficult.
The client-side part of the application automatically sends changes to the server a couple seconds after the user modifies the resource. In addition, there is a "save and close" button that the user can press to send the latest version of the resource to the server immediately before returning to the home page.
My first problem was how to update the managed entity from the database with the unmanaged object coming from the client. Since the data sent to the client deliberately omits database keys, this was a bit tedious as it came down to explicitly "merging" elements from the unmanaged object into the Hibernate object. This isn't my question, but if anyone knows of an elegant way to do this, I'd be very interested to hear about it.
My second problem, and the object of this post, occurs when I press the "save and close" button around the same time as the auto-save operation I mentioned earlier is going on. More often than not, I get an optimistic locking exception. This is because the second update operation is being handled in a separate thread while the first is still being processed.
The resource has an "updated" time-stamp that is set each time an update is processed, so an update to the database is pretty much guaranteed each time, even if nothing has changed. This in itself is probably an issue, but even after I fix it, there is still a "window of opportunity" where the user could make a modification and send it to the server while an auto-save is in progress, triggering the same problem.
The simplest approach I can think of to address this issue is to rework some of the client-side Javascript to ensure that there is only ever one outstanding "update" operation from that client at any point in time. (Note that if a different client happens to update the same resource at the same time, an optimistic locking exception is perfectly fine.) However, I'm concerned that forcing this limitation on the client may be deviating from the spirit of ReST. Is it reasonable to expect a given client to have no more than one outstanding "update" (PUT) request to a particular resource at any point in time in a ReSTful application?
This seems like a fairly common scenario, but I haven't been able to find a definitive answer about how best to handle it. Other ideas I've considered and discarded include somehow serializing requests from the same client (perhaps based on HTTP session) so that they are handled in order, implementing a "queue" of updates for a JPA/Hibernate worker thread, and inserting new "versions" of the resource while keeping track of the latest one rather than updating any single record.
Any thoughts? Does the "one outstanding update at a time" limitation on the client seem reasonable, or is there a better approach?