Tuesday, November 6, 2018

Data Conflict Solution for ADF BC REST with Versioning

I would like to share sample solution for data conflict processing in ADF BC REST using versioning. When multiple users are editing concurrently the same data row - it is important to inform user before overriding changes already committed by another user. There are other approaches to implement data conflict control, you should evaluate if solution explained below is suitable for your use case, before applying it.

I'm using custom change indicator property, to evaluate if client data is expired. Change indicator value is sent to the client together with request data. PATCH request must include current client side change indicator value, if change indicator will match value in backend - PATCH is allowed, otherwise new change indicator will be returned to the client and response will be marked with 409 Conflict status code. Based on this, client could decide either to resubmit PATCH request with new change indicator and overwrite current data in DB or refresh client side data and try to submit changes later.

In this example - PATCH was executed with valid change indicator, response status is 200 OK. New change indicator value is returned to the client (it should be submitted for the next PATCH call for current row):




To test data change conflict, I would go directly to DB and change same record. Change indicator will be updated too:



Client doesn't know about change indicator update (data was changed by another user). Client will include currently known change indicator value and execute PATCH. This will result in 409 Conflict status. Backend returns latest change indicator value in the response:



Data wasn't updated, PATCH request was stopped on the backend:



Client knows latest change indicator value and can submit it again - this time successful (no one else changed data in the meantime):



Status 200 OK is returned, along with new change indicator value. Data is changed in DB as expected:



Backend implementation is not complex. You need DB trigger, which will get value from DB sequence and assign it for each changed row:



ADF BC REST includes change indicator attribute, it is marked with Refresh on Update support. This allows to get latest value assigned from DB trigger and return it to the client:



In doDML method we compare change indicator attribute value currently stored in DB and the one which comes from the client. If values do not match (client doesn't have the latest value) - update is not allowed:



When update is not allowed, we also must change HTTP response code to be 409 Conflict. This will allow to execute error callback on client side and take required action to process data conflict on the client. HTTP response code is set from custom ADF BC REST filter:


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):




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:





Implementing Handle Patch Method in JET Offline Toolkit

When executing PATCH requests offline, JET Offline Persistence Toolkit will record that request and synch it to the backend, once online. But it will not update data stored in cache, this is by design. Since cached data will not be updated, search queries against offline cache would not bring results based on latest changes. To solve this we need to implement cache update ourself by providing handle patch method.

Handle patch is configured through requestHandlerOverride property while registering persistence manager:



Sample implementation for handle patch. This method is invoked, when PATCH is executed while offline only. We must read information from request and pass it to cache store. Search for entry in cache based on key, updating record and updating info back to the store:




Let's do offline test - switch browser tab to be offline (you can do it Chrome browser developer tools). Do search and check log from JET Offline Persistence Toolkit - it executes search automatically against cache store:


Update same record, while offline - PATCH request will be recorded for later synchronisation. Our handle patch method will be invoked to write changes to cache store:


You will notice in the log, actions executed from handle patch method. It finds record by key in cache and updates it:



Search by updated value - updated value is found and returned from cache store:








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:






Monday, October 29, 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:


Sunday, October 28, 2018

Oracle Webcenter Sites 12c (12.2.1) – Installation & Configuration

In this post I will show you how to install & configure Oracle Webcenter Sites 12c (12.2.1) on Oracle Linux 6.7.


My Environment:
  • Oracle Linux 6.7 64 Bit Virtual Machine
  • Oracle Database 12.2.0.4
  • Oracle Fusion Middleware Infrastructure 12.2.1.0
  • Oracle Webcenter Sites 12.2.1
  • Java Development Kit (JDK) 1.8
I have my Oracle Linux 6.7 64 Bit virtual machine already built along with Oracle Database 12c & JDK 1.8.

Software Required:
  • fmw_12.2.1.0.0_wcsites.jar
  • fmw_12.2.1.0.0_infrastructure.jar
Fusion Middleware Infrastructure Installation:
  • Make sure JAVA_HOME is set & JAVA executable is added to PATH environment variable.
  • Navigate to software directory and execute infrastructure installer using JAVA
  • Follow the on screen instructions as shown per below screen shots.










Oracle Webcenter Sites Installation:
  • Navigate to software directory and execute WebCenter Sites installer using Java
  • Click Next on the welcome screen


  • Skip Auto Updates and click Next
  • Provide Middleware Home used during Infrastructure Installation. Click on View to confirm the components in Middleware Home
    • /u01/app/oracle/product/fmw
  • Select Webcenter Sites and click Next
  • Make sure prerequisite checks are successful and click Next
  • Click Install on the Summary screen
  • Make sure all installation steps are successful and click Next
  • Click Finish on Installation Complete screen

Oracle Webcenter Sites Repository Creation:
  • Navigate to oracle_common/bin and execute RCU
  • Click Next on the welcome screen
  • Select “Create Repository” – “System Load and Product Load” and click Next
  • Provide database details as per below screenshot and click Next. Make sure you are using sys account and selected “SYSDBA” role
  • Make sure DB prerequisites are successful and click OK
  • Provide schema prefix and select below components
    • WebCenter Sites
    • WebCenterSites – Visitor Services
  • Below components are selected automatically
    • AS Common Schemas – Oracle Platform Security Services
    • AS Common Schemas – Audit Services
    • AS Common Schemas – Audit Services Append
    • AS Common Schemas – Audit Services Viewer
  • Make sure component specific prerequisites are successful and click OK
  • provide schema password and click Next
  • Verify table spaces and click Next. Click OK on the confirmation screen. Change the table space parameters if required by click “Manage tablespaces”


  • Click create on Summary screen
  • Repository creation progress
  • Make sure the creation status is success for each component and click Close


Oracle Webcenter Sites Domain Creation:

  • Navigate to oracle_common/common/bin and execute configuration script
  • Select “Create a new domain”, provide domain location and click Next
    • Domain Location : /u01/app/oracle/product/fmw/user_projects/domains/WCSDomain
  • Select below product templates and click Next
    • Oracle WebCenter Sites
    • Oracle WebCenter Sites – Visitor Services
    • Oracle WebCenter Sites – Insights
    • Oracle WebCenter Sites – SiteCapture
    • Oracle WebCenter Sites – Satellite Server
  • Below components are selected automatically
    • Oracle Enterprise Manager
    • Oracle JRF
    • Weblogic Coherence Cluster Extension
  • Provide Application Location and click Next
    • Application Location : /u01/app/oracle/product/fmw/user_projects/applications/WCSDomain
  • Provide Weblogic administration username & password and click Next
  • Select production Mode & JDK Location and click Next
  • Provide STB schema details and click “Get RCU Configuration” and make sure schema retrieval is successful
  • Verify retrieved schema and click Next
  • Make sure JDBC component schema test is successful for all schema and click Next
  • Select below components in “Advanced Configuration” and click Next
    • Administration Server
    • Node Manager
    • Managed Servers, Clusters and Coherence
  • Provide Admin Server name, port & listen address and click Next
  • Select “Per Domain Default Location”. Provide Node Manager username & password and click Next
  • Provide managed Server details as shown below and click Next
  • Clusters are recommended in Production environments. For test & single server environments clusters can be ignored
  • Leave default values for Coherence cluster and click Next
  • Create Unix Machine with below details and click Next
  • Assign Managed servers to the newly created machine and click Next
  • Click Create on “Configuration Summary” screen
  • Make sure domain creation process is successful and click Next
  • Make a note of Domain Location & Administration URL and click Finish

Oracle Webcenter Sites Domain Startup:
  • Navigate to DOMAIN_HOME/bin and execute startNodeManager
  • Navigate to DOMAIN_HOME and create security directory using below commands
  • Create boot.properties inside security directory with below content
  • Execute startWeblogic.sh from Domain Home
  • Once Admin Server is started completely, start Managed Servers from Weblogic administration console URL
  • Make sure all managed servers are in RUNNNING state


Oracle Webcenter Sites Configuration:
  • Grant OPSS permissions to /u01/app/oracle/product/fmw/wcsites/wcsites_common/lib/sites-security.jar using below command
  • Access below URL to start Webcenter Sites Configurator
  • Click Begin on the Configurator Home Page
  • Provide WCS Shared Directory path or accept the default path and click Next
    • Default Location : /u01/app/oracle/product/fmw/user_projects/domains/WCSDomain/wcsites/config
  • Provide the Data Source Name of WCS database.
    • wcsitesDS
  • Provide Web Application Parameters as below and click Next
  • Provide CAS Deployment Information as shown below and click Next
  • Provide passwords for Administrator accounts and click Next
  • Click Test to test the configuration and make sure the configuration test is successful

  • Configuration progress. The configuration might take approximately 10-15 minutes.
  • Make sure the configuration is successful.
  • Restart wcsites_server1 Managed Server.
Oracle Webcenter Sites Console:
  • Access Webcenter Sites Console using below URL.
  • Login using “fwadmin” and password provided during configuration
  • Select Admin Site and click on WEM Admin, Admin Icons
  • WEM Admin Application Home Page
  • Sites Admin Application Home Page
Thats It !! You now have a working Oracle Webcenter Sites 12c installed & configured.
Hope you found this post helpful. If you have any questions please post in the comments section.