Tuesday 17 November 2015

region refresh after a button is clicked

Lets begin with an use case - I have got reusable taskflow which is drag&dropped on a page as a region. It should be refreshed each time the button is clicked. Easy? Easy!

To explicitly check if task flow is refreshed, I've used System.out stream to log messages. Whole initial implementation (bean, view activity, task flow diagram, bean definitions and the test page itself).






I'd like to have test message logged each time a button is pressed. It can be done with a lot of java code, but I won't write any java code more than test method. I'll print screen actions performed to implement the requirement.





What has happend? Step by step. First of all I need to have something which gives me more or less a random value. A value which will change on each request. Defining java.util.Date as a bean in the request scope in adfc-config.xml file I have got ability to get current date in EL expression. Inspiration can be found on one Duncan Mills post.

My reusable task flow must be extended with additional input parameter. I've named it refreshIndicator and marked it as mandatory. But it can stay optional too.

Changing task flow interface, each page definition must be updated with the new parameter. But do not set it with #{now} expression. I've used pageFlowScope memory to store the "random" value. Request scope is too low - the page or the region can invoke multiple requests during its lifetime. And the requirement was to refresh it only after a button is clicked.

The second change in the page definition file is value of task flow Refresh attribute - IfNeeded means that a task flow must be refreshed if any binding parameter value is changed. In this case if refreshIndicator parameter is changed.

So the last step is to update #{pageFlowScope.param} with #{now} value after a button is clicked. The easiest declarative way is af:setPropertyListener. And that's it. Below is the result:


Tuesday 6 October 2015

High Available (HA) checklist for ADF applications

Making ADF application HA enabled, there are two groups of actions that should be performed. One is the configuration and the second is the development part of work. Below you'll find my checklist:
  1. in adf-config.xml descriptor put code <adf-scope-ha-support>true</adf-scope-ha-support>
  2. in weblogic.xml descriptor set session persistent store type as REPLICATED_IF_CLUSTERED
  3. each application module must have jbo.dofailover attribute set to true
  4. if you're using POJO DataControls, you need to implement three methods there: createSnapshot(), restoreSnapshot(Serializable handle) and removeSnapshot(Serializable handle); more about that here: Creating and Configuring Bean Data Controls
  5. each bean defined in the memory scope higher than request level must implement java.io.Serializable interface
    • avoid using java transient keyword regarding to the bean attributes
    • each attribute that extends UIComponent aren't serializable! if UI component must be binded with the code, use org.apache.myfaces.trinidad.util.ComponentReference wrapper there
    • make the framework aware of changes that needs to be replicated against the cluster, mark the scope as dirty, ie. using ControllerContext.getInstance().markScopeDirty(AdfFacesContext.getCurrentInstance().getViewScope());
  6. each page flow and session attributes must implement java.io.Serializable interface
 As short as possible. Hope it'll be helpful :)

Thursday 16 July 2015

what is page definition scope? how many instances of the data controls will be created at runtime?

Asking question about pageFlowScope, sessionScope and others leads to one of the most important (in my opinion) graphs:

source:http://docs.oracle.com/cd/E24382_01/web.1112/e16181/img/lc_scope.png

What is worth to mention, applicationScope lives with an application within the JVM container. If you have clustered environment, you'll have at most one instance per node (lazy init principle).

Nevertheless, what is page definition scope or data control scope? How many instances of data controlls will be created in runtime? Quote from the docs:

"(...) the binding container, the binding objects it contains, and the values the binding objects reference are defined in session scope."

But it doesn't mean that there is equation one session == one binding container (data control instance). Please notice that ADF introduces taskflows and task flow transactions. If your application uses a lot of task flows as regions on one page and some of them are always creating new transactions (on the controller level), per each session you'll have more than one binding frame.

As a summary - from the time point of view, each data control instance (each binding container) will live as long as user session exist. From the instances count point of view, per each session you'll have 0..n instances of the data controls (depends on total number of used task flows on your pages, task flow transaction setting and the page definition contents).

Wednesday 17 June 2015

state machines validation using Groove expressions

Very often there is a business requirement that defines some kind of a state machine. Each business entity has its own lifecycle, it can be created, published, modified, archived and so on. Transitions between states are usually one way. If a bank transfer is complete it cannot be rolled back to the prepared state. In other words, it means that validation depends on new and old value of the same attribute.

Recently I've worked on such requirement and the validation have been implemented as valueChangeListener on af:selectOneChoice. There is simplier solution and development must be done in model layer. Reasonable because valueChangeListener is assigned to one instance of the attribute usage in the project. And such attribute may be used in various pages. And there is no guarantee that developers there know about such validation.

Because new value depends on the previous, it fits to other patterns as well. Employees in a company can have their salary attribute to be updated. But who wants to have the new salary lower than current? :) Nobody I think.

Please open entity Employees, select Salary attribute and specify new script validation rule:



Print command is just to log the new value in the JDev console. Further, specify the error message and run the example page:





Which is the most important here - Groove allows to refer to new and old values by using newValue and oldValue keywords.

Wednesday 6 May 2015

data controls refactor and MDS-00013 exception

There are a lot of questions about MDS-00013 after refactoring DataControl.dcx file - renaming or moving to other locations.

As a starting point I have got ViewController project with one page and custom Model project with sample POJO Data Control. A page is using specified DC by presenting collection as a read-only table.

My SamplePojoDataControlImpl.java class is defined in model package in Model project. After data control creation I've got DataControls.dcx file created in the same package in the same project. Just to make sure that it works fine I'm creating test page with drag'n'dropped read only table there. The project structure looks similar to the screenshot below:



The page works good, so lets change it. The best way to achieve it is to refactor it. I would like to move java class to model.java package and DCX file to model.dc package. Also i'd like to rename java file just to make it more complicated. I've used Refactor menu from the toolbar, so each important thing should be changed. OK, so run the test page one more time and...



an exception... I've digged the Internet for phrase:

oracle.mds.core.MetadataNotFoundException: MDS-00013: no metadata found for metadata object {0}

and the solution is not so obvious. The key to fix the issue is to understand the ADF descriptors. The files that are in the background, contain a lot of magic inside and nobody likes to mix with them too often.

Each project that has got data controls inside, has got such descriptors. DCs are defined in DCX file. Data control registers are pointed by adfm.xml descriptors. In my case after refactoring the project adfm.xml points correctly the register and DCX file points to renamed implementation class:



I'll revert the value of id attribute of AdapterDataControl node to avoid changes in other layers. But even so the result of running the page is the same - MDS-00013 exception is thrown.


So what else needs to be checked? There is CPX file which maches pages or task flow steps with their definitions (pageDefs). It also tells to the ADF framework which data controls are used in the projects and where are they located.


Please look carefully on the dataControlUsages node. There is one definition and a path attribute. From java point of view the path is correct. But the path is not a real path. It should point to the DC id in the registry. So proper value there is:

model.dc.SamplePojoDataControlImpl


Please run it one more time and... now it works as it should be!

Meanwhile please also check my other posts about validation and proxying web services for more details about usage of POJO data controls in your projects :)

Thursday 16 April 2015

useful tricks for ADF and services integration

Nowadays it's though to imagine an application that doesn't consume web services. In my previous post I've described how to add declarative validation on Data Control level. WebService Data Control have been the best example in my opinion. Now I would like to make a step forward about how to combine ADF and web services.

I believe that you have already watched ADF Architecture channel about services integration in ADF. Accodring to the architecture that Frank has described, you'll have web service proxy and kind of java facade. It helps to avoid UI changes caused by WSDL definition changes and gives a mean to cache the values. I assume that all of this is done. Let us explore POJO DC a little bit more.

The start point of this post is creation of transfer object and data access object: Person entity and PojoDataControlImpl class.


The second file is POJO DataControl implementation file. Having all this, please create the Data Control and a test page. Drag and drop persons collection as ADF Form and run it.




Let us focus on the first field which is age. Go to Bindings section and explore it. Right click on the collection in Data Control section. Click on Edit Definition.



What has happend? Framework creates XML file that corresponds with PersonEntity java class. Do you recognize the central part of JDeveloper? It is very similar to BC4J configuration wizard. And it allows to change it and use it in the same manner as BC4J entities. Please do some changes and run the page again.



The changes are applied to view layer by the framework. Nothing more to add. Need to iInternationalize your application? You've got model bundle file. Need to create new page? Just drag and drop attribute or collection and all of the validation, labels, read-only settings are applied.

Hope it is helpful :)

Wednesday 25 February 2015

validating attributes in pagedef's variables iterator

In the classic ADF stack validations are propagated from the model (entity) up to the view (pages). It is easy. Harder task is when DataControl is based on other type of data source - web service, JMX or just POJO. I'll use Java class to describe how validation can be added in easy, declarative way. First of all setup of the application - implementation and Data Control:





The simplest possible Data Control is there. Now the sample web page:


Now drag and drop the method invocation as ADF Parameter Form, leave defaults:




If we consider a validation flow, it goes through page definitions. How to practically mix with that layer? Please go to the page definition and check what has been created. In variables iterator there is one new variable defined. Select it and go to Property Inspector.


My artificial business requirements specifies that field as mandatory, at most 8 chars and only letters. Above I've implemented two of them. How to handle third one here? Select the node in the Structure window and right click on it:



Fulfill the pattern and run the application. With "test" and "test2" options.