Tuesday, December 5, 2017

JET Composite Component in ADF Faces UI - Deep Integration

Oracle JET team doesn't recommend or support integrating JET into ADF Faces. This post is based on my own research and doesn't reflect best practices recommended by Oracle. If you want to try the same - do it on your own risk. 

All this said, I still think finding ways of further JET integration into ADF Faces is important. Next step would be to implement editable grid JET based component and integrate it into ADF to improve fast user data entry experience.

Today post focus is around read-only JET composite component integration into ADF Faces. I would recommend to read my previous posts on similar topic, today I'm using methods described in these posts:

1. JET Composite Component - JET 4.1.0 Composite - List Item Action and Defferred Loading

2. JET and ADF integration - Improved JET Rendering in ADF

You can access source code for ADF and JET Composite Component application in my GitHub repository - jetadfcomposite.

Let's start from UI. I have implemented ADF application with regions. One of the regions contains JET Composite. There is ADF Query which sends result into JET Composite. There is integration between JET Composite and ADF - when link is clicked in JET Composite - ADF form is refreshed and it displays current row corresponding to selected item in JET Composite. List on the left is rendered from series of JET components, component implements one list item:

As you can see, there are two type calls:

1. ADF Query sends result and JET Composite. ADF -> JET call
2. JET Composite is forcing ADF form to display row data for selected item. JET -> ADF call

Very important to mention - JET Composite is getting data directly from ADF Bindings, there is no REST layer here. This simplifies JET implementation in ADF Faces significantly.

What is the advantage of using JET Composite in ADF Faces? Answer - improved client side performance. For example, this component allows to expand item. Such action in pure ADF Faces component would produce request to the server. While in JET it happens on the client, since processing is done in JS:

There is no call to the server made when item is expanded:

Out of the box - JET Composite works well with ADF Faces geometry. In this example, JET Composite is located inside ADF Panel Splitter. When Panel Splitter is resized, JET Composite UI is nicely resized too, since it is out of the box responsive. Another advantage of using JET Composite in ADF Faces UI:

When link "Open" is clicked in JET Composite - JS call is made and through ADF Server Listener we update current row in ADF to corresponding data. This shows how we can send events from JET Composite to ADF Faces:

It works to navigate to another region:

And come back - JET content is displayed fine even after ADF Faces PPR was executed (simple trick is required for this to work, see below). If we explore page source, we will see that each JET Composite element is stamped in HTML within ADF Faces HTML structure:

Great thing is - JET Composite which runs in JET, doesnt require any changes to run in ADF Faces. In my example, I only added hidden ID field value to JET Composite, to be able to pass it to ADF to set current row later:

I should give couple of hints regarding infrastructure. It is not convenient to copy JET Composite code directly into ADF application. More convenient is to wrap JET code into JAR and attach it this way to ADF. To achieve that, I would recommend to create empty Web project in JDEV, copy JET Composite code there (into public_html folder) and build JAR out of it:

Put all JET content into JAR:

If Web project is located within main ADF app, make sure to use Working Sets and filter it out to avoid it to be included into EAR during build process:

Now you can add JAR with JET into ADF app:

In order for JET HTML/JS resources to be accessible from JAR file, make sure to add required config into main ADF application web.xml file. Add ADF resources servlet, if it is not added already:

Add servlet mapping, this will allow to load content from ADF JAR library:

To load such resources as JSON, CSS, etc. from ADF JAR, add ADF library filter and list all extensions to be loaded from JAR:

Add FORWARD and REQUEST dispatcher filter mapping for ADF library filter from above:

As I mentioned above, JET Composite is rendered directly with ADF Bindings data, without calling any REST service. This simplifies JET Composite implementation in ADF Faces. It is simply rendered through ADF Faces iterator. JET Composite properties are assigned with ADF Faces EL expressions to get data from ADF Bindings:

JET is not compatible with ADF PPR request/response. If JET content is included into ADF PPR response - context gets corrupted and is not displayed anymore. To overcome this we are re-drawing JET context, if it was included into PPR response. This doesn't reload JET modules, but simply re-draws UI. In my example, ADF Query sends PPR request to the area where JET Composite renders result. I have overridden query listener:

Other methods, where PPR is generated for JET Composite - tab switch and More link, which loads more results. All these actions are overridden to call methods in the bean:

Method reDrawJet is invoked, which calls simple utility method to invoke JS function which actually re-draws JET UI:

JET UI re-draw happens in JS function, which cleans Knockout.JS nodes and reapplies current JET model bindings:

JET -> ADF call is made through JET Composite event. This event is assigned with JS function implemented in ADF Faces context. This allows to call JS located in ADF Faces, without changing JET Composite code. I'm using regular ADF server listener to initiate JS -> server side call:

ADF server listener is attached to generic button in ADF Faces:

ADF server listener does it job and applies received key to set current row in ADF. Which automatically triggers ADF form to display correct data:

Monday, November 27, 2017

JET 4.1.0 Composite - List Item Action and Defferred Loading

I was reviewing JET 4.1.0 features and decided to build simple composite component. Would like to share some of the items I learned.

Composite component comes with collapsible UI and action link, it implements list item, which can be rendered in any kind of parent UI container:

When item is expanded, more info is displayed:

Once user clicks on Open link, JS call is made and key from current item is printed in the background:

Let's take a look into component metadata. I'm using several properties and one event. Through event we can call JS method outside of composite component, this can be very useful:

How this event is used? Take a look into composite HTML implementation, click is handled by JS method, inside that function event will be initialized:

One more interesting thing - I'm using JET Defer functionality, to render HTML expandable content, when item is expanded. This allows to minimize client side load by lazy loading, renders content when it is displayed:

JS method, which handles click - creates event. This will allow to execute event implementation method outside composite component. Syntax looks pretty similar to ADF Server listener call:

Naming of the event is important. If event name is openDetails, then make sure to use on-open-details as property name for the event handler in composite component interface. Here I define external method to be invoked when event is fired:

Here is the code for event listener JS method in main view module:

Let's see how JET Defer works on runtime. This is source from JET running app, when list item is rendered initially, there is no content for expanded block - it only contains JET Defer block:

After we expand it:

Content is rendered in source. This is called lazy loading and this concept allows to improve performance, especially for large lists (or tabs, etc.), when a lot of content is rendered:

Now few hints how to create JET Composite with OJET tooling. Run similar command (if you run this command outside JET app context, it will create new shell JET app with this component. if you run command in context of JET app, it will create component inside the app):

ojet create component list-itemrs

This will create JET Composite with given name. To be able to run JET Composite from index page, add applyBindings to main.js require block:

Don't forget to add JET composite module and actual composite loader:

Finally add your own JET Composite tag to index.html:

Sample code can be accessed in GitHub repository (run ojet restore) - list-itemrs.

Thursday, November 23, 2017

TensorFlow - Getting Started with Docker Container and Jupyter Notebook

I'm studying Machine Learning and would like to share some intro experience working with TensorFlow. To get started with TensorFlow you need to install it, easiest way (at least for me) was to run TensorFlow using Docker. Read installation instructions - Installing TensorFlow.

Once TensorFlow Docker image is installed. I suggest to create container in detach mode (--detach=true) and provide port for Jupyter UI. Make sure to provide meaningful name for Docker container:

docker run --detach=true --name RedSamuraiTensorFlowUI -it -p 8888:8888 gcr.io/tensorflow/tensorflow

Make sure to start and stop container using Docker start/stop commands, don't run and create container each time (this way you will loose your work, since new container will be created each time):

docker start RedSamuraiTensorFlowUI (docker stop RedSamuraiTensorFlowUI)

Once container is running in detached mode, you can access logs by executing docker logs command and specifying container name:

docker logs -f RedSamuraiTensorFlowUI

At this point you should see output in Docker container log, copy URL to Jupyter UI with token and paste it to the browser (for example: http://localhost:8888/?token=d0f617a4c719c40ea39a3732447d67fd40ff2028bb335823):

This will give you access to Jupyter UI. Is possible to run TensorFlow Python scripts directly through command line in Docker environment, but is more convenient to do the same through UI:

UI gives option to create new Terminal session:

Terminal allows to run Python code using command line:

Instead of using command line, more convenient is to create new notebook:

Notebook environment allows to type in Python code and execute math calculations. In the example below I multiply two arrays (1x5, 2x6, 3x7, 4x8) in Python code through TensorFlow library. Result is printed through TensorFlow session object right below and prompt for the next command is displayed - very convenient:

Jupyter UI allows to track running notebooks and terminals:

Whatever action you do in Jupyter UI, it can be tracked using log printed in Docker container log. Jupyter UI is client side JS application:

To double check Docker config, I have TensorFlow Docker image:

And Docker container, which can be started/stopped by name (see command listed above), without running new Docker container every time during restart:

Sunday, November 19, 2017

How to Setup Node.js and Oracle JET on Oracle Linux

What if you want to develop Oracle JET in Oracle Linux? Certainly this is possible - both Node.js and Oracle JET run on Oracle Linux or any other Linux distribution. If you follow Oracle JET Setup Guide, you will see Node.js is listed as prerequisite. But it may not be exactly straightforward to install Node.js on Oracle Linux. Below I will guide you through the steps.

Run command to install development tools to build native add-ons to be installed:

yum install -y gcc-c++ make

Enable Node.js yum repository:

curl -sL https://rpm.nodesource.com/setup_8.x | sudo -E bash -

Install Node.js:

sudo yum install nodejs

Verify if node and npm was installed successfully:

Next you can follow steps described in Oracle JET setup guide, all straightforward. Install Oracle JET:

sudo npm -g install @oracle/ojet-cli

Create new JET application with OJET utility:

sudo ojet create jetwinapp --template=navdrawer

Run application with OJET utility:

sudo ojet serve

JET application runs on Oracle Linux: