Sunday, January 29, 2017

Contextual Event API Improvements in ADF 12.2.1.x

ADF 12.2.1.x brings improved API support for Contextual Event implementation - this should simplify Contextual Event usage. Now Contextual Events can be produced without referencing ActionEvent or SelectionEvent, also there is no need to define Data Control to implement Contextual Event handler. Read more in ADF 12.2.1.x documentation - 46.4 Creating Contextual Events Using Managed Beans. I will provide example and explanation how to use these improvements.

Download sample application - This sample is based on two isolated ADF regions - table and chart. When row is changed in the table, through table selection listener method I generate Contextual Event with Job Id payload and send it over, event is consumed in chart region and it allows to refresh chart by key:

Row is changed in the table - new Contextual Event is produced and consumed - chart is refreshed:

We should check in the log - it prints what happens from event initialization to consumption. This gives useful info to debug Contextual Event flow:

Let's jump into code of event producer - method for table row selection (JSFUtils helper method allows to execute table row selection event programmatically, just before producing Contextual Event, this allows to access information about current row). Event is constructed without any event definition in the bindings, directly using method action and event dispatcher API - we can pass payload information directly - no need to describe it in the definition (this is advantage, as sometimes payload definition expression could execute too late and payload could be empty):

Method action definition doesn't represent any real method, it contains event name and acts as helper for event producer:

Consumer region contains Contextual Event handler mapping - it specifies event name and handler info (this is same as before). There is no need to define handler through data control anymore. Method action points directly to the bean method, through instance name. Payload value is sent through using paramVal name and ${data.payLoad} expression:

Consumer receives payload and re-executes VO:

Sunday, January 22, 2017

SQL Bind Variable Support in ADF BC REST

Is not that obvious from Oracle ADF BC REST developer guide how to provide value for bind variable defined directly in the View Object SQL statement. I did research around this and would like to post few hints to make your life easier, if you have same requirement - pass values from REST request to View Object required bind variables. This topic is especially useful, when you want to reuse existing ADF BC implementation for ADF BC REST access.

We are going to use View Object Row Finder. Oracle ADF BC REST developer guide explains how to use Row Finder with View Criteria. In our case we have different situation -  we would like to use Row Finder for required bind variables, referenced directly in SQL statement.

You can't define Row Finder without View Criteria. First trick is to define empty View Criteria, just to be able to define Row Finder - we are not going to use View Criteria functionality, our bind variables are referenced directly in SQL WHERE clause:

Once Row Finder is defined, you are going to see bind variables listed. Keep in mind - this doesn't means bind variables are referenced by Row Finder, they are just listed for possible use. Now main trick - go and define some dummy expression for each bind variable you want to use in REST request (make sure to uncheck - Save expression to groovy file):

This action would generate Groovy expression for each bind variable and list these bind variables under Row Finder. Go to source of View Object to see the structure:

Now remove Groovy expressions assigned to each bind variable - we don't need them, keep only bind variable names assigned to Row Finder:

Visually in the wizard is going to look like there are no changes made - but we keep bind variables under Row Finder tag now:

Bind variables are included directly into SQL statement WHERE clause:

ADF BC REST service is defined in regular way, no special tips here:

This is how REST call looks like: Departments?finder=RESTFilter;depNameVar=IT.locIdVar=1700. We include Row Finder name and two bind variables with values:

In the background we could check ADF BC log, where it prints SQL statement with both bind variables assigned with values:

Download and browse sample application ADFBCRestApp from my GitHub repository - jetcrud.

Wednesday, January 18, 2017

Multi Language Support in Oracle JET

There is great post from Geertjan Wielenga about Translating Oracle JET Applications. If you want to introduce multi language support into JET app - this is great place to start reading from. We are building production Oracle Cloud app with ADF BC REST and JET. This app requires multi language support - English and Lithuanian. I will describe below how we integrated multi language into various areas in the app.

Download or browse through sample application in GitHub repo - JETPlaygroundApp.

In JET we could set default language in index page html root tag. By default it is set to en-US, but it can be set to lt-LT for Lithuanian language or any other language:

Translation texts are located in message bundles. There is one default message bundle for English and translations are located in sub folders. English bundle:

Lithuanian bundle with translations for the same message keys:

Multi language bundle support must be registered in main.js (bundle file name can be anything):

Values for all labels/texts must be defined as observables and initialised from JET translation API by passing message key - this will bring default text:

When language is changed, we need to update observable values and reset language value in HTML tag. I'm changing menu labels as well by re-configuring JET router:

On UI in index.html message key is referenced directly from observable variable:

We can access message key defined in appController from individual JET module UI through $parent. For example, I'm using dueDate message key in incidents module:

Same message key is reused in another module - customers:

This is how language switch looks on UI - language change is available in preferences:

When we switch to Lithuanian language - texts are changed (the ones assigned with translatable messages):

Menu labels are also changes, JET Router is reset:

Labels are change in built-in JET components - such as date. Though is not translated completely for Lithuanian language (Today text remains in English):

Saturday, January 7, 2017

Oracle JET Router API Example

One of the examples of JET Router API usage - sign-in/sign-out implementation. After sign-in we need to change menu structure and allow access to application modules, on sign-out menu structure should be changed again. JET Router API allows to manage application navigation and menu structure from JavaScript. Check complete API methods list here - JSDoc: Class: Router.

Sample application code is available on GitHub - JETPlaygroundApp. This application is generated with JET NavDrawer template and is runnable in NetBeans and from command prompt with Grunt. I was using such Yeoman command to generate it:

yo oraclejet JETPlaygroundApp --template=navdrawer

I have changed index page to stretch to entire width and hamburger button to be always available. This is how sign-in module looks like:

After sign-in, user gets hamburger icon to access menu structure:

Oracle Developer Cloud service UI looks similar, it also gets menu list on the left, user can open it with hamburger icon:

Sign-out is available in the drop-down list:

Router API is used in three places in my sample app:

1. Initial sign-in module setup in appController.js. This is executed when application is initialized. Router is configured here with single module - login. Developer should get root instance, configure it with module list and define array with description how each menu item will look like:

2. On sign-in, when login function is called - we get the same root instance of the router. Configure it with new set of modules, one of them is marked as default, define array with descriptions and reset current navigation. At the end we should sync all changes with Router instance, this is done through sync() method call:

3. On sign-out, when logout functionality is called. We reset router configuration with single login module. Login module is set as default. Here we call Router API method go(). Method doesnt need parameter, it will navigate to default module, if no parameter specified. Depending on URL state, if current module before sign-out is default one, URL will not change - this would require to call sync() method to force sign-in module display. If user is on any other module, not the default one - go() method will navigate to sign-in module automatically:

Friday, January 6, 2017

Oracle ADF - Strategic Oracle Technology

Happy New Year !

There is update for Oracle ADF Statement of Direction dated to November 2016:

You can read full document on Oracle Support site, search for document ID 1985782.1.

To summarise outlined roadmap for Oracle ADF:

1. Oracle continues its commitment to Oracle ADF as a strategic technology

2. Oracle ADF will bring new technologies minimising the negative effect of change (recent examples - ADF BC REST, HTML5 support)

3. In future versions of ADF there will be more focus on JavaScript solutions

4. There are plans for ADF 12.2.1 and beyond