Tuesday, May 29, 2018

Effective Way to Get Changed Rows in ADF BC API

Did you ever wondered how to get all changed rows in the transaction, without iterating through entire row set? It turns out to be pretty simple with ADF BC API method - getAllEntityInstancesIterator, which is invoked for Entity Definition attached to current VO.

Method works well - it returns changed rows from different row set pages, not only from the current. In my experiment, I changed couple of rows in the first page:


And couple of rows in 5th page. Also I removed row and created one:


Method returns information about all changed rows, as well as deleted and new:


Example of getAllEntityInstancesIterator method usage in VO Impl class. This method helps to get all changed rows in current transaction, very handy:


Sample application source code is available on GitHub.

Sunday, May 27, 2018

Oracle ADF BC REST - Performance Review and Tuning

I thought to check how well ADF BC REST scales and how fast it performs. For that reason, I implemented sample ADF BC REST application and executed JMeter stress load test against it. You can access source code for application and JMeter script on my GitHub repository. Application is called Blog Visitor Counter app for a reason - I'm using same app to count blog visitors. This means each time you are accessing blog page - ADF BC REST service is triggered in the background and it logs counter value with timestamp (no personal data).

Application structure is straightforward - ADF BC REST implementation:


When REST service is accessed (GET request is executed) - it creates and commits new row in the background (this is why I like ADF BC REST - you have a lot of power and flexibility in the backend), before returning total logged rows count:


New row is assigned with counter value from DB sequence, as well as with timestamp. Both values are calculated in Groovy. Another bonus point for ADF BC REST, besides writing logic in Java - you can do scripting in Groovy - this makes code simpler:


Thats it - ADF BC REST service is ready to run. You may wonder, how I'm accessing it from blog page. ADF BC REST services as any other REST, can be invoked through HTTP request. In this particular case, I'm calling GET operation through Ajax call in JavaScript on client side. This script is uploaded to blogger HTML:


Performance

I'm using JMeter to execute performance test. In below example, REST GET request is invoked in infinite loop by 100 concurrent threads. This creates constant load and allows to measure how ADF BC REST application performs under such load:


ADF BC REST scales well, with 100 concurrent threads it does request processing in 0.1 - 0.2 seconds. If we would compare it to ADF UI request processing time, it would be around 10 times faster. This is expected, because JSF and ADF Faces UI classes are not used during ADF BC REST request. Performance test statistics for 100 threads, see Avg logged time in milliseconds:


Tuning

1. Referenced Pool Size and Application Module Pooling

ADF BC REST executes request is stateless mode, REST nature is stateless. I though to check, what this mean for Application Module tuning parameters. I have observed that changing Referenced Pool Size value doesn't influence application performance, it works either with 0 or any other value in the same way. Referenced Pool Size parameter is not important for ADF BC REST runtime:


Application performs well under load, there are no passivations/activations logged, even when Referenced Pool Size is set to zero.


However, I found that it is still important to keep Enable Application Module Pooling = ON. If you switch it OFF - passivation will start to appear, which consumes processing power and is highly unrecommended. So, keep Enable Application Module Pooling = ON.

2. Disconnect Application Module Upon Release

It is important to set Disconnect Application Module Upon Release = ON (read more about it - ADF BC Tuning with Do Connection Pooling and TXN Disconnect Level). This will ensure there will be always near zero DB connections left open:


Otherwise if we keep Disconnect Application Module Upon Release = OFF:


DB connections will not be released promptly:


This summarises important points related to ADF BC REST tuning.

Thursday, May 17, 2018

Microservice Approach for Web Development - Micro Frontends

This post is based on my Oracle Code 2018 Warsaw talk. View presentation on slides share:


Wondering what micro frontends term means? Check micro frontends description here. Simply speaking, micro frontend must implement business logic from top to bottom (database, middleware and UI) in isolated environment, it should be reusable and pluggable into main application UI shell. There must be no shared variables between micro frontends. Advantage - distributed teams can work on separate micro frontends, this improves large and modular system development. There is runtime advantage too - if one of the frontends stops working, main application should continue to work.

I have implemented micro frontends architecture with Oracle JET. Source code is available on GitHub repository. There are three applications, two with micro frontends and one is the master UI shell. Both micro frontends are implemented as JET Composite Components. First is hosted on WebLogic, it calls ADF BC REST service in the backend. Second is hosted on Node.JS and returns static data. First micro frontend implements listener, it allows to handle actions from the outside.


When JET application is accessed in your browser, bunch of HTML, JS and CSS files are downloaded from the server. Core idea with micro frontends - instead of loading HTML, JS and CSS for micro frontend from the same host as master app - load it from different host. JET Composite Component rendered inside master application will be downloaded from different host. Not only downloaded, all backend calls should go to that host too, not to the master host. JET Composite Component integration into master application architecture:


This is how it works in practice. Each of these charts is separate JET Composite Component, loaded as micro frontend from different host into master application. We can see that in network monitor. Loader.js scripts for both micro frontends are downloaded from different hosts:


Runtime advantage - if one or multiple micro frontends are down, application continues to run:


JET Composite Component runs on the client, even it is hosted in its own micro frontend. This gives possibility to subscribe to the events happening in the component in the master app and route that event to another micro frontend. In this example, once item is selected in job chart - employees chart (another micro frontend) is filtered:


Technical implementation

Main application must be configured to support remote module loading for JET Composite Component. Read more about it in Duncan Mills blog post - JET Custom Components XII - Revisiting the Loader Script. In short, you should add Xhr config in JET application main.js:


Server where micro frontend is hosted, must set Access-Control-Allow-Origin header.

Main module where both micro frontends are integrated is using JET module component. Each micro frontend in master UI shell is wrapped into JET module. This allows main application to function, even when micro frontend in the module stops:


JET module is initialized from variable, which returns module name:


Jobs module contains Jobs micro frontend - JET Composite Component. It is hosted and WebLogic and calls ADF BC REST in the backend. Component is assigned with listener:


The most important part is in JS script. Here instead of referencing JET Composite Component locally, we load it from remote host. This allows to develop and host micro frontend JET Composite Component on its own:


Listener refers to c2 element and cals the method. Element c2 in the main app relates to second micro frontend:


This component is loaded from another host, from Node.JS:


Important hint - for JET Composite Component to load from remote host, make sure to add .js for JET Composite Component script, as highlighted (refer to source code):