Monitoring the State of Persistent Apples


The StateTracker program allows you to use nearly all of the explicit and implicit operations of JDO while monitoring the persistent, transactional, and unmanaged fields of persistent, transactional, and unmanaged apples.

Figure 8-1 diagrams the relationships of the main classes and interfaces of the StateTracker program. The StateTracker class implements the user interface and is the client of the Monitor and StateHandler services. It creates new apples and worms and modifies the state of existing ones. The source file StateTracker.java contains all of the command classes of the StateTracker program. The application classes and interfaces shown in Figure 8-1 are contained in the com.ysoft.jdo.book.statetracker and com.ysoft.jdo.book.statetracker.client packages.

click to expand
Figure 8-1: The classes and interfaces of the StateTracker program

Figure 8-1 diagrams ten classes and interfaces. There are two application data classes, Apple and Worm. These have an n-m relationship to each other. The worms in the StateTracker program have the transcendental ability to exist in more than one apple at a time. The major purpose of the worms is to provide persistent fields that are not in the apple's default fetch group. The Apple class divides its fields into three groups, persistent, transactional, and unmanaged. The persistent group has the five fields shown in Listing 8-9. The fields were selected to give a representative sample of persistent fields. The first three fields are in the default fetch group, while the remaining two are not. The set of transactional (but not persistent) fields and the set of unmanaged fields are identical in type and similarly named.

Listing 8-9: The Persistent Fields of the Apple Class

start example
 private String   persistentName; private int      persistentSize; private Date     persistentPicked; private HashSet  persistentWorms; private Worm     persistentHeadWorm; 
end example

The remaining classes and interfaces in Figure 8-1 serve the following purposes. The Apple class implements the Monitored interface. The Monitor service uses the Monitored interface to determine the apple's management state without affecting it. The Monitored interface also ensures that Apple has a public clone method that is used by the StateTracker to snoop on the state of an apple without affecting the apple's managed state. The StateHandler is the application service that uses the persistence manager. It handles objects, and knows nothing about apples and worms. The Apple class implements InstanceCallbacks. These callback methods serve two purposes: they capture the persistent object's identity string, and they provide notification to the user interface when the callbacks occur.

Building the StateTracker Program

To build the StateTracker program, go to the bookants directory and type ant statetracker. This build is part of the ant learning-programs build. Listing 8-10 shows some of the expected output from the build when using the reference implementation.

Listing 8-10: Expected Output from Running ant statetracker

start example
 statetracker:     [javac] Compiling 7 source files to E:\Bookcode\build      [echo] returned from com/ysoft/jdo/book/statetracker/build.xml      [copy] Copying 1 file to E:\Bookcode\enhanced\com\ysoft\jdo\book      [java] done.      [echo] creating runStatetracker.bat BUILD SUCCESSFUL 
end example

To run the StateTracker program, go to the bookcode-home directory and type runStatetracker.

Getting Started with the StateTracker Commands

If you enter the help command after starting the StateTracker program, you see all the commands that it supports. The expected output is shown in Listing 8-11.

Listing 8-11: Example of Help Output from the StateTracker Program

start example
 E:\Bookcode>runstatetracker Using adaptor class: com.ysoft.jdo.book.factory.jdori.JDORIAdaptor The database (FOStoreTestDB.btd) exists Using URL: (fostore:FOStoreTestDB) enter command: --> help commands:    quit    begin    commit    rollback    active    find all    add apple    select apple    modify apple    add worm    delete worm    snoop    view    get JDO state    make persistent    delete persistent    make transactional    make nontransactional    make transient    evict    evict all    refresh    refresh all    retrieve    tickle default fetch group    dirty    toss exception    configure    configuration    open    is open    close enter command: --> 
end example

As Listing 8-11 shows, the program recognizes a large number of commands. The commands begin, commit, rollback, and active allow you to control and monitor transactional boundaries. A good place to start is to add a few worms. Their only attribute is a name. For example, the following interaction adds one new worm named Henry:

 enter command: --> add worm Enter worm's name: --> Henry Okay, but worms are made persistent only by being in a persistent apple enter command: --> 

A new worm remains unmanaged. It becomes persistent only when it is reached from a persistent apple. After creating a few worms, make a new apple. Listing 8-12 shows a sample interaction that adds a new McIntosh apple with three worms.

Listing 8-12: User Commands to Create a New McIntosh Apple with Three Worms

start example
 enter command: --> add apple Enter apple's name: --> McIntosh Enter apple's size (> 0): --> 3 Enter date picked (mm-dd-yy): --> 10-15-02    Date accepted:Tue Oct 15 00:00:00 EDT 2002 Add a worm?:    1. true    2. false Enter selection: --> 1 Pick a worm:    1. Worm Henry    2. Worm Martha    3. Worm Jack Enter selection: --> 1 Add a worm?:    1. true    2. false Enter selection: --> 1 Pick a worm:    1. Worm Martha    2. Worm Jack Enter selection: --> 1 Add a worm?:    1. true    2. false Enter selection: --> 1 Pick a worm:    1. Worm Jack Enter selection: --> 1 Add a worm?:    1. true    2. false Enter selection: --> 2 Pick the head worm:    1. Worm Henry    2. Worm Martha    3. Worm Jack Enter selection: --> 2 Okay, the new transient apple has been added to the selection list enter command: --> 
end example

The new apple remains unmanaged. To see this, first use the select apple command to select the apple from the current list of apples. Then use the get JDO state command to determine the current JDO management state of the selected apple.

 enter command: --> select apple Select an apple:    1. Apple transientName: McIntosh Enter selection: --> 1 Okay enter command: --> get JDO state Apple transientName: McIntosh is in JDO state transient enter command: --> 

Because all actions so far have occurred on unmanaged state, there has been no reason to start a transaction.

Next, execute the begin and the make persistent commands to make the unmanaged McIntosh apple persistent. Now execute the view and get JDO state commands to determine the unmanaged, transactional, and persistent state of the apple and to determine its management state. Using any implementation, you should see output like the following, which was produced by the reference implementation:

 enter command: --> view Viewing managed state for: OID: 105-12 [JVM ID:4066855]    transient state: McIntosh, 3, 10-15-02, Worm Martha,          3 worms {Worm Martha,Worm Jack,Worm Henry}    transactional state: McIntosh, 3, 10-15-02, Worm Martha,          3 worms {Worm Henry,Worm Martha,Worm Jack}    persistent state: McIntosh, 3, 10-15-02, Worm Martha,          3 worms {Worm Henry,Worm Martha,Worm Jack} enter command: --> get state OID: 105-12 [JVM ID:4066855] is in JDO state persistent-new enter command: --> 

Notice that all three states are the same. That is because the values entered when the apple was created were copied to all three sets of fields, as a way to reduce the amount of user input. As expected, the management state after the make persistent command is persistent-new.

If you have not executed the configure command, then all transactional attributes are off at this point, and the configuration commands returns the following output:

 --> configuration Current transaction properties: active, !Opt, !RetainV, !RestoreV, !NTR, !NTW enter command: --> 

At this point, commit the transaction and ask for the apple's management state. You should see output that looks like the interaction in Listing 8-13, which was produced by the reference implementation.

Listing 8-13: Sample Output from Committing the New McIntosh Apple

start example
 enter command: --> commit Synchronization.beforeCompletion called OID: 105-12 [JVM ID:4066855] jdoPreStore OID: 105-12 [JVM ID:4066855] jdoPreClear Synchronization.afterCompletion called with status: committed Okay enter command: --> get state OID: 105-12 [JVM ID:4066855] is in JDO state hollow enter command: --> 
end example

After committing the transaction, you will get an exception if you execute the view command because a transaction is not active. Instead run the snoop command. The snoop command produces a view of the object without affecting the managed state or requiring a transaction. The expected output will look like the output in Listing 8-14.

Listing 8-14: Sample Output from Snooping on the Hollow Apple

start example
 enter command: --> snoop Viewing raw state for: OID: 105-12 [JVM ID:8083121]    transient state: McIntosh, 3, 10-15-02, OID: 106-21,          3 worms {OID: 106-21, OID: 106-22, OID: 106-20}    transactional state: null, 0, no date, null, null worms    persistent state: null, 0, no date, null, null worms enter command: --> 
end example

There are four things to notice in Listing 8-14. One, the JVM ID has changed from Listing 8-13. The change occurs because the snoop command views a clone of the original apple. (Remember from Chapter 5 that, by default, cloning a persistent object gets a snapshot of the current memory state without invoking transparent persistence.) Two, the persistent state has Java default values. This is expected since the object is in the hollow management state. Three, the transactional state also has Java default values. This is an unexpected outcome. The specification describes eviction only in terms of clearing the persistent state. It says nothing about clearing the nonpersistent and transactional state. In fact, the specification strongly implies that eviction does not clear the nonpersistent and transactional state. This behavior has been reported as a bug in the JDO reference implementation at the Java bug parade (http://developer.java.sun.com/developer/bugParade).

Finally, note that the transient state is not changed, except that all of the worms are now unnamed. The transientWorms field and the transientHeadWorm field both point to persistent objects even though the fields are unmanaged. When the new apple was created, the same worms were used to set the unmanaged, transactional, and persistent fields. As a result, all worm fields are referring to the same worms, which became persistent when the apple became persistent. When the snoop command executes, it clones the apple, but it does not clone the worms. The worm's toString method catches the exception that results from trying to examine the persistent name of a Worm outside of a transaction, and it recovers from the exception by returning the worm's identity string instead of its name.

Brief Look at the Other StateTracker Commands

The previous section describes many commands that the StateTracker program recognizes. This section describes the remaining commands.

Many of the command strings are self-describing. For example, the make transactional command will make a nontransactional object transactional. In some cases, for the command to succeed, the implementation must support the appropriate implementation options. An unmanaged object cannot be made transactional unless the implementation supports, as the reference implementation does, the javax.jdo.option.TransientTransactional feature. Most commands operate on the selected apple, but some operate on a set of apples. The evict all command evicts all persistent-clean apples (and worms) and the refresh all command refreshes all transactional apples and worms.

The configure command sets the five properties of the Transaction object: Optimistic, RetainValues, RestoreValues, NontransactionalRead, and NontransactionalWrite. The is open command checks whether the persistence manager is open. The open and close commands open and close the persistence manager.

The toss exception command sets a flag in the transaction's Synchronization object that will cause it to throw a JDOUserException on the next commit. It's a one-shot setting that does not block a subsequent commit. The tickle default fetch group command reads a couple of fields of the default fetch group and outputs a message with their values. It will cause the default fetch group to load in most cases. The dirty command will call the makeDirty method in JDOHelper for the selected managed field.

The StateTracker program has been invaluable in writing this book, and you will find it very useful for test driving your selected JDO implementation.




Using and Understanding Java Data Objects
Using and Understanding Java Data Objects
ISBN: 1590590430
EAN: 2147483647
Year: 2005
Pages: 156
Authors: David Ezzio

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net