This website uses cookies for visitor traffic analysis. By using the website, you agree with storing the cookies on your computer.More information

OpenShift Deployment

OpenShift is a PaaS product from Red Hat.
Read further details at Wikipedia or the product site.

It's of interest to us because it's easy to use, supports deployment of pre-created war files and it offers an application server (e.g. Tomcat, JBoss) and a database (MySQL, PostgreSQL) for your applications. OpenShift also has Vert.x as runtime platform if you won't use an application server. The configuration is super easy and your server is ready in around 5 minutes.

The access to your server is protected and you should use a specific client tool from RedHat for advanced configuration or an SSH client like putty.

The PaaS service is so nice because it's the perfect deployment platform for JVx applications. There's a free service for simple tests and maybe smaller applications because there are some limits for memory usage, CPU, and number of applications.

We made some tests with OpenShift and the result was as expected: Our applications did work without problems. Sure, the whole deployment procedure could be more end-user friendly but it wasn't designed for end-users without technical know-how, I guess. It's good enough for software developers or admins.

Our test

We created a new JVx application with VisionX (because it creates the database, has a GUI builder and creates the war file for us) and the application should run with VaadinUI on OpenShift. We didn't have any experience with OpenShift, but with other PaaS products, e.g. Heroku, Cloudbees, Jelastic, AWS.

First steps:

  1. Registering an account (what else :) )
  2. Creating a first application
  3. Cartridge: Tomcat 7 (JBoss EWS 2.0)
  4. Setting application name and domain
  5. Adding MySQL 5.5 cartridge

Above steps were enough to run our OpenShift service(s).

Next was accessing the server via SSH client because we didn't install the RedHat client tool (We won't use client tools for cloud services - why the hell). Sure, we had to use another client tool for accessing the server via SSH, but it was working without installation: PuTTY (still strange). A nice web UI would be great... just my thoughts. We found a Java client but didn't test it.

So, what we did:

  1. Creating private/public RSA keys with PuTTYgen
  2. Configuring OpenShift (used the key from PuTTYgen TextArea because OpenShift didn't like other formats)
  3. Testing connection

    Username was displayed in Application settings under SSH Code, e.g. ssh://<username>@app-domain.rhcloud.com/....
    Used the private key file for putty as key (Key authentication, without password)

Next task was, configuring the access to the database because SSH access was already working. It wasn't possible to access the database without tunnel - means, no direct (Internet) access from your client. This wasn't a real problem and PuTTY had support for port tunneling. Simply detected the IP address of the MySQL server. The hostname was set as environment variable and the command export displayed all variables. The variable OPENSHIFT_MYSQL_DB_HOST had all information and our tunnel was working. There's also a property for the MySQL Port but 3306 is default.

What was next?

Deployment.

This wasn't trivial because the platform expected source code and a maven project for automatic deployment. Wrong for us. But there's an official documentation for manual war deployment.

Short summary of steps

  1. GIT clone
  2. Delete src folder and pom.xml
  3. GIT commit & push
  4. Copy WAR file into webapps folder
  5. GIT commit & push

You don't need git on your client, it's available in your terminal. But... as a developer, git is one of those standard tools...
It's also possible to upload the WAR file via SCP or SFTP...

Done...

Not really because our application was deployed without problems but it didn't work because the JDBC URL was wrong. We set the MySQL servername to localhost because of the tunnel!

Here's the original config.xml:

<?xml version="1.0" encoding="UTF-8"?>

<application>
  <securitymanager>
    <class>com.sibvisions.rad.server.security.DBSecurityManager</class>
    <accesscontroller>com.sibvisions.apps.server.object.DBWorkScreenAccess</accesscontroller>
    <passwordalgorithm>SHA</passwordalgorithm>
  </securitymanager>
  <connection>
    <!-- GLOBAL | DATASOURCE | OFF -->
    <property name="client.metadata_cacherole">OFF</property>
  </connection>
  <lifecycle>
    <application>com.sibvisions.apps.openshifterp.Application</application>
    <mastersession>com.sibvisions.apps.openshifterp.Session</mastersession>
  </lifecycle>
  <datasource>
    <db name="default">
      <url>jdbc:mysql://localhost:3306/erp</url>
      <username>username</username>
      <password>password</password>
    </db>
  </datasource>
</application>

JVx has a nice feature which allows environment dependent settings and VisionX sets the environment automatically to prod. So, we simply changed the datasource to:

<datasource>
    <db name="default">
      <url>jdbc:mysql://localhost:3306/erp</url>
      <url_prod>jdbc:mysql://hostname_from_env_variable:3306/erp</url_prod>
      <username>username</username>
      <password>password</password>
    </db>
  </datasource>

VisionX sets the environment to prod, if it creates a WAR file:

<securitymanager>
    <class>com.sibvisions.rad.server.security.DBSecurityManager</class>
    <accesscontroller>com.sibvisions.apps.server.object.DBWorkScreenAccess</accesscontroller>
    <passwordalgorithm>SHA</passwordalgorithm>
    <environment>prod</environment>
  </securitymanager>

Sure, the solution isn't perfect because the MySQL hostname should be read from the environment variable.
Would be better:

<url_prod>jdbc:mysql://${env:OPENSHIFT_MYSQL_DB_HOST}:${env:OPENSHIFT_MYSQL_DB_PORT}/erp</url_prod>

But JVx doesn't support this syntax (right now) -> Feature Request.

Done. Really done.

The application works fine (Login as admin with password admin).

Here's a screenshot, for the case that our OpenShift service isn't running:

OpenShift ERP with JVx and VaadinUI

OpenShift ERP with JVx and VaadinUI

JavaFX UI and VisionX

We've good news for you. Since our JavaFX UI has reached version 1.0, we thought it might be a good idea to integrate the UI into VisionX. It wasn't that easy because JavaFX needs Java8 and VisionX runs with Java7. It wasn't enough to switch the JVM because VisionX had Eclipse JDT under the hood and the used version wasn't Java8 ready and also some other libraries had problems with Java8.

It was a lot of work to support JavaFX but now it's done. We have Java8 support in VisionX and all referenced projects were updated. We don't have a public version for you right now because the new features need some additional tests. But we're very happy with the current status. Our development version is very stable and all features are still working.

We have a short screencast for you:

JavaFX with VisionX


JVx.vert.x update to vert.x 3.0

Our JVx connection implementation for vert.x is up-to-date. It's now based on vert.x 3.0. We support http and socket connections - no API changes.

Updating to vert.x 3.0 from 2.2 was not funny because package structure was changed and some APIs as well. Whatever, it's working.

If you're interested in our vert.x implementation, check the github repository because we don't offer binaries.

Multi-IDE Feature for next VisionX release

Our current VisionX releases have built-insupport for Eclipse, because every new application is also a complete Eclipse project. Simply import an application in your Eclipse IDE and use all features of your IDE to develop/modify the application.

We didn't support other IDEs like NetBeans or IntelliJ IDEA because Eclipse was our preferred IDE and it's still the most used IDE. But nowadays it makes sense to support the big 3. So, why not :)

Our next VisionX release will come with support for NetBeans and IntelliJ IDEA. Simply open the application and run it. No more manual project creation!

We made a short video which demonstrates our upcoming IDE support. First, an application was created in 1 minute and this application was used with NetBeans, IntelliJ and Eclipse - Open.Run.Done.

Here's the preview video:

Multi-IDE support for VisionX


Above video was made with current development version of VisionX and the next release, with version number 2.2, will be available in this summer.

JVx' JavaFX UI 1.0

We're happy to announce that our JavaFX UI 1.0 was released.

The release contains all planned features and some more. We have the complete MDI implementation, Zoom support for windows and the scene, a custom scene style, custom comboboxes and much more.

MDI control

MDI control

Combobox

Combobox

Styled Scene

Styled Scene

Table format (cells)

Table format (cells)

Zoom

Zoom

Master/Detail with Tables and Tree

Master/Detail with Tables and Tree

All custom controls are available as separate library, JFXtensions. This library will work without JVx because it has no dependency to JVx. Simply use our MDI implementation or zoom feature for your own JavaFX application without using JVx.

Jar files are available at SourceForge or Maven central.

Our next steps?

We'll integrate the UI in our product VisionX to allow Live Preview with JavaFX. The first update release with version number 1.1. will contain smaller bugfixes and improvements based on user feedback.

So, send us your Feedback if you use our library.

AngularJS with JVx in action

Our JVx library has REST support since 2011. It's not only support for using REST libraries, it's a generic solution for action calls and storage access (e.g. database records). This means that your whole business logic is usable via REST with same security restrictions as usual.

In 2011, REST wasn't as popular as today and not supported from soo many different frameworks than today. But now, in 2015, SOAP is legacy and REST is the thing to use. I'm sure you have heard about this modern JavaScript frameworks like AngularJS.

Not sure if it's so successful because it's from Google, but it's often used and developers love working with AngularJS. So we started a simple research project to connect an AngularJS app to our JVx backend application.

AngularJS and JVx is a perfect match because Angular was designed for JS frontends and JVx provides your business logic. Sure, JVx is a full-stack framework and you could create the whole web application, based on vaadinUI, but it's also open for all other UIs.

The most important thing is that everything works out-of-the-box. No additional coding for REST services or authentication, no special knowledge needed. Here's an example service for accessing a customer table (full CRUD support):

public class Customers extends Session
{
        public DBStorage getCustomer() throws Exception
        {
                DBStorage dbsCustomer = (DBStorage)get("customer");
                if (dbsCustomer == null)
                {
                        dbsCustomer = new DBStorage();
                        dbsCustomer.setWritebackTable("customer");
                        dbsCustomer.setDBAccess(getDBAccess());
                        dbsCustomer.open();

                        put("customer", dbsCustomer);
                }
                return dbsCustomer;
        }
}

The class was copied from our DemoERP application (Login as: manager with password: manager). The source code of the whole application is available here.

Yes, there are no more methods like save, update, delete, query, ... The DBStorage encapsulates all calls for you and our generic REST service handles the communication with your business logic.

We have a simple Angular app for you (click on the pencil to edit the record):

This solution is based on AngularJS 1.4.0, Bootstrap 3.3.4 on client-side and JVx with RESTlet on server-side. Here's the JS file:

(function()
{
    var app = angular.module('contactApp', ['ngResource', 'ngRoute']);

    app.config(function($routeProvider)
    {
      $routeProvider.when('/',
      {
        controller:'ListContactsController as contactList',
        templateUrl:'list.html',
        resolve: {contacts: function (Contacts)
                            {
                              return Contacts.fetch();
                            }}
      })
      .when('/edit/:contactId',
      {
        controller:'EditContactController as editContact',
        templateUrl:'edit.html'        
      })
      .otherwise({
      redirectTo:'/'
      });
    });
   
    app.factory('ContactsFactory', ['$resource', function($resource)
    {
       var auth = 'Basic ' + btoa("manager:manager");
       
       return $resource('/demoerp/services/rest/DemoERP/Customers/data/customer/:contactId',
                        null,
                        {'get':    {method:'GET', headers: {'Authorization':auth}},
                         'save':   {method:'POST', headers: {'Authorization':auth}},
                         'update': {method:'PUT', headers: {'Authorization':auth}},
                         'query':  {method:'GET', isArray:true,
                                    headers: {'Authorization':auth}},
                         'delete': {method:'DELETE', headers: {'Authorization':auth}}});
    }]);  

    app.service('Contacts', function($q, $http, ContactsFactory)
    {
      var self = this;
     
      this.fetch = function()
      {
        var deferred = $q.defer();

        return ContactsFactory.query(function(data, status, headers, config)
        {
            self.contacts = data;
           
            deferred.resolve(data);
        },
        function(data, status, headers, config)
        {
            console.log("Error while received data.");
            deferred.reject();
        });
       
        return deferred.promise;
      };
    });

    app.controller('ListContactsController', function(contacts)
    {
        var contactList = this;
        contactList.contacts = contacts;
    });
   
    app.controller('EditContactController', function($location, $routeParams,
                                                     Contacts, ContactsFactory)
    {
        var editContact = this;

        this.fillData = function()
        {
            var idx = Contacts.contacts.reduce(function(cur, val, index)
            {
               if (val.ID == $routeParams.contactId && cur == -1 )
               {
                  return index;
               }
               
               return cur;
            }, -1);
           
            editContact.contact = Contacts.contacts[idx];
           
            editContact.save = function()
            {
                ContactsFactory.update({contactId : $routeParams.contactId},
                                       editContact.contact, function()
                {
                    $location.path('/');
                });
            }
        };
       
        if (typeof Contacts.contacts == 'undefined')
        {
            Contacts.fetch().$promise.then(this.fillData);
        }
        else
        {
            this.fillData();
        }
    });    
})();

It's a useful script because it combines REST with Basic authentication for querying and updating remote database records. Sure, it's not a fat application but this wasn't our intention :)

We have a web application archive for you, if you're interested. Simply use this war together with our DemoERP application and install both applications on e.g. Tomcat application server.

JVx with official connection pooling support

The last black stain was removed. JVx didn't fully support connection pools. It was because of our internal statement cache mechanism and load-on-demand.
We had inofficial support for connection pooling but it wasn't a solution without problems (we weren't proud of it).

With next JVx release or next nightly build, you will be able to use connection pools with same caching mechanism and with full backwards compatibility. We still support load-on-demand for storage records and binary data e.g. BLOBs.

We've some documentation for you:

Connection pooling

and for another new JVx (server-side) feature:

Server-side Call events

Thanks for your patience ;-)

Java Framework comparison and JVx

In the last month we‘ve started a big research project. It is a comparison of Java frameworks for backend and frontend development. We knew that there are many different frameworks for the same job, but which one is the best? Is there one framework that would outpace all others? What are the pros and cons of each framework and how fast could we develop with them?

The idea was trivial: Implementing the same application or screen with different technologies with developers without prior knowledge of the specific technology, always from scratch. Afterwards we could compare the development time, functionality and complexity.

We tried to find out which framework saves most time during development because time is money, e.g. development with framework A needs 6 months and same solution needs 3 months with framework B. Which one is better?

Better doesn't mean that framework B is technological better than A and it doesn't tell us anything about the framework quality. As well, faster is not always better because code quality is very important. We tried to create comparable results and choosen frameworks fulfilled high quality standards. We also knew that every developer is different and development speed matters.

To keep results fair, we tried to find some fresh developers (students) with same experience and without prior knowledge in our framework candidates.

The results were really cool and it was great to get feedback from different developers without marketing slides and no buzzwords. Just reality!

One statistic has extremely amazed us:

Required time (2 passes)

Required time (2 passes)

We tried to use "top-ten frameworks" and our own selection.

Custom comboboxes with JavaFX

We got great feedback about our first beta release of our JavaFX UI. Many of our ideas were right but our comboxes weren't good enough. We had missing features and some technical problems. One missing feature was: Live search in comboboxes with list of values. Our old implementation of comboboxes was like this:

Combo Box

Combo Box

Our implementation didn't support live filtering, e.g. if you typed a key, the list wasn't shortened...

One problem with this feature was JavaFX' focus handling and popups. It was tricky to keep the focus in the right editor and to keep the popup open or to re-open the popup after every keypress. We had a solution but it was too dirty. So we tried to find a better solution. We moved the the editor in the popup, to avoid focus problems. We had crazy effects with two blinking cursors in two different text fields, very strange.

Our current solution is this:

Filterable combobox

Filterable combobox

The design is not perfect but we're working on it. The good thing is that we have no problems with focus and filtering is already working. Here's a screenshot of our date editor:

Date editor in combobox

Date editor in combobox

Our date editor needs a small redesign but it's working. The optimization was planned for release 1.1

If you're interested in our current state, check the source code. We're looking forward to your feedback!

Our code is open source and we still have a separete lib (.ext) for all custom FX controls. The UI implementation for JVx is based on this library. So we have JVx independent JavaFX extensions and our JVx UI implementation.

JVx' vaadinUI and CORS

CORS

All details about Cross-origin resource sharing.

Use-case

Embedd a vaadin application in your CMS (e.g. Joomla, Typo3). The CMS runs in an hosted environment without Java application server (standard and cheap web hosting).

Howto

There's an excellent blog post from vaadin. It's not rocket science to implement this, but you have to do it. We think this things could be done automatically and so we've added the support to our UI implementation for JVx.

It's really simple to use:

Add following parameter to your web.xml:

<init-param>
  <param-name>cors.origin</param-name>
  <param-value>http://www.hosteddomain.com</param-value>
</init-param>
   
<init-param>
  <param-name>pushmode</param-name>
  <param-value>automatic</param-value>
</init-param>
   
<async-supported>true</async-supported>

(be sure that async-support was enabled for all vaadin servlets/filters)

The cors.origin parameter can be a comma separated list.

And here's an example html file:

<!DOCTYPE html>

<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=11;chrome=1" />
    <link rel="shortcut icon" type="image/vnd.microsoft.icon"
          href="./VAADIN/themes/jvx/favicon.ico" />
    <link rel="icon" type="image/vnd.microsoft.icon"
          href="./VAADIN/themes/jvx/favicon.ico" />

    <title>Embedded Vaadin application</title>

    <script type="text/javascript"
             src="./VAADIN/widgetsets/com.sibvisions.rad.ui.vaadin.ext.ui.Widgetset/
                  com.sibvisions.rad.ui.vaadin.ext.ui.Widgetset.nocache.js?05202015200542"></script>

  </head>
 
  <body scroll="auto">
 
    <div id="content">
      <script type="text/javascript" src="./VAADIN/vaadinPush.js?v=7.4.5"></script>
      <script type="text/javascript" src="./VAADIN/vaadinBootstrap.js?v=7.4.5"></script>

      <div id="MyEmbeddedUI" class="v-app">
        <div class="v-app-loading"></div>
        <noscript>You have to enable javascript in your browser to use an application
                  built with Vaadin.</noscript>
      </div>
      <script type="text/javascript">

      if (!window.vaadin)
      {
        alert("Failed to load the bootstrap javascript:
               ./VAADIN/vaadinBootstrap.js?v=7.4.5");
      }
   
      vaadin.initApplication("MyEmbeddedUI",
                             {"browserDetailsUrl": "ui/" + appname + params,
                              "serviceUrl": "ui/",
                              "theme":"jvx",
                              "versionInfo":{"vaadinVersion":"7.4.5",
                                             "atmosphereVersion":"2.2.4.vaadin5"},
                              "widgetset":"com.sibvisions.rad.ui.vaadin.ext.ui.Widgetset",
                              "comErrMsg":{"caption":"Communication problem",
                                           "message":"Take note of any unsaved data,
                                                      and <u>click here</u> or press ESC to
                                                      continue.",
                                           "url":null},
                              "authErrMsg":{"caption":"Authentication problem",
                                            "message":"Take note of any unsaved data,
                                                      and <u>click here</u> or press ESC to
                                                      continue.",
                                            "url":null},
                              "sessExpMsg":{"caption":"Session Expired",
                                            "message":"Take note of any unsaved data,
                                                      and <u>click here</u> or press ESC key
                                                      to continue.",
                                            "url":null},
                              "vaadinDir":"./VAADIN/",
                              "standalone":false,
                              "debug":false,
                              "heartbeatInterval":300,
                              "comErrMsgDetails":true,
                              "authErrMsgDetails":true,
                              "sessExpMsgDetails":true});
      </script>
    </div>
  </body>
</html>

And the rest of our web.xml:

<servlet>
  <servlet-name>EmbeddedUI</servlet-name>
  <servlet-class>com.sibvisions.rad.ui.vaadin.server.VaadinServlet</servlet-class>
  <init-param>
    <param-name>UI</param-name>
    <param-value>com.sibvisions.rad.ui.vaadin.impl.VaadinUI</param-value>
  </init-param>
  <init-param>
    <param-name>widgetset</param-name>
    <param-value>com.sibvisions.rad.ui.vaadin.ext.ui.Widgetset</param-value>
  </init-param>
  <init-param>
    <param-name>main</param-name>
    <param-value>com.sibvisions.apps.MyEmbeddedApplication</param-value>
  </init-param>
  <init-param>
    <param-name>Launcher.uifactory</param-name>
    <param-value>com.sibvisions.rad.ui.vaadin.impl.VaadinFactory</param-value>
  </init-param>
  <init-param>
    <param-name>pushmode</param-name>
    <param-value>automatic</param-value>
  </init-param>

  <async-supported>true</async-supported>  </servlet>
</servlet>

<servlet-mapping>
  <servlet-name>EmbeddedUI</servlet-name>
  <url-pattern>/*</url-pattern>
</servlet-mapping>

The application was deployed in ROOT context of Tomcat8.

If you have a different context, simply change the URLs: browserDetailsUrl, serviceUrl and vaadinDir (see html page).

The CORS support is not available in our latest vaadinUI release (1.2), because its a very new feature. Simply use our nightly builds for testing.

Happy embedding.