Chapter 12. Hints and tips

12.1. General Tips

12.1.1. Using Transactions in Constructors

Examples throughout this manual use transactions in the implementation of constructors for new persistent objects. This it guarantees correct propagation of the state of the object to the object store. The state of a modified persistent object is only written to the object store when the top-level transaction commits. Thus, if the constructor transaction is top-level and it commits, the newly-created object is written to the store, and becomes available immediately. However, if the constructor transaction commits but is nested because some another transaction, which was started prior to object creation, is running, then the state is only written if all of the parent transactions commit.
On the other hand, if the constructor does not use transactions, inconsistencies may arise in the system. For example, if no transaction is active when the object is created, its state is not saved to the store until the next time the object is modified under the control of a transaction.

Example 12.1. Transactions causing System Inconsistencies

AtomicAction A = new AtomicAction();
Object obj1;
Object obj2;

obj1 = new Object();			// create new object
obj2 = new Object("old");		// existing object

A.begin(0);
obj2.remember(obj1.get_uid());	// obj2 now contains reference to obj1
A.commit(true);				// obj2 saved but obj1 is not
Here, the two objects are created outside of the control of the top-level action A. obj1 is a new object. obj2 is an old existing object. When the remember method of obj2 is invoked, the object is activated and the Uid of obj1 is known. Since this action commits, the persistent state of obj2 may now contain the Uid of obj1. However, the state of obj1 itself has not been saved, since it has not been manipulated under the control of any action. In fact, unless it is modified under the control of some action later in the application, it will never be saved. However, if the constructor would have used an atomic action, the state of obj1 would have automatically been saved at the time it was constructed, preventing this inconsistency.

12.1.2. More on the save_state and restore_state Methods

JBoss Transaction Service may invoke the user-defined save_state method of an object at any time during the lifetime of an object, including during the execution of the body of the object’s constructor. This is especially true if it uses atomic actions. All of the variables saved by save_state are correctly initialized.
Use caution when writing the save_state and restore_state methods, to ensure that no transactions are explicitly or implicitly started. The reason is that JBoss Transaction Service may invoke the restore_state method as part of its commit processing, causing the execution of an atomic transaction during the commit or abort phase of another transaction. This may violate the atomicity properties of the transaction being committed or aborted, so it is discouraged.
To support crash recovery for persistent objects, all save_state and restore_state methods of user objects need to call the super.save_state and super.restore_state.

12.1.3. Packing Objects

All of the basic types of Java, such as int and long, can be saved and restored from an InputObjectState or OutputObjectState instances by using the pack and unpack methods provided by InputObjectState and OutputObjectState. However, you should handle packing and unpacking objects differently, because packing objects brings in the additional problems of aliasing. Alias means that two different object references may actually refer to the same item. See the Example 12.2, “Aliasing Problem with Packing Objects”.

Example 12.2. Aliasing Problem with Packing Objects

public class Test
{
    public Test (String s);
    ...
	private String s1;
    private String s2;
};

public Test (String s)
{
    s1 = s;
    s2 = s;
}
Here, both s1 and s2 point to the same string, and a naive implementation of the save_state method has the potential to copy the string twice. From the perspective of the save_state method, this is merely inefficient. However, it would cause the restore_state method to unpack the two strings into different areas of memory, destroying the original aliasing information. JBoss Transaction Service packs and unpacks separate object references.