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

DOAG 2017

Auch in diesem Jahr sind wir wieder auf der DOAG anzutreffen. Details zur Veranstaltung.

Neu ist, das wir mit 3 Vorträgen vertreten sind:

  • Transformation: Fachbereich & IT digitalisieren gemeinsam
  • Low Code Plattform – A Web & Mobile UI Live Coding Session
  • Pimp your Forms - Forms Modernisierung mit Java

Nähere Details zu den Vorträgen, sind demnächst im Vortragsprogramm zu finden.

GUI Testing with VisionX

A new AddOn for VisionX is coming :)

Our GUI testing tool

A first impression

Application tester

Application tester

The tool is a recorder for VisionX/JVx applications. It has an option to export created tests as JUnit tests which makes it easy for Software developers to integrate the GUI tests in their CI systems. It's a super easy tool with so much value for you!

The App Tester will be available in our solution store and will be an AddOn for VisionX.

If you are interested in details, leave a comment.

VisionX 2.4 update I is out

VisionX 2.4 update release I is out. The exact version number is 2.4.544.310.
It's a powerful update release becasue it contains latest versions of relevant opensource libraries and frameworks.

What's new?

  • Thumbnails

    If application contains a thumbnail, VisionX won't add a random thumbnail anymore.

  • HTML5 Theme

    It's now possible to change the HTML5 theme via web settings: Standard, Valo, Mobile

    Web settings

    Web settings

  • Live preview

    Live preview does now work if you apply external changes or if you change the source code in Eclipse (with installed EPlug).

  • GridLayout is now supported

    The GridLayout of JVx is now officially supported in VisionX' Designer.

  • Vaadin 7.7.9

    VisionX updates contains Vaadin 7.7.9.

  • Solution store update

    The solution store now shows available solutions based on your VisionX version.

  • New demo solutions

    We have awesome new demo applications for licensed users.

    Demo applications

    Demo applications

  • New Reporting demo

    The reporting demo is a complete documentation about VisionX reporting features and the reporting API.

    Reporting

    Reporting

    Report overview

    Report overview

  • Smaller bugfixes

All customers will find the new version in their download area!
The trial version was updated as well!

Alexa, shutter control

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

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)

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.

Map component for JVx applications

We played around with some interesting stuff in the last weeks. Some customers and users asked us if we have a Map component.

We don't have a ready-to-use component but there are many free and commercial solutions available. The integration in a JVx application with custom components is not a problem and doesn't need much effort. But sure, an out-of-the-box solution would be useful.

Our Research team did create a PoC for a Map. The results is very nice and we want to show you some screenshots from our tests.

Swing integration (Tab mode)

Swing integration (Tab mode)

Swing integration (frame mode)

Swing integration (frame mode)

Vaadin integration

Vaadin integration

Vaadin integratin (corporation mode)

Vaadin integratin (corporation mode)

We didn't add the component to JVx because it's just a PoC and not ready-to-use.
But the Map integration looks great :)

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

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

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

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 ;-)