Showing posts with label Transaction Management. Show all posts
Showing posts with label Transaction Management. Show all posts

Tuesday, August 16, 2011

Rollback is executed when a region is refreshed

We are using Task flows as regions in jdeveloper 11.1.1.4 in the latest project.
I have just noticed that when a region refreshes then a data control transaction rollback is executed transparently.
This does not happen the first time the region is displayed but every time it is refreshed after that.
This cause unexpected behavior of loosing data and the current rows of any other shared transaction task flow.

Could this be an expected (designed) functionality? Why?

As a test case I have 2 application modules (DepartmentsModule and Employees module) and a page that has departments and a region that has Employees with ‘share transaction if possible’ in the EmployeesTaskFlow.
Also the EmployeesTaskFlow get as parameter the current DepartmentId and has Refresh condition ifNeeded so that it refresh every time I navigate into departments.

Yet when I press next button I loose any change made on current department and I stay in the same row.
What I see in log is that Rollback is executed as a consequence of region Refresh and releaseViewPort.



Is this expected behavior or a bug?

I will check also what happens in 11.1.2 that it seems the nesting implementation have changed:
http://one-size-doesnt-fit-all.blogspot.com/2011/08/task-flows-sayonara-auto-am-nesting-in.html

It reproduce also in 11.1.2

Test Case
http://adfbugs.googlecode.com/files/TestRegionRollback.zip

A Perfect explanation and solution is given by Oracle Support. I will put it as is here:
@ At the point when the customer decided the region should share the
@ transaction with its parent, he also made the region a potential actor on the
@ parent transaction. Since the transaction mode on the region is not 'Always
@ Use Existing Transaction', the region transaction is not necessarily created
@ by the parent (and I will come back to that later), the behavior of the
@ region becomes the behavior of the parent even if they don't share the same
@ datacontrol. That is because both datacontrol are in one transaction since
@ the transaction is shared. When the region refresh, it rollback the
@ transaction which rollback both datacontrol.
@ .
@ To make the share mode work, the main point the customer should pay attention
@ to is that the transaction should be created by the parent, not by the
@ region. If it is created by the region, then the region become the owner of
@ the transaction and will rollback when the region is refreshed. If the
@ transaction was created by the parent it will work as expected.
@ .
@ What you need to do is ensure that the transaction is owned by the parent.
@ You need to have it created before the region. They are several ways to do
@ that:
@ 1) Have the parent page in a bounded taskflow with 'Always Begin New
@ Transaction' mode on.
@ 2) Call beginTransaction() on the DataControlFrame in an action that
@ navigates to the parent page with the region.
@ 3) Have a method activity that executes beginTransaction() on a request bean
@ before navigating to the parent page with the region.
@ The code to do begin the transaction is:
@ .
@ public void beginTransaction()
@ {
@ BindingContext context = BindingContext.getCurrent();
@ .
@ String dcFrameName = context.getCurrentDataControlFrame();
@ DataControlFrame dcFrame = context.findDataControlFrame(dcFrameName);
@ dcFrame.beginTransaction(new TransactionProperties());
@ }
@ .
@ To prevent the region from owning the transaction and run into these types of
@ issue for share mode, you can set the transaction mode on the taskflow to:
@ or 'Always Use Existing Transaction' in the
@ property inspector. If the transaction does not exist, an exception is
@ thrown.
@ .
@ I modified the original test case to illustrate the different options. Open
@ the workspace and look at adfc-config.xml. Run the Start page, withoutTrans
@ is the original test case, withTrans and beginTrans are 2 options that work.
@ .


Resolution Test Case
http://adfbugs.googlecode.com/files/TestRegionRollback2.zip
Hello

Unfortunately it seems that the issue is not fully resolved.
This works until a Data control frame commit or Rollback is executed.
Then it seems that the parrent looses control again of the transaction and regions rollback again on every refresh...
In the test case i added 2 buttons that do :

DataControlFrame dcFrame = context.findDataControlFrame(dcFrameName);
dcFrame.commit();
and
DataControlFrame dcFrame = context.findDataControlFrame(dcFrameName);
dcFrame.rollback();

The test case work fine until any of the commit or rollback transaction is pressed
Then Next button still causes rollback to be executed.

This means that still i cannot control the full data control frame transaction when i have regions with parameters.

New test case
http://adfbugs.googlecode.com/files/TestRegionRollback3.zip

Tuesday, May 3, 2011

Application Module cannot get principal when you use transaction controller in task flows (Fixed in 11.1.2)

When you use Transaction behavior in Task flows then ApplicationModuleImpl.getUserPrincipalName gives a java.lang.NullPointerException
To reproduce it I have an application module with an exposed method:

public void checkTransaction(){
System.out.println(this.getDBTransaction().getSession().getEnvironment().get("jbo.user.principal"));
System.out.println(this.getUserPrincipalName());
}

I also have 2 ‘isolated’ task flows, StartNewTransaction with ‘Always Begin new Transaction’ and UseExistingTransaction with ‘Use existing transaction if possible’




I have user: ‘user1/welcome1’ and run TestTransactions page and loggin.
In main page checkTransactions works as expected. Yet in other task flows it gives a:

java.lang.NullPointerException
at oracle.jbo.server.ApplicationModuleImpl.getUserPrincipalName(ApplicationModuleImpl.java:8429)
at model.modules.AppModuleImpl.checkTransaction(AppModuleImpl.java:31)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)


Is this a specific method bug?
Will I have issues with history columns?
Do I loose any other security context?

Test Case:
http://adfbugs.googlecode.com/files/testTransactions.zip

Does not reproduce in jdeveloper 11.1.2

Tuesday, December 22, 2009

Composition Association and Locking (Fixed in 11.1.1.4)

We had a lot of locking problems in our ADF application even though we use optimistic locking.

We found out that it was caused by composition Association and Lock Top Level Container Option.
This is the default way the association is generated by the wizard when the foreign key constraint in database is cascade.
In my test case I set it by hand to reproduce in Department Employees relationship.


The master Entity Table in database is locked every time you create a new record in the detail composed entity.
This is happening when creating detail data and not when posting data as in optimistic locking
This does not happen when you update or delete data from detail entity.

Is this a bug?

If pessimistic mode of Application Module is not a good practice for Fusion Applications then composition Association Locking should also be not.

Composition Association is a rule to prevent details to exist without a master. But this is also prevented if the foreign key attribute in detail entity is required. So I also don’t see the usage of composition association.

Test Case:
http://adfbugs.googlecode.com/files/TestCompositionLock.zip

Monday, December 14, 2009

Pending changes in ADF application

So far I have seen 2 ways to check if there are pending changes in ADF application

1 is from ApplicationModule.getDBTransaction().isDirty();

2. is from DataControlFrame.isTransactionDirty();

Yet their functionality is not the same.
To demonstrate it I created a master –Detail, Departments - Employees test case with backing bean that return :

public String getAmChangesExist() {
BindingContext bc = BindingContext.getCurrent();
ApplicationModule am = bc.getDefaultDataControl().getApplicationModule();
return am.getTransaction().isDirty()?"True":"false";
}

public String getDcFramechangesExist() {
BindingContext bc = BindingContext.getCurrent();
String currentDataControlFrame = bc.getCurrentDataControlFrame();
return bc.findDataControlFrame(currentDataControlFrame).isTransactionDirty()?"True":"false";
}

If I change anything on department(except TransientAttribute) or employees and press submit then both methods show there are pending changes.



Yet if I change value of transient attribute only dataControlFrame.isTransactionDirty() shows there is a change, and am.getTransaction().isDirty() shows false


If I press button createInsert on Department or on Employees then again :
dataControlFrame.isTransactionDirty() shows there is a change, and am.getTransaction().isDirty() shows false
I feel that changes should not include transient attributes that dont exist in entities, since they are not used in transaction.
But it should include new rows created on views and entities.
In order to be sure i would chose dataControlFrame.isTransactionDirty() since it also keeps its value even with diferent application modules through task flows with shared data control scope.
Test case:

Tuesday, October 13, 2009

No inconsistency check after any Exception during posting data

During working on previous bug I found out that after any exception while posting Entity Data, inconsistency is not checked again.

Normally if 2 users query same row and change it then the user that commits last will get RowInconsistentException (JBO-25014)


But if second user get any exception while posting i.e. Foreign Key constraint exception, and then he correct it and commit again then he never gets a RowInconsistentException (JBO-25014)

To reproduce it in test case do the following

Run application and for ManagerId of department put an number that does not exist. Try to commit and you get constraint exception.

Open new instance of application and change anything and commit.

Go back to the first application correct the ManagerId to a valid value and commit.
You don’t get any RowInconsistentException

Is this a bug?

test case:

Friday, October 9, 2009

Open Locks in optimistic locking bug !!!

Open Locks in optimistic locking bug !!!

Yes it is possible, it was happening in our application and could not imagine why.
After research we found out that it was in the CustomDBTransactionImpl.
We use it to override doCommit in order to do staff after all data are posted but not yet committed according to :
Fusion Developer's Guide for Oracle ADF, D ADF Equivalents of Common Oracle Forms Triggers:

POST-FORMS-COMMIT
Execute code after Forms has "posted" all necessary rows to the database, but before issuing the data commit to end the transaction

If you want a single block of code for the whole transaction, you can override the doCommit() method in a custom DBTransactionImpl object and write code before calling the super.


I managed to reproduce it in a simple test case.

I just have Departments entity and view and an application module with CustomDatabaseTransactionFactory. In CustomDBTransactionImpl I override doCommit and throw an exception:

@Override
protected void doCommit() {
if (true){
throw new JboException("Exception in doCommit");
}
super.doCommit();
}

I run the application, make a change and press commit. I get the error:

Now the row is locked in the database!!!!

I run a new instance of the application i make a change and try to commit and I get:


If I try to do rollback before I throw the exception then the locks are lost of course but also all the changes made on page.

Is this a bug?
If not, is there an other way to check and throw exception, after data are posted to database and before commit, without locking?