Tuesday, December 25, 2012

Contextual Event - Interface based Consumer - NO DataControl Yey!

In my last blog, I showed how using an interface as a parameter will allow you to decouple your ADF beans even more.

A couple days before Christmas, somebody in EMG forums asked about ADF utilizing too many pageDefinition files. This led me to a link by Steve Muench's blog #164 - His example basically demonstrates how you can have a manage bean be defined as an instance method in your pageDefinition.

So this gave me the idea to upgrade my earlier blog to use this so that we will ultimately clean up the amount of files generated in our project.

I highly recommend to go through my previous blog since it involves showing the invocation and the initial use case of the listener interface. This time though, I'll be showing the handler interface.

First create an interface which our bean will implement. This interface will be defined by the requestScope bean which will represent the instance name of the pageDef. If you notice in Steve's blog, he pointed out how to use this method binding properly, the instance name has to use the $ notation for its EL Expression oppose to the normal # (I'm still looking for more resources to explain this) - just in case, this means you can't use ${requestScope.<Bean>} you have to call it ${<Bean>}.

Interface Handler

Uhm.. the request scope part is only because there is no point using a bigger scope for something that is only used as needed.

Request Bean

So here's the screenshots.

Event Mapping - pageDef
And just in case you're curious which lifecycle it lands, here's the console logger of the lifecycle.

Invoke Application Phase

Monday, December 10, 2012

Contextual Event - Interface based Consumer

It's no excuse to skip blogging all year but since it's not yet the end of the year, I still have enough time to post one last hoorah for 2012.

And to keep up with all the trend about contextual events, I've decided to publish an article in utilizing contextual events into an Observer Bean design pattern.

A bit of disclaimer here, I only came out with this idea while eating pizza and wondering why I can't publish a pizza order online and have any pizza company in the vicinity to cater it. All this happened an hour ago so I apologize for any small implementations I might miss... but I'll try to be brief and precise as always... moving on!

So, to start with - I'll assume that this is already the n-th time you've read contextual events. If not, I would recommend going through the online Oracle documentation, a couple blogs by some google'able ADF authors (F.Nimphius, A.Baranovskis, and etc.).

I do want to thank Jobinesh for pointing out a cool implementation in invoking contextual events. There are a couple of ways to invoke it, but I really like this one, particularly because it actually has a "contextualEvent" keyword in it. Why I like it? Well it's because of readability, and in the programmatic world - readability is key. Well good-code > readability > less-code.

I've setup a starting project that runs with a single entry point page (mainIndex.jspx).

The mainLayoutRegion is a simple bounded taskflow that has one fragment called mainFlowFgmt.jsff. This fragment will be our main fragment that wraps other regions as defined in the project structure. Please refer to the project structure as reference to the defined region.

BoundedTaskFlows: main-layout-flow, sub-flow-alpha, sub-flow-omega


Project Structure

If I run everything, things will basically look like this (Take Note, I've labeled where the region starts).

Running Sample
So here's the plan:

  • Wire up (queue the event) from the two buttons defined in Alpha. Both events will be unique so that we can test a couple scenarios. (Haven't got the chance to code the 2nd event but you'll get the gist of it soon)
  • Both events will have a unique eventName with a no parameter definition (meaning no-payload).
  • Calling this event mockEvent!
  • Listen for the event in mainFlowFragment.
  • Listen for the event in mainIndex page.
  • Listen for the event in Omega region.
  • Use a common handler for all of these BUT each of these fragments's backingBean will be the listener to a common event handler.
  • Let me repeat that last one... Handler (DataControl) one-is-to-many Listener (Beans). 
  • One more time... One datacontrol method... many backingBeans listening and being utilized by the same datacontrol method in different levels.
Here's a utility that invokes/queues the event to start the bubble of the contextualEvent. Again, code is thanks to Jobinesh.

Going back to Alpha fragment. Here's the pageDef binding definition as well as the backingBean which invokes it.

Alpha pageDef - Contains the Event Declaration

Here comes the fun part. I'll define a class to represent the datacontrol handler for the event but this class will cater a listener interface (Observer) so that whenever there is a listening pageDef (consumer) I will be able to define a/the oberserver (bean/method) which will handle the event. I'll also show in the code, a single backingBean handling two consuming definition from a single event (whoo!).

Quick ADF talk here: To be able to handle/consume an event, an event mapping has to be made. Part of the event mapping is to define the consumer as well as the method binding to handle the event. This method binding is defined by converting a class into a datacontrol (more in the developer guide).

Technically, the datacontrol (class) will still be the real listener, but because I want to allow the interface to start with the beans rather than the main listener - I am going to distribute the event with the observing beans.

What's the advantage?
  • Beans will be well defined in the xml of the event map.
  • Bean methods can provide the interface. 
  • So yes, you can actually point to use the pageFlowScope or any scope beans in that taskflow to handle it without touching the datacontrol again.
Less talk more code.

Interface Class - MockEventListener.java

DataControl Class - MockEventHandler.java

And here's a sample mapping to my mainLayoutBb.

Event Mapping pageDef - Double Consumer Same Bean!!! Notice the value.

Two Anonymous Implementation of listening!

So far is it making sense? If not consider the Observable pattern in java and see if it explains the idea. To expand it a bit, we'll make the MainIndex.jspx have it's own backing bean and use the same datacontrol.

MainIndexBb.java (defined in adfc-config)

mainIndex.jspx PageDefinition

Here's the console output when I hit the event - I'm also printing the lifecycle so that you can see that the invocation is all happening in InvokeApplication phase. It is worth noting though that the order of the events can vary a bit. I'm still trying to figure it out myself - but then again it shouldn't matter because you shouldn't rely on the order of the queued events. All the events should be nothing but observing factors.

So real quick, I've show you how to use/define one datacontrol to cater several listening interfaces. This is basically an application of the observable pattern in a contextual event framework. Things to keep in mind is that all of these is happening in one request - so ideally you wouldn't want to place too much logic when listening to events because it can get really complicated really fast. You would also want to keep a solid event handler that you'll rarely change that's why keeping it interfaced is always a plus.

Saturday, May 12, 2012

Task to Refresh a Task Flow

First 2012 post I guess? Due to some really really busy time in the office, I have to apologize for not being able to blog for quite some time.

With that said, I recently notice how a lot of developers tries to play it safe when using Task Flows by sticking with the obvious. So, to start my 2012 blog, I am going to clear out one item in the bucket list of task-flow-bewilderness.

Task Flow Refresh

So the most obvious way of refreshing a task flow is based on the initial design which is:

"When there is a change in the data, the task flow needs to refresh."

Simple definition of terms.
Refresh - Restarts the task flow as if the entire flow was reentered from the start. That seems explanatory but trust me, such a word strives to be confusing at times.
TaskFlow Binding (TFB) - Page definition ADF task flow bindings.
TaskFlow == or === (in javascript) Task Flow - enough said.

Moving on.

The simplest solution for the above "dilemma" is to use the TFB's properties refresh=ifNeeded and simply feed the taskFlow parameters with the changing data.

As per ADF Fusion Middleware Documentation - 21.5.1 How to Configure the Refresh of an ADF Region .... well let's just test it shall we.

#1. Reconfig - Does nothing but hits an ActionEvent
#2. Reconfig-Refresh - Hits the ActionEvent but also changes a viewScope parameter
#3. Reconfig-Refresh-Again - Same as #2 with different value.

ToolBar Buttons

Initial Run
MainPage - Containing Region - PageDef

So yes everyone already knows what's going to happen. Since the variable is an input parameter, combined with refresh=ifNeeded then it will DEFINITELY restart the task flow.

So let's complicated things a bit by looking at it in a different requirement.

"When the data changes, not by something direct in the screen but rather as triggers in the data themselves, the task flow needs to refresh."

With that said, data is not the trigger, but the event is the trigger.

Ironically, I got a suggestion where all they'll do is do exactly what I previously explained earlier (with the refresh=ifNeeded) and simply send an Integer which increments on eventChange. Might fly... but let's try to find a more logical solution.

Which goes back to the ADF Fusion Middleware Documentation - 21.5.1 How to Configure the Refresh of an ADF Region.

Let's use the refreshCondition this time. The only thing with the refreshCondition that you need to be aware of, is that you would probably want to contain the implementation with its own bean handler/manager rather than mixing it with simply any available beans.

So here goes with the simple demo.

I'm still going to use the above mainFragment while simply using the boolean flag, and here's the new pageDef.

RefreshCondition Used
A boolean flag? In a backingBeanScope? Yes a boolean flag and yes in the short lived scoped. I initially tried it in a viewScope but with the simple way of changing a flag from true to false, why not go with something even more "compact". So here's the bean.

BackingBean - Handles Simple Refresh Condition

So what do we have here.. Bean does nothing but handles the refreshCondition of the taskFlow by always returning FALSE and only, ONLY TRUE once something tried to change it.

Since I have no better way of explaining this visually, I'll print the console of what we have. So what do we have, we have  a simple task flow with a finalizer and initializer and also an initial method call as entry point. Enough?

TaskFlow BackingBean

Simple TaskFlow Fragment
Here are the logs when doing anything but refresh:

----- DEBUG: Initializer Firing
----- DEBUG: Initial Task Flow Method Call
----- DEBUG: testReConfig -- This is the ToolBar ActionEvent
----- DEBUG: Checking isRefrehRegion[false]

And here's the log when I triggered the refresh:

----- DEBUG: Initializer Firing
----- DEBUG: Initial Task Flow Method Call
----- DEBUG: testReConfig -- This is the ToolBar ActionEvent
----- DEBUG: Checking isRefrehRegion[true]
----- DEBUG: Reconfiguring
----- DEBUG: Finalizer Firing
----- DEBUG: Initializer Firing
----- DEBUG: Initial Task Flow Method Call

There goes a technical 2012 blog!