Friday, October 19, 2018

ADF Task Flow Performance Boost with JET UI Shell Wrapper

ADF application with UI Shell and ADF Task Flows rendered in dynamic tabs would not offer instant switch from one tab to another experience. Thats because tab switch request goes to the server and only when browser gets response - tab switch happens. There is more to this - even if tab in ADF is not currently active (tab is disclosed), tab content (e.g. region rendered from ADF Task Flow) still may participate in the request processing. If user opens many tabs, this could result in slightly slower request processing time overall.

ADF allows to render ADF Task Flows directly by accessing them through URL, if it is configured with page support on the root level. ADF Task Flow can be accessed by URL, this means we can include it into iframe. Imagine using iframe for each tab and rendering ADF Task Flows inside. This will enable ADF Task Flow independent processing in each tab, similar to opening them in separate browser tab.

Iframe can be managed in Oracle JET, using plain JavaScript and HTML code. My sample implements dynamic JET tabs with iframe support. Iframe renders ADF Task Flow. While navigating between tabs, I simply hide/show iframes, this allows to keep the state of ADF Task Flow and return to the same state, when opening back the tab. Huge advantage in this case - tab navigation and switching between tabs with ADF Task Flows works very fast - it takes only client time processing. Look at this recorded gif, where I navigate between tabs with ADF content:


Main functions are listed below.

1. Add dynamic iframe. Here we check if frame for given ADF Task Flow is already created, if no we create it and append to HTML element


2. Select iframe, when switching tabs. Hide all frames first, select frame which belongs to the selected tab


3. Remove iframe. Remove frame, when tab is closed


4. Select frame after remove. This method helps to set focus to the next frame, after current tab was removed


We can control when iframe or regular JET module is rendered, by using flag computed function assigned to main div:


In this app I have defined static URL's for displayed ADF Task Flows. Same can be loaded by fetching menu, etc.:


To be able to load ADF Task Flow by URL, make sure to use ADF Task Flow with page (you can include ADF region with fragments into that page). Set url-invoke-allowed property:


This is how it looks like. By default, JET dashboard module is displayed, select item from the menu list to load tab with ADF Task Flow:


JET tab rendering iframe with ADF table:


You can monitor ADF content loading in iframe within JET application:


JET tab rendering iframe with ADF form:


Download sample app from GitHub repository.

Wednesday, October 10, 2018

Oracle Offline Persistence Toolkit - Applying Server Changes

This is my final post related to Oracle Offline Persistence Toolkit. I will show simple example, which explains how to apply server changes, if data conflict comes up. Read previous post about - Oracle Offline Persistence Toolkit - Submitting Client Changes.

To apply server changes is easier, than to apply client changes. You need to remove failed request from sync queue and fetch server data to client by key.

Example of data conflict during sync:


User decides to cancel his changes and bring data from the server. GET is executed to fetch latest data and push it to the client:


In JS code, first of all we remove request from sync queue, in promise we read key value for that request and then refetch data:


Download sample code from GitHub repository.

Sunday, October 7, 2018

Oracle Offline Persistence Toolkit - Submitting Client Changes

One of the key topics related to Oracle Offline Persistence toolkit - submitting client changes to backend when data conflict exists. If data was updated on the backend, while client was offline and client wants to submit his changes - we inform about the conflict and ask what client really wants to do. If client choose to submit changes, this means we should push client changes to the backend with the latest change indicator.

There is a special case, when client updates same data multiple times while offline - during online sync we need to make sure, change indicator will be retrieved in after sync and applied in before sync listeners, to make sure subsequent requests execute correctly. Check my previous post about before request sync listener - Oracle Offline Persistence Toolkit - Before Request Sync Listener.

Example - let's update a record and submit change to the backend:


Assume another user is offline and updates same record:


User updates same record again, before going online. Now we will have two requests in the sync queue:


Once going online, sync will be executed and we will get conflict for the first request (same row was updated already by another user). At this moment, after sync listener will get info about conflict and will cache latest change indicator value returned from backend. If user decides to apply his changes, requests is removed, new request is constructed with the latest change indicator value received from backend and this request is inserted into sync queue:


If same record was updated multiple times, second request will fail too - because this request wasn't updated yet with latest change indicator:


Assuming user decided to apply changes from the second request too, we will update request with latest change indicator and submit it for sync. In after sync listener, change indicator value stored in local cache will be updated.

Successful sync with change indicator = 296:


New change indicator value will be retrieved in after sync listener and applied in before sync listener for the second request, updating same data row:


Here is the code, which allows user to apply changes to backend. We remove failed request, update it and create new request in sync queue, resuming sync process:


Download sample code for the described use case from my GitHub repository.

Tuesday, October 2, 2018

Oracle Offline Persistence Toolkit - Before Request Sync Listener

One more post from me related to Oracle Offline Persistence Toolkit. I already described how after request listener could be useful to read response data after sync - Oracle Offline Persistence Toolkit - After Request Sync Listener. Today will explain when before request listener could be useful. Same as after request listener, it is defined during persistence manager registration:


Before request listener must return promise. We can control resolved action. For example if there is no need to update request, we simply return continue. We would need to update request, if same row is updated multiple times during sync. Change indicator value must be updated in request payload. We read latest change indicator value from array, initialised in after request listener. Request payload is converted to JSON, value updated and then we construct new request and resolve it with replay. API allows to provide new request, by replacing original:


Here is the use case. While offline - update value:


While remaining offline, update same value again:


We should trace executed requests during sync, when going online. First request, initiated by first change is using change indicator value 292:


Second request is using updated change indicator value 293:


Without before and after request listener logic, second request would execute with same change indicator value as the first one. This would lead to data conflict on backend.

Sample application code is available on GitHub.

Friday, September 28, 2018

Oracle Offline Persistence Toolkit - After Request Sync Listener

In my previous post, we learned how to handle replay conflict - Oracle Offline Persistence Toolkit - Reacting to Replay Conflict. Additional important thing to know - how to handle response from request which was replayed during sync (we are talking here about PATCH). It is not as obvious as handling response from direct REST call in callback (there is no callback for response which is synchronised later). You may think, why you would need to handle response, after successful sync. Well there could be multiple reasons - for instance you may read returned value and update value stored on the client.

Listener is registered in Persistence Manager configuration, by adding event listener of type syncRequest for given endpoint:


This is listener code. We are getting response, reading change indicator value (it was updated on the backend and new value is returned in response) and storing it locally on the client. Additionally we maintain array with mapping of change indicator value to updated row ID (in my next post I will explain why this is needed). After request listener must return promise:


On runtime - when request sync is executed, you should see in the log message printed, which shows new change indicator value:


Double check in payload, to make sure request was submitted with previous value:


Check response, you will see new value for change indicator (same as in after request listener):


Sample code can be downloaded from GitHub repository.

Saturday, September 22, 2018

Oracle Offline Persistence Toolkit - Reacting to Replay Conflict

This is next post related to Oracle Offline Persistence Toolkit. Check my previous writing on same subject - Implementing Handle Patch Method in JET Offline Toolkit. Read more about toolkit on GitHub repo.

When application goes online, we call synchronisation method. If at least one of the requests fails, then synchronisation is stopped and error callback is invoked, where we can handle failure. In error callback, we check if failure is related to the conflict - then we open dialog, where user will decide what to do (to force client changes or take server changes). Reading latest change indicator value from response in error callback (to apply it, if user decides to force client changes in the next request):


Dialog is simple - it displays dynamic text for conflicted value and provides user with a choice of actions:


Let's see how it works.

User A editing value Lex and saving it to backend:


User B is offline, editing same value B and saving it in local storage:


We can check it in the log - changes value was stored in local storage:


When going online, pending requests logged offline, will be re-executed. Obviously above request will fail, because same value was changed by another user. Conflict will be reported:


PATCH operation fails with conflict code 409:


User will be asked - how to proceed. To apply changes and override changes in the backend, or on opposite take changes from the backend and bring them to the client:


I will explain how to implement these actions in my next post. In the meantime you can study complete application available on GitHub repo.

Wednesday, September 19, 2018

Query Logic Implementation in VBCS for ADF BC REST

Oracle Visual Builder Cloud Service allows to define external REST service connections. In this post I will explain how to implement query logic against such service. Connection is defined for ADF BC REST service.

Wizard provides option to add query parameters, both static and dynamic. I have set one static parameter onlyData=true, to return data only from the service. Also I have created multiple dynamic parameters, the one used in this use case - q parameter. This parameter accepts query expression to filter data. Later in VBCS action chain, I will assign value to this parameter and service will be re-executed to bring filtered data:


Search form elements will be assigned with page scope variables, to hold user query input. On search button click, VBCS action chain will be invoked to read these values and update query parameter. Page scope variables:


Variables firstNameQueryVar and lastNameQueryVar are assigned to search form fields, here is example:


Search button invokes action chain:


Action chain does two things - calls JS function to construct query parameter and then assigns returned value to rest service query parameter to execute search:


JS function is mapped to accept input parameters from search form input fields:


JS function code - parameters are joined into ADF BC REST query string:


JS function result is mapped with page scope variable - result is assigned to this variable:


REST service query parameter q variable is assigned with this value. Once value changes, query is automatically re-executed:


In my next post I will explain how to implement filtering and pagination with transformation function, on top of service connection:


VBCS sample application code is available on GitHub (if you download ZIP from GitHub, make sure to extract it and create new archive including extracted content directly, without top folder).