Extending the BC4J Transaction
Monday 28 November 2005 @ 12:06 pm
Filed under:

One of the things we like about the Oracle Frameworks is open-ness and extensibility of the frameworks.

During our project we encountered the infamous web application problem of having two users edit the same data. The database and framework lead us to a few nice exceptions that resemble ‘RowInconsistentException’ or ‘RowAlreadyLockedException’.

The Oracle ADF Business Components framework gives us the possiblity of extending the transaction to catch this exception and do somethnig about it. We currently have decided that when these kind of exceptions are encountered that we want the transaction to be rolled back and a humanly readable exception to be displayed.

As an example we used the example of Steve Meunch (the Oracle ADF guru) and made this:


package nl.denhaag.grip.model;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import oracle.jbo.AlreadyLockedException;
import oracle.jbo.ApplicationModule;
import oracle.jbo.DeadEntityAccessException;
import oracle.jbo.DeadViewRowAccessException;
import oracle.jbo.JboException;
import oracle.jbo.Key;
import oracle.jbo.Row;
import oracle.jbo.RowAlreadyDeletedException;
import oracle.jbo.RowInconsistentException;
import oracle.jbo.ViewObject;
import oracle.jbo.server.DBTransactionImpl2;
import oracle.jbo.server.TransactionEvent;

/**
* Custom ADF DBTransaction implementation.
*
* Works in tandem with a custom DatabaseTransactionFactory implementation
* which returns instances of this subclass of DBTransactionImpl2
* instead of the default one.
*
*/
public class GRIPDBTransactionImpl extends DBTransactionImpl2 {

/**
* This framework method is called by clients to commit any pending
* changes in the transaction. It will first post any outstanding changes
* then issue the database commit to end the transaction.
*/
public void commit() {
try {
super.commit();
}
catch( JboException e ) {
handleException( e ) ;
}
}

/**
* This framework method is called by clients to validate all invalid
* objects in the transaction.
*/
public void validate() {
try {
super.validate();
}
catch( JboException e ) {
handleException( e ) ;
}
}

/**
* This framework method is invoked both by the postChanges()
* and by the commit() methods to post pending transaction changes.
*
* @param te TransactionEvent object
*/
protected void postChanges(TransactionEvent te) {

try {
super.postChanges(te);
}
catch( JboException e ) {
handleException( e ) ;
}
}

/**
* This framework method is called to actually issue the final
* 'COMMIT' statement to the database to end the transaction.
*/
protected void doCommit() {
try {
super.doCommit();
}
catch( JboException e ) {
handleException( e ) ;
}
}

private void handleException( JboException e ) throws JboException {
if( e instanceof RowInconsistentException
|| e instanceof RowAlreadyDeletedException
|| e instanceof AlreadyLockedException
|| e instanceof DeadEntityAccessException
|| e instanceof DeadViewRowAccessException
) {
rollback() ;
throw new JboException( "Een andere gebruiker heeft dezelfde gegevens ook gewijzigd. Uw wijzigingen zijn niet doorgevoerd, de nieuwe gegevens worden getoond." ) ;
}
else {
throw e ;
}
}

public void rollback() {
try {
// storeCurrencies
ApplicationModule appModule = this.getRootApplicationModule();

HashMap currencies = new HashMap() ;

String[] voNames = appModule.getViewObjectNames() ;

for( int voIndex = 0; voIndex < voNames.length; voIndex++ ) {
ViewObject vo = appModule.findViewObject( voNames[ voIndex ] ) ;

Row row = vo.getCurrentRow() ;

if( row != null ) {
Key key = row.getKey() ;
currencies.put( vo, key ) ;
}
}

super.rollback();

// reset Currencies
for( Iterator i = currencies.entrySet().iterator(); i.hasNext() ; ) {
Map.Entry entry = (Map.Entry)i.next() ;

ViewObject vo = (ViewObject)entry.getKey() ;
Key key = (Key)entry.getValue() ;

Row[] rows = vo.findByKey( key, 1 ) ;

if( rows != null && rows.length == 1 ) {
vo.setCurrentRow( rows[ 0 ] ) ;
}
}
}
catch (Exception e) {
if( e instanceof JboException ) {
throw (JboException)e ;
}
else {
throw new JboException(e) ;
}
}
}
}

It actually doesn’t do much. but enough for our purposes. For the framework you need to wrap this transaction implementation in a factory:


package nl.denhaag.grip.model ;

import oracle.jbo.server.DBTransactionImpl2;
import oracle.jbo.server.DatabaseTransactionFactory;

public class GRIPDBTransactionFactory extends DatabaseTransactionFactory {

public DBTransactionImpl2 create() {
return new GRIPDBTransactionImpl();
}
}

Even less code…

Now the magic to extend the framework: Open up your Configuration of your Application Module and goto the properties page. Scroll down all the way and find the ‘TransactionFactory’ property. Fill the with the complete classname of your own factory and presto….

Note: when using the BC tester to run your Application Module, make sure you choose the Configuration (at the top right of the screen where you select your connection) or your settigns won’t be loaded.

— By Robert Willems of Brilman     PermaLink

5 Responses to “Extending the BC4J Transaction”

  1. okke Says:

    So, correct me if I’m wrong, in order to get human readable error messages out of ADF, you need to hack around Oracle’s transaction factory implementations :-) ? Why not implement a descent exception handling routine in your presentation layer?? It’s a good idea to make transaction management pluggable, and it’s a very good idea to show an example howto so other readers can learn from it!, but I would advice not to abuse this power.

  2. Robert Willems of Brilman Says:

    Main reason to do this is to:

    a. Make it reusable in all your applications
    b. To also handle the error. When catching the exception we want to rollback all our changes because another user has already change the data before us.

    To code that rollback behaviour in our presentation layer would be the wrong place in my eyes. Also you would need to plug it in every page, so why not put it in the business layer where it belongs. To make the error humanly readable is just a bonus ;-)

  3. Okke van 't Verlaat Says:

    Agree, when its *always* the case that those five exceptions should be followed by a roll back, the solution sits where it belongs. But the *always* must be exactly 100% and not 99.9%. And I’m not sure if the bonus is humanly readable, especially for the non native dutch readers :-)

    Another question, the rollback code is something you had to write yourself? as a non ADF developer I’m sure I can’t reproduce it by head :-) or was this something you have cutted and pasted into your code?

  4. Robert Willems of Brilman Says:

    For our project we have defined it as 100%…. There sure are some exceptions, but those can be neglected safely (until proven otherwise, they are mainly that the row has been deleted, 3 of them, the row has been locked by another or the row has been changed; the row locked could be argued to be ‘illegal’ here, but in my opinion a locked is followed by a change)…

    The bonus is simplified here. In business components we use a resource bundle most of the time, especially for prompts/message/etc. In

    The rollback code is a ‘known’ problem in Business Components… the rollback itself are the resetting of the code is handled by the framework, however it also reset all your row currencies (to the row before first) and that is quite annoying from an application view. (Think master detail detail and you rollback something editted in the last detail). It is modelled after a solution for the presentation layer (with uses the bindings that Oracle has proposed in JSR-227), but rewritten for Business Components. Also it takes a little time to write it, but as it is reusable you never have to code it again….

  5. Martijn Stalenhoef Says:

    Question: did you stop to think what happens if you have a master / detail relationship between view objects? If you try to restore the detail’s current row before the master’s the restore will fail.

Leave a Reply


Menu


Sha256 mining

Blog Categories

Browse by Date
November 2005
M T W T F S S
 123456
78910111213
14151617181920
21222324252627
282930EC

Upcoming Events

Monthly Archives

Recent Comments

Links


XML Feeds Option


Get Firefox  Powered by WordPress

code validations
Valid RSS 2.0  Valid Atom 0.3
Valid W3C XHTML 1.0  Valid W3C CSS