WhatAreTheCodingRestrictionsMyClientClassesHaveToObey

This is a rough rendering of a page from the old Prevayler wiki. Please see the new wiki for current documentation.

Every command your client objects issue to your business objects must be represented as a serializable Command object.
   
   
Is it prohibited for a developer to use direct method calls to any of its BusinessObjects? Must he always use a command object instead? -- EmmanuelHaardt
No. Any call between two BusinessObjects and any query from a client to a BusinessObject can be done through a direct method call.


Isn't using commands between clients and business objects a burden?
Some people find it a burden. For most distributed systems, mind you, commands already come in a serializable form anyway. Http requests are an example.

Apart from that, some people actually find this "Command Pattern" guideline quite useful. Many projects use it regardless of Prevayler. Typically, you will have one class representing each use-case in your system.


You do not make it compulsory, for instance, to have only protected methods in BusinessObjects. Does this mean you don't have the possibility to check if a programmer respects the use of commands and so can drive his system to become inconsistent? -- EmmanuelHaardt
I find it a good design procedure, but Prevayler does not make it compulsory to use protected methods. You can make that a compulsory thing in your project, if you want. -- KlausWuestefeld


Can a Command hold references to BusinessObjects?
No. Commands must be serializable independently of the BusinessObjects or else they would have no effect when re-executed during recovery. That is because new business object "clones" would be created during recovery (unserialization) and garbage collected after the Command is re-executed, leaving the original business objects untouched. Commands have to know, therefore, how to find the business objects they need given the system. See the Prevayler Demos for examples.


If any query from a client to a Business Object can be done through a direct method call, how is read consistency guaranteed? Isn't it possible that the "reading" method is interrupted by a "write" command? -- AndreasBaumgart
Yes, it is possible. Prevayler does not impose any particular locking scheme. Read consistency is guaranteed by the BusinessObjects themselves. There are several strategies you can choose from, therefore:
-Fine-grained locking: Each BusinessObject will use standard Java synchronization to guarantee read consistency at the object level.
-Coarse-grained locking: Execution of commands and queries is synchronized at the system level. Normally in prevalent systems the actual execution of commands (after logging) and queries is so brutally fast that you can easily afford to do that. Your BusinessObjects no longer have to worry about synchronization.


See: DontINeedTransactions?
Back to: ObjectPrevalenceSkepticalFAQ.  
The answer to "direct references to Business Objects" is a bit confusing... perhaps what you meant to say is that a command can reference a business object (it probably has to do anything useful), but it must not store a reference to that business object in a member variable in the command constructor.

I have made it clearer. --KlausWuestefeld.

Can commands hold references to mutable client objects?

The CommandLogger uses Java ObjectOutputStream objects to serialize commands to log files. Serialization rule 5 states, "If the object has already been written to the stream, its handle is written to the stream and writeObject returns." (See http://java.sun.com/j2se/1.3/docs/guide/serialization/spec/output.doc1.html)

Consider a command that updates the shipping address for an account.  Following the bank demo examples, the command will store the account number and the shipping address object (street, city, state, ...). If the client changes that shipping address object and creates a second updateShippingAddress command, won't the ObjectOutputStream record a handle to the shipping address object instead of storing its revised field contents? -- JoelShprentz

Yes. Commands cannot hold references to mutable client objects, therefore. --KlausWuestefeld

A possible, and simple, solution for this is to clone() the mutable client objects if you create a setter on your Command. Here's an example:

  public void setUserLogin(String userLogin) {
    this.userLogin = userLogin.clone();
  }

-- CarlosVillela


The two strategies offered for guarunteeing read consistency both seem to have limitations.  Fine grained locking is insufficient in cases where a write Command updates multiple objects and overall consistency depends on the successful completion of all of those updates.  Coarse grained locking seems impractical and inefficient - every time you wanted to query an attribute (or a series attributes - say when poplating a form) of your BusinessObjects you would have to lock the entire system against updates.  This is a real implementation hassle, not to mention quite inefficient.  Doesn't the fact that this problem exist also violate the Consistency constraint of ACIDTransactions? --CharlesBlaxland


The following web site supplementing Doug Lea's book "Concurrent Programming in Java" has a concurrent programming toolkit for Java that is a precursor to the JSR-166 work being done by Doug. The website is

http://gee.cs.oswego.edu/dl/classes/EDU/oswego/cs/dl/util/concurrent/intro.html

One of the classes is a read write lock with several different reader and writer access policies.

Richard Hensley


Examining the most recent "production" distribution, I see that in demo2, the Deposit Command object is given and retains a reference to an Account object. Doesn't this violate the constraint above? --Jay Sachs

It does not keep a reference to the Account. It keeps the account number. --KlausWuestefeld


Please forgive a possibly-naive question:  How does Prevaylor cope when you have to make changes to your business object class definitions (e.g. altering attributes, associations or methods) but you don't want to lose your existing data.
See SchemaEvolution.