Monday, May 20, 2013

Custom Transaction Factory in ADF BC for After Commit

We were facing issues overriding Custom Transaction Factory in ADF 11g R1, it was initialized only for the first loaded AM, this seems is not the case anymore in ADF 11g R2 (11.1.2.x). I would like to present today a use case of implementing global after commit call. Read more about use cases with Custom Transaction Factory in ADF Developer Guide - 12.8 Customizing Business Components Error Messages.

Sample application - CustomDBTransactionApp.zip is based on two separate AM's:


First AM is configured with Custom Transaction Factory:


Second AM is configured with Custom Transaction Factory:


Referenced Transaction Factory class creates new instance of DB Transaction implementation, where commit() and doCommit() methods are overriden:


You can see that message is printed after calling super in both cases:


If you want to execute code after commit operation was completed, you should call it after super in commit() method. This will be called one single time after commit, for all EO's at once.

In addition I have overriden doDML and afterCommit methods available in EO implementation to compare invocation time. Obviously these methods will be invoked separately for each EO:


We can test it now. Edit data from the first AM and commit transaction with Save button:


Check the log - first it starts executing SQL update statement. It calls doDML() method from EO implementation, next it calls doCommit() method from Transaction Factory, right before DB commit it calls afterCommit() method from EO implementation and finally after DB commit - commit() method from Transaction factory (after calling super) is called. This means afterCommit() method from EO is really invoked after data was posted to DB, but not after actual DB commit. In contrast, after super in Transaction Factory commit(), we can call custom logic and it will be executed after DB commit:


Test the same for the second AM:


It does same logic as for the first AM, you can check it applies correct AM instance:

11 comments:

Siu Fai Ng said...

Hi,

I use java class to create a data control and the function is to retrieve information from another application module and populate to the screen. As I know, there are 2 methods to get the application module.

Method 1
DCDataControl dc = BindingContext.getCurrent().findDataControl("RootAppModuleDataControl");
ApplicationModule am = (ApplicationModule)dc.getDataProvider();

Method 2
ApplicationModule am = Configuration.createRootApplicationModule("model.service.RootAppModule","RootAppModuleLocal");

If I use method 2 in java class application module to get another AM, say RootAppModule, they are not in the same transaction.

Do you know if I can call BindingContext in java class application module?

Thanks.

Andrejus Baranovskis said...

You should never useConfiguration.createRootApplicationModule, this creates another instance of AM. You can use this only for testing or if you want to access ADF BC out of ADF context.

Andrejus

Siu Fai Ng said...

Thanks for your help.

If I do not use createRootApplicationModule, do you have any suggestion how I can get the application module, say RootAppModule in my example, in a java class AM ? We need to process the un-posted records created by RootAppModule, and so it should be in the same transaction.

May I use method 1?

Many thanks.

Tony

Andrejus Baranovskis said...

Yes you can, also you can use helper method from ADFUtils (it does same thing).

Andrejus

Siu Fai Ng said...

Thanks for your prompt reply.

Siu Fai Ng said...

I still have one more question on transaction. I have created 2 applications, say App1 and App2. In App1, there are 2 AM, say AM11 and AM12. In App2, there is only one AM, say AM2. Both applications have only 1 VO referring to the same table.
I have added App2 to the library of ViewController of App1 through the Resource Palette, so there are total 3 data controls, AM11DataControl, AM12DataControl and AM2DataControl.

In App1, I have created a task flow with transaction "Always new transaction" and added a page fragment to the task flow. The page fragment contains 3 parts coming from the VO of 3 different data controls.

I find that the first 2 parts are in the same transaction, but the last part coming from the AM2DataControl is not in the same transaction.

It seems that the AM from external library is not in the same transaction.

Am I correct? Should I need to do any configuration?

Thanks.

Andrejus Baranovskis said...

I will test this tomorrow and let you know.

Andrejus

Siu Fai Ng said...

Thanks for your help.

I find that the reason behind is that the AM of these 2 applications are using different entity objects EO to represent the same table. Although the table is the same, but EO is different. If they use the same EO, all the AMs will be in the same transaction.

Thanks again.

Andrejus Baranovskis said...

I still going to test this and post a blog probably.

Andrejus

Andrejus Baranovskis said...

It worked for me, even with different EO's. I will post in my next blog post.

Regards,
Andrejus

Yo said...

If using Task Flow transaction control, seems that TransactionFactory is "ignored", still on 11g R2...