Thursday, November 25, 2010

Executing Javascript in an ADF RC Page from a backing bean method

ADF lets us do some pretty wild things and one of them is the ability to easily inject Javascript into a page from a backing bean method and execute it. For example, from the action assciated with a command button, to run run a simple JavaScript the only code required is
FacesContext fctx = FacesContext.getCurrentInstance();
StringBuilder script = new StringBuilder();
script = script.append("alert('Hello World !');");

As can be seen, the backing bean code for executing java script in an ADF page is very simple and makes use of the ExtendedRenderKitService from the Trinidad codebase. The approach becomes very useful when you need to generate dynamic JavaScript to inject and execute it in a page at runtime.

Monday, November 22, 2010

Executing EL expression for a method from a backing bean

In ADF we use expression language(EL) a lot when developing declaratively. At times though, we need to override or more likely, enhance the default functionality, by wrapping the the out of the box functionality with some extra code. A common case is when you have a button or action that is bound to an operation, on the data control though EL, and you want to invoke a backing bean before executing the binding. Inside the backing bean method,  after doing whatever that needed to be done, to invoke the actual server side functionality you can use the same EL that was bound by creating a method expression and invoking it. So to invoke any operation on the DataControl, like Commit, or Create or CreateInsert, from a backing bean using EL, you can create a helper method like this :
public Object invokeMethodExpression(String expr, Class returnType,
                                       Class[] argTypes, Object[] args)
    FacesContext fc = FacesContext.getCurrentInstance();
    ELContext elctx = fc.getELContext();
    ExpressionFactory elFactory =
    MethodExpression methodExpr =
      elFactory.createMethodExpression(elctx, expr, returnType, argTypes);
    return methodExpr.invoke(elctx, args);

and invoke it like this :
String expr = "#{bindings.CreateInsert.execute}";
    invokeMethodExpression(expr, null, new Class[]{}, null);

The method uses the createMethodExpression method from ExpressionFactory. Read the javadoc to see how to pass arguments to the method.
This way, you can easily wrap the built in operations on a data control with your own custom code.

Monday, November 15, 2010

Printing in ADF, the <af:showPrintablePageBehavior> and showing the browser print dialog

ADF comes with a couple of rather easy to implement options for printing and rendering printable pages. The most obvious one is the <af:showPrintablePageBehavior/>. As the document describes, this renders the page without any command components, and as such will look better on paper. The big drawback however is that this is just the same page rendered differently. What if the actual behavior you need is to open the print dialog of the browser ?
There is a javascript function in the ADF client side API hat you can use to do exactly this. The function is simply self.print() and it opens up the browser's print dialog.

To use the function, just drop an tag into a command button like so :

The corresponding code in your jspx/jsff would be :
<af:commandToolbarButton text="show print dialog" id="ctb2">
    <af:clientListener method="self.print" type="action"/>

And of course you can use the self.print()function insde your own custom java script that ou embed with the af:resource tag. The downside of this approach is that what you see is what you get.
The page is sent to the printer as is, Its not specifically made "printer friendly" by removing CSS and command buttons that the <af:showPrintablePageBehavior/> does .

The <af:showPrintablePageBehavior/> approach would be :
<af:commandToolbarButton text="show printable page" id="ctb1">

Friday, November 5, 2010

Bookmarking Taskflows in ADF / Accessing ADF Taskflows by URLs

The problem

I need to bookmark or deep link a page in an ADF application, either to save a link to the page or share the page by email or other means. Unlike a normal web-app, JSF does not play well with bookmarks, but ADF comes bundled with (somewhat limited)support for doing this. This sort of a requirement is common when we need to include an application link in a generated email report to enable to user to see additional interactive information or to secure the information itself by sending not the report but just a link to it, so that he user will authenticate before accessing the information.

The solution

ADF has bookmark support for pages in the unbounded task flow, so we take a look at how the bookmark attribute works and how to use it. The built in support has limitations in that only pages in the unbounded taskflow can be bookmarked, and at times we would want pages within a bounded taskflow to be bookmark-able, so we take a look at a method for bookmarking/deep-linking a page within a bounded taskflow.

Bookmarking in the unbounded taskflow

The following example of the out-of-the-box support for bookmarking is based on the standard Oracle documentation here.

You start out with a standard app, in this case a page that lists  the departments in the HR schema and a second page that displays the details of  the staff in a given department. We need to make this second page bookmark-able, i.e. we need the ability to directly give a URL with parameters and pull the staff information of the department that we use as the parameter in the URL. The taskflow is simple and is shown below.
click to enlarge

You can download the full example for the complete code, but the essentials of the example are these :
  • The first page lists the depatments table, and the second page gets the staff details for a specific department 
  • The second page is using a sql query (ViewObject) that has the departmentName as a bind parameter.
  • You have the first page(welcome) with the department list(from DEPARTMENTS table in HR schema) displayed on a table, and each row has an <af:commandButton> that has its action attribute set to a navigation rule that directs the flow to the staff details page.
  • The  <af:commandButton> also takes care of passing the parameter to the details page.(code below)
click to enlarge

 Now, for the purpose of the example, the command button has an action listener that is bound to a custom method on the AM that takes the department name as a method parameter and executes the Staff Details VO(this dept name being a bind param for the VO). An <af:setActionListener> sets the dept name corresponding to the button in to a backing bean property. Then in the pageDef for the Department page, an operation binding for the AM method(via DataControl) created and is configured to pickup the backing bean property as a parameter to the AM method. So when the button is clicked: 
  1. The <af:setActionListener>  copies the respective department name to a backing bean property 
  2. Then the actionListener for the button fires executing the method binding, 
  3. The method binding takes the department name from the backing bean property(set in step 1), and uses it as a parameter to the AM method. 
  4. This AM method in turn executes the StaffdetailsVO binding the given department name to it. 
  5. Now the staff details VO contains the staff information for the given department. 
click to enlarge

AM Method - click to enlarge

Then, since the action attribute of the command button was set to a navigation rule to the staff page, the Staff Details page loads displaying the staff VO that has been executed already.
click to enlarge

This is the basic working of the example app. Now for bookmarking, we need the ability to extract the URL parameter from the URL and execute the StaffDetailsVO when loading the Staff Details page. ADF provides exactly this.

In the unbounded taskflow, open the property inspector for the view activity representing the staff detail page(Click on the StaffDetail ViewActivity) and you can see there is a properties section for bookmarking. 
click to enlarge

Here you will see the URL parameter name and value. They basically mean that the framework will take whatever value is in the URL for the given name, and it will populate that value to the destination. The optional method property lets you invoke a custom method after the values have been processed and before the page is loaded to do custom processing, like execute a VO with the param we get  from the URL !      

In this case, name is set to “dept”  and value is set to #{pageFlowScope.deptDetails.departmentName}, which is the departmentName property in the backing bean. So essesntially what the framework does is look at the URL for the parameter named “dept”, take the value for tht parameter and populate the value to the backing bean property . Now we also have a custom method defined as #{pageFlowScope.deptDetails.loadDepartmentDetails} which is a method defined in the backing bean as:

click to enlarge

Since the above method is invoked after processing the parameters, the departmentName property of the backing bean has been set to the value specified by the URL param “dept”. So the call to getDepartment will return the department name that was passed though the URL. The rest is like clockwork, we get the same method binding and execute it. Its worthwhile to note here that the method binding here is created on the Staffdetails page’s pageDef and defaults to the backing bean property departmentName for the department name parameter it needs to execute the Staffdetails VO. So setting the operationBinding parameter manually in this method is not required and is shown for demonstration.

Bookmarking in bounded task-flows
Bounded task-flows are a little bit more tricky and before we dive in to the implementation, consider this: When we say URL accessible, we are essentially saying a publicly available resource reachable by a URL, whereas a bounded taskflow is like a component, which needs a container. So we need a way to make the hidden innards of a bounded taskflow accessible in the form of a URL, with optional parameters. One way to do this to setup/construct the state for a page in the bounded taskflow based on the parameters in the URL that we’ll use. Since pages in bounded taskflows cannot be reached directly(actually they can, but the URL is not human readable and is very snarly) the approach here is to create a "container" page in the unbounded taskflow, and embed our bounded taskflow inside the container as a region. Then we will make that "container" page bookmark-able as described above. This way the clients will always see the "container" page's URL  which would be nice and simple too. The bookmark-able page takes the URL parameters and passes them to to the taskflow as taskflow params and the task flow will be constructed so that it can recreate state based on the input parameters. Bounded taskflows do have a property called URL invoke. This enables the taskflow to be invoked with a URL, and is a good option when you want to expose the whole taskflow to be URL accessible, not just a page within the taskflow. We will not look at this option as we are trying to gain access to a specific page/part of a taskflow without going though the taskflow’s normal flow.

About the example
As the example, we’re going to do the exact same app as before, but time as a bounded taskflow with parameters. In the example, we will see the whole flow implemented, from search and details, and this is not necessary in most cases where you want to make a single page of your application bookmark-able/linkable. This is more of a pattern that I have found that will save time, and keeps code consistent. Develop the whole taskflow as bounded and provide the extra “hooks” to parts of your bounded taskflow from the unbounded one. This way, you can reap all the benefits of a bounded taskflow (like reusability, security), and the taskflow consumer can expose parts of the taskflow as URL accessible.

First we design the bounded taskflow. Since this taskflow takes parameters, the taskflow parameters and properties can be set in the property inspector by clicking on the blank area in the taskflow diagram.
click to enlarge

The taskflow starts with a router which decides which page to see. although this is not required, it demonstrates an approach for structuring task flows that are built for URL accessibility(see the “about the example” box note). The important part is the taskflow parameters, as you can see from the property inspector image above. We’ll see how these parameters are passed to the task flow later on. The router looks at one parameter(viewMode) to decide which page page it wants to show. In the example, it is always the StaffDetails page. Once it determines that the details page is to be loaded, it then invokes a MethodCallActivity, passing the second input parameter, which is the deptName, to the method.
This MethodCallActivity has a page definition/ binding container so that it can invoke the AM method to execute the Deatils VO by passing in the dept Name. To open this pageDef file, right click the MethodCallActivity and choose "Go to Page Definition". Once the VO has been executed, the method call outcome loads the StaffDetails page which simple displays the executed VO as before. To make the page URL accessible, we put a “hook” page in the unbounded taskflow that is Bookmarkable and captures the URL parameters. 
click to enlarge

This page contains the bounded taskflow as a region and passes the URL parameters to the taskflow though the page’s pageDef/binding container.
click to enlarge
Well that's it. You can download the sample workspace with both approaches here:
[Built on Jdev, HR schema]
To run the example
You can run

  •  welcome.jspx file to see bookmarking in unbounded taskflow
Once the page is run, for URL accessibility you can use URLs of the form :

You would also notice that when using "Staff Details" button on the welcome page to navigate to the details page, the URL in the browser contains the parameter. Thats right. The name and value pair that was configured works both ways. When navigating to a bookmark-able page, the URL is constructed based on this name/value pair by evaluating the value and putting it on the URL as a named parameter. Just the way the same value is extracted from the URL.
  • BoundedFlowContainer.jspx for the bounded task flow technique 
The example wont display anything by default, unless you put a deptName named parameter on the URL.
Once the page is run, for the bounded flow you can use the URL of the form :
http://<host>:<port>Bookmarking_with_ADF-ViewController-context-root/faces/BoundedFlowContainer?deptName=IT (or any other dept name)