Dive into Oracle ADF

Send me a mail
 Dive into Oracle ADF   Click to see the XML version of this web page.   (Updated: 9/2/2009; 2:12:45 AM.)
Tips and tricks from Steve Muench on Oracle ADF Framework and JDeveloper IDE

Search blog with Google:
 

Search BC4J JavaDoc:
 

August 2009
Sun Mon Tue Wed Thu Fri Sat
            1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31          
Jul   Sep

Get Firefox!

The views expressed on this blog are my own and do not necessarily reflect the views of Oracle.

Thursday, August 20, 2009

The latest maintenance release (10.1.3.5) of JDeveloper 10g is now available on OTN. Peruse the fix list at your leisure.


8:07:02 PM    



We added the createRootApplicationModule() API (in the oracle.jbo.client.Configuration class) to simplify acquiring an application module from the pool for brief programmatic manipulation before it is released back to the AM pool in unmanaged/stateless mode by a required call to the corresponding releaseRootApplicationModule() API. This simple method is a two-edged sword, however. It makes its intended use case very easy to accomplish, but frequently I'm observing that its ease of use tempts developers into using it incorrectly.

The context where I see this method most commonly misused is in JSF backing beans. Developers think, "I need to invoke a method on the client interface of my application module", and often the first thing that pops into mind for how to access an application module instance is the Configuration.createRootApplicationModule() API. However, this method should never be called from a backing bean. The reason it should not be used is that it leads to creating additional application module instances which are distinct from the AM instance that is automatically checked out and checked in for you by the ADF data binding layer for use by your UI pages and task flow method call activities. At a minimum, this can lead to an incorrectly functioning application (when the custom code you run actually happens on a different AM instance that the one your UI page is using) or at worst can least to performance and memory problems if your backing bean code calls Configuration.createRootApplicationModule() without ever calling releaseRootApplicationModule().

So, to reiterate, never call Configuration.createRootApplicationModule() in a backing bean.

Instead, to invoke a client interface method on an application module, view object, or view row, you should use a ADFM action binding to invoke it declaratively instead. This way requires no code, often obviating the need for any backing bean in the first place. If you do need to write some custom backing bean code (for example to perform programmatic manipulation of UI components before or after invoking the client interface method), then your backing bean code should exclusively invoke the client interface method on the application module using the action binding. One key reason to use the action binding even from your own custom code is to ensure that any exceptions are handled in the same, consistent way as if ADF had invoked the method declaratively.

You should ensure that your backing bean is invoked in a context where a pageDef has been defined (for example, the pageDef for a page or pageFragment, or the pageDef associated with a task flow method call activity), and then your backing bean code can invoke the method action using code like this:

public ... yourBackingBeanMethod(...) {
  /* Custom code before invoking the method action goes here... */

  /* Get the current binding container */
  BindingContainer bc = BindingContext.getCurrent().getCurrentBindingsEntry();
  /* Lookup and invoke the action binding named "yourMethodName" */
  bc.getOperationBinding("yourMethodName").execute();

  /* Custom code after invoking the method action goes here... */

}

The "yourMethodName" above is the name of the action binding (also called an "operation binding" in JSR 227 parlance), which the JDeveloper 11g design time typically creates with the same name as the method being invoked. The BindingContext.getCurrent().getCurrentBindingsEntry() accesses the current binding container without having to parse the EL expression "#{bindings}", and then the getOperationBinding() method looks up the action binding by name, and the execute() method invokes the binding. The above works great for a void method being invoked (with no return value), but if you are calling a method that returns a result and want to work with the result, just change the code to look like this: this:

public ... yourBackingBeanMethod(...) {
  /* Custom code before invoking the method action goes here... */

  /* Get the current binding container */
  BindingContainer bc = BindingContext.getCurrent().getCurrentBindingsEntry();
  /* Lookup and invoke the action binding named "yourMethodName" */
  Object retVal = bc.getOperationBinding("yourMethodName").execute();

  /* Do something with 'retVal' here */

  /* Custom code after invoking the method action goes here... */

}

Section 9.10.3 How to Access an Application Module Client Interface in a Fusion Web Application in the 11g R1 developer's guide explains a technique for accessing the AM client interface directly by accessing the data control from the method action and calling the getDataProvider() on it to cast the AM instance to its client interface. However, I'm working to get that documentation section changed to reflect the advice above since invoking the client interface directly does not handle exceptions in the same consistent way (using the ADFM Exception Handler described in section 27.9 Customizing Error Handling of the dev guide).

In the case of an ADF Task Flow method call activity, the easiest way to invoke a custom method exposed on one of your component's client interface is to simply drag that method from the Data Control Palette and drop it onto the method call activity. No backing bean needed. If you do need to augment the method call with some custom code, you can first do this drag/drop operation, then adjust the method call activity to call a backing bean that used the technique described above to perform custom code before and/or after invoking the method action.

A note for developers using JDeveloper/ADF 10.1.3: The BindingContext.getCurrent().getCurrentBindingsEntry() call is new in 11g. In the 10.1.3 release you can follow the above advice but will need to access the binding container by evaluating the "#{bindings}" expression, perhaps using some helper code like the EL.get() method from my favorite EL helper class.


7:14:36 PM    


© Copyright 2009 Steve Muench.