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.