Package com.objectwave.transactionalSupport

Provide the core functionality the allows us to 'commit' and 'rollback' changes to TransactionalObjects.

See:
          Description

Interface Summary
AccessSecurityIF We may want to implement security at a field access level.
ObjectChangeRequest The interface to objects that will keep track of details of a change to a transactional object.
ObjectEditingView The interface to the object that will keep track of ObjectChanges.
SetAndGetDelegateIF  
TransactionalObjectIF In order to be a transactional object it is necessary for this interface to be implemented.
 

Class Summary
ExampleObject An example of a persistent business object that extends from TransactionalObjectAdapter.
ExpandingObjectModifiedArrayCache Maintain a collection of ObjectModified objects.
ExpandingObjectModifiedCache Maintain a collection of ObjectModified objects.
NoFieldObjectEditor Tracks changes to a TransactionalObjectIF.
NoFieldObjectEditor.Test  
NoFieldObjectModified The details of a change to a particular object.
NoFieldObjectModified.Test  
ObjectEditor Tracks changes to a TransactionalObjectIF.
ObjectEditor.Test  
ObjectModified The details of a change to a particular object.
ObjectModified.Test  
Session A utility class to allow multiple threads share a single transaction context.
Session.Test Unit Tests
SessionManager Used to manage multiple threads.
SupportedCollections This is to allow the transactional support to work well with collections.
ThreadContext This is used for performance optimization.
TransactionalObjectAdapter A sample implementation of a TransactionalObject.
TransactionLog A key piece of a the TransactionalSupport is the transaction log.
TransactionLog.Test Unit tests for the tranasaction log.
TransactionManager  
TransactionManager.MyLockManager A very efficient lock manager that takes advantage of the following assumptions.
WrapClassLoader This is used for performance optimization.
 

Exception Summary
UpdateException This exception may be thrown when trying to commit changes to a transactional object.
 

Package com.objectwave.transactionalSupport Description

Provide the core functionality the allows us to 'commit' and 'rollback' changes to TransactionalObjects. The com.objectwave.transactionalSupport.ObjectEditor, com.objectwave.transactionalSupport.TransactionLog, and the com.objectwave.transactionalSupport.ObjectChangeRequest work together to provide commit and rollback functionallity to any object that implements the com.objectwave.transactionalSupport.TransactionalObject interface.

Lets start with the TransactionalObject interface.

ObjectEditor getObjectEditor();
void setObjectEditor(ObjectEditor edit);

Every TransactionalObject relates to an ObjectEditor. It is this relation that enables the transactional support. When a change is made, via one of the mutator methods (set methods), the actual set call is made to the ObjectEditor. The ObjectEditor will keep track of all of the changes made to the TransactionalObject.

void update(boolean get, Object [] data, Field [] fields);
This method provides a 'back door' to updating the values of a TransactionalObject. It is with this method that we actually modify the TransactionalObject. Since any call to the accessor and mutator methods actually update the ObjectEditor. Since we need to update variables that may be 'private' in scope this method MUST be implemented on every TransactionalObject.

boolean isDirty();
This will tell you if the ObjectEditor knows of any changes to the TransactionalObject. When we 'commit' the changes, the TransactionalObject will no longer be dirty.

void setAsTransient(boolean value);
boolean isTransient();

A Transient object is one that doesn't use the ObjectEditor. Any calls to the mutator method will directly update the TransactionalObject. This effectively removes our transactional capability of our TransactionalObject. There are some instances where we may wish to disable the commit, rollback functionality of an Object, and these methods enable us to do just that.

The TransactionLog is the key Object to manager your transactions. The key methods:
public static TransactionLog getCurrentInstance()
Return the current instance. Since we may have multiple or nested transactions, this the method that should be used to get the current instance. The current instance will in part be defined by the current context. When we create a transaction, we provide a context. Whenever a setContext(Object obj) method is called, our current instance will be changed based upon the context parameter. Frequently, transactions are based upon screen navigation, so frequently the context will be the GUI object.

public static void startTransaction(TransactionLog log, Object context)
To begin a transaction, use this method. This will take care of nesting issues. The parameter 'context' is useful if you are going to have multiple transactions executing at the same time. You can associate a context with a given transaction to enable switching between two transactions. If a transaction is already underway at the time this command is issued, the new transaction is a subtransaction to the existing transaction. When we 'commit' the new transaction, all of our changes are migrated to the existing (or parent) transaction. If, for some reason, you exlicitly want a transaction to be a root transaction, you can use the startRootTransaction(TransactionLog log, Object context) method.

public void commit() throws UpdateException
When a transaction is complete, and you wish to make all of the changes permanent, getCurrentInstance() and commit() the changes.

public void rollback()
Similar to commit, however, this method just drops any changes made to the TransactionalObject.

You are now armed with enough knowledge to begin building transactional applications. Lets walk through some high level event scenario diagrams to follow the flow of the application.

---startTransaction(aTransactionLog , null) ---> TransactionLog
       
-setValue(aValue)--> aTransactionalObject    

 

|---set(aField, aValue)-->

aObjectEditor  
   

|--set(aField, aValue)->this

 
   

|---addChanged(this)-->

aTransactionLog
---commit()---> TransactionLog.getCurrentInstace()  

|--For each ObjectEditor-->

aObjectEditor.commit()

When the previous completes, our aTransactionLog is aware that aObjectEditor is one of the ObjectEditors with changes in that particular transaction log. Our ObjectEditor is aware that aField on aTransactionalObject has changed to aValue. When we commit the TransactionLog, each ObjectEditor is told to commit the ObjectEditor's changes. Since the ObjectEditor is aware of what field was changed to what value, the ObjectEditor uses the update method 'back door' to get the TransactionalObject to actually contain these changes.

There is one more step of complexity to this scenario. In the actual code, we also support multiple transactions updating the same TransactionalObject. So the ObjectEditor not only keeps track of aField and aValue for a given change, but the also the current TranasctionLog when the change occurred. When a TransactionLog asks the ObjectEditor to commit(), the ObjectEditor commits only those changes found to occur in that particular transaction log.

An IMPORTANT NOTE: To make transactions work, all object state modifications MUST be done with attribute accessors.