Skip navigation.

Andrejus Baranovski

Syndicate content
Blog about Oracle technology
Updated: 1 hour 31 min ago

Red Samurai ADF Performance Audit Tool Major Update v 5.0

Tue, 2016-05-03 13:42
Our ADF performance audit tool is growing and getting more advanced with each release. Current major update v 5.0 brings ADF Click History integration and allows to track ADF UI client request time. This allows to understand, how long it takes to execute action from user perspective. Combined with ADF BC performance monitoring, we could give precise answer about performance bottlenecks from top to bottom.

New features in v 5.0:

1. Redesigned UI with ADF 12.2.1 Responsive template. UI is aligned with Alta UI best practices

2. Group by ECID functionality. We can track request action from top to bottom. This includes client request time (time needed to complete action on UI, including network traffic time). Executed SQL queries and any issues in ADF BC performance for the given request

3. ADF Click history logging. Click history data about UI performance is being intercepted and logged into Red Samurai DB, for analysis. This gives a database of all user requests and time for each request

4. User request statistics visualization dashboard

Here you can see sample data from ADF demo application. User request statistics are presented to help in understanding system performance. Time for each user request is visualized, along with detail information about request (component ID, name, type, etc.). Average times are presented, along with user statistics and top actions. We display total requests count vs. recent requests, to visualize the load on the system:


Each of the logged requests can be tracked down by ECID. Here we can see a list of VO's invoked during UI request and any slow performance behavior happening in ADF BC:


In the next updated v 6.0, we are going to implement UI behavior analysis, to extract most common UI usage patterns in ADF application.

Optimize ADF HTTP Response Size with ChangeEventPolicy

Tue, 2016-04-26 02:18
You should read this post, if you are looking how to reduce ADF HTTP response size. This can be important for ADF application performance tuning, to improve PPR request response time. By default in ADF 12.2.1, iterator is assigned with ChangeEventPolicy = ppr. This works great for UI component bindings refresh, no need to set individual partial triggers. On other side, this generates extra content in ADF HTTP response and eventually increases response size. I would recommend to use ChangeEventPolicy = ppr, only when its really needed - dynamic forms, with unknown refresh dependencies. Otherwise set ChangeEventPolicy = none, to generate smaller response.

I will demonstrate below the difference for ADF HTTP response with ChangeEventPolicy=ppr/none. First let's take a look into page load response size:


Page contains list component and form. Both are based on two different iterators, set with ChangeEventPolicy = ppr. This generates AdfPage.PAGE.updateAutoPPRComponents calls for each UI item, referencing attributes from the iterator. In complex screens, this adds significant amount of extra text to the response, could increase size even by half:


Partial response also contains same calls added to the response. Select list item:


Each item from the form will be referenced by JavaScript call, to register it for refresh:


Let's change it to ChangeEventPolicy = none. Set it for both iterators:


We should set refresh dependencies manually. Form block must be set with PartialTrigger, referencing list component - to refresh, when list selection changes:


Next/Previous buttons dependency also must be set, to change form row:


With manual refresh dependency changes, there are no extra calls added to ADF HTTP response, reducing overall response size:


Same applies for PPR response:


Download sample application - ChangeEventPolicyPPRApp.zip.

ADF 12c Custom Property Groovy and AllowUntrustedScriptAccess Annotation

Sun, 2016-04-17 03:41
To execute Groovy expression in ADF 12c (to call Java method from Groovy), you must specify trusted mode. Read more about it in my previous post - ADF BC 12c New Feature - Entity-Level Triggers. Setting mode to trusted, works in most of the cases. It doesn't work if we want to execute Groovy expression (calling Java method in ViewRow or Entity class) for custom property. In a case of custom property and Groovy calling custom method, we need to annotate Java class with AllowUntrustedScriptAccess. This makes a trick and Groovy expression can call custom method.

To demonstrate the use case, I was using mandatory property. This is standard property to control if attribute is required or no. By default, mandatory property is static, but we can make it dynamic with Groovy expression. I have implemented a rule, where Salary attribute is required, if value is more than 5000:


Salary is not required, if value is less than 5000. This is just example, you can implement more complex logic:


There is a method in ViewRow class, to calculate required property for Salary attribute:


Method is callable from custom property Groovy expression, as we have set annotation AllowUntrustedScriptAccess for ViewRow class. Annotation definition, must list all allowed methods:


Here you can see Groovy expression, to call ViewRow class method - mandatory. Expression is assigned for custom property, this will be referenced from ADF UI:


There is issue with JDEV 12c, it fails to parse custom properties set with Groovy expressions. It fails to parse and removes custom property from the code. To prevent such behavior, specify empty string for custom property value (this will allow to keep Groovy expression):


Luckily in this case of mandatory check, JDEV by default generates mandatory property for ADF UI component. We simply override its original value with custom property and calculate new value in custom trusted method, referenced by Groovy expression:


Download sample application - ADF12cGroovyCustomPropertyApp.zip.

Monitoring ADF 12c Client Request Time with Click History

Sun, 2016-04-10 11:55
You must be excited to read this post, I will describe one very useful feature, available in ADF 12c. This feature - Click History. You can follow steps described by Duncan Mills, to enable and read click history data in server log. There is one more option available - we can read click history data from ADF request (captured by filter class) and log it in custom way (for later analysis). Click history gives such information as client request start/end time (you can calculate client request duration), component client ID, component type, action event type, etc. All this is useful to understand application performance perceived by the client.

Download sample application - DashboardApp.zip (it contains JET libraries, to render JET content within ADF). To test click history and view generated statistics, click on any button and selection component. Click history returns previous action statistics. Let's click on Cancel button:


You should see similar XML message printed in the log (click history statistics data):


To view it in readable way, you can copy it into XML file and format in JDEV:


Logged properties, useful to track client request performance:

1. CID - ECID number, identifies request
2. CST - client request start time
3. CET - client request end time
4. ETY - client event type
5. CLD - client component ID
6. CTY - client component type

XML message can be parsed and property values can be logged to DB for performance history analysis.

To enable click history, you only need to set parameter (true) in web.xml oracle.adf.view.faces.context.ENABLE_ADF_EXECUTION_CONTEXT_PROVIDER:


To read click history data from ADF request, we need to define custom filter in web.xml. Register filter under Faces Servlet:


In the filter, override doFilter and retrieve oracle.adf.view.rich.monitoring.UserActivityInfo parameter (this will return click history XML string, as above):

ADF BC View Criteria Query Execution Mode = Both

Thu, 2016-04-07 09:55
View Criteria is set to execute in Database mode by default. There is option to change execution mode to Both. This would execute query and fetch results from database and from memory.  Such query execution is useful, when we want to include newly created (but not commited yet) row into View Criteria result. Newly created row will be included into View Criteria resultset.

Download sample application - ViewCriteriaModeApp.zip. JobsView in sample application is set with query execution mode for View Criteria to Both:


I'm using JobsView in EmployeesView through View Accessor. If data from another VO is required, you can fetch it through View Accessor. View Accessor is configured with View Criteria, this means it will be automatically filtered (we only need to set Bind Variable value):


Employees VO contains custom method, where View Accessor is referenced. I'm creating new row and executing query with bind variable (primary key for newly created row). View Criteria is set to execution mode Both, this allows to retrieve newly created row (not commited yet) after search:


View Criteria execution mode Both is useful, when we want to search without loosing newly created rows.

Change ADF BC Data Update Locking with FOR UPDATE WAIT

Wed, 2016-03-30 07:43
Each time when data is changed and updated through ADF BC, before posting changes to DB, SQL query with FOR UPDATE NOWAIT is generated and executed. In case if other process locks row to be updated, or another user in the same moment is updating it, error will be generated and update will be stopped. There might be use cases, when you would like to wait for certain period of time, until row will be unlocked and then commit row changes. This is especially true, if 3rd party (PL/SQL) process is updating rows and you have defined change indicator attribute in ADF BC (see my previous post - ADF BC Version Number and Change Indicator to Track Changed Rows).

We can change default behavior, instead of requesting for immediate lock - we can wait a period of time. If lock becomes available during this period, session acquires lock. If row remains locked, error is returned. Instead of default FOR UDPATE NOWAIT, we can generate FOR UDPATE WAIT (time period in seconds).

To override default behavior, we need to specify custom SQLBuilder class. This can be registered in Application Module configuration jbo.SQLBuilder property:


Class must extend from OracleSQLBuilderImpl and override getSqlVariantLockTrailer() method. My sample application is implemented to return FOR UPDATE WAIT 30:


We can do a test. We can simulate PL/SQL lock by executing SQL query with FOR UPDATE from SQL Developer:


Try to update same row from ADF BC with default behavior, error will be returned - "Failed to lock the record, another user holds the lock". This is expected, because row remains locked:


With overriden SQL Builder, FOR UPDATE WAIT 30 is generated. It waits 30 seconds, as soon as lock is removed - lock from current session is set and row data is updated:


Download sample application - LockUpdateApp.zip.

ADF BC Version Number and Change Indicator to Track Changed Rows

Fri, 2016-03-25 10:12
One of the common use cases in enteprise applications is to track concurrent user changes. There are two types of changes possible - when two real users are changing data in the same row, or when single user is changing data and same row is updated by PL/SQL procedure/function (all happen in the same user session). In the first case, we would like to inform a user - row data was changed (two different users changing data). In the second case, there is no need to inform user (data wasn't changed by another real user, it was changed by PL/SQL function/procedure invoked in the same session).

ADF BC by default tracks all attributes and checks if they values were changed. This would mean, if any attribute value is changed directly in DB, EO cache will be out of synch and changed row error will be reported. We can minimize number of attributes to be checked to single attribute - Version Number. There must be additional number type column created in DB table, we are going to use it for Version Number in the EO. EO attribute should be marked as Change Indicator and set to be "version number" in Track Change History property. This means, row will be considered as changed by another user, only if Version Number attribute value will be changed. All changes happening directly from PL/SQL will not increment Version Number (it will be incremented only for the changes submitted from ADF BC):


There should be new column created in the DB for Version Number attribute:


Let's see how it works. I will use two different browser sessions, to simulate two users. Change value for First Name, take a look into Version Number. Value is equal to 4, before Save:


Data is saved successfully to DB. New value 5 is assigned automatically for Version Number:


Switch to different session now. Version Number is equal to previous value 4 (this session was opened before recent commit from first session). Both sessions are working with the same row. Change value for Salary:


Try to save this change. You will get standard error message, informing user about changes in the same row. This happens, because Version Number value doesn't match with recent Version Number for the same record:


At the same time, Version Number is synchronized automatically (updated to 5) and user can try to commit his changes again. This time data is saved and Version Number is increased to 6:


We should check now, how it works data is changed in the DB directly, without increasing Version Number (the case of update happening from PL/SQL). I'm changing Employee_Id = 100 record directly in DB (changing Salary value). Version Number is not changed:


Go back to Web session and change First Name value, press Save:


Despite data was changed in DB, save was successful - Version Number was recent. First Name was successfully changed and Version Number was increased to 7:


Download sample application (make sure to create manually VERSION_NO(10, 0) column in the EMPLOYEES DB table) - ADFChangedRowApp.zip.

How To Be More Productive with JDeveloper 12c Application Redeployment

Fri, 2016-03-18 02:56
When you work on larger JDeveloper/ADF 12c project, most likely you will experience issues with application redeployment (rerun). These two issues will be encountered:

1. It doesnt work anymore (it worked on 11g) to simply rerun application (applies for 12.1.3 and 12.2.1), without stopping it and then running again. In most of the cases if you try to rerun application, some strange errors are returned or changes are not visible at all. It takes time to stop application and run it from scratch

2. Oracle recommended approach is to use Make All to recompile the code and then refresh or reopen browser (Servlet Reload or Fast Swap options). This should bring the changes in ADF BC, Bindings, Task Flows and UI. While this works on simple use cases, often it doesnt work if many files are changed at once

What if you want to re-run application in JDeveloper 12c, same as it was possible in 11g? Yes, you can do it. There is a simple configuration change in JDeveloper 12c, to be able to rerun application without issues:


Go to JDeveloper preferences wizard and select Run option. Uncheck option "Enable Application Rerun Optimizations" - this will allow to rerun ADF application without errors and without a need to stop and start it manually:


Once application rerun optimizations are disabled in JDeveloper, you should add simple configuration to your ADF application (to make sure application redeploys fast). Disable auto generation for JDBC descriptors in application profile (Deployment -> WebLogic):


Provide external Data Source in AM configuration, or set direct JDBC URL (suitable for testing locally, as in my case):


Do above steps, when Make All (Servlet Reload or Fast Swap) doesn't work for you:

Accessing Oracle Mobile Cloud Service (MCS) REST from Postman

Thu, 2016-03-17 09:54
Do you want to test in your environment REST service running on Oracle MCS cloud? I have implemented public REST service hosted on Oracle MCS, you can call it from Postman application (Google Chrome extension).

Implemented use case - SOAP Connector in MCS is reading Stock Quote information for the company supplied in the request. Information is transformed by MCS Custom API (with Node.js) into REST structure and returned to the client through MCS Mobile backend.

Here is the REST GET url to invoke in Postman: https://mobileportalsetrial1304dev-mcsdem0001.mobileenv.us2.oraclecloud.com:443/mobile/custom/STOCKQUOTE_API_REDSAMURAI_BLOG_1/stockquote/ORCL. Try to run it, you can replace ORCL with another company ID. To execute this REST request in Postman, you need to provide configuration file (this allows to call MCS). Configuration file can be downloaded from here - Postman_MCS_1.json. This file contains all required info to make REST request from Postman:


To add configuration file to Postman, go to Configuration and upload it through Import data option:


Make sure MCS profile is selected:


When you copy paste REST URL, go to Headers section and select MCS from Presets - this will add two required headers:


You should see company stock information returned back from REST call:


Let's switch to MCS. There are three main concepts in MCS - Mobile Backend, custom API, Connector. Mobile Backend is a service interface, it allows to configure mobile access functionality and contains a list of Web Services (API's) exposed to the clients. It allows to track service usage and view statistics in the dashboard:


My example contains single Web Service (custom API). This service is responsible to handle REST GET method and return company stock quote data:


Custom API defines REST resource /stockquote/{company}, this is what we are executing in Postman URL:


Resource /stockquote/{company} is configured with GET method:


GET method is configured to handle two type of responses - 200 (OK) and 404 (Not Found):


To provide API implementation (mapping between Connector and API response), we can download (see example - stockquote_api_redsamurai_blog_1.zip) Node.js file from MCS and edit it locally (edited file can be uploaded back in the archive):


We need to specify Connector name to be available in Node.js, this is how it will call Web Service defined in the Connector:


Node.js function is responsible to call Web Service from Connector, pass parameter and check the result (here you can do complex transformations between SOAP and REST):


I'm using SOAP connector, pointing to external Web Service to fetch Stock Quote information for the company:

OFM Forum Session Slides - Oracle JET and WebSocket

Wed, 2016-03-16 09:46
I would like to post slides from my session on Oracle Fusion Middleware Forum - Oracle JET and WebSocket. This session was done today.

Slides are available on slideshare:


Sample application used for the demo, can be downloaded from here (it consists of three parts - WebSocker server implementation, ADF BC tester application to generate continuos DB updates and JET application) - Oracle JET Live List with WebSocket.

ADF application with live data DVT component rendered in JET can be downloaded from here - When JET Comes To Rescue - Live Data Charts in ADF.

Oracle JET and ADF BC REST Basic Authentication

Fri, 2016-03-04 17:03
You might be interested to check my previous sample about CRUD implementation in JET - Handling ADF BC 12.2.1 REST Validation in Oracle JET. I'm going to describe how to access secure ADF BC REST service from JET, based on the CRUD sample app. We need to pass authorization header on each REST request, this way server can authenticate user and authorize access to the REST resource. There are couple of other tips applied on ADF BC REST service side, all described below.

Blog reader rjahn shared a link in this blog comment - Oracle JET - Rendering Table from ADF BC REST Service, he describes how to pass authorization header using oauth property, while executing GET and fetching collection in JET. I'm using same approach for GET, but for PATCH, POST and DELETE authorization header is set in slightly different way.

First of all we need to take a look into ADF BC REST security implementation. Each time when custom header is attached in JET, it executes OPTIONS method without appending authorization header. I have disabled security check for OPTIONS in web.xml:


Important tip - by default security operations granted to ADF BC resource are all assigned through single permission (in jazn-data.xml):


I have found this doesn't work, even from Postman - only first operation from the list is authorized. This must be a bug in ADF BC REST security. Workaround is to separate each operation into different permission group manually:


GET executed from JET is authorized and data is coming through:


We can see in network monitor recorded GET execution from JET - authorization header is submitted along with request:


Authorization header is encoded with JavaScript btoa function. Obviously it must run on HTTPS to be completely secure, otherwise someone can intercept and decode the password. Authorization header is being constructed in JET (you would fetch username/password from HTML form, etc.) and is attached to the collection (this way it gets included into request header executed by GET). It doesn't work to attach it to collection through header property (as it works for POST, PATCH and DELETE), but it works with oauth:


Authorization header can be set for PATCH. Data can be updated through secure service:


Authorization header is present in PATCH request:


Authorization header is injected through property - headers (differently than for collection and GET). It didn't work to use oauth here:


Create case is executed through POST, security is enforced through authorization header here also:


We can see header is present in the request:


Authorization header is attached in the same way as for PATCH:


Delete case is executed through DELETE, same authorization header is applied:


Header info:


Authorization header is attached to JET destroy operation:


Download sample application (JET and ADF BC code) - JETCRUDApp_v5.zip. You should include JET code into JET toolkit distribution.

ADF BC REST Support for List Of Values (LOV) Data

Mon, 2016-02-29 19:21
ADF BC REST service out of the box supports LOV list data. You can define LOV for ADF BC View Object attribute and use it straight away in REST service. This is especially useful when LOV list is filtered based on other attributes from current row - no need to collect and send these attributes to the service separately, filtering logic will be handled for you in ADF BC backend. One more benefit - you can reuse existing ADF BC with LOV's implementation and expose it through REST service.

Below you can see employee #108 attributes with values returned by REST service, generated on top of ADF BC View Object. ManagerId attribute in View Object is configured with LOV list. Based on this configuration, each item in REST collection will have a link to REST resource providing LOV data (Employees/280/lov/EmployeesLovView1). For employee #108, it retrieves LOV data from VO EmployeesLovView1:


We can get LOV list entries for employee #108 by executing simple REST request, no need to specify additional parameters (Employees/280/lov/EmployeesLovView1):


LOV VO is set with View Criteria to return a list of possible managers, employees with the same job, excluding employee himself:


LOV View Accessor in the main VO (Employees) is configured to use employee ID and job ID from current row (current REST collection item) - in this way LOV list will be filtered automatically, by View Criteria:


The only thing that needs to be done to enable LOV support - define LOV for manager ID attribute in the base VO:


As you see, it is pretty easy to reuse ADF BC LOV's in REST service. Download sample application - ADFBCRestApp_v6.zip.

Oracle JET Live List with WebSocket

Sat, 2016-02-27 19:47
I have updated sample - Oracle JET and WebSocket Integration for Live Data, to include live data list. Along with live updates delivered to the chart component, list component displays changed data. I'm displaying five last changes, with new data appearing in the last row:


Watch recorded demo, each 4 seconds new data arrives and chart is updated, along with list records:


JET list component UI structure (data grid) is rendered with a template, to arrange separate column for each job:


When new data arrives, it is being pushed into JET observable array (this triggers automatic UI list reload/refresh). If there are more than five items in the list, first one is removed. List observable array is configured with 500 ms. delay, to make UI refresh smoother:


Download sample application (JET, WebSocket server side and ADF to simulate updates in the DB) - JETWebSocket_v2.zip.

I'm going to present JET and WebSocket integration on Oracle Fusion Middleware Partner Community Forum 2016.

Extending ADF Cloud User Experience Rapid Development Kit (RDK)

Tue, 2016-02-23 22:35
You should be familiar with AppCloudUIKit ADF application from - The Cloud User Experience Rapid Development Kit. It provides a set of templates, components and sample flows to get you started with successful ADF setup. I will explain how to extend it, if you want to add extra parameters for the menu item, to be passed to the Task Flow.

The use case - each time when custom TF Manage Users is opened, criteria item First Name is assigned with TF parameter value (value "C" in the example below):


RDK is extended to support parameters for menu item. Each menu item in RDK is defined by Node object. I have updated Node object with HashMap to represent a set of parameters:


All menu items in RDK are defined in SessionState class. I have updated one of the menu items (Manage Users) with parameter - firstName:


ADF regions are rendered in RDK with ADF Multi Region binding. A set of regions is controlled through FilmStripBean class. Region attributes are set in buildTaskFlowBindingList method. For each menu item, I check if there are extra parameters to be set. If there are parameters, map is constructed and assigned for the region binding (map value with TF parameter):


Assigned value is used in the TF, to set search criteria item:


Download sample application (I have included only projects with changes) - AppsCloudUIKit_v2.zip.

Basic Authentication Hint for ADF BC REST

Tue, 2016-02-23 00:32
If you follow step by step ADF BC REST developer guide - 16.5 Granting Client Access to the ADF REST Resource, still you would not be able to implement basic authentication for the REST service. Thats because one step is missing, it is not described (and required setting is not auto generated by JDEV). In order to enable basic authentication for ADF BC REST service, you should manually define security constraint (based on context root) for RESTServlet resource.

When security is enforced for ADF BC REST project, and you are testing REST resource with authorization header (encoded username/password) - there will be authorization error - NotAuthorizedException (even with correct username/password):


If you encounter this error after configuring ADF Security for ADF BC REST project with the wizard. Do one extra step to declare security constraint manually - set /rest/* URL pattern for RESTServlet resource in web.xml:


Basic authentication will start to work:


Download sample application - ADFBCRestApp_v5.zip.

ADF and Cloud User Experience Rapid Development Kit

Fri, 2016-02-19 09:51
Oracle published new set of UI templates - The Oracle Applications Cloud User Experience Rapid Development Kit (RDK). This includes methodology based on Oracle Fusion Applications experience and contains ADF source code. Kit is shipped with ADF application (download it from Oracle site), you could use it as a jumpstart. This could be next UI Shell. It is more than UI Shell, RDK comes with a set of declarative components (header/toolbar is one of them).

I have implemented my own simple TF and tested how it works in RDK. Custom TF can be opened from My Team group, Manage Users item. Home UI in RDK:


Manage Users - custom TF. When TF is opened, in the top area user have possibility to switch to other items (items can be hidden). First fragments brings search screen, user can edit selected record:


UI is adaptive, it stretches according to screen size. Below you can see edit screen. Fusion Applications have Save, Save and Close, Cancel buttons as standard in edit screens:


Complete menu structure can be displayed at any time from top left menu item:


User can select My Team option from the menu, it will render another TF in the main area:


RDK ADF application is shipped with SessionState bean. Menu items can be registered in this bean. I have registred my own TF under existing Manage Users entry (it was empty originally). But you could create new menu items by adding new entries into SessionState bean:


Custom TF is created in the new project - UsersUI, it is dependent on ADF BC from UsersModel project:


TF is based on two fragments - search and edit:


Page header can be set with declarative component:


Toolbar buttons Save, Save and Close, Cancel are rendered by the same declarative component where page header is set:


Download RDK application with my custom TF - AppsCloudUIKit_RS.zip.

When JET Comes To Rescue - Live Data Charts in ADF

Fri, 2016-02-12 09:57
I have described previously, how you can run JET in ADF UI - Improved JET Rendering in ADF. This was technical steps explanation. Today I will describe a case, when such rendering can be important and useful. The case is related to live data delivered through WebSocket and rendered in chart. WebSocket client must be implemented in JavaScript, but we can't access ADF DVT component values in JavaScript and update them, without making a call to the server and reloading binding value. Which would require client/server roundtrip.

In this post I'm using JET/WebSocket integration solution described previously - Oracle JET and WebSocket Integration for Live Data. Technical steps for JET rendering in ADF are the same as in the post above. Download sample application (it contains WebSocket and ADF (with JET code) projects) - JETWebSocketADF.zip.

Pie chart is rendered by JET in ADF UI:


You should check demo video, where two sessions are running in parallel and each second new data is coming from WebSocket. See how synchronous JET rendered chart is changing in both sessions:


JET HTML code is included into ADF fragment. It renders DVT pie chart component, with value initialized from JavaScript variable:


Main ADF page must include a reference to WebSocket JavaScript file, this is where WebSocket client is implemented:


ADF fragment with JET code is included into main ADF page:


Whats the difference with ADF DVT chart? It gets data in different way, from bindings - this means data must be prepared on the server. ADF DVT chart value property must point to Collection Module from bindings. This is not bad, it is just different approach. It works perfect to display server side data, but makes it complex to render live data received in JavaScript:


WebSocket client contains onMessage method, where update is received and pushed to JET context:


JET handles update and changes chart data directly on the client:


To simulate continues updates, I have implemented ADF BC method to update DB data multiple times. DB change listener picks up these changes and makes a call through WebSocket to deliver update event. JET re-draws chart UI, based on the update:


Currently Oracle doesn't support JET in ADF. While JET can be rendered in ADF, you will not get official support through Oracle Support channels. 
You may run into issue of session timeout handling. ADF page sends a "ping" to the server whenever there is interaction on the page. JET does not do anything of that kind, so if you are sitting on an ADF page, and only interacting with the JET portion of that page, there is nothing telling the server that you are still active. This could result in ADF session timeout, while user is still working with JET component. In practice this would rarely happen, especially if ADF timeout is set to be long, but you should be aware of that.

Oracle JET and WebSocket Integration for Live Data

Sat, 2016-02-06 09:57
I was researching how to plugin WebSocket into JET. I would like to share my findings and explain how it works. It is amazing, how scalable and quick it is to send JSON message through WebSocket channel and render it in JET. Luckily WebSocket client is implemented in JavaScript, this integrates perfectly with Oracle JET (also based on JavaScript).

Watch recorded demo, where I'm sending updated data with JSON message through WebSocket. UI chart is rendered with JET. See how nicely JET re-draws chart, based on received new data (watch at 6th second):


Download sample application - JETWebSocket.zip. This contains both WebSocket application (implemented with JDeveloper) and JET (implemented with NetBeans).

On WebSocket server side, I'm listening for DB changes (Database Change Notification Listener Implementation). Each time when DB change happens, all changes are collected into one collection and sent to the clients through WebSocket:


Changes are collected into array. WebSocket message must be encoded into JSON Array, this makes it easier to read it on client. Multiple JSON Objects are added into JSON Array:


Message is sent to all connected WebSocket clients:


All this happens on server side. Now lets take a look into client side. We should open WebSocket connection when JET is loading. I have included WebSocket client JavaScript code from separate file websocket.js. JET renders chart component:


Each time when WebSocket message is received by the client, onMessage method is invoked. This method is responsible to parse JSON message and pass it to function from JET context, where chart data update happens:


WebSocket is opened, when document is rendered. In the next step, JET View Model is created along with bindings:


Variable viewModel is accessible from WebSocket onMessage method, because it is defined outside of JET function:


Method updateChart invoked from onMessage, applies received changes to chart data. JET re-draws chart automatically, because changes are applies for observable array. This is really cool:


See how it works. Page is loaded with JET chart component, WebSocket is opened:


Go to DB and update few records, commit changes:


JET receives changes through WebSocket and chart is updated instantly:

Database Change Notification Listener Implementation

Sat, 2016-01-23 08:43
Oracle DB could notify client, when table data changes. Data could be changed by third party process or by different client session. Notification implementation is important, when we want to inform client about changes in the data, without manual re-query. I had a post about ADS (Active Data Service), where notifications were received from DB through change notification listener - Practical Example for ADF Active Data Service. Now I would like to focus on change notification listener, because it can be used in ADF not only with ADS, but also with WebSockets. ADF BC is using change notification to reload VO, when configured for auto refresh - Auto Refresh for ADF BC Cached LOV.

Change notification is iniatilized by DB and handled by JDBC listener. There are two important steps for such listener - start and stop. Sample application - WebSocketReusableApp.zip, implements servlet DBNotificationManagerImpl:


I'm starting and stopping DB change listener in servlet init and destroy methods:


DB listener initialization code is straightforward. Data changes are handled in onDatabaseChangeNotification method. Listener is registered againt DB table executed in initial query:


In my example I'm listening for changes in Employees table. Each time, when change happens - query is re-executed to calculate new average salary values for jobs:


On first load, when servlet is initialized - listener is registered. Initial data read happens and listener is reported as started:


I can change value in DB, commit it:


DB change listener is notified and query is being executed to fetch new averages. Value for SA_REP is changed:


I hope it makes it more clear how to use DB change listener. In my future posts I will describe how to push changes to JET through WebSocket.

Automatic ADF Logout on Browser Close with WebSocket

Sat, 2016-01-16 12:15
Every ADF project could have a requirement to handle browser close event effectively. Differently than desktop applications where we could handle such events, browser doesn't send any event to the server, when browser page is closed. This is especially important for transactional data, when user locks data row and lock must be released automatically, in case if user is closing browser without unlocking. Besides transactional data management, it is important for performance improvement - Web session will be closed instantly and WebLogic resources will be released. There was no reliable solution to handle this, now we can do it with WebLogic 12c and WebSockets. WebLogic 12c supports WebSockets natively, there is no need to configure anything or add libraries.

When WebSocket channel is closed, it delivers event to the server on browser close. We could use this event to release locked resources, we need to logout ADF session to force ROLLBACK. Sample application implements HTTP client invoked by WebSocket server endpoint. This HTTP client simulates browser activity and redirects to adfAuthentication with logout request, using original JSESSION ID from closed browser session. This works also during accidental client computer power off. Download sample application where I have described all important implementation steps - ADFSessionHandlingWebSocket.zip.

Sample application is protected with ADF Security, you can login with redsam/welcome1 user. It includes Oracle JET libraries, one of the dashboard tiles implements JET fragment. JET is not required for the sample to work, it is used only to implement dashboard UI.

You can observe from browser log when WebSocket connection is opened. Connection is established on initial page load, immediatelly after login. This opens WebSocket communication chanel, as soon as this chanel will be closed - WebSocket server endpoint will force logout for ADF session from closed browser:


As soon as WebSocket channel is established, ADF web session ID (JSESSIONID is retrieved from the cookie) is sent to WebSocket server endpoint. Sample logs ID of ADF web session:


I'm going to lock one of the records, I'm invoking ADF BC lock method (DB pool is disabled, this will keep DB connection assigned for AM):


Lock action for row data is visible in the log, SELECT FOR UPDATE is executed for ID 102:


Let's close a browser now without issuing ROLLBACK, invoke Quit action in the browser:


WebSocket channel will be closed and this will trigger ADF Authentication servlet request to logout from ADF web session. As logout happens, ADF resources are released, ADF BC is triggering ROLLBACK in DB:


Session is closed based on JSESSIONID. With HTTP Client we simulate user logout after browser was closed:


Now we should overview technical implementation. WebSocket channel is opened from JavaScript:


This happens on page load, with clientListener triggering connectSocket method:


Method connectSocket in JavaScript is using standard WebSocket API to open connection:


WebSocket server endpoint is defined with custom configurator. Through configurator we can reference HTTP session initiated in ADF. HTTP client in WebSocket endpoint will use it later, to simulate ADF logout:


ADF HTTP session is referenced through WebSocket configurator:


Helper session listener class is defined in web.xml, here I'm copying JSESSIONID from the cookie into session attribute (to be able to reference JSESSIONID in WebSocket endpoint):


OnClose method in WebSocket endpoint is invoked, when connection channel between client and server is closed (browser is closed). Here I'm invoking custom method handleLogout method:


I'm constructing HTTP client request with the same JSESSIONID value as it was copied from ADF session. HTTP Get is executed against ADF Authentication servlet with logout request using JSESSIONID value. This is forcing ADF session to logout from simulated HTTP session by HTTP client: