Friday, March 4, 2011

Using Popup to Confront user to Save/Forget Changes

This is an example topic followed by the previous post. Here I am presenting an example that using a popup to confront the user to save or forget the pending changes when navigate to different frame.

The example can be download from here. The example is based on Andrejus Baranovskis's example on how to detect pending changes using dynamic regions. What Andrejus did for pending changes is to throw an Warning message, but I came up with a scenario that to confront the user with popup and let use to choose either stay on the page or go ahead forget the change for the next frame.

1. How the pending changes are detected through ADF controller layer.











2. How to navigate to a different frame in dynamic region. If there are pending changes, the popup will be thrown to the user.












3. How to handle the logics if the user choose to forget the pending changes and navigate away.

















4. Main.jspx page structure:



Here are the UI of this example:

1. Make some changes on the location flow.
















2. Navigate to a different frame - Department Flow.


3. A warning pop up has been thrown.












4. User choose to forget the changes and successfully navigate to department flow.






















5. Go back to the location flow and pending changes have been wiped out.


Task Flow Pending Changes

Task flow as a functional unit provides great flexibility and offers developers lots of ways to get a hand on its state, transaction and management. Common requirements exist like web application needs to prompt to the user asking for save/cancel pending changes before navigating to a different frame.


In ADF, pending changes can be caught at the modal layer by calling getTransaction().isDirty() in ApplicationModuleImpl. That's common for developer to come up with at the first moment. Here I present how it's easily handled by using task flow in terms of pending changes detection.


ADF task flow, as main player in the ADF controller layer, provides several context interface to manage its state and transaction. In our case today, the context interface class is ControllerContext class.


The ControllerContext class provides per-request information about the controller state for a web application. 


To get hold of the ControllerContext in your managed bean:


ControllerContext cctx = ControllerContext.getInstance();


To detect the pending changes, there is a method "isDirty()" available in ViewPortContext or TaskFlowContext just like the one in DBTransactionImpl class. The difference as well as the advantage is the method exist in the viewController layer and no need to get hold the DataBinding and subsequent Application Module of the modal layer.


cctx.getCurrentViewPort().getTaskFlowContext().isDataDirty();
or
cctx.getCurrentViewPort().isDataDirty();


ViewPortContext.isDataDirty() 
          Returns true if this view port, or any of its children view ports, has a current task flow with uncommitted ADF model data.



TaskFlowContext.isDataDirty()
          Returns true if task flow contains any uncommitted ADF model data.

Thursday, March 3, 2011

Does your task flow need a transaction?

Task flow is a great feature in ADF and serve as a milestone for ADF 11g. The best documentation for ADF matters is to dig into the fusion developer's guide. The particular matter for task flow is here (11.1.1.3).


In ADF task flow, there is a concept - "transaction". It is a persisted collection of work that can be committed or rolled back as a group. Task flow present itself as a perfect group for such transaction. Transaction applies when one task flow is interacting with another. For example, there are two task flows here, one is parent task flow (flow P) and the other is child task flow (flow C). When P calls C, there are several transaction options for C. The options specify whether C will join P's existing transaction, create its own transaction or only create its own transaction if no existing transaction in P. Of course, C could also not have a transaction at all, which is the default option.


Steve Muench stated the following in his article: If your bounded task flow modifies data or wants to control when to commit or roll back data modified by anycalled task flows, it will require a transaction. You indicate this by setting the task flow’s transaction property torequires-transaction . At runtime, when Oracle ADF starts a bounded task flow that requires a transaction, one of two things occurs. If no transaction is currently active, Oracle ADF will begin a new transaction and remember the task flow that was responsible for starting the transaction. In contrast, if a current transaction is already open, the new task flow will participate in that existing transaction. Given this rule of thumb, any task flow you build that requires a transaction will either coordinate one or be coordinated by a calling task flow’s transaction, depending on how the task flow is used. Sometimes a task flow requires a transaction but also requires parameters from a calling task flow in order to work properly. In such a case, set the task flow’stransaction property to requires- existing-transaction instead. This says a task flow can participate in an existing transaction but not start a new transaction itself. To indicate that a task flow should never be used as part of an existing transaction, set its transaction property to new-transaction .


Besides the transaction options, there are two more parameters in the context: whether share the data control with the calling task flow and whether set the save point on the task flow entry. I will talk about the two one by one.


Let's look at the whether set the save point on the task flow entry, which is pretty straightforward. ADF save point is a saved snapshot of the ADF model state. It will automatically created if the task flow is called based on a existing transaction. Upon the return of the called task flow, there is an option "return save point" to set to true to roll back to the implicitly save point created by ADF. The default value is set the save point at the task flow entry. This parameter is not available the transaction option is set to "always start a new transaction" which literally tells since the a new transaction will be created upon task flow entry, there is no effect to the previous transaction at all, so the save point is no need here.


Whether share the data control with the calling task flow is an important parameter to note. I will demonstrate it using an example. Say we have 3 task flows, A calls B, and B calls C. A and B have the same data control frame (save Application Module), and C has a different data control frame. If the share data control parameter is set to true, which is the default. What happens is a data control instance created upon A flow enters. When B called from A, it will detect it's the same data control and will refer to the same instance as A does. When C called from B, even though it's not the same data control, ADF will nest the C's data control instance under A and B's data control instance. It's like the nested application module. The advantage is share the data control across the task flows will use the same DB connection.