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:
- Some value entered on a page fragment main1 gets passed to a utility task flow (module).
- The value gets modified in a utility task flow (utilityFlowCall)
- 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.