These past days we had the oppportunity to give Oracle Jet a try. Coming from the javascript world, I was really happy to discover that Oracle had started using Javascript for their own products and even released Jet as an open-source library.
The challenge
As our Middleware team is running performance tests for SOA/BPM nowadays, one of the areas of focus is the use of Weblogic Data Sources. So a colleague asked me if we could perhaps use Oracle Jet to plot data obtained from MBeans, thus allowing us to monitor these in real-time. We developed a quick API for exposing MBeans as REST services using Jersey (we are using 11g for this) and deployed it to all targets, including the Admin server.
The JMX API
The REST API has 3 methods:
- [GET] /get/{mbean}: returns all attributes from the mbean attribute
- [GET] /find/{filter}: lists all object names found using the filter
- [POST] /query/{filter}?key=Name: returns specific stats from target object names and attributes, grouped by the Name attribute
Getting started
Following the getting started guide, it was really easy to create a project to test. At first, we used the Netbeans approach to quickly start up, but then we moved on to the second approach (the one listed in the quickstart guide) and used yeoman, grunt and bower instead.
The Frontend API client
After yeoman created our project, we developed our client module with all the functions needed to access our backend service:
We then wrapped this into a RequireJs module so we could add it the requireJs config, thus importing it using the keyword jmx_client
in the rest of the components. The result looks like this:
Sharing variables between components
We created the config module, which works basically like the jmx_client :
In this way we can share configuration information between components and/or modules.
Dealing with knockout components and Oracle ojModules
The latest version of Knockout JS allows creating custom html tags, similar to the web components standard, which is an excellent way to organize the different parts of an application.
However, Oracle Jet does not take advantage of this yet and rather uses its own ojModule. While this is not really a problem per-se, it does mix things up a bit and makes development a bit messy if you are trying to use the knockout way.
Our final structure is this:
js/
├── app
├── components
├── libs
├── main-release-paths.json
├── main.js
├── viewModels
└── views
We kept the views/viewModels folder to load the page controllers and to allow us to have the knockout components in our components folder. Therefore, if our app grows we can segregate between smart and dumb components (as in Redux/ReactJS) allowing us to have a cleaner project structure in the same way that all modern javascript frameworks are doing nowadays (KnockoutJs, React, Angular 2).
Knockout Components
The first step we took to use our own components was to create a file into app folder called register_components.js, an utility to help registering the other components to use in our app:
By adding this file in the require definition of our main.js all the components to use in our app will be added automatically. As for the project structure, we use a folder structure as follows:
js/components
└── widget
├── widget.html
└── widget.js
With the widget.html containing the component HTML template while the widget.js skeleton contains all the component logic:
The last step is then to just use our custom tag wherever we want in our HTML files and even pass parameters where needed, which can then be referenced in the WidgetModel's params argument:
Adding third party libraries
One of the most wonderful things of open-source technologies is that the community involved is usually quite large, which helps create a variety of good quality of modules, libraries and resources. To experience how to deal with using external libraries when developing with Oracle Jet, we attempted to add one of the most popular date parsing libraries called momentjs.
As we are using bower to handle libraries, the command bower install moment —save
saves your library under bower_components folder in your root project folder. This however was not enough to make use of the library. Since libraries are loaded from the js/libs folder (see folder structure below), this means that you need to take an additional step.
.
├── bower_components
│ ├── es6-promise
│ ├── hammerjs
│ ├── jquery
│ ├── jquery-ui
│ ├── js-signals
│ ├── knockout
│ ├── moment
│ ├── oraclejet
│ ├── requirejs
│ └── text
└── js
└── libs
├── dnd-polyfill
├── es6-promise
├── hammer
├── jquery
├── js-signals
├── knockout
├── moment
├── oj
└── require
The libs folder is generated by a grunt task called bower_copy
. Every time you run grunt build
it automatically re-creates the libs folder.
Thus, the additional step you need to take is edit the bower_copy task in scripts/grunt/config and add the files to be copied to libs folder, as shown below:
After running grunt build
the momentjs library is copied to the libs folder and all we need to do then is add it to our list of libraries in our requirejs.config
:
Using the library becomes straightforward: just import moment and pass it as an argument:
Personally it seems a bit strange to have to deal with these steps for every third-party library that we use. Other frameworks deal with this automatically directly from using bower. Whilst is not the end of the world, it does mean that we need to follow a few extra steps which at the end of the day means another thing that can go wrong.
Working with Oracle Jet Charts
This was the easiest part of the exercise. Adding a chart is straightforward and keeping it updated is just referencing an array of data in the model, which again does not imply a great deal of work. In the case below we are rendering a series of lines for each datasource chart:
We use a javascript setInterval function to periodically fetch obtain data then push the values for the datasources/fields arrays. By using an observableArray the charts are updated automatically.
Performance
It is worth mentioning that we can end up with 10 or more charts, each displaying 10 lines ore more. As you might imagine, this is quite heavy for the client side, since every piece of data is stored in memory. Also, we needed to disable every chart animation, since it would cause a re-draw every time data is added.
The best solution for this problem is to avoid updating the data in real time and rather record the values and then render them when the performance test has finished.
So, how does the final application look like?
Conclusion
Things I didn't like
- Quite a bit of knowledge on different technologies is required (yeoman, bower, grunt, etc.)
- Jet is based on AMD modules which makes it more difficult to use with other frameworks
- Looks to merge with webpack projects
- Too dependant on knockoutJs and RequireJs, which seems to be against the trend nowadays of making agnostic frameworks
- The documentation is not really clear of the SASS/CSS process
- The documentation to make more complex things is hard to find and to read, as it is not very clear sometimes
Things I did like
- Jet is open-source and based on trending technologies (yeoman, bower, grunt etc.)
- It provides a large and fancy catalogue of components that every application needs
- The components are easy to understand and use
- The basic documentation is nice (there are lots of examples on how to do things)
- You can use any Javascript module you want (with bower)
- You can use SASS or another proprocessors for CSS, thanks to a grunt tasks
- It is mobile ready (using a Cordova module)
Wishlist
- Improve the docs and provide more complex examples
- Improve the core by dropping the AMD modules definition
- Compatibility with ES6 syntax or at least support ES6 module definition
- Update the core making a more independent system from a framework, or at least offer a solution to use in the most trending frameworks
- Update grunt tasks to provide better control over assets generation, css pre-processing etc. and automate bower components installation
- Update ojModule and Router to make use of the latest knockoutJs features
Overall, I think Oracle Jet needs a bit of work on its core to make it more independent from KnockoutJs and thus turn it into a real Javascript library. In addition, it also needs to be compatible with ES6 modules which are becoming the de-facto standard.
I really like the fact that Jet is quite easy to use once you get started. And to be fair, the fact that Oracle has started to develop Javascript resources (and open-source them) definitely looks like steps in the right direction and definitely a possitive movement for them. +1 Oracle!