Using Oracle JET with VisionX/JVx

Post to Twitter

The shiny new technology from Oracle is JET (Javascript Extension Toolkit). It's a really interesting thing because it bundles relevant technologies like jQuery, jQuery UI, Knockout, Require, Hammer, ...

You don't need know-how for every used technology, only JET is enough. This is a nice and new approach in the JS world. A possible problem with such an approach could be the update of single libraries, but this isn't your problem because Oracle has to maintain the right versions and bugfixes in JET. So it's not our problem :)

I'm not a big fan of Javascript libraries/technologies but from time to time I like to play around with such things and proof the interaction with JVx. Some time ago my new friend was AngularJS.

This time, I tried to work with Oracle JET.

The use-case was trivial: I'd like to visualize a list of contacts as simple table. The contacts are available as REST service. The REST service needs basic authentication.

Foreword: JET has much documentation and some useful examples, but it's inconsistent because the documentation shows different solutions for the same problem and you don't know which is best or recommended. And the examples are sometimes too complex. The start with existing examples is simple but if you start coding, it's not so simple. But this is a documentation problem and has nothing to do with the product itself. I prefer source code to find out how things work and this procedure worked without problems for JET.

Foreword 2: I couldn't find a description for Basic authentication. Not in the forum, not in the documentation and not in different blog posts. But I found many questions regarding Basic authentication. I found a solution for the problem but if someone has a better solution, please add a comment. My solution is more or less not API compliant - but works with JET version 1.1.2 and hopefully with newer versions as well.

Conditions

I've used our VisionX tool and the Contacts demo application for this example because VisionX has an embedded tomcat and REST access is pre-configured. It's not tricky to use any other simple JVx application but it requires more work because you need an application server and a deployed application.

The Trial version of VisionX is a good start. Before I show you the source code, I'll show you the result:

Contacts table

Contacts table

You're right, this isn't rocket science. But it's not hard to add more columns and some css.

What about the source code?

We have one html page, index.html:

<!DOCTYPE html>

<html>
  <head>
    <title>JET with VisionX/JVx</title>
   
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="icon" href="css/images/favicon.ico" type="image/x-icon" />

    <link rel="stylesheet" href="css/libs/oj/v1.1.2/alta/oj-alta-min.css" type="text/css"/>
    <link rel="stylesheet" href="css/demo-alta-patterns-min.css"/>
    <link rel="stylesheet" href="css/override.css" type="text/css"/>

    <script data-main="js/main" src="js/libs/require/require.js"></script>
  </head>
 
  <body>
    <br/>
    <div id="mainContent" class="oj-md-12 oj-col page-padding">
      <div class="demo-page-content-area page-padding">  
        <h1>Contacts via VisionX</h1>
        <br/>
        <table id="table"
          data-bind="ojComponent: {component: 'ojTable',
                                   data: dataSource,
                                   columns: [{headerText: '#',
                                              field: 'ID', sortable: 'enabled'},
                                             {headerText: 'First name',
                                              field: 'FIRSTNAME', sortable: 'enabled'},
                                             {headerText: 'Last name',
                                              field: 'LASTNAME'}]}">

        </table>
      </div>
    </div>    
  </body>
</html>

We need two javascript files, main.js:

requirejs.config({
    paths: {
        'knockout': 'libs/knockout/knockout-3.3.0',
        'jquery': 'libs/jquery/jquery-2.1.3.min',
        'jqueryui-amd': 'libs/jquery/jqueryui-amd-1.11.4.min',
        'promise': 'libs/es6-promise/promise-1.0.0.min',
        'hammerjs': 'libs/hammer/hammer-2.0.4.min',
        'ojdnd': 'libs/dnd-polyfill/dnd-polyfill-1.0.0.min',
        'ojs': 'libs/oj/v1.1.2/min',
        'ojL10n': 'libs/oj/v1.1.2/ojL10n',
        'ojtranslations': 'libs/oj/v1.1.2/resources',
        'signals': 'libs/js-signals/signals.min',
        'text': 'libs/require/text'
    },
    shim: {
        'jquery': {
            exports: ['jQuery', '$']
        },
        'crossroads': {
            deps: ['signals'],
            exports: 'crossroads'
        }
    },
    config: {
        ojL10n: {
            merge: {
                //'ojtranslations/nls/ojtranslations': 'resources/nls/menu'
            }
        }
    }
});

require(['ojs/ojcore',
         'knockout',
         'jquery',
         'app',
         'ojs/ojknockout',
         'ojs/ojknockout-model',
         'ojs/ojdialog',
         'ojs/ojinputtext',
         'ojs/ojinputnumber',
         'ojs/ojbutton',
         'ojs/ojtable',
         'ojs/ojdatacollection-common'],
        function(oj, ko, $, app)
        {
            var vm = new app.contactsVM();
         
            $(document).ready(function()
            {
                ko.applyBindings(vm, document.getElementById('mainContent'));

                //Show the content div after the REST call is completed.
                $('#mainContent').show();
            });
        });

and app.js

define(['ojs/ojcore', 'knockout', 'ojs/ojmodel'],
       function(oj, ko)
       {
           function viewModel()
           {
                var self = this;
                self.serviceURL =
                   'http://localhost/services/rest/vxdemo/ContactsWorkScreen/data/contacts';
                self.dataSource = ko.observable();
                self.ContactsCollection = ko.observable();
               
                self.myBasicAuth = function() {};
                self.myBasicAuth.prototype.getHeader = function ()
                {
                    var headers = {};
                    headers['Authorization'] = 'Basic ' + btoa("admin:admin");
                   
                    return headers;
                };
               
                parseContact = function(response)
                {
                    return {ID: response['ID'],
                            FIRSTNAME: response['FIRSTNAME'],
                            LASTNAME:response['LASTNAME']};
                };

                var Contact = oj.Model.extend(
                {
                    urlRoot: self.serviceURL,
                    parse: parseContact,
                    idAttribute: 'ID'
                });
   
                var myContact = new Contact();
               
                var ContactsCollection = oj.Collection.extend(
                {
                    url: self.serviceURL,
                    model: myContact,
                    oauth: new self.myBasicAuth(),
                    comparator: "ID"
                });
               
                self.ContactsCollection(new ContactsCollection());
               
                //simple Request test
                //self.ContactsCollection().fetch({headers: {"Authorization": 'Basic ' + btoa("admin:admin")}});
               
                self.dataSource(new oj.CollectionTableDataSource(self.ContactsCollection()));      
           }

           return {'contactsVM': viewModel};
        }
    );

Above files are not enough to run the example because you need a full JET application. You can download a JET application from the official site (-> Getting started with Oracle JET -> Downloading Oracle JET). The QuickStart template works well. Unzip the application into the directory: <VisionX_folder>/rad/apps/visionx/WebContent/ojet (ojet must be created manually). Simply copy the example files in the ojet, ojet/js folder.
Open the browser and navigate to: http://localhost/ojet/

My source code is small and simple but I don't know if it could be optimized. The official CRUD example application has more features and doesn't connect to a real REST service.
It wasn't funny to use/read the example because it's much for such a simple use-case. I found a similar but inofficial example. This was nice but didn't solve the Basic authentication problem!

Long story, short:

I found no option for Basic authentication and no documentation, but found that OAuth is supported. Not the same as Basic authentication but something I could search in the source code. The Model file was the right place to search (-> oauth).

And my simple solution for Basic authentication was:

self.myBasicAuth = function() {};
self.myBasicAuth.prototype.getHeader = function ()
{
  var headers = {};
  headers['Authorization'] = 'Basic ' + btoa("admin:admin");
                   
  return headers;
};

Username and password are hardcoded, but it's easy to replace the code with a better solution.

The "authenticator" will be set as oauth property:

var ContactsCollection = oj.Collection.extend(
{
    url: self.serviceURL,
    model: myContact,
    oauth: new self.myBasicAuth(),
    comparator: "ID"
});

The problem with this API is that it's not guaranteed that the getHeader method will be used in future releases. And it's also not perfect to use oauth for Basic authentication, but whatever.

Our example runs with VisionX' embedded tomcat. If you want to test with your own application server, you should enable CORS for VisionX to use the REST services from an external server:

To enable CORS, change the web.xml in <VisionX_folder>/conf/ and add

<init-param>
  <param-name>cors.origin</param-name>
  <param-value>http://localhost:8080</param-value>
</init-param>

to RestletServlet definition.

Example Download

Use OBridge together with JVx

Post to Twitter

OBridge is a nice Java FOSS project. The description according to the website:

OBridge generates standard Java source code for calling PL/SQL stored procedures and functions.

It's focus is on Oracle but this wasn't a limitation for us to test it with JVx.

Most of you know that JVx has generic support for procedure/function calls which is DB independent. The implementation is not really type-safe but it's simple.
If type-safety is preferred, you could use OBridge for your application.

I write about this library, because it's super small and simple. We love small and simple things :)

Assume, we have following PL/Sql procedure:

CREATE OR REPLACE PROCEDURE execProcedure(pNumber IN OUT NUMBER,
                                          pInText IN VARCHAR2,
                                          pOutText OUT VARCHAR2) IS
  nr NUMBER := pNumber;
BEGIN
  pOutText := 'Out: '|| pOutText ||' In: '|| pInText;

  pNumber := pNumber + pNumber;
END execProcedure;

and function:

CREATE OR REPLACE FUNCTION execFunction(pNumber IN OUT NUMBER,
                                        pInText IN VARCHAR2,
                                        pOutText OUT VARCHAR2) RETURN VARCHAR2 IS
  res VARCHAR2(200);
  nr NUMBER := pNumber;
BEGIN
  pOutText := 'Out: '|| pOutText ||' In: '|| pInText;

  pNumber := pNumber + pNumber;

  RETURN 'IN-Param Nr: '|| nr;
END execFunction;

 

With JVx, the procedure and function call will look like following JUnit test:

@Test
public void testCall() throws Exception
{
    DBAccess dba = DBAccess.getDBAccess("jdbc:oracle:thin:@localhost:xe", "test", "test");
    dba.open();
   
    /**
     * Procedure call.
     */

    OutParam ouTextParam = new OutParam(InOutParam.SQLTYPE_VARCHAR);
    dba.executeProcedure("execProcedure", BigDecimal.valueOf(25),
                         "Hello JVx' procedure", ouTextParam);

    Assert.assertEquals("Out:  In: Hello JVx' procedure", ouTextParam.getValue());

    /**
     * Function call.
     */

   
    ouTextParam = new OutParam(InOutParam.SQLTYPE_VARCHAR);
    Object oResult = dba.executeFunction("execFunction", Types.VARCHAR,
                                         BigDecimal.valueOf(25),
                                         "Hello JVx' function", ouTextParam);
   
    Assert.assertEquals("IN-Param Nr: 25", oResult);
    Assert.assertEquals("Out:  In: Hello JVx' function", ouTextParam.getValue());
}

 

and the same with OBridge:

@Test
public void testCall() throws Exception
{
    DBAccess dba = DBAccess.getDBAccess("jdbc:oracle:thin:@localhost:1521:xe", "test", "test");
    dba.open();
   
    /**
     * Procedure call.
     */

    Execprocedure proc = ProceduresAndFunctions.execprocedure(BigDecimal.valueOf(35),
                                           "Hello OBridge procedure", dba.getConnection());
   
    Assert.assertEquals("Out:  In: Hello OBridge procedure", proc.getPouttext());

    /**
     * Function call.
     */

   
    Execfunction func = ProceduresAndFunctions.execfunction(BigDecimal.valueOf(35),
                                            "Hello OBridge function", dba.getConnection());
   
    Assert.assertEquals("IN-Param Nr: 35", func.getFunctionReturn());
    Assert.assertEquals("Out:  In: Hello OBridge function", func.getPouttext());
}

 

The OBridge code saves two LoC for the call, but it needs some additional classes and packages in your application. If you change your procedure or function definition in the database, you have to recreate the Java files.
This is not needed with pure JVx, but it's your choice.

The code generation is not tricky, simply follow the official documentation. Our steps:

  • Create the file config.xml in the working directory of your project
    <?xml version="1.0" encoding="UTF-8"?>

    <configuration>
        <jdbcUrl>jdbc:oracle:thin:test/test@localhost:1521:xe</jdbcUrl>
        <sourceRoot>./src/</sourceRoot>
        <rootPackageName>com.sibvisions.apps.obridge.db</rootPackageName>
        <packages>
            <entityObjects>objects</entityObjects>
            <converterObjects>converters</converterObjects>
            <procedureContextObjects>context</procedureContextObjects>
            <packageObjects>packages</packageObjects>
        </packages>
    </configuration>

  • Run the main class: org.obridge.OBridge with argument: -c config.xml
    (or use -c fullqualified_path_to_config.xml)
 

If you love our generic built-in solution, you don't need OBridge but if you prefer type-safety it's definitely an option.

New VisionX Feature (maybe)

Post to Twitter

We tried to improve the UX of our tool VisionX in the last weeks. The current concept is wizard based and all wizards are kept very simple. This concept works well but requires curiosity. It would be better go guide the user through the application and show the features.

Some software tools use strict guides and explain the application with step-by-step instructions. This is nice but also boring because you can't play around. We tried to add a sort of a guide but without restrictions.

The first preview of this new concept is available as YouTube video. We're not sure if this solution will be available in the next release but our testers love it. It fills the gap between wizards and the question: What should I do next?

Here's the screencast:

New Feature: app guides

VisionX 2.3 - Feb, 5th

Post to Twitter

The next version of our flagship VisionX will be available tomorrow - Feb 5th, 2016. The version number is nice because 2 could be the month and 2+3 = 5 :)

We invest more time/resources/work than ever before in this version. It has many new features and great improvements. All included open source libraries were updated and offer additional features because not all available library features/APIs are covered by VisionX.

So what's new?

  • Vaadin 7.5.7

    The open source project JVx Vaadin UI was updated to Vaadin 7.5.7 and the UI implementation got many performance tunings. It's now significant faster than before - up to 5 times faster. The performance boost depends on your UIs because it makes no difference if you only have two input fields in your screen. But if you have large screens with Tabs and many input fields, it will rock. The API got support for FontAwesome and Vaadin font icons.

  • HTML5 Live Preview

    The live preview now supports an external CSS file. It's super easy to change the style of your application while creating it with VisionX.

  • HTML5 Live Reload

    This feature automatically reloads changed screens in the browser after you've changed it with VisionX. Simply use add URL Parameter liveReload=true. This features save click time and is great if you have multiple screens conntected to your workstation.

  • Responsive coporation layout

    Our corporation application layout is now responsive and fully customizable.

    full mode

    full mode

    small mode

    small mode

    mini mode

    mini mode

    mini mode (menu)

    mini mode (menu)

    Use the API to show/hide the menubar or the sidebar. Add custom or remove default buttons.

  • Support for custom code format rules

    It's possible to use your custom code formatting rules. The rules are based on Eclipse Code Formatter and all Eclipse (Luna) options will work with Eclipse.

  • Morph Panel improvements

    The Morph Panel is a one-for-all solution. It was introduced in VisionX 2.2. We improved the popup mode, e.g. if you double click the table, the popup will be opened if you don't use the navigation. We added more APIs for power users.

  • No more automatic database changes

    VisionX doesn't change the database objects automatically. It's your decision:

    Modify fields

    Modify fields

    Delete screen

    Delete screen

  • Java 8 u60

    VisionX runs with Java8 update 60.

  • Action editor automatic scrolling

    The action editor now automatically scrolls to the input field if it's not visible. It's not a big thing but creates great UX.

  • Automatic import organisation

    VisionX automatically removes unused imports from the source files. This is an optional feature and can be disabled.

  • Single line javadoc for fields

    The Javadoc for fields will be written in a single line (if possible). This feature is optional an can be disabled.

  • Better customizing support

    VisionX changed the class loading mechanism of customizers and controls. It'll be possible to use your custom controls without any tricks. It's possible to customize VisionX for your needs.

  • Mobile application creation (optional AddOn needed)

    This feature is awesome because it makes it be possible to create a mobile app from your application in under 5 minutes.

    JavaFX mobile LIVE CSS hacking

  • Additional licensing options

    User based, Subscription based, Floating, individual.

    Please contact our Sales Team for more details.

All customers will find the new version in their download area!