Saturday, July 22, 2017

ADF Goes Client Side - UI Performance Boost with JavaScript

If you would like to boost ADF UI performance, you should look into client side validation and formatting options possible to be done in ADF UI. Today I will describe how you can implement client side converter, to format number value on client side, without making request to the server. Same approach could be used to implement client side validators. You can raise error message and it will be assigned to UI field in the same way, just like any standard ADF error message. While this approach is documented long ago in Oracle ADF developer guide - How To Create Client Side Converter, it is not well known and not often used.

Client side converter is attached to ADF UI field through JSF tag, it points to custom converter ID (make sure autoSubmit=false is set, we don't want request to the server on value change):


Custom converter is defined in Faces Configuration file, it points to custom converter class:


Converter class is responsible to load JavaScript file, where number formatting logic is implemented. Also we have an option to pass initialization parameters:


Example of client side converter logic (to format numbers) code in JS:


Formatting happens on the client, no request to the server is done. User enters value and navigates out of the field - value is formatted:


If fractional part is incorrect, error raised from converter is displayed same as any other error in ADF - attached to the field:


If value is invalid - error is displayed too, this simple validation error comes from JS converter. Request is processed on the client, no call to the server:


Server side formatter in ADF BC is still required. When data is fetched from DB, ADF BC server side formatter is applied to transform data to correct format (this happens when data is fetched and doesn't affect end user performance):


Custom number formatter implemented in ADF BC (read more about it: Generic BigDecimal Formatter in ADF 12.2.1.1):


Download sample application - ADFFormattingApp.zip.

Sunday, July 16, 2017

ADF BC - Create View Object From Query with Custom Implementation Class

I had a request to explain how to create dynamic ADF BC VO from SQL statement and set custom VO implementation class for newly created VO instance. Custom VO implementation class extends from ADF BC ViewObjectImpl and overrides super method:


There is a method createViewObjectFromQueryStmt, in previous ADF versions this method had two parameters - VO instance name and SQL statement. In current ADF 12c - there is a second signature of the same method, which contains option to specify VO implementation class name. Dynamic VO from SQL with VO implementation class:


ADF BC custom methods can be tested with ADF BC tester:


Overridden method from custom VO implementation class is called:


Download sample application - ADFVOFromSQLApp.zip.

Monday, July 10, 2017

ADF 12c BC Proxy User DB Connection and Save Point Error

If you are modernising Oracle Forms system, high chance you need to rely on DB proxy connection. Read more about it in my previous post for ADF 11g - Extending Application Module for ADF BC Proxy User DB Connection. It works in the same way for ADF 12c, but there is issue related to handling DB error, when DB proxy connection is on. DB error is propagated to ADF but is being substituted by save point error (as result - user would not see original error from DB). It seems like related to JDBC driver in 12c. The workaround is to override ADF SQL builder class and disable save point error propagation (there might be better ways to workaround it).

Proxy connection is established from prepareSession method in generic AM Impl class:


If I would change salary value to negative and save data - DB constraint error would fire (negative not allowed). Unfortunately, end user would not see that error - he gets message about failed save point:


Workaround -  we can disable save point error propagation. Override SQL Builder class and add try/catch block in rollbackToSavepoint method. If error happens, do nothing:


You must register SQL Builder class with AM. Add jbo.SQLBuilderClass property in bc4j.xcfg, pointing to the class:


You should be able to see DB errors after this change is applied:


However, there is one drawback of this workaround to keep in mind. When data is posted to DB, ADF executes lock statement. If update fails, normally ADF would execute rollback to save point and lock will be removed. But not in the case of DB proxy, now rollback to save point is failing - this means lock will stay:


If user would fix data and try to save again - lock error will be returned:


Error during lock:


To bypass lock issue, you should enable DB pooling for AM instance. In this case, after each request DB connection will be returned back to the pool and lock will be released automatically:


Download sample application - AMExtendApp_v3.zip.

Thursday, July 6, 2017

Working with Location and Permissions in JET Hybrid

What if you want to access mobile device location data from JET Hybrid application? This can be achieved with Cordova Geolocation plugin. But you want it to be nicely done and want to make sure application is granted with permission to access location information. Use Cordova Permissions plugin for that.

You could add Cordova plugin to JET app by executing this command:

cordova plugin add 

If this command doesnt work for any reason, you could add plugin information directly into config.xml file (check Geertjan post about the same - Plugging into Devices with Oracle JET on Cordova (Part 1)):




In JS function, before calling location API - we call permissions API to check if app is already granted permission to read location data. In hasPermission method, in case of success - location data is accessed. In case of no permission, request for permission is sent. If request is satisfied - location is accessed (and permission is granted at the same time):


Location data is retrieved through callback:


This is how it works. On very first location access, when permission is not granted yet - we request permission through permission API:


When permission is granted, location is displayed:


Download sample application from GitHub repository - rslocationapp.

Tuesday, July 4, 2017

JDeveloper 12.2.1.2 Patch for Transient Expression Compilation Infinite Loop

If you are using JDeveloper 12.2.1.1 or 12.2.1.2, probably you run into transient expression compilation infinite loop issue. Infinite loop happens when you open ADF BC project and navigate to VO, which contains Groovy expressions. JDeveloper starts to print repeating message in the log - compiling TransientExpression and soon at some point JDeveloper window closing down without any feedback:


For those of you, who are not aware - there is a patch for this issue. Patch can be downloaded from Oracle Support, search for Patch: 25218838 (there is one for JDEV 12.2.1.2 and another one for JDEV 12.2.1.1):


If its your first time applying Oracle patch - no worries, process is very simple and smooth. Extract download patch zip archive first. Next setup ORACLE_HOME environment variable, point to root folder of JDEV install:


Once environment variable is set, run OPatch by executing opatch apply from the directory where patch archive was extracted. You can reference OPatch by direct path:


Hopefully fix provided by this patch will be included into next JDEV version by default.

Saturday, July 1, 2017

Oracle JET Router State Control

In my use case there is requirement to navigate to JET module, without displaying it in menu structure. Navigation is a simple task, more complex is to make sure current menu item will be unselected after navigation to invisible module (so that later we are able to re-open it).

There is accounts module in JET sample app (download it from GitHub - JETModularArchitecture):


Accounts module is included into router, but not included into array of visible menu items:


On button click (dashboard module) we call function, where router navigation happens to accounts module:


Let's see how this functionality works. I click on Accounts button to call a function and force router navigation:


Accounts module will be opened (through router navigation), but currently highlighted menu item will stay as it was (Dashboard). This makes it impossible to navigate back to Dashboard (unless we navigate to another module and then navigate to Dashboard):


Solution for this problem is to change selection property of ojNavigationList component in HTML:


Instead of pointing to router stateId directly, we should point to computed function. This will help to control currently selected menu item. But we still need to update router state, when menu item is selected. For that reason I'm using beforeSelect property, which points to function, where router state is changed:


Selection property value is calculated by function, which returns NULL, if accounts is currently selected module. This allows to remove focus from Dashboard menu item, after navigation to accounts. Once focus is removed, we can click back on Dashboard and navigate. For all other modules - current router state ID is returned. Select handler call router API to navigate to the module:


Navigation to accounts module from dashboard. Dashboard menu item doesn't remain focused anymore:


Navigation back to dashboard work too: