Thursday, August 23, 2012

Designing Modular Applications By Using Dynamic Task Flow Call in Oracle ADF

You might already asked yourself a question like this: How to design an application in a modular way? The principle of "Divide and conquer" helps us to get a complexity under control by breaking possibly complex system into a smaller manageable pieces a.k.a. modules.

This blog post shows how the features of ADF Framework like Dynamic Task Flow Calls, ADF Libraries together with JSF2 Bean annotations can be combined to achieve modularity on a View-Controller side.

The sample Application, available to download and run in JDeveloper R2, includes two projects: ADFDynamicTaskFlowSample and UtilityTaskFlow.
There is one bounded flow in each project:
main-task-flow-definition.xml and utility-task-flow-definition.xml

Loose coupling at design time


The Project UtilityTaskFlow is aimed to simulate a module encapsulating some piece of functionality. The module is  packaged as  jar and is being consumed (as jar on a class path) in a project  ADFDynamicTaskFlowSample like this:

There is no "hard" reference to our module in a consuming task flow main-task-flow-definition.xml at design time:
Notice the message in JDeveloper complaining that a reference utilityFlowReference is unknown. Actually the message states that almost everything regarding a module is "unknown". It should be ok -  we know, that the implementation will be available at runtime - we put it on a classpath :)


The consuming task flow main-task-flow-definition.xml  consists of two page fragments ( main1 and main2) and one taskFlowCall activity (utilityFlowCall).  Our module gets activated on a transition between two pages.

The sample use case is very simple:

  1. Some value entered on a page fragment main1 gets passed to a utility task flow (module).
  2. The value gets modified in a utility task flow (utilityFlowCall)
  3. The result of modification is displayed on a main2 page.
Let's start the  ADFDynamicTaskFlowSample (run home.jsf)  to see it in action.

Loose coupling in action


The first page fragment (main1.jsff) shows up.
We enter some value, like 'ADF' in this picture, and click on Next. Utility task flow gets activated:
We simulate some utility functionality by modifying the text a little bit to fit a scope of this blog post:
We click on Next - a utility flow is finished - it returns a result of our efforts to the consuming flow. The result gets displayed on a page fragment main2.jsff:
I think it should be enough to get the idea. It's time to have a look at the details now.

Defining the interface 


A quote from a definition of loose coupling: "In computing and systems design a loosely coupled system is one in which each of its components has, or makes use of, little or no knowledge of the definitions of other separate components".

What kind of little knowledge is needed in our case?

The Dynamic Task Flow Call activity in ADF requires to provide a Dynamic Task Flow Reference:

Therefore, the expression #{utilityFlowReference.flowId} is a first part of our conceptual interface: we defined, that a module being consumed must be a bounded ADF Task Flow, must identify itself by a name utilityFlowReference and must provide the reference to some implementing task flow as TaskFlowId.

The second part of our interface is defined in a section Parameters of task flow diagramm:
Our components should agree also about an input and return parameters and values in order to be able to  collaborate with each other a meaningful way.
In the second part of our conceptual interface we define that our utility flow should have on input parameter, named inputParameter and one return value, named returnValue.

Definition of our conceptual interface is finished.

Note: There is also an implicit agreement in place - about the types used for input and return, in our case it is String.  Consider using a composition by defining custom types for input and output messages to accumulate the data specific to your application domain. 

Implementing the interface


The conceptual interface is implemented in a project UtilityTaskFlow:
Essential  parts (actually all parts) are the class UtilityTaskFlowREference.java and a bounded task flow utility-task-flow-definition.xml.

A complete source code for the class shows implementation details of the first part of our conceptual interface (the name utilityFlowReference  and task flow Id)
And the section Parameters of the bounded task flow utility-task-flow-definition provides the second part of it (one input parameter, named inputParameter and one return value, named returnValue):

The utility flow looks like this (one page fragment utility.jsff and two task-flow-return actions):

Finaly a fragment of utility1.jsff for the sake of completeness: A value of input parameter is bound to inputText and is copied to return on a button click.

Note: please refer to a broad range of resources and tutorials available in case you just starting with ADF  and particularly with ADF Task Flows.

Packaging the module


The Project UtilityTaskFlow is packaged in JDeveloper as ADF Library jar like this:
 Create Deployment Profile in JDeveloper:

Deploy to ADF Library Jar file:
We get utilityTaskFlowADFLib.jar as a result (in less than one second :) containing our module:

Our module is finished and ready to be used where needed.

Conclusion


At this blog post we looked at a modularity aspect of  ADF application design.

ADF Task Flows, Dynamic Task Flow Call  together with JDeveloper ADF Library packaging facility facilitate the design an implementation of  modular enterprise applications.

The interface used to stick our modules together is a "virtual" one: it consists of a few design decisions and naming conventions.  Modularity efforts for a java platform might result in a standard way of building a modular applications one day.

Feel free to take sources of this sample at github to find out how the concepts and techniques described and used in this blog post can fit to your needs now.

No comments:

Post a Comment