Sunday, February 13, 2011

ADF Region Communication - Region Refresh Through Contextual Event

I will extend previous sample application - ADF Region Communication - Data Exchange Through Shared Data Control Java Class and will describe how you can enrich it and apply contextual events. Even you would think about contextual events as about something cool, be careful - its not a panacea for all problems, and should be used carefully to avoid system architecture complexity explosion. While its not always true, I would prefer to use contextual events mostly for dependent region refresh, without passing payload directly. When system grows, its easier to track data references from Data Control Java class (see referenced blog post above), than contextual events payload variables. Its possible to refresh dependent region through ADF bounded task flow parameters - but contextual events provide better separation level between two regions.

Download sample application - ADFRegionCommunication2.zip. Two regions are implemented - Jobs and Employees:


Based on user selection, second region is refreshed - rows for selected job are highlighted:


If selection is changed, dependent region is refreshed as well:


As in previous blog article referenced above, user can insert new row - CreateWithParams operation will get JobId selected from the first region:


JobId data is passed as before, through Data Control Java class. Region is being refreshed through contextual event. This event (jobIdSelectionEvent) is generated on row selection and is triggered from table selection listener method:


Event (jobIdSelectionEvent) is declared in page definition file for Jobs region:


Main page provides contextual event mapping between two regions - producer (headerflow1) and consumer (detailflow1):


Finally consumer region assigns contextual event to be handled by refreshDetailTable method:


This method is coming from managed bean associated with consumer region:


In order to be able to map this method from consumer region page definition, you need to create Data Control for managed bean class:


It is good practice to generate Data Control for managed bean from early beginning, while there are ADF classes declared yet. Otherwise generated Data Control will include attributes from ADF classes and will be unnecessary big. There is no option to deselect class objects from being included into Data Control.

Row color is controller by expression language, we are referencing Data Control Java class to retrieve current selection from header region and compare it with each row value from detail region:

25 comments:

Anonymous said...

Hi Andrejus
Is it possible to refresh ADF regions on multipe user sessions? For example if two users are on the same page and of course in different sessions. On one user selection I want to be able to refresh the second region on both the user sessions.
Thanks
KK

Andrej Baranovskij said...

Hi,

Only if you will store changed data into data base and then will use ADS (Active Data Service) to get these changes automatically for another user.

Andrejus

Anonymous said...

Hi Andrejus
Interesting. With ADS I assume I can only refresh the data pieces or can I also push updates and have UI elements react?
Thanks
KK

Andrej Baranovskij said...

Hi,

ADS works for those ADF Faces components:

activeCommandToolbarButton
activeImage
activeOutputText
table
tree
All DVT components

Andrejus

Anonymous said...

In this post you created a data control for a managed bean. Does that imply that the same object would be used in each instance? I have a business service (local, not ws) that I need to use application wide, but I cant figure out how to pass constructor arguments or managed properties to it, while still using it as a data control. Any tips?

Andrej Baranovskij said...

Hi,

DataControl is shared across objects in the same session.

Andrejus

Anonymous said...

Ok. However, can you set properties of the data control via a managed bean in adfc-config? I.e. does ADF consider the managed bean and the data control the same object? I think Ive tried this and it does not work. What I'm trying to do is pass arguments to my java bean data controls when they are instantiated.

Andrej Baranovskij said...

Its separate objects. Pass data through Data Control method.

Andrejus

Anonymous said...

What if the data control needs the data in the constructor. ie the data control is a thin wrapper around a service that needs to be configured before it is used.

My current theory of doing this to have the data control grab an application scoped bean from the ADFContext. However, when the data control is first instantiated, the application scoped bean does not exist, and ADFContext is returning null.

Is there any other way to get configuration data into the data control?

Andrej Baranovskij said...

I would suggest to use ADF Task Flow approach and implement default method call, same as ADF Task Flow init activity. This will act as a constructor.

Can it work for you?

Andrejus

Anonymous said...

Hi Andrejus,

Could you please post an example of how to use ADS?

Thanks in Advance.

Bharath

oceans said...

Hi
andrejus,

Thanks 4 a great tip up there,

I have a scenario where I have a parent page which is more like a dashboard where I have four regions which shows data for monitoring purpose of different reports of the application.

* All there regions are put inside a panel Box with the command link to refresh the data in the regions.
* The regions are dynamic regions where different task flow are assigned at runtime governed by their backing bean TaskFlow Id's (No input parameter for taskFlows).

The problem I face is, I am able to restart the taskFlows in the regions to their default activity by hitting the refresh the link using this small piece off code.

BindingContext bctx = BindingContext.getCurrent();
BindingContainer bindings = bctx.getCurrentBindingsEntry();
DCTaskFlowBinding taskflowBinding = (DCTaskFlowBinding) bindings.get("dynamicRegion2");
taskflowBinding.getRegionModel().refresh(FacesContext.getCurrentInstance());

But the iterators in the page fragments of the task flows are not getting me the fresh values in the DB, instead they give me the values that are fetched during the initial loading.

So can anyone kindly tell me how to refresh the regions from the parent page such that it refresh's the taskflow and get a fresh values from DB very time it loads.

Thanks and Regards,
Vijai

Andrej Baranovskij said...

Hi,

May be this post will help - http://andrejusb.blogspot.com/2010/02/dynamic-dashboard-ui-shell.html

Andrejus

oceans said...

Hi Andrejus,

Thanks for ur relpy,

All ur recommendations are to refresh the region say by setting the refreshCondition to true, taskFlow parameter change to refresh, Contextual region refresh etc. All these are right unless and until they make sure that the iterators get the fresh value from DB every time they refresh right (As for my requirements).

So is there a way to make dame sure that the iterators in the page fragments are refreshed when the region is refreshed. Cause I tried quite a few way. All off them were not consistent always. Or some other consistent workaround way to meet my requirements.

Andrej Baranovskij said...

Yes, you need to have Method Call in TF initializer, this call should take care for iterators refresh.

Andrejus

oceans said...

Hi Andrejus,

Thanks again,
I fell this will work... But like clear what I understood actually....

U mean to say like the method called by the TF initializer should programmatically find all the iterators in the TF's page fragments and refresh them right ?
If so what is the best way to get all the iterators.

Andrej Baranovskij said...

Its only one of the ways, I cant suggest 100% correct approach without working on your project. You should try and test.

Andrejus

ಆಶ್ವಿನ್ ಆಲ್ಮೆಡ (Ashwin Almeida) said...

Hi Andrejus,

You have said it better to create datacontrol. My Question is what is the diffrence between using Datacontrols & Managed bean (Directly without creating a DC ). Are there any pro and cons of this approach

Andrej Baranovskij said...

Yes, definitely. With managed bean, you would need to declare it in Session scope to pass data. This means application will not work in browser multitab environment. While Data Control objects are not shared between browser tabs.

On other hand, from architecture point of view - in ADF its better to access business objects through standard Data Control, instead of directly.

Andrejus

BradW said...

Hi Adrejus. Will this approach work with the UISHell pattern? Would we have to define all the various mappings in the UIShell page or part of the template?

Thanks,

Anonymous said...

Hi Andrejus,
Will contextual events work for the interaction of 2 regions, both of which are in different tabs of the same parent page.Each of the region is active only when the user clicks on the respective tab.

As per my understanding, since the second region's binding container is not active when user does some active in first region, contextual events in this case wouldn't work.Please correct me if am wrong.

Regards,
Ann

Andrej Baranovskij said...

Hi Ann,

Unless you set region activation property active="immediate". With this setting, region should be activated, even tab was not opened yet. However, this is not performance effective.

If regions are in different tabs, I would say Contextual Event is not needed at all. You could simply set Refresh = ifNeeded property and pass parameter into TF (make sure to change it, when you want to refresh). In this case, region from second tab will reload by itself, when parameter will be changed.

Andrejus

Anonymous said...

thank you for the prompt reply, Andrejus.

regards,
Ann

Rakesh said...

Hi

Can we use a task flow inside af:iterator to show multiple regions @ runtime by passing iterator value as input parameter to region?????

Andrej Baranovskij said...

Yes, you could use multiTaskFlowBInding - http://andrejusb.blogspot.com/2011/11/building-custom-ui-shell-with-adf-11g.html

Andrejus