Monday, March 28, 2011

What is Oracle ADF Task Flow

The concept of unbounded and bounded task flows is new to JavaServer Faces (JSF) and is an extension exclusively available to Fusion web application developers who use the ADF Controller, which extends the JSF navigation model, for their application flow handling.

In this article, we will describe what a task flow is and compare unbounded task flows with bounded task flows.

ADF Task Flow

ADF task flows provide a modular approach for defining control flow in an application. Instead of representing an application as a single large JSF page flow, you can break it up into a collection of reusable task flows. Each task flow contains a portion of the application's navigational graph. The nodes in the task flows are activities. There are two types of activities: visual vs. non-visual. The transitions between the activities are called control flow cases.

Because only pages and page fragments are displayed in a browser, ADF Controller continues any navigation to non-visual activities until a visual activity is reached. This turns non-visual activities into intermediary actions that are performed on the navigation path between two views.

Task flows don't own the pages they reference. All ADF Faces pages are located in the web project HTML root directory or a subdirectory of it. Independent of whether or not a page is referenced in a bounded or unbounded task flow, or both, it is always directory accessible from the browser URL field. Developers should be aware of this and implement a protection strategy, such as one through ADF security, that prevents users from directly accessing pages that they are not authorized to access.

At design time, developers need to consider the following issues with task flows:
  • Whether to use a shared data control frame or its own, isolated data control frame (this creates a new application module connection). Note that a data control frame is the container associated with a task flow that contains data control instances.
  • Whether a new transaction is to be begun or not
  • Whether a task flow should allow reentry or not
  • Whether an unbounded task flow or a bounded task flow should be used

Bounded Task Flow

Bounded task flow represents modular and reusable application flows with a defined entry (i.e., default activity) and zero to many defined exit points (i.e., task flow return activities). They can be called from other task flows, referenced from a browser URL or embedded as a region in a view. They support reuse, parameters, transaction management and reentry.

In addition, bounded task flows have the following features:
  • Operate within their own private memory scope--page flow scope
  • Are loaded lazily at runtime
  • A new instance of TaskFlowContext (can be accessed using EL ${controllerContext.currentViewPort.taskFlowContext}) will be created each time a bounded ADF flow is entered. This context:
    • Manages the lifespan of all DataControl instances within the bounded task flow
    • Holds the information about the task flow ID and whether or not it contains uncommitted data
  • Don't support multiple transactions when sharing the data control frame with parent flow
  • To call a bounded task flow directly from a URL, the default activity must be a view activity
  • Can be set to be critical (i.e., dictates the framework to create an implicit save point when entering a bounded task flow. Also helps to prevent users from closing the browser window or browser tab if uncommitted data is present).
  • If protected by ADF Security, authorization is checked first.
  • You can create train-based activities in a bounded task flow and only one train is allowed in each.
Bounded task flow should be used if it:
  • Should be reused in same or other applications
  • Should run as part of a page within a region container
  • Requires an isolated transaction context
  • Changes data and then either commits or rollbacks on exit
  • Has a requirement for a single entry point

Unbounded Task Flow

A Fusion web application always contains an ADF unbounded task flow, which contains the entry point or points to the application. Its XML configuration file (i.e., adfc-config.xml) is automatically created when building a new application using the Fusion Web Application (ADF) application template or when adding the ADF Page Flow Technology Scope to an existing or new web project. There will always exist a single instance of unbounded task flow at runtime, even if there is no activity added to it.

A unbounded task flow has the following features:
  • You cannot declaratively specify input parameters for it.
  • It cannot contain a default activity (i.e., an activity designated as the first to run in the task flow). This is because an unbounded task flow does not have a single point of entry.
  • It can be configured by one or many configuration files that are parsed and loaded the first time the user starts the application.
  • View activities of an unbounded task flow can be configured bookmarkable
  • Managed beans that are in session or application scope should be configured in the unbounded task flow definition.
  • You cannot create a train from activities in an unbounded task flow.
  • You cannot use a task flow template as the basis for creating a new unbounded task flow

You typically use an unbounded instead of a bounded task flow if:
  • You want to take advantage of ADF Controller features not offered by bounded task flows, such as bookmarkable view activities.
  • The task flow will not be called by another task flow.
  • The application has multiple points of entry. The task flow can be entered through any of the pages represented by the view activity icons on the unbounded task flows.
  • You want to bookmark more than one activity on the task flow.
  • For application flows that are not restrictive on where a user enters the flow.

Wednesday, March 16, 2011

adf-richclient-demo

http://jdevadf.oracle.com/adf-richclient-demo/faces/components/skinningKeys/index.jspx

Custom Java Bind Variable in a Where Clause of an ADF View Object


You can make a JDeveloper model View Object (VO) use a data query that has a custom variable accessor in Java.  This is useful for cases where you want your where clause to select based on the current user name from the ADF Security context.
Go to the “Query” tab of your view object:

Add a new Bind Variable and make sure to specify “Expression” and give the value the Groovy expression “adf.object.viewObject.yourPropertyName”.  The “adf.object.viewObject” portion is essentially like saying “this object” and then it will call getYourPropertyName() to fetch the value:

Back in your query expression, refer to this new bind variable by its name but prepend “:” to indicate that it is a bind variable as shown above.
Select the “Java” tab of your view object and then click the pencil icon to edit the settings:

Select the “Generate View Object Class” and “Include bind variable accessors” options:

This will generate a new “.java” entry under your view object in the JDeveloper application navigator:

Finally, open that Java file and change the implementation of your get accessor as you wish.  In my case, I am simply returning the user name property from the ADF security context.  I also changed my set accessor to do nothing:

Tuesday, March 15, 2011

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.

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.


How to connect to MS SQL Server through Jdeveloper 11.1.1.3


To connect to MS SQL Server you need to follow the following steps.


Pre-requisite: You need to have a sqljdbc4.jar file placed in the jdev/lib/folder. It can be downloaded from this  (1033\sqljdbc_3.0.1301.101_enu.tar.gz) path and extracted to get sqljdbc4.jar. Finally it needs to be at jdev/lib location.


1. Go to New Database Connection and create a Database Connection by providing all the required details. Remember to select SQLServer as Connection Type.


2. In the Library section click Browse and add the Library entry as shown below.


3. Click on Test and it says Success....


However, for the projects using MS SQL Server connection deployed on Weblogic server, some server side configuration also needs to be done that can be found here.

Tuesday, March 8, 2011

ADF UI - Performance Tip: Lazy load task flows for better performance


Before discussing the performance improvement by implementing lazy loading for the task flows, let us go through the task flow basics.


How task flows are loaded normally?
If you're dropping task flow as a region in your jsff, the task flow binding will be added in the pagedef file as an executable. So, anything under executables section including the task flows in pagedef file will be loaded by default when the jsff page is loaded.

How it impacts the performance?
As ADF loads all the task flows that are inlcuded in a page, even if they are not rendered by default, it'll be a performance hit as we're loading the task flows which are not needed by default. Examples below:
Popups: Task Flows on a popup should be loaded  only when user clicks on Pop-up link but ADF loads them during the page invocation itself and hence reduce the perfomrance of the page .
Hidden Taks Flows or Conditionally Rendered Task Flows: ADF page could have some of the task flows that are hidden based on a condition. In this scenario as well ADF loads the task flows during page loading even if those task flows are hidden and the model content in that will get executed during the page loads hence results in lower  performance of the page.
Panel Tabs: Page could have multiple tabs on a page with respective task flows , ADF loads all the task flows even though only one tab will be showed at a time.

So, What is lazy loading and how it improve the performance?
Lazy loading means loading the task flows only when they are required to be rendered. i.e., we won't load the task flows that are included inside popups, and those hidden initially, and the ones that are present in other than the default tab. We'll load them only when the popup is invoked, when the task flow region is unhidden/shown, on clicking the tab that has the task flow respectively.

How to implement lazy loading for the task flows?
1. For task flows in popups
i. Define a af:setPropertyListener of type 'popupFetch' and set some constant to one pageFlowScope variable.


ii. In the pagedef, set 'Activation' property for task flow binding to 'Conditional' and 'Active' property to above defined pageFlowScope variable with EL expression which evaluates to true when the popup is fetched.

2. For the hidden or conditionally rendered task flows:
i. Conditionally rendered task flows will have the 'rendered' property set to some condition defined as EL expression based on which the region will be hidden or shown. You need to specify the same condition for the 'Active' property of the task flow binding in the pagedef. And, don't forget to set the 'Activation'  property for task flow binding to 'Conditional'.

Jsff containing taskflow:

The task flow in the corresponding pagedef file:

3. For panel tabs (af:panelTabbed) components:
i. Add a af:setPropertyListener of type 'disclosure' in each af:showDetailItem under af:panelTabbed and set some constant value to a pageFlowScope variable. You need to set value to the same pageFlowScope variable in each tab. On reading the pageFlowScope variable value, you should be able to tell in which you're currently in.


ii. In the pagedef, set 'Activation' property for task flow binding to 'Conditional' and 'Active' property to above defined pageFlowScope variable with EL expression which returns true when the tab containing that particular taskflow is clicked.


That's quite simple. Now, your pages will load double faster than previous even with multiple task flow in your pages. Bingo :) !

ADF Model: Getting attribute values from parent VO to child VO and vice versa using view link accessors



In this post, let us see how to access parent VO attributes from child VO and child VO attributes from parent VO using view link. To have the basic idea about view links and how to create them, you can go through my blog post 'ADF Model: Creating View Link'.


Example Use Case:
For example we have two VOs DeptVO and EmpVO and both are linked via foreign key 'DeptId' using the view link EmpVOToDeptVO. Here, this relationship depicts the parent-child relationship using the foreign key DeptId. In other words, for a given current EmpVO(child) row, I need to know the DeptName from DeptVO(parent). Similarly, for a given current DeptVO(parent) row, I need to know all the empVO(child) rows. Sample application demonstrating this example can be downloaded from here.

Implementation Steps:
1. Create EmpVO and DeptVO and generate RowImpl classes for both of these two VOs.

2. Now, create a new view link say DeptVOToEmpVO between these two VOs via foreign key DeptId.

3. In the view link definition, select options to generate accessors in both source and destination VOs. i.e., in DeptVO and EmpVO.

4. Checking the above options will generate accessor methods in EmpVORowImpl and DeptVORowImpl. The accessor's return type in each VO is based on the type of relationship between the VOs. In other words, as the relationship between Dept and Emp is 1-to-many, the accessor in DeptVORowImpl will return multiple Emp rows(i.e, the return type of the accessor will be RowIterator). And, the accessor in EmpVORowImpl will return a single row (as an employee can be in only one dept).


If you observe the source of EmpVO and DeptVO, you can also see that a tag is added in each of these VOs for the viewLinkAccessor.


5. Now, you can use these accessors to get reference EmpVO from  DeptVO and vice versa. You can also get attribute values from the same. Sample codes below:

Sample method in EmpVORowImpl to get the dept name.

Sample method in DeptVORowImpl to get the list of employees in the dept.

How to call/use these view link accessor methods in AMImpl methods?
This should be now pretty straightforward. Here is the sample AMImpl method which prints emp names in each dept. The code is self-explanatory.

Here is the sample output in console on running the above AMImpl method.


That's it. Now, you got the idea how to use view link accessors to get the values of child attributes from parent and vice versa. Enjoy!


Read more: Oracle ADF - Tips and Techniques: ADF Model: Getting attribute values from parent VO to child VO and vice versa using view link accessors http://www.adftips.com/2010/12/adf-model-getting-attribute-values-from.html#ixzz1G1TBg8gt