Category: Development

JVx Reference, Application Basics

Post to Twitter

Let's talk about the basics, how a JVx application starts, works and how the connection strings together the client and server side.

Multitier Architecture

JVx is designed to be Multitier by default. It allows a clean and easy separation of processes and makes it easy to build, maintain and extend applications by separating the client, server and data storage.

Launchers

The following method is a simplified way to launch a JVx application. Normally, you'd use the technology specific launcher to launch the application. These launchers do know exactly what is required to set it up and start the technology and the application. However, covering the launchers is out of scope for this post, so we will review them and their mechanics in a follow-up.

The simplest JVx application: Just the GUI

But first, we will start without anything. The most simple application you can create with JVx is an application which does open a single window and only works with in memory data (if at all). This can be easily achieved by "just starting" the application.

The JVx GUI is a simple layer on top of the Technology which implements the actual functionality. So if we want to have a GUI we'll need to initialize the factory before doing anything else:

UIFactoryManager.getFactoryInstance(SwingFactory.class);

With this little code we have initialized everything we need to create a simple Swing application. Now we can start to create and populate a window with something:

UIFrame frame = new UIFrame();
frame.setLayout(new UIBorderLayout());
frame.addComponent(new UILabel("Hello World!"));

frame.pack();
frame.setVisible(true);

frame.eventWindowClosed().addListener(() -> System.exit(0));

We can start to create and manipulate the GUI, in this case we are building a simple window with a label inside. Last but not least, we make sure that the JVM will exit when the window is closed.

A very good example and showcase for that is the JVx Kitchensink.

That's it. That is the most simple way to start a JVx application. We can use all controls and we can use MemDataBooks without any problem or limitation. And best of all, we can simply switch to another Technology by using another factory.

Anatomy of a remote JVx application

Of course JVx wouldn't be that useful if it would just provide static GUI components. Now, to explain what else is required for a remote JVx application I have to go far afield, so let's head down the rabbit hole.

JVx Layers

What you are seeing here is a rough sketch of how the architecture of JVx looks like. Let's walk through the image step by step. We will look at each successive layer and work our way from the database on the server to the databook on the client.

DBAccess, accessing a database

Accessing a database is easy when using DBAccess. All we must do is to set the JDBC URL of the server and connect to it:

DBAccess dbAccess = DBAccess.getDBAccess(
           "jdbc:postgresql://server:5432/schema",
           "username",
           "password");
dbAccess.open();

As a note, the instance returned by getDBAccess is the database specific DBAccess extension, which does know how to handle its database.

We can of course use DBAccess to directly access the database:

dbAccess.executeStatement("insert into SOME_TABLE values (?, ?);",
        BigDecimal.valueOf(1),
        "Some Value");

List<Bean> data = dbAccess.executeQuery("select * from SOME_TABLE");

...or manipulate the database, or query information about the database or execute procedures or do anything else.

DBStorage, preparing the database access for databooks

The downside of using DBAccess is that everything must be database specific. To become database agnostic we must use DBStorage. DBStorage does not care which database it is connected to and can operate on any of them:

DBStorage storage = new DBStorage();
storage.setDBAccess(dbAccess);
storage.setWritebackTable("SOME_TABLE");
storage.open();

We can use this to insert, update, delete and fetch data. Additionally the DBStorage does retrieve and manage the metadata of the table we've set, which means that we can query all column names, what type they are, we can even access the indexes and the default values. Short, the DBStorage leaves little to be desired when it comes to operating on a database.

If we query data from the DBStorage we receive a List of rows. The rows are are either represented as Object array, IBean or a POJO and we can easily manipulate the data, like this:

for (IBean row : storage.fetchBean(null, null, 0, -1))
{
    row.put("SOME_COLUMN", "newvalue");
    storage.update(row);
}

As one can see, it looks quite familiar to the DataBook, which isn't a coincidence. The DBStorage "powers" the DataBooks on the server side, a DataBook will get its data from and will send its modified data to the DBStorage.

I've been using the DBStorage here as an example, but actually the Storage is not dependent on a database. IStorage can be implemented to provide any sort of data provider, like reading from an XML or JSON file, scraping data from a website, fetching data from a different process or reading it directly from a hardware sensor.

Life Cycle Objects, the business objects with all the logic

Life Cycle Objects, or LCOs, are the server side business objects which contain and provide the business logic. They are created and destroyed as is requested by the client-side and are used to provide specific functionality to the client, like providing functionality specific to one screen or workflow. This is done by RPC, Remote Procedure Calls, which means that the client is directly calling the methods defined in the LCOs, which includes getting the Storages for the DataBooks.

There is also a security aspect to these, as you can permit one client access to a certain LCO but lock out everyone else, which means that only that client can use the functionality provided by the LCO.

But let's not get ahead of our selves, there are three important "layers" of LCOs which we will look at.

Application

The LCO for the application represents the application itself and provides functionality on the application layer. It is created once for the lifetime of the application and this instance is shared by all sessions.

public class Application extends GenericBean
{
}
Session

The LCO for the session represents one session, which most of the time also equals one client connection. It provides functionality which should be session-local, like providing the database connection which can be used.

public class Session extends Application
{
    protected DBAccess getDBAccess() throws Exception
    {
        // Code for initialization and caching of DBAccess goes here.
    }
}
Sub-Session aka Screen

The sub-session, also known as screen, LCO is the last in the chain. It provides functionality specific to a certain part of the application, like a single screen, and provides the storages required to power the databooks and other functionality.

public class MySubSession extends Session
{
    public DBStorage getTablename() throws Exception
    {
        // Code for initialization and caching of DBStorage goes here.
    }
}

Server, serving it up

There really isn't much to say about the server, it accepts connections and hands out sessions. Of course it is not that easy, but for this guide we will not go into any further detail.

Connection, connecting to a server

The connection which strings together the client and the server is used for the communication between them, obviously. It can be anything, from a simple direct connection which strings two objects together to a HTTP connection which talks with a server on the other side of the planet.

By default we provide different IConnection implementations, the DirectServerConnection, DirectObjectConnection, the HttpConnection and the VMConnection. The DirectServerConnection is a simple IConnection implementation which does simply forward method calls to known Objects - without serialization - and is used when the client and server reside inside the same JVM. The HttpConnection communicates with the server over a HTTP connection and is used whenever the client and server are not inside the same JVM. The DirectObjectConnection and VMConnection are used for unit tests.

As example we will use the DirectServerConnection, which serves as Server and Connection. It is used if the server and client reside in the same JVM.

IConnection connection = new DirectServerConnection();
// The connection will be automatically opened by the MasterConnection.

Master- and SubConnections, client-side lifecycle management

The MasterConnection is the main connection which is used to access the server and its functionality. When a MasterConnection is established, a Session LCO on the server is created.

MasterConnection masterConnection = new MasterConnection(connection);
masterConnection.open();

A SubConnection is a sub connection of the MasterConnection and allows to access specific functionality encapsulated in an LCO. When a SubConnection is established, the requested/specified LCO on the server is created and can be accessed through the SubConnection.

SubConnection subConnection = masterConnection.createSubConnection("MySubSession");
subConnection.open();

The SubConnection can now access the functionality provided by the Application, the Session and the LCO which was specified.

subConnection.callAction("doSomethingOnTheServer");

DataSource, preparing the connection for the databook

To provide data to the databooks we can use the connection which we've described earlier. However, the DataBook does not directly know about the connection, it expects an IDataSource, which is used as an intermediate:

IDataSource dataSource = new RemoteDataSource(subConnection);
dataSource.open();

Of course the RemoteDataSource is just one possible implementation of IDataSource which can be used to provide data to the DataBook.

DataBook, accessing data

And now we are at the other end of the chain, at the databook on the client side. We just need to tell our databook what datasource to use, and we are done.

RemoteDataBook dataBook = new RemoteDataBook();
dataBook.setDataSource(dataSource);
dataBook.setName("storagename");
dataBook.open();

The name of the DataBook is used to access the DBStorage object in the LCO provided by the datasource. The mechanism for that is a simple search for a getter with the set name.

Interactive Demo

Here is an interactive demo which allows you to explore the connections between the client and server side. The complement classes are always highlighted and you can click on the names of the objects to receive additional information about them.

The JVx application: Manual example

Now that we have seen all layers that make up the architecture of JVx, let us put all of that into code:

public class JVxLocalMain
{
    public static void main(String[] pArgs) throws Throwable
    {
        // ############################## Server ##############################
       
        // ----------------------------- DBAccess -----------------------------
       
        // The DBAccess gives us access to the database.
        DBAccess dbAccess = DBAccess.getDBAccess(
                "jdbc:h2:mem:database",
                "",
                "");
        dbAccess.open();
       
        // We'll insert some data for this example.
        dbAccess.executeStatement("create table if not exists TEST("
                + "ID int primary key auto_increment,"
                + "NAME varchar(128) default '' not null);");
        dbAccess.executeStatement("insert into TEST values (1, 'Name A');");
        dbAccess.executeStatement("insert into TEST values (2, 'Name B');");
        dbAccess.executeStatement("insert into TEST values (3, 'Name C');");
       
        // ---------------------------- DBStorage -----------------------------
       
        // Our sole storage.
        DBStorage testStorage= new DBStorage();
        testStorage.setDBAccess(dbAccess);
        testStorage.setWritebackTable("TEST");
        testStorage.open();
       
        // -------------------- LCO / Session / Application -------------------
       
        // We are skipping the LCO, Session and Application in this example.
       
        // ####################### Network / Connection #######################
       
        // For this example we are initializing a DirectObjectConnection, which
        // does not require a server.
        // It is designed to be used mainly for unit testing.
        DirectObjectConnection connection = new DirectObjectConnection();
        connection.put("test", testStorage);
       
        // ############################## Client ##############################
       
        // ------------------------- MasterConnection -------------------------
       
        MasterConnection masterConnection = new MasterConnection(connection);
        masterConnection.open();
       
        // -------------------------- SubConnection ---------------------------
       
        // We are skipping the SubConnection in this example.
       
        // ---------------------------- DataSource ----------------------------
       
        IDataSource dataSource = new RemoteDataSource(masterConnection);
        dataSource.open();
       
        // ----------------------------- DataBook -----------------------------
       
        RemoteDataBook dataBook = new RemoteDataBook();
        dataBook.setDataSource(dataSource);
        dataBook.setName("test");
        dataBook.open();
       
        // You can use the DataBook here.
       
        // Perform cleanup of all opened objects here.
    }
}

With this little example we have a completely working JVx application. We provide ways to create most of this out of the box and read most of it from configuration files, so there really is just little code to be written, see the JVx FirstApp as a perfect example for that. So there is rarely any need to write code like this, all you have to do is create a new application and start it.

Additionally, we could combine this long example with the simple one from before to initialize and create a GUI which could use our RemoteDataBook, like this:

// Insert after the RemoteDataBook has been created.

// Set the UI factory which should be used, in this case it is
// the SwingFactory.
UIFactoryManager.getFactoryInstance(SwingFactory.class);

UIFrame frame = new UIFrame();
frame.setLayout(new UIBorderLayout());
frame.add(new UITable(dataBook));

frame.pack();
frame.setVisible(true);

frame.eventWindowClosed().addListener(() -> System.exit(0));

Abstractions on every step

As you can see, you always have full control over the framework and can always tailor it to your needs. There is always the possibility to provide a custom implementation to fulfill your needs:

  1. Accessing a not supported database can be achieved by extending DBAccess
  2. Having a different service/way of providing data can be implemented on top of IStorage
  3. Supporting a different connection can be implemented on top of IConnection
  4. And a completely different way of providing data can be implemented on top of IDataSource

You can swap out every layer and provide custom and customized implementations which exactly work as you require it.

Just like that

Just like that we've walked through the whole stack of a JVx application, from the database which holds the data all the way to the client GUI. Of course there is much more going on in a full-blown JVx application, for example I've spared you here the details of the configuration, server, network and providing actual LCOs and similar. But all in all, this should get you going.

Alexa, shutter control

Post to Twitter

It's time for some words about my "shutter control" side project.

My house has electrical roller shutters with remote control units for every window. It was/is possible to close and open the shutters with these remote control units without any problems. But it wasn't possible to open/close them automatically because I don't own a central control unit. I'm not sure if such a central control unit is available for my "old" receiver modules?
Anyway, I'm a researcher and builder. So I built a central control unit based on a Raspberry Pi. I wrote about it in the past:

In the meantime, the project got a lux sensor to close the shutter if it's dark outside and it recognizes public holidays for later opening. It's not a good idea to open shutters on public holidays at 6 am :) The whole project is working very stable and it's so useful!

A few months ago, I heard about Google Home and Amazon Echo because both systems offer Voice control. I thought that voice control would be an awesome feature for my shutter control because sometimes it happens that my smartphone or remote control units are not at hand. And voice control is faster than using a smartphone or remote control. The only problem was that Google Home and Amazon Echo weren't available in Austria, not for German language and I didn't find any information about their APIs and whether if it's possible to develop addons. ... Sometimes you have to wait...

Things have changed in the meantime and both devices have APIs but only Amazon Echo is available for German language. I read some test reviews about both devices and Amazon is the pioneer. It supports more 3rd party devices than Home and looks proven. I had no preferences for Echo or Home, but Echo was available. The decision was simple :)

I made some simple tests with Echo because I tried to find out if it's really useful to have such a thing at home. And for sure, it is. It works really great and saves time :) It's great as replacement for standard radios or to stream your favourite music. It's also nice to listen to daily news or the weather forecast. A nice feature is the alarm clock!

But enough, it's a nice and useful device which simply works. The idea was voice control of my roller shutters.

Amazon Echo allows developers to create AddOns. Such AddOns are called Skills. It's not trivial but also not complex to create a custom Skill. The getting started is well documented and more documentation is available online. A developer forum exists and is active enough. It's really no problem to start but some pieces of the puzzle are unclear. I didn't find a detailed technical overview or didn't search long enough. It also was unclear where the Skills will be executed. I thought a skill is like an app and runs directly on the device... This was not the case.

Amazon Echo is a simple client and sends all requests to the amazon cloud. It handles responses but the brain is in the cloud. This means that all your services must be in the cloud. It's not a problem to host your own services in your own infrastrcuture but all your services have to be available via Internet. It's not possible to access a server in your Intranet directly. It's not possible to tweak with custom router configurations or custom dns records. Your services have to be available as cloud services. I found many solutions with service proxies or request forwarding but I didn't like this solutions because my home network is private.

But this was the only limitation and not really a problem because we have technologies like MQTT. I didn't use MQTT in the past but read a lot about it. The problem was that I didn't have a use-case for it. This was changed with Echo.

I played around with Mosquitto some hours and after TLS with and without user certificates were working, I was ready for connecting my shutter client. I don't write about my Mosquitto configuration here because there are so many good blog entries available in the wild.
It might be interesting that I use Eclipse paho as Java client library.

Ooh... and this utility class was really helpful. It made it possible to communicate secure to my Mosquitto broker. The class didn't support authentication without user certificate and it didn't read from InputStreams, but it was a good starting point. It also didn't work in with my Jetty application server. Here's a snippet of my code:

public static SSLSocketFactory getSocketFactory(Object pCACrt, Object pCrt,
                                Object pKey, String pPassword)
{
    try
    {
        // Load Certificate Authority (CA) certificate
        PEMParser reader = new PEMParser(createReader(pCACrt));
        X509CertificateHolder caCertHolder = (X509CertificateHolder)reader.readObject();
        reader.close();

        JcaX509CertificateConverter conv = new JcaX509CertificateConverter();
       
        X509Certificate caCert = conv.getCertificate((X509CertificateHolder)caCertHolder);
       
        // CA certificate is used to authenticate server
        KeyStore caKeyStore = KeyStore.getInstance(KeyStore.getDefaultType());
        caKeyStore.load(null, null);
        caKeyStore.setCertificateEntry("ca-certificate", caCert);

        TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(
                                TrustManagerFactory.getDefaultAlgorithm());
        trustManagerFactory.init(caKeyStore);
       
        // Create SSL socket factory
        SSLContext context = SSLContext.getInstance("TLSv1.2");

        if (exists(pCrt))
        {
            // Load client certificate
            reader = new PEMParser(createReader(pCrt));
            X509CertificateHolder certHolder = (X509CertificateHolder)reader.readObject();
            reader.close();

            X509Certificate cert = conv.getCertificate(certHolder);

            // Load client private key
            reader = new PEMParser(createReader(pKey));
            Object keyObject = reader.readObject();
            reader.close();

            PEMDecryptorProvider provider = new JcePEMDecryptorProviderBuilder().
                                build(pPassword.toCharArray());
            JcaPEMKeyConverter keyConverter = new JcaPEMKeyConverter().setProvider("BC");

            KeyPair key;

            if (keyObject instanceof PEMEncryptedKeyPair)
            {
                key = keyConverter.getKeyPair(((PEMEncryptedKeyPair)keyObject).
                                decryptKeyPair(provider));
            }
            else
            {
                key = keyConverter.getKeyPair((PEMKeyPair)keyObject);
            }

            // Client key and certificates are sent to server so it can authenticate
            // the client
            KeyStore clientKeyStore = KeyStore.getInstance(KeyStore.getDefaultType());
            clientKeyStore.load(null, null);
            clientKeyStore.setCertificateEntry("certificate", cert);
            clientKeyStore.setKeyEntry("private-key", key.getPrivate(),
                                pPassword.toCharArray(), new Certificate[] { cert });

            KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(
                                KeyManagerFactory.getDefaultAlgorithm());
            keyManagerFactory.init(clientKeyStore, pPassword.toCharArray());
           
            context.init(keyManagerFactory.getKeyManagers(),
                                trustManagerFactory.getTrustManagers(), null);
        }
        else
        {
            context.init(null, trustManagerFactory.getTrustManagers(), null);
        }

        return context.getSocketFactory();
    }
    catch (Exception e)
    {
        throw new RuntimeException(e);
    }
}

So, the communication via MQTT was configured and ready to use. The next step was the creation of a Skill. Echo supports using external services via https. The Skills-API comes with a special Servlet, the SpeechletServlet. You have to extend this servlet for every service. This creates boilerplate code because the servlet does nothing special. It usually configures the Speechlet. A Speechlet is more or less the main class for your service. So I decided to create a generic Servlet:

public class GenericServlet extends SpeechletServlet
{
    public void init(ServletConfig pConfig) throws ServletException
    {
        String sSpeechlet = pConfig.getInitParameter("speechlet");
       
        try
        {
            Class<?> clazz = Class.forName(sSpeechlet);
           
            Object obj = clazz.newInstance();
           
            if (obj instanceof Speechlet)
            {
                setSpeechlet((Speechlet)obj);
            }
            else
            {
                setSpeechlet((SpeechletV2)obj);
            }
        }
        catch (Exception e)
        {
            throw new ServletException("Can't init speechlet, e");
        }
       
        super.init(pConfig);
    }

}   // GenericServlet

Simple configuration in web.xml and no additional servlets needed:

<servlet>
    <servlet-name>ShutterService</servlet-name>
    <servlet-class>com.sibvisions.alexa.services.GenericServlet</servlet-class>

  <init-param>
    <param-name>speechlet</param-name>
    <param-value>com.sibvisions.alexa.services.shutter.ShutterSpeechlet</param-value>
  </init-param>
</servlet>

The Skill itself doesn't need source code. Amazon offers a web UI for the configuration and a simple test tool. The creation was straight forward and I simply followed an example from the Skills-API package. One tricky step was the certificate configuration, but Amazon supports self-signed certificates and wildcard certificates without problems. So, the Skill creation was done very fast because everything was done online without coding.

The custom service creation wasn't very difficult because the API is really simple and doesn't need more than implementing 4 interface methods:

@Override
public void onSessionStarted(SessionStartedRequest pRequest, Session pSession) throws SpeechletException
{
}

@Override
public void onSessionEnded(SessionEndedRequest pRequest, Session pSession) throws SpeechletException
{
}

@Override
public SpeechletResponse onIntent(IntentRequest pRequest, Session pSession) throws SpeechletException
{
    Intent intent = pRequest.getIntent();
   
    String intentName = (intent != null) ? intent.getName() : null;

    TranslationMap tmap = getTranslation(pRequest);
   
    if ("DownIntent".equals(intentName)
        || "UpIntent".equals(intentName)
        || "HaltIntent".equals(intentName))
    {
        String sText;

        try
        {
            if ("DownIntent".equals(intentName))
            {
                client.down();
               
                sText = "The shutters are moving down!";
            }
            else if ("UpIntent".equals(intentName))
            {
                client.up();
               
                sText = "The shutters are moving up!";
            }
            else
            {
                client.halt();
               
                sText = "The shutters are stopping!";
            }
        }
        catch (Exception e)
        {
            sText = "Shutter control not possible!";
        }
       
        sText = tmap.translate(sText);
       
        // Create the Simple card content.
        SimpleCard card = new SimpleCard();
        card.setTitle(tmap.translate("Shutter control"));
        card.setContent(sText);

        // Create the plain text output.
        PlainTextOutputSpeech speech = new PlainTextOutputSpeech();
        speech.setText(sText);

        return SpeechletResponse.newTellResponse(speech, card);
    }
    else
    {
        throw new SpeechletException(tmap.translate("Invalid intent!"));
    }
}

@Override
public SpeechletResponse onLaunch(LaunchRequest pRequest, Session pSession) throws SpeechletException
{
    TranslationMap tmap = getTranslation(pRequest);
   
    String sText = tmap.translate("Here we go!");
   
    // Create the Simple card content.
    SimpleCard card = new SimpleCard();
    card.setTitle(tmap.translate("Shutter control"));
    card.setContent(sText);

    // Create the plain text output.
    PlainTextOutputSpeech speech = new PlainTextOutputSpeech();
    speech.setText(sText);

    PlainTextOutputSpeech repromptSpeech = new PlainTextOutputSpeech();
    repromptSpeech.setText(tmap.translate("Tell me the direction!"));
   
    Reprompt reprompt = new Reprompt();
    reprompt.setOutputSpeech(repromptSpeech);

    return SpeechletResponse.newAskResponse(speech, reprompt, card);
}

It's also possible to use Amazons infrastructure for your services, but I have my own application server.

After some days, my roller shutters were controlled by Amazon Echo aka Alexa with voice commands. It was really cool and simple!

Here's a demonstration of the result (it's in German):

Alexa in action

I can only recommend this device!

Simple Drop File Support for JVx applications

Post to Twitter

Our next update release of VisionX will support Dropping files. It's a very useful feature and was easy to implement. Sure, it's a Swing specific feature, but our VisionX is more or less JVx Swing UI based.

Get a first impression

VisionX Drop file support

We drop an exported application archive into VisionX and the import wizard is starting. It's also possible to Drop a file directly into the import wizard.

VisionX is a JVx application and it's super easy to implement such feature for your own JVx application. Here's a code snippet how it'll work:

public SimpleFileDropHandler addTarget(IComponent pTarget, IFileHandleReceiver pListener,
                                       String... pExtension)
{
    Object oResource = pTarget.getResource();
   
    if (!(oResource instanceof JComponent) && !(oResource instanceof JFrame))
    {
        throw new IllegalArgumentException("Given object can't be a drop target!");
    }
   
    SimpleFileDropHandler handler = new SimpleFileDropHandler(pListener, pExtension);
   
    if (oResource instanceof JFrame)
    {
        ((JFrame)oResource).setTransferHandler(handler);
    }
    else
    {
        JComponent jcomp = getComponent((JComponent)oResource);
       
        if (jcomp != null)
        {
            jcomp.setTransferHandler(handler);
        }
    }
}

private JComponent getComponent(JComponent pComponent)
{
    if (pComponent instanceof JVxEditor)
    {
        JComponent comp = ((JVxEditor)pComponent).
                          getCellEditorHandler().getCellEditorComponent();
       
        if (comp instanceof JScrollPane)
        {
            Component cView = ((JScrollPane)comp).getViewport().getView();
           
            if (cView instanceof JComponent)
            {
                return ((JComponent)cView);                    
            }
            else
            {
                return null;
            }
        }
        else
        {
            return comp;
        }
    }
    else
    {
        return pComponent;
    }        
}

In principle, we set the TransferHandler for a JComponent. Above code detects the right JComponent because there's a difference if you use an IEditor.

The TransferHandler could be implemented like our SimpleFileDropHandler

public class SimpleFileDropHandler extends TransferHandler
{
    private IFileHandleReceiver listener;
   
    private String[] extensions;
       
    public SimpleFileDropHandler(IFileHandleReceiver pListener, String... pExtension)
    {
        listener = pListener;
        extensions = pExtension;
    }
   
    @Override
    public boolean canImport(TransferHandler.TransferSupport pSupport)
    {
        if (!pSupport.isDrop())
        {
            return false;
        }

        if (!pSupport.isDataFlavorSupported(DataFlavor.javaFileListFlavor))
        {
            return false;
        }

        boolean copySupported = (COPY & pSupport.getSourceDropActions()) == COPY;
       
        if (copySupported)
        {
            pSupport.setDropAction(TransferHandler.COPY);
            return true;
        }            
       
        return false;
    }
   
    @Override
    public boolean importData(TransferHandler.TransferSupport support)
    {
        if (!support.isDrop())
        {
            return false;
        }

        List<File> files;
        try
        {
            files = (List<File>)support.getTransferable().
                    getTransferData(DataFlavor.javaFileListFlavor);
        }
        catch (UnsupportedFlavorException ex)
        {
            // should never happen (or JDK is buggy)
            return false;
        }
        catch (IOException ex)
        {
            // should never happen (or JDK is buggy)
            return false;
        }
       
        if (listener != null)
        {
            for (File file : files)
            {
                try
                {
                    listener.receiveFileHandle(new FileHandle(file));
                }
                catch (Exception e)
                {
                    ExceptionHandler.raise(e);
                }
            }
        }
       
        return true;
    }
}

Have fun ;-)

Docking Framework with JVx application (Swing)

Post to Twitter

In last weeks, we got some inguiries about Docking support in JVx. Our answer was always the same:

JVx itself doesn't offer a Docking API because there are many docking frameworks available and it's super easy to integrate one of them.

But this wasn't the expected answer (for most people) because it wasn't clear enough or it wasn't believed. We said that the integration of any existing library or framework is super easy and super fast because it's usually not more effort than the integration in any other source code. But still....

Let's add some numbers

Integration in our existing JVx application
10 minutes (only one screen) and 30 minutes (the whole desktop)

Docking Framework Evaluation
3 hours (Test code, examples, ...)

Implementing Docking Features
6 hours (because of missing documentation and/or incomplete examples)

So, the integration took not more than 10 minutes, but the missing knowledge of Docking Frameworks was expensive. But this had nothing to do with JVx because getting know-how with frameworks or tools are always expensive.

We tried two different docking frameworks, but found much more: Stackoverflow question

We didn't consider commercial frameworks and inactive projects. Also GPL solutions weren't an option for us.

The first candidate was FlexDock because "the screenshot was impressive".
Our first demo was working but we didn't find any documentation (only one inofficial getting started). The demo application was complete enough but we had some problems because the framework uses a static context for component registration and this was a no-go. The API was simple but unclear/inconsistent in many situations.

We tried the next framework and this was Docking Frames. The last update of this framework was Feb 2017 and documentation is available. The tutorials are good and more than enough. The framework itself is super powerful but the API.... (oh my good). There is a core API and a common API. You shouldn't use the core API and work with common API instead. After some hours we had all our features working, but the documentation is soo complex and all examples are really complex. Long story, short: Very powerful but not easy to understand.

We took a simple demo application and tried to replace a Split Panel, in one of our screens, with dockable panels. After this was done, we replaced the whole MDI desktop (internal fames) with a dockable desktop (dockable panels).

The result is shown in different videos:

Docking Framework integration (simple Screen)

Docking Framework integration (frame and tab mode)

And the whole use-case, with replaced MDI desktop:

Docking Framework integration (desktop mode)

And, finally I want to show you the source code of our changes:

/** the data table. */
private NavigationTable tableElegantdock = new NavigationTable();
/** the details group. */
private UIGroupPanel groupPanelElegantdock = new UIGroupPanel();
/** the docking control. */
private CControl ccontrol;

private void initializeUI() throws Throwable
{
    ...

    ccontrol = new CControl();
    ccontrol.putProperty(StackDockStation.TAB_PLACEMENT, TabPlacement.TOP_OF_DOCKABLE);
   
    DefaultSingleCDockable dock1 = new DefaultSingleCDockable("data");
    dock1.setTitleText("Data");
    dock1.setMinimizable(false);
    dock1.setExternalizable(false);
    dock1.add((Component)tableElegantdock.getResource());

    DefaultSingleCDockable dock2 = new DefaultSingleCDockable("detail");
    dock2.setTitleText("Details");
    dock2.setMinimizable(false);
    dock2.setExternalizable(false);
    dock2.add((Component)groupPanelElegantdock.getResource());

    CGrid cgrid = new CGrid(ccontrol);
    cgrid.add(0,  0,  1,  1, dock1);
    cgrid.add(1,  0,  1,  1, dock2);
   
    ccontrol.getContentArea().deploy(cgrid);
   
    dock1.setVisible(true);
    dock2.setVisible(true);

    add(new UICustomContainer(ccontrol.getContentArea()), UIBorderLayout.CENTER);

The relevant code for JVx integration (will only work for JVx' swing UI):

dock1.add((Component)tableElegantdock.getResource())

Use the JVx resource (JPanel) and add it as component.

dock2.add((Component)groupPanelElegantdock.getResource());

Use the JVx resource (JPanel with a TitledBorder) and add it as component.

add(new UICustomContainer(ccontrol.getContentArea()), UIBorderLayout.CENTER)

Adds the dock control to the screen as custom container. This class connects a standard Container with JVx UI.

I won't publish the code for the desktop replacement because it's the same again with different variable names.

Smooth Forms 10g, 11i, 12c to Java Migration

Post to Twitter

This is a follow up for Smooth Forms 6i to Java Migration.

The following video demonstrates the integration of a Java screen into a Forms application. Since WebForms, it's possible to embedd Java swing components directly. We did create a compatibility layer to support special mouse features and to fix repaint problems. Our integration layer allows you to integrate a complete Java application, based on JVx.

Smooth Forms 10g, 11i, 12c Java Migration

The application is the standard Summit demo application for Forms. The Java application is very similar to the original application because we want to show how easy a 1:1 migration could be. The application was created with our low code platform VisionX. It offers a modern UI and is based on JVx, the OpenSource Java application framework. The final scene shows the embedded Java screen in Forms. It's super easy and doesn't need additional code. It just works with our compatibility layer.

Smooth Forms 6i to Java Migration

Post to Twitter

Following video demonstrates our Java integration for Forms 6i. In Forms 6i you can't embedd a Java application without complex ActiveX controls. So we chose an alternative for a smooth integration. It's more like an IPC between Forms and Java but with some additional features like automatic window switching.

Our solution is super flexible and it's possible to send custom events from Forms to Java and from Java to Forms. Here's an impression:

Smooth Forms6i Java Migration

Both applications use the same database. The Forms application is like any other Forms application and the Java Application was created with VisionX based on the Open Source Java Application Framework JVx.

toPDF 1.2 is available

Post to Twitter

Our Open Source PDF converter (toPDF) server is available in version 1.3

It contains some smaller bugfixes and very useful new features.

What's new?

  • BCL easyPDF SDK 8.0 support

    Convert via native Java API or COM interface. We've introduced EasyPdfNativeOperator which is now the default operator for PDF conversion.

  • Bookmark option

    This option creates bookmarks in your PDF document for headlines/sections in Word. Simply set the X-BOOKMARKS header parameter or use the REST API.

  • Additional attributes

    Set additional attributes for the conversion to PDF via Request parameters or REST API.

Get the current version from the project site ;-)

JVx Oracle Forms integration got better

Post to Twitter

We have a solution for Oracle Forms developers which allows integration of JVx applications and screens directly in your Oracle Forms screen/window. It's an awesome feature and works like a charm but had some limitations with repaints.

Let's have a look

Redraw problem (menu)

Redraw problem (menu)

Redraw problem (window)

Redraw problem (window)

We fixed the problem with our current version

No redraw issues (menu)

No redraw issues (menu)

No redraw issues (window)

No redraw issues (window)

It's was very tricky to solve the problem and it's well known. Our solution will work with other Swing based components as well.

JVx Reference, Custom Components

Post to Twitter

Let's talk about custom components, and how to create them.

The GUI of JVx

We've previously covered how the GUI of JVx works, and now we will have a look on how we can add custom components to the GUI.

In the terminology of JVx there are two different kinds of custom components:

  1. UI based
  2. Technology based

We will look at both, of course.

Custom components at the UI layer

The simplest way to create custom components is to extend and use already existing UI classes, like UIPanel or UIComponent. These custom components will be Technology independent because they use Technology independent components, there is no need to know about the underlying Technology. You can think of those as a "remix" of already existing components.

The upside is that you never have to deal with the underlying Technology, the downside is that you can only use already existing components (custom drawing is not possible, for example).

Let's look at a very simple example, we will extend the UILabel to always display a certain postfix along with the set text:

public class PostfixedLabel extends UILabel
{
    private String postfix = null;

    // We must store the original text so that we can return
    // it if requested. Otherwise we could only return the text
    // with the appended postfix, which works unless the postfix
    // changes.
    private String text = null;

    public PostfixedLabel()
    {
        super();
    }

    public PostfixedLabel(String pText)
    {
        super(pText);
    }

    public PostfixedLabel(String pText, String pPostfix)
    {
        super(pText);

        setPostfix(pPostfix);
    }

    @Override
    public String getText()
    {
        return text;
    }

    @Override
    public void setText(String pText)
    {
        text = pText;

        if (!StringUtil.isEmpty(postfix) &amp;&amp; !StringUtil.isEmpty(pText))
        {
            // We translate the text and the postfix now separately,
            // the underlying label will obviously try to translate
            // the concatenated version.
            super.setText(translate(pText) + translate(postfix));
        }
        else
        {
            super.setText(pText);
        }
    }

    public String getPostfix()
    {
        return postfix;
    }

    public void setPostfix(String pPostfix)
    {
        postfix = pPostfix;

        // If the postfix changed, we must update the text.
        setText(text);
    }
}

It will be treated just like another label, but every time a text is set, the postfix is appended to it.

Another example, we want a special type of component, one that always does the same but will be used in many different areas of the application, it should contain a label and two buttons. The best approach for a custom component which should not inherit any specific behavior is to extend UIComponent:

public class BeepComponent extends UIComponent
{
   public BeepComponent()
   {
       super(new UIPanel());
       
       UIButton highBeepButton = new UIButton("High Beep");
       highBeepButton.eventAction().addListener(Beeper::playHighBeep);
       
       UIButton lowBeepButton = new UIButton("Low Beep");
       highBeepButton.eventAction().addListener(Beeper::playLowBeep);
       
       UIFormLayout layout = new UIFormLayout();        

       uiResource.setLayout(layout);
       uiResource.add(new UILabel("Press for beeping..."), layout.getConstraints(0, 0, -1, 0));
       uiResource.add(highBeepButton, layout.getConstraints(0, 1));
       uiResource.add(lowBeepButton, layout.getConstraints(1, 1));
   }
}

So we extend UIComponent and set a new UIPanel as UIResource on it, which we can use later and which is the base for our new component. After that we added a label and two buttons which will play beep sounds if pressed. This component does not expose any specific behavior as it extends UIComponent, it only inherits the most basic properties, like background color and font settings, yet it can easily be placed anywhere in the application and will perform its duty.

Custom controls at the Technology layer

The more complex option is to create a custom component at the Technology layer. That means that we have to go through a multiple steps process to create and use the component:

  1. Create an interface for the functionality you'd like to expose
  2. Extend the Technology component (if needed)
  3. Implement the necessary interfaces for JVx
  4. Extend the factory to return the new component
  5. Create a UIComponent for the new component
  6. Use the new factory

I will walk you through this process, step by step.

The upside is that we can use any component which is available to us in the Technology, the downside is that it is quite some work to build the correct chain, ideally for every technology.

Creating an interface

The first step is to think about what functionality the component should expose, we will use a progress bar as example. We don't want anything fancy for now, a simple progress bar on which we set a percent value should be more than enough:

/**
 * The platform and technology independent definition for a progress bar.
 */

public interface IProgressBar extends IComponent
{
    /**
     * Gets the current value, in percent.
     *
     * @return the current value. Should be between {@code 0} and {@code 100}.
     */

    public int getValue();
   
    /**
     * Sets the current value, in percent.
     *
     * @param pValue the value. Should be between {@code 0} and {@code 100}.
     */

    public void setValue(int pValue);
}

Might not be the most sophisticated example (especially in regards to documentation) but it will do for now. This interface will be the foundation for our custom component.

Extending the component, if needed

We will be using Swing and the JProgressBar for this example, so the next step is to check if we must add additional functionality to the Technology component. In our case we don't, as we do not demand any behavior that is not provided by JProgressBar, but for the sake of the tutorial we will still create an extension on top of JProgressBar anyway.

public class ExtendedProgressBar extends JProgressBar
{
    public ExtendedProgressBar(int pMin, int pMax)
    {
        super(pMin, pMax);
    }
}

Within this class we could now implement additional behavior independent of JVx. For example, we provide many extended components for Swing, JavaFX and Vaadin with additional features but without depending on JVx. The extension layer is the perfect place to extend already existing components with functionality which will be used by, but is not depending on, JVx.

Creating the Implementation

The next step is to create an Implementation class which allows us to bind our newly extended JProgressBar to the JVx interfaces. Luckily there is the complete Swing Implementation infrastructure which we can use:

public class SwingProgressBar extends SwingComponent
                              implements IProgressBar
{
    public SwingProgressBar()
    {
        // We can hardcode the min and max values here, because
        // we do not support anything else.
        super(new ExtendedProgressBar(0, 100));
    }
   
    @Override
    public int getValue()
    {
        return resource.getValue();
    }
   
    @Override
    public void setValue(int pValue)
    {
        resource.setValue(pValue);
    }
}

That's it already. Again, in this case it is quite simple because we do not expect a lot of behavior. The implementation layer is the place to "glue" the component to the JVx interface, implementing missing functionality which is depending on JVx and "translating" and forwarding values and properties.

Extending the factory

Now we must extend the Factory to be aware of our new custom component, that is equally simple as our previous steps. First we extend the interface:

public interface IProgressBarFactory extends IFactory
{
    public IProgressBar createProgressBar();
}

And afterwards we extend the SwingFactory:

public class ProgressBarSwingFactory extends SwingFactory
                                     implements IProgressBarFactory
{
    @Override
    public IProgressBar createProgressBar()
    {
        SwingProgressBar progressBar = new SwingProgressBar();
        progressBar.setFactory(this);
        return progressBar;
    }
}

Again, it is that easy.

Creating the UIComponent

So that we can use our new and shiny progress bar easily, and without having to call the factory directly, we wrap it one last time in a new UIComponent:

public class UIProgressBar extends UIComponent
                           implements IProgressBar
{
    public UIProgressBar()
    {
        // We'll assume that, whoever uses this component,
        // is also using the correct factory.
        super(((IProgressBarFactory)UIFactoryManager.getFactory()).createProgressBar());
    }
   
    @Override
    public int getValue()
    {
        return uiResource.getValue();
    }
   
    @Override
    public void setValue(int pValue)
    {
        uiResource.setValue(pValue);
    }
}

Nearly done, we can nearly use our new and shiny component in our project.

Using thecustom factory

Of course we have to tell JVx that we want to use our factory, and not the default one. Depending on the technology which is used, this has to be done at different places:

Swing and JavaFX

Add the factory setting to the application.xml of the application:

<Launcher.uifactory>your.package.with.custom.components.SwingProgressBarFactory</Launcher.uifactory>
Vaadin

Add the following setting to the web.xml under the WebUI Servlet configuration:

<init-param>
    <param-name>Launcher.uifactory</param-name>
    <param-value>your.package.with.custom.components.VaadinProgressBarFactory</param-value>
</init-param>

Using our new component

And now we are done, from here we can use our custom component like any other.

UIProgressBar progressBar = new UIProgressBar();
progressBar.setValue(65);

// Skip

add(progressBar, constraints);

Wrapping custom components with UICustomComponent

There is a third way to have Technology dependent custom components in JVx, you can wrap them within a UICustomComponent:

JProgressBar progressBar = new JProgressBar(0, 100);
progressBar.setValue(100);

UICustomComponent customProgressBar = new UICustomComponent(progressBar);

// Skip

add(customProgressBar, constraints);

This has the upside of being fast and easy, but the downside is that your code has to know about the currently used Technology and is not easily portable anymore.

Conclusion

As you can see, there are multiple ways of extending the default set of components which are provided by JVx, depending on the use case and what custom components are required. It is very easy to extend JVx with all the components one does require.

EPlug 1.2.6

Post to Twitter

We're happy to announce the release of EPlug 1.2.6. Again this small version bump does not only yield important bug fixes, but also new features which will make your life a lot easier.

Fixes

This release includes bug fixes along with new features. One of the most notable problems fixed was that compile time checks might not be run if the communication with VisionX was active.

Cleaner context menu with more actions

We have restructured our approach to the context menu entries and introduced a new menu item which holds all EPlug related actions:

New context menu

As you can see we've also added new actions to jump to the configuration files.

Resources outside of source folders

We do support autocompletion and compile time checks for resources, like images. But we only supported resources inside of source folders, with this version we do now also support resources anywhere in the project.

Resources

Improved DataBook handling

DataBook handling has been improved once more. There are now additional checks which make sure that a RemoteDataBook receives the correct DataSource and there for if the MetaData can reliably be determined.

Additionally, the type of flag issued if no MetaData could be determined is now a configurable build option on the project.

New context menu

An example:

private void changeSomeValues(RemoteDataBook pDataBook)
{
    pDataBook.setValue("COLUMN_A", "A");
    pDataBook.setValue("COLUMN_B", "B");
    pDataBook.setValue("COLUMN_C", "C");
}

This would have been flagged as warning, because no MetaData could be determined for pDataBook. Now the check determines that determining MetaData for this DataBook is impossible and flags it accordingly. You can configure whether you want to see this flag or not in the project settings.

EPlug does also recognize if a "foreign" datasource has been set:

RemoteDataBook dataBookA = new RemoteDataBook();
dataBookA.setDataSource(getDataSource());
dataBookA.setName("a");
dataBookA.open();

RemoteDataBook dataBookB = new RemoteDataBook();
dataBookB.setDataSource(dataSourceFromSomewhereElse);
dataBookB.setName("a");
dataBookB.open();

// This will be flagged as error.
dataBookA.setValue("NON_EXISTING", BigDecimal.ZERO);

// This will be flagged according to the settings.
dataBookB.setValue("NON_EXISTING", BigDecimal.ZERO);

Usernames for sessions

Last but not least, there is now a project setting which allows to set the username which is used by EPlug for the session it creates.

A little background, to acquire the MetaData (and some other information about the application) EPlug creates a session of the application and executes the server side code. It could be that projects do have checks and manipulations on the username somewhere in their code on the server. Previously EPlug would set null as username, but now it does either use the configured autologin username or the username configured in the project settings. That allows server side code which does operate on the username of the session to run without a problem, which means that there are no checks necessary if the session was initialized by EPlug or not.

How to get it?

Simply update EPlug via Eclipse!