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

Category: Development

MacOS JInternalFrame border problem

With new MacOS versions, the good old Aqua LaF has some problems.

If you create a simple MDI application with JDesktopPane and JInternalFrame, following problem will occur:

Default JInternalFrame

Default JInternalFrame

The code for our problem:

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Insets;
import java.awt.Rectangle;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

import javax.swing.JDesktopPane;
import javax.swing.JFrame;
import javax.swing.JInternalFrame;
import javax.swing.JLabel;
import javax.swing.JTabbedPane;
import javax.swing.border.Border;
import javax.swing.border.CompoundBorder;
import javax.swing.plaf.UIResource;

public class TestJVxTabbedPane
{
    public static void main(String[] args) throws Exception
    {
        new TestJVxTabbedPane();
    }
   
    public TestJVxTabbedPane()
    {
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().setLayout(new BorderLayout());
       
        JDesktopPane dpan = new JDesktopPane();
        dpan.setBackground(Color.white);
               
        JInternalFrame fr = new JInternalFrame();
        fr.setTitle("Super Frame");
        fr.setPreferredSize(new Dimension(200, 200));
        fr.pack();
        fr.setResizable(true);
        fr.setMaximizable(true);
        fr.setIconifiable(true);
        fr.setClosable(true);
        fr.setVisible(true);
               
        dpan.add(fr);
       
        frame.getContentPane().add(dpan, BorderLayout.CENTER);
        frame.setSize(500, 400);
        frame.setLocationRelativeTo(null);

        frame.setVisible(true);      
    }
}

(nothing special, a simple JInternalFrame, JDesktopPane combination)

We don't like bad looking UIs, so we fixed the problem in JVx:

JInternalFrame without border problem

JInternalFrame without border problem

The fix will work without JVx as well. We made tests with different MacOS versions and our solution worked in all our tests.

JVx Reference, Launchers and Applications

Let's talk about Launchers, and how they are used to start JVx applications.

Starting an application

We've previously outlined a simple way to start a JVx application, and now we're going to look at how to do it with a launcher to benefit from everything JVx has to offer. From a technical point of view, there are two prerequisites which must be fulfilled before a JVx application can run:

  1. the JVM must have started.
  2. the technology specific system must have started.

Then, and only then, the JVx application can run. Depending on the implementation that is used, that can be as easily as instancing the factory (Swing, JavaFX), but can also mean that a servlet server has to start (Vaadin). Because we do not wish to encumber our applications with technology specific code, we have to entrust all this to an encapsulated entity, meaning the implementations of ILauncher and IApplication.

Following the chain

The steps for getting an application to start are as follows:

  1. The first thing that must run is obviously the JVM, without it we won't have much luck starting anything.
  2. The launcher must be created and it must start the Technology.
  3. The launcher than creates the application which the user is seeing.

Launcher chain

So we need two classes, the ILauncher implementation which knows how to start the Technology and the IApplication implementation. That we already knew, so let's try to put this into code. For simplicity reasons (and because I don't want to write a complete factory from scratch for this example) we will reuse the Swing implementation and write a new launcher and application for it.

Entry point

The Main class that we will use as example is very straightforward:

  1. public class Main
  2. {
  3.     public static void main(String[] pArgs)
  4.     {
  5.         // All we have to do here is kickoff the creation of the launcher.
  6.         // The launcher will do everything that is required to start for us.
  7.         //
  8.         // In a real world scenario and/or application there might be more
  9.         // setup or groundwork required, for example processing the arguments,
  10.         // but we don't need any of that here.
  11.         new SwingLauncher();
  12.     }
  13. }

All we have to do there is start the launcher itself. As the comment suggests, there might be work required for a "real" application startup. For this example, it is all we need to do. Of course we could also directly embed this little function into the launcher implementation itself, to save us one class.

The launcher

The ILauncher implementation on the other hand contains quite some logic, but nothing not manageable:

  1. public class SwingLauncher extends SwingFrame
  2.                            implements ILauncher
  3. {
  4.     // We have to extend from SwingFrame because there is no factory
  5.     // instantiated at that point, so we can't use UI components.
  6.    
  7.     private IApplication application;
  8.    
  9.     public SwingLauncher()
  10.     {
  11.         super();
  12.        
  13.         try
  14.         {
  15.             SwingUtilities.invokeAndWait(this::startup);
  16.         }
  17.         catch (InvocationTargetException | InterruptedException e)
  18.         {
  19.             e.printStackTrace();
  20.         }
  21.     }
  22.  
  23.     @Override
  24.     public void dispose()
  25.     {
  26.         try
  27.         {
  28.             // We must notify the application that we are being disposed.
  29.             application.notifyDestroy();
  30.         }
  31.         catch (SecurityException e)
  32.         {
  33.             e.printStackTrace();
  34.         }
  35.        
  36.         super.dispose();
  37.        
  38.         // We have to make sure that the application is exiting when
  39.         // the frame is disposed of.
  40.         System.exit(0);
  41.     }
  42.  
  43.     private void startup()
  44.     {
  45.         // We create a new SwingFactory and it is directly registered as global
  46.         // instance, that means it will be used by all components which are
  47.         // created from now on.
  48.         UIFactoryManager.getFactoryInstance(SwingFactory.class);
  49.        
  50.         // Also we set it as our factory instance.
  51.         setFactory(UIFactoryManager.getFactory());
  52.        
  53.         // Because the IApplication implementation we use is based upon
  54.         // UI components (which is advisable) we have to wrap this launcher
  55.         // in an UILauncher.
  56.         UILauncher uiLauncher = new UILauncher(this);
  57.        
  58.         // Now we create the main application.
  59.         // Note that the ExampleApplication is already based upon
  60.         // UI components.
  61.         application = new ExampleApplication(uiLauncher);
  62.        
  63.         // Then we add the application as content to the launcher.
  64.         uiLauncher.add(application);
  65.        
  66.         // Perform some setup work and start everything.
  67.         uiLauncher.pack();
  68.         uiLauncher.setVisible(true);
  69.        
  70.         // We also have to notify the application itself.
  71.         application.notifyVisible();
  72.     }
  73.    
  74.     // SNIP
  75. }

In short, the launcher is kicking off the Swing thread by invoking the startup method on the main Swing thread. This startup method will instantiate the factory and then create the application. From there we only need to set it visible and then our application has started.

The launcher extends from SwingFrame, that is required because there hasn't been a factory created yet which could be used by UI components to create themselves. If we'd try to use an UI component before creating/setting a factory, we would obviously see the constructor of the component fail with a NullPointerException.

The method startup() is invoked on the main Swing thread, which also happens to be the main UI thread for JVx in this application. Once we are on the main UI thread we can create the application, add it and then set everything to visible.

The application

The IApplication implementation is quite short, because we extend com.sibvisions.rad.application.Application, an IApplication implementation created with UI components.

  1. public class ExampleApplication extends Application
  2. {
  3.     public ExampleApplication(UILauncher pParamUILauncher)
  4.     {
  5.         super(pParamUILauncher);
  6.     }
  7.    
  8.     @Override
  9.     protected IConnection createConnection() throws Exception
  10.     {
  11.         // Not required for this example.
  12.         return null;
  13.     }
  14.    
  15.     @Override
  16.     protected String getApplicationName()
  17.     {
  18.         return "Example Application";
  19.     }
  20. }

Because the launcher has previously started the technology and created the factory we can from here on now use UI components, which means we are already independent of the underlying technology. So the IApplication implementation can already be used with different technologies and is completely independent.

Notes on the launcher

As you might have noticed, in our example the launcher is a (window) frame, that makes sense for nearly every desktop GUI toolkit as they all depend upon a window as main method to display their applications. But the launcher could also be simpler, for example just a call to start the GUI thread. Or it could be something completely different, for example an incoming HTTP request.

Also don't forget that the launcher is providing additional functionality to the application, like saving file handles, reading and writing the configuration and similar platform and toolkit dependent operations, see the launcher for Swing for further details.

Conclusion

This example demonstrates how a simple launcher is implemented and why it is necessary to have a launcher in the first place. Compared with the "just set the factory" method this seems like a lot of work, but the launchers used by JVx are of course a lot more complex than these examples, that is because they implement all the required functionality and also take care of a lot of boiler plate operations. It is taking care of all technology specific code and allows to keep your application free from knowing about the platform it runs on.

VisionX 2.4 u2 is out

We're happy to announce VisionX 2.4 Update Release 2. It's another milestone for us.

The new version is a bugfix release with some important features for all our customers. The top bug was a missing license check for our HTML5 implementation. With older versions it was possible to use our HTML5 application without valid license. This wasn't a hidden feature, it was a real bug. The new version has a clean license check and some of you will need a new license. This is no problem, simply contact us.

What's new?

  • Full-Screen mode

    Press F12 to maximize VisionX without frame border.

  • HTML5 Live preview options

    It supports "application per session", custom UI factory, custom Application setups, main, config and externalCss URL parameter.

  • VisionX is now http session ready

    It will be possible to use VisionX on server-side as backend for remote application development.

  • Fixed Copy/Paste for DnD fields

    It's now possible to Copy/Paste into field with DnD support.

  • Automatic UI tests

    VisionX now supports automatic UI tests with an optional AddOn. The mechanism isn't limited to our AddOn. It's also possible to create custom Modules/AddOns.

  • Tibero Database support

    VisionX has built-in support for Tibero Database (tested with version 6).

  • Auto-restart feature

    VisionX got a Preloader. This allows custom libraries without manually changing the classpath. The old classpath mechanism is still available, but we use the Preloader by default.

  • Action Editor with custom editor support

    It's now possible to add custom editors in the action editor via action.xml and/or a custom module.

  • GridLayout support

    It's now possible to use panels with GridLayout, if set in Source Code.

  • Custom vaadin widgetsets and themes

    It's now possible to create custom vaadin widgetsets, e.g. add an AddOn from the Vaadin Directory. It's super easy to create a custom theme and setting your custom css attributes.

  • Performance improvement

    We reduced the fetch calls during screen creation. This will improve performance with big tables and complex views.

  • New modules, AddOns and demo applications (optional)

    The VaadinAddon can be used to create a custom widgetset or theme. The AppTeste is an automatic UI test tool. There is a new demo application for testing Validators. The new reporting demo application will show all features of our reporting engine.

  • Configurable EPlug ports

    It's now possible to configure the EPlug communication ports via system properties.

  • Better Application signing

    Our signing mechanism now supports TSA Urls, Proxies, signing algorithms and much more.

  • Service module merging

    Newly created applications will automatically merge service modules. This is an important bugfix for e.g. the profiles module.

The new version is available in your download area or as Trial version.

JVx and Lua, a proof of concept

We've found the time to look at something that was floating around the office for quite some time. A few of us had previous experiences with Lua, a simple scripting language, but nothing too concrete and while doing a prototype a question popped up: Would it be easy to create a JVx GUI in Lua? As it turns out, the answer is "yes".

Lua, a short tour

Lua is a lightweight, multi-paradigm programming language designed primarily for embedded systems and clients.

Lua was originally designed in 1993 as a language for extending software applications to meet the increasing demand for customization at the time. It provided the basic facilities of most procedural programming languages, but more complicated or domain-specific features were not included; rather, it included mechanisms for extending the language, allowing programmers to implement such features. As Lua was intended to be a general embeddable extension language, the designers of Lua focused on improving its speed, portability, extensibility, and ease-of-use in development.

That is what Wikipedia has to say about Lua, but personally I like to think about it as "Basic done right", no insults intended. Lua is easy to write, easy to read and allows to quickly write and edit scripts. There are quite a few implementations for different languages and systems available which makes it very versatile and usable from in nearly every environment.

The most simple Lua script is one that prints "Hello World":

  1. print("Hello World")

Because it is a prototype based language, functions are first-class citizens, which can be easily created, passed around and invoked:

  1. local call = function()
  2.     print("Hello World")
  3. end
  4.  
  5. call()

Additionally, we can use tables to store state. They work like a simple key/value store:

  1. local operation = {
  2.     method = function(string)
  3.         print(string)
  4.     end,
  5.     value = "Hello World"
  6. }
  7.  
  8. operation.method(operation.value)
  1. local operation = {}
  2. operation.method = function(string)
  3.     print(string)
  4. end
  5. operation.value = "Hello World"
  6.  
  7. operation.method(operation.value)

Additionally, with some syntactic sugar, we can even emulate "real" objects. This is done by using a colon for invoking functions, which means that the table on which the function is invoked from will be provided as first parameter:

  1. local operation = {
  2.     method = function(valueContainer, string)
  3.         print(valueContainer.value .. " " .. string)
  4.     end,
  5.     value = "Hello World"
  6. }
  7.  
  8. operation:method("and others")

Last but not least, the rules about "new lines" and "end of statements" are very relaxed in Lua, we can either write everything on one line or use semicolons as statement end:

  1. local call = function(value) return value + 5 end print(call(10))
  2.  
  3. local call = function(value)
  4.     return value + 5;
  5. end
  6.  
  7. print(call(10));

But enough of the simple things, let's jump right to the case.

World, meet JVx.Lua

JVx.Lua is a proof of concept Java/Lua bridge, which allows to use the JVx classes in Lua scripts. Additionally, we've created a short demo application, JVx.Lua Live, which allows to directly write Lua code and see the output live in the application.

JVx/Lua live demo

The example code should be self-explanatory and the API is as close to the Java one as is possible. If an exception is thrown by the Lua environment it will be displayed in the live preview.

JVx/Lua live demo

This allows to quickly test out the Lua bindings and create a simple GUI in no time. But note that this simple demo application does not store what you've created, when you close it, it will be gone.

How does it work?

Glad you asked! The demo application is, of course, a simple GUI build with JVx, there are two core components which make it possible:

  1. RSyntaxTextArea, a Swing component for displaying and editing code.
  2. LuaJ, a Lua interpreter and compiler which allows to compile Lua directly to Java bytecode.

RSyntaxTextArea does not need to be further explained, it just works, and working very well it does. So does LuaJ, but that one has to be explained.

To create a new "Lua environment" one has to instance a new set of Globals and install the Lua-to-Lua-Bytecode and Lua-Bytecode-to-Java-Bytecode compilers into it.

  1. Globals globals = new Globals();
  2. LuaC.install(globals);
  3. LuaJC.install(globals);
  4.  
  5. globals.load("print(\"Hello World\")");

And that's it! With this we can already execute Lua code directly in Java, and most importantly, at runtime.

By default, LuaJ does provide nothing for the Lua environment, which means that it is sandboxed by default. If we want to add functionality and libraries, we'll have to load it into the Globals as so called "libs". For example if we want to provide all functions which can be found inside the string table, we'll have to load the StringLib:

  1. Globals globals = new Globals();
  2. LuaC.install(globals);
  3. LuaJC.install(globals);
  4.  
  5. globals.load(new StringLib());
  6.  
  7. globals.load("print(string.sub(\"Hello World\", 7))");

There are multiple libs provided with LuaJ which contain the standard library functions of Lua or provide access directly into the Java environment. For example we can coerce Java objects directly into Lua ones:

  1. BigDecimal value = new BigDecimal("-5.1234");
  2.  
  3. globals.set("value", CoerceJavaToLua.coerce(value));
  1. local absoluteValue = value:abs()
  2. local squaredValue = absoluteValue:pow(2)
  3.  
  4. print(squaredValue:toString())

Which gives us all the power of Java at our fingertips in Lua.

JVx bindings for Lua

Armed with that knowledge, we can have a look at the bindings which make it possible to use the JVx classes. JVxLib and LuaUtil are the main classes which coerce a single class to be used by Lua, the procedure looks as follows:

  1. Create a LuaTable to hold the class and register it globally.
  2. Add all public static fields (constants) to it.
  3. Add all static methods to it.
  4. Add a single constructor with a vararg argument to it.

The most interesting point is the constructor call, we simply register a method called "new" on the table and give it a vararg argument, which means that it can be called with any number of arguments. When this function is invoked the arguments are processed and a fitting constructor for the object is chosen. The found constructor is invoked and the created object is coerced to a Lua object, that created Lua object is returned.

This allows us to use a clean syntax when it comes to accessing the static or instance state of the objects. Static methods and constants, including constructors, are always accessed using the "dot" notation, while everything related to the instance is accessed using the "colon" notation.

Downside, binding events

For events and event handlers we had to dig a little deeper into LuaJ. The main problem with our EventHandler is that it has two methods: addListener(L) and addListener(IRunnable), at runtime the first one is reduced to addListener(Object). Let's assume the following code:

  1. button:eventAction():addListener(listener)

With such a construct LuaJ had a hard time finding the correct overload to use even when listener was a coerced IRunnable. This turned out to be undefined behavior, because the order of methods returned by a class object during runtime is undefined, sometimes LuaJ would choose the correct method and all other times it would use the addListener(Object) method. Which had "interesting" side effects, obviously, because an IRunnable object ended up in a list which should only hold objects of type L.

We've added a workaround so that functions with no parameters can be easily used, but for "full blown listener" support we'd have to invest quite some time. Which we might do at some point, but currently this is alright for a proof of concept.

Conclusion

Using Lua from Java is easy thanks to LuaJ, another possible option is Rembulan, which can not go unmentioned when one talks about Java and Lua. It does not only allow to quickly and easily write logic, but with the right bindings one can even create complete GUIs and applications in it and thanks to the ability to compile it directly to Java bytecode it is nearly as fast as the Java code. But, with the big upside that it can be easily changed at runtime, even by users.

VisionX, a short look at Validators

It is time to have a short look at Validators, what they are, how they work and how they can be used.

Okay, what are they?

A Validator is a component which is available to our customers who have purchased VisionX, it allows to quickly and easily add field validation to a form or any screen with records.

Validators in VisionX

Validators are readily available in VisionX as components which can be added to the screen.

VisionX Validators - Toolbox

It can be added to the screen by simply dragging it like any other component, but must be configured afterwards to know which field required validation.

VisionX Validators - Properties

There are three important properties to the Validator:

  • Binding: The field to which the Validator should be bound to. This works analog to selecting to a field for an Editor.
  • Automatic validate: If the validation process should be automatically performed on value changes.
    If this is checked, the Validator will listen for value changes on the specified field and will automatically run the validation action on every change. If not checked, the validation process must be run manually by calling Validator.validate() as needed.
  • Hide until first validate: If the Validator should stay hidden until at least one validation was performed.
    If this is checked, the Validator will not be visible until at least its validation has been called once, afterwards it will always be visible.

Validating values

To actually validate something, we have to attach an action to the Validator which will perform the validation. This can be readily done through the VisionX action designer, which provides everything needed to create such an action and we will not go into detail on how to do this.

We will, however, have a short look at the code of a simple action.

  1. public void doValidateNonEmpty(Validator pValidator) throws Throwable
  2. {
  3.     if (Logical.equals(rdbData.getValue("COLUMN"), ""))
  4.     {
  5.         throw new Exception("A value for the COLUMN must be entered.");
  6.     }
  7. }

It is a very simple action, the current value of the DataBook is checked and if it is empty, an Exception is. This is the most simple validation action one can create.

Validators in action

Once we have everything setup, we can put the Validators to good use. When the validation is performed, may it be automatically or manually, the validation actions will be invoked and if all of them return without throwing an Exception, the Validator will display a green check mark. However, if the actions should throw an Exception, the Validator will display a red "X".

VisionX Validators - Failed

Manual validation

Manually invoking the validation process as needed is quite simple by calling Validator.isValid(), which will return either true or false.

  1. public void doSaveButtonPressed(UIActionEvent pEvent) throws Throwable
  2. {
  3.     if (validator.isValid())
  4.     {
  5.         rdbData.saveSelectedRow();
  6.     }
  7.     else
  8.     {
  9.         labelError.setVisible(true);
  10.     }
  11. }

Above you see a sample action which manually performs the validation process and either saves the data or sets an error label to visible.

The ValidationResult

One can quickly end up with many Validators in a single screen, which might make it difficult for the user to directly see why a field is not correctly validated. So it suggest itself that there should be a short summary close to the save button to make sure that the user is readily provided with the information why the action could not be performed. For this scenario there is the ValidationResult, which is another component which can be added to the screen from the toolbox.

It will automatically find all Validators in the screen and will perform their validation as needed. Afterwards it will gather all error messages and display them in a list.

VisionX Validators - ValidationResult

The ValidationResult can be used similar to the Validator in an action.

  1. public void doSaveButtonPressed(UIActionEvent pEvent) throws Throwable
  2. {
  3.     if (validationResult.isValid())
  4.     {
  5.         rdbData.saveSelectedRow();
  6.     }
  7.     else
  8.     {
  9.         labelError.setVisible(true);
  10.     }
  11. }

Additionally, there is the clearMessage() method which allows to clear the list of errors.

Conclusion

The Validator and ValidationResult provide quick and easy means to add data validation to forms and screens with records and can be added and configured completely through the VisionX designer. Additionally, it provides a rich API which allows it to be easily used when writing the code manually or extending it with additional functionality.

Wordpress/Contact Form 7 post request to Java Servlet

This article is an upgraded version of Joomla/RSForms post request to Java Servlet.

The use case is the same: Calling a Java Servlet, after submitting a form. The servlet should read the form data and start e.g. the creation of a license file.

The form plugin Contact Form 7 is very popular for Wordpress. It's powerful and easy to use.

But sadly, it doesn't support custom php scripts, only custom Javascript calls. So it's possible to add custom javascript calls with predefined hooks. Not exactly what we want because Javascript functions run on client side and not in the same context as the php backend.

It wasn't possible to implement missing features without coding php, but it was not tricky.

What we did to call a Java Servlet?

1. Register a custom module

Modified wp-content/plugins/contact-form-7/settings.php

public static function load_modules() {
    ...
    self::load_module( 'submit' );
    self::load_module( 'text' );
    self::load_module( 'textarea' );
    self::load_module( 'hidden' );

    self::load_module( 'sibvisions' );
}

Added load_module('sibvisions');

2. Create the new module

Created wp-content/plugins/contact-form-7/modules/sibvisions.php

<?php
/**
 ** Module for SIB Visions.
 **/

add_action('wpcf7_submit', 'wpcf7_sibvisions_submit', 10, 2);

function wpcf7_sibvisions_submit($contactform, $result)
{
    if ($contactform->in_demo_mode() || $contactform->is_true('do_not_store'))
    {
        return;
    }

    $servletURL = $contactform->additional_setting('sib_servletURL');

    if (empty($servletURL[0]))
    {
        error_log('Servlet URL is not set in form!');
        return;
    }

    $cases = (array)apply_filters('wpcf7_sibvisions_submit_if',
                                  array('spam', 'mail_sent', 'mail_failed'));

    if (empty($result['status']) || ! in_array($result['status'], $cases ))
    {
        return;
    }

    $submission = WPCF7_Submission::get_instance();

    if (!$submission || ! $posted_data = $submission->get_posted_data())
    {
        return;
    }

    if (isset($posted_data['g-recaptcha-response']))
    {
        if (empty($posted_data['g-recaptcha-response']))
        {
            return;
        }
    }

    $fields_senseless = $contactform->scan_form_tags(
                                        array('feature' => 'do-not-store'));

    $exclude_names = array();

    foreach ( $fields_senseless as $tag )
    {
        $exclude_names[] = $tag['name'];
    }

    $exclude_names[] = 'g-recaptcha-response';

    foreach ($posted_data as $key => $value)
    {
        if ('_' == substr($key, 0, 1) || in_array($key, $exclude_names))
        {
            unset($posted_data[$key]);
        }
    }

    $url = str_replace('"', "", $servletURL[0]);
    $url = str_replace("'", "", $url);

    $ch = curl_init();

    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_POST, 1);
    curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
    //curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
    //curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);

    $data = array();

    foreach ($posted_data as $post => $value)
    {
        if (is_array($value))
        {
            foreach ($value as $post2 => $value2)
            {
                $data[] = $post.'[]='.urlencode($value2);
            }
        }
        else
        {
            $data[] = $post.'='.urlencode($value);
        }
    }

    curl_setopt($ch, CURLOPT_POSTFIELDS, implode('&', $data));
 
    $data = curl_exec($ch);

    if (curl_errno($ch))
    {
        wp_mail('noreply@sibvisions.com', 'Service error',
                'Call to service ('.$url.') failed with error ('.curl_error($ch).')');
    }
    else
    {
        $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE)
       
        if ($http_code != 200)
        {
            wp_mail('noreply@sibvisions.com', 'Service error',
                    'Call to service ('.$url.') failed with error ('.$data.')');
        }
    }
   
    curl_close($ch);
}

The script is based on module flamingo.php because it had all useful validations.

Be careful, because the script will be applied to all your forms. It's form independent.

3. Additional setting

The only thing you'll need is am additional setting (for your form):

sib_servletURL:'https://server/services/registration'

This setting configures the servlet to use for the form. If you don't configure a servlet, the module will do nothing!

DONE

The new module will forward all form data to the servlet. The servlet is the same as in our original article - no changes needed.

Full-Screen Mode for JVx applications

If you have a JVx application and want to use it without the frame border, it's not supported out-of-the-box. Sometimes it's very useful to have a full-screen application or to grab a screenshot without frame.

We now support this feature for Swing based applications but not in the official UI API. Here's a code snippet:

//F12 for toggling mode
KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(new KeyEventDispatcher()
{
      @Override
      public boolean dispatchKeyEvent(KeyEvent e)
      {
          if (e.getKeyCode() == KeyEvent.VK_F12)
          {
              if (ObjectCache.get("FULLSCREEN") == null)
              {
                  ObjectCache.put("FULLSCREEN", Boolean.TRUE, 500);
                 
                  SwingApplication app = (SwingApplication)getLauncher();
                  app.setFullScreen(!app.isFullScreen());
                 
                  return true;
              }
             
              return false;
          }
         
          return false;
      }
});

The trick with FULLSCREEN is necessary because the event fires sometimes more than once.

Simply press F12 key to toggle between Fullscreen/Frame mode.

JVx Reference, Resource and UIResource

Let's talk about Resources and UIResources, and why they sound similar but are not the same.

The Basics

We've previously covered how the JVx GUI layer works, now we are going to have a better look at the Resources and UIResources. With "Resource" we do not mean images or similar, we mean the implementation at the technology layer which is encapsulated by a wrapper class (Bridge Pattern). An "UIResource" on the other hand is an encapsulated concrete implementation of one of the interfaces on the UI layer.

Let's do a short brush-up on how the JVx architecture looks like in regards to the GUI stack:

JVx Resource

The UI Wrappers are the main UI classes which are used to create the GUI (f.e. UIButton). These are wrapping the Implementations (f.e. a SwingButton) which themselves are wrapping the Extension/Technology (f.e. a JVxButton/JButton). Only the UI and Implementation classes are implementing the interface required for the component (f.e. IButton). That also means that the Implementation is dependent on the Extension/Technology component, but the UI can use any object which implements the interface.

Now, with that knowledge we can start defining what is what:

JVx Resource 2

The resource itself, accessed by calling <uiwrapper>.getResource(), is the Extension/Technology component. The uiresource can be accessed by calling <uiwrapper>.getUIResource(). The uicomponent can be accessed by calling <uiwrapper>.getUIComponent() and is usually the UI Wrapper itself. If we use our previous Swing example, the resource would be a JVxButton/JButton, the uiresource would be the SwingPanel and the uicomponent would be the UIButton.

As one can see, access to all objects which are comprising the GUI is at all times possible. We, of course, have the UI component, we can access the Implementation component and we can access the Extension/Technology component. Theoretically we could also swap them at runtime, but in JVx this is limited to the construction of the object to greatly reduce the error potential.

Creating custom components

Equipped with that knowledge, we can revisit the previous guide on how to create custom components, the part about the BeepComponent to be exact:

  1. public class BeepComponent extends UIComponent<IPanel>
  2. {
  3.    public BeepComponent()
  4.    {
  5.       super(new UIPanel());
  6.        
  7.       UIButton highBeepButton = new UIButton("High Beep");
  8.       highBeepButton.eventAction().addListener(Beeper::playHighBeep);
  9.      
  10.       UIButton lowBeepButton = new UIButton("Low Beep");
  11.       highBeepButton.eventAction().addListener(Beeper::playLowBeep);
  12.      
  13.       UIFormLayout layout = new UIFormLayout();        
  14.      
  15.       uiResource.setLayout(layout);
  16.       uiResource.add(new UILabel("Beep"), layout.getConstraints(0, 0, -1, 0));
  17.       uiResource.add(highBeepButton, layout.getConstraints(0, 1));
  18.       uiResource.add(lowBeepButton, layout.getConstraints(1, 1));
  19.    }
  20. }

We are setting a new UIResource (an UIPanel) in the constructor (at line #5) which is to be used by the UIComponent. In this case it is not an Implementation, but another UI component, but that doesn't matter because the UIResource only must implement the expected interface. At line #15 we start using that custom UIResource.

Because UIComponent is an abstract component designed for exactly this usage, the example might not be the most exciting one, but it clearly illustrates the mechanic.

Bolting on functionality

Also from the previous guide on how to create custom components we can reuse the PostfixedLabel as example.

  1. private UILabel testLabel = new UILabel()
  2. {
  3.     public UILabel()
  4.     {
  5.         super(new PostfixedLabel("", "-trial"));
  6.     }
  7. };

Now testLabel will be using the PostfixedLabel internally, but with no indication to the user of the object that this is the case. This allows to extend the functionality of a component completely transparently, especially in combination with functions which do return an UIComponent and similar.

An important note about the component hierarchy

If we create a simple component extensions, like the BeepComponent above, it is important to note that there is one other layer of indirection in regards to the hierarchy on the technology layer. If we create a simple frame with the BeepComponent in it, one might expect the following hierarchy:

         UI                   Technology
---------------------    ----------------------
 UIFrame                  Frame
   \-UIPanel                \-Panel
       \-BeepComponent          \-BeepComponent
                                    \-Panel
                                        |-Label
                                        |-Button
                                        \-Button

With the BeepComponent added and its sub-components as its children. However, the actual hierarchy looks like this:

         UI                   Technology
---------------------    ----------------------
 UIFrame                  Frame
   \-UIPanel                \-Panel
       \-BeepComponent          \-Panel
                                    |-Label
                                    |-Button
                                    \-Button

That is because such extended components are not "passed" to the Technology, they do only exist on the UI layer because they do not have a Technology component which could be used. That is done by adding the UIComponent to the UI parent, but for adding the actual Technology component the set UIResource is used.

The special case of containers

Another special case are containers. For example we could create a panel which does display an overlay in certain situations and we will need to use that throughout the whole application.

UIResourceContainer Example

That means we do not want to build it every time anew, so one option would be to use a factory method to "wrap" the content, something like this:

  1. UIFormLayout panelLayout = new UIFormLayout();
  2. panelLayout.setHorizontalAlignment(UIFormLayout.ALIGN_CENTER);
  3. panelLayout.setVerticalAlignment(UIFormLayout.ALIGN_CENTER);
  4.    
  5. UIPanel panel = new UIPanel();
  6. panel.setLayout(panelLayout);
  7. panel.add(new UILabel("Firstname"), panelLayout.getConstraints(0, 0));
  8. panel.add(new UITextField("John"), panelLayout.getConstraints(1, 0));
  9. panel.add(new UILabel("Lastname"), panelLayout.getConstraints(2, 0));
  10. panel.add(new UITextField("Doe"), panelLayout.getConstraints(3, 0));
  11. panel.add(new UILabel("Street"), panelLayout.getConstraints(0, 1));
  12. panel.add(new UITextField("Old R. Road"), panelLayout.getConstraints(1, 1, 3, 1));
  13. panel.add(new UILabel("ZIP"), panelLayout.getConstraints(0, 2));
  14. panel.add(new UITextField("11946"), panelLayout.getConstraints(1, 2));
  15. panel.add(new UILabel("Place"), panelLayout.getConstraints(2, 2));
  16. panel.add(new UITextField("Hampton Bays"), panelLayout.getConstraints(3, 2));
  17.    
  18. parentContainer.add(OverlayPanelFactory.wrap(panel), UIBorderLayout.CENTER);

And the wrap method itself:

  1. public static final UIPanel wrap(IComponent pContent)
  2. {
  3.     UILabel overlayLabel = new UILabel("FOR YOUR<br>EYES ONLY");
  4.     overlayLabel.setBackground(null);
  5.     overlayLabel.setFont(UIFont.getDefaultFont().deriveFont(UIFont.BOLD, 48));
  6.     overlayLabel.setForeground(UIColor.createColor("#3465a4"));
  7.     overlayLabel.setHorizontalAlignment(UILabel.ALIGN_CENTER);
  8.    
  9.     UIFormLayout layout = new UIFormLayout();
  10.    
  11.     UIPanel panel = new UIPanel();
  12.    
  13.     panel.setLayout(layout);
  14.     panel.setBackground(UIColor.createColor("#3465a4"));
  15.     panel.add(overlayLabel, layout.getConstraints(0, 0, -1, -1));
  16.     panel.add(pContent, layout.getConstraints(0, 0, -1, -1));
  17.    
  18.     return panel;
  19. }

Which is easy enough, but let's say we'd like to add logic to that wrapper, at that point it becomes more complicated. We can't use the same technique as for custom component from above, because in that case the "overlaying panel" would simply not be displayed. However, there is a similar mechanism for containers, setting the UIResourceContainer.

The UIResourceContainer is another special mechanism which works similar to setting the UIResource, but it works exactly the other way round. While setting the UIResource does "hide" components from the Technology which are there in UI layer, setting the UIResourceContainer does hide components from the UI layer while there are added in the Technology. A little bit complicated, here is our example again using this technique:

  1. public static class OverlayedPanel extends UIPanel
  2. {
  3.     public OverlayedPanel()
  4.     {
  5.         super();
  6.        
  7.         UILabel overlayLabel = new UILabel("FOR YOUR<br>EYES ONLY");
  8.         overlayLabel.setBackground(null);
  9.         overlayLabel.setFont(UIFont.getDefaultFont().deriveFont(UIFont.BOLD, 48));
  10.         overlayLabel.setForeground(UIColor.createColor("#3465a4"));
  11.         overlayLabel.setHorizontalAlignment(UILabel.ALIGN_CENTER);
  12.        
  13.         UIPanel innerPanel = new UIPanel();
  14.        
  15.         UIFormLayout layout = new UIFormLayout();
  16.        
  17.         setLayout(layout);
  18.         setBackground(UIColor.createColor("#3465a4"));
  19.         add(overlayLabel, layout.getConstraints(0, 0, -1, -1));
  20.         add(innerPanel, layout.getConstraints(0, 0, -1, -1));
  21.        
  22.         setUIResourceContainer(innerPanel);
  23.     }
  24. }

What we've done is extend an UIPanel (line #1), setting it up and adding children and then we've declared one of its children as the UIResourceContainer (line #22). So all methods which are specific to IContainer (adding children, setting a layout, etc.) are now forwarding to the innerPanel and manipulating the contents of the OverlayedPanel directly is not directly available.

And here is how it is used:

  1. UIFormLayout panelLayout = new UIFormLayout();
  2. panelLayout.setHorizontalAlignment(UIFormLayout.ALIGN_CENTER);
  3. panelLayout.setVerticalAlignment(UIFormLayout.ALIGN_CENTER);
  4.    
  5. UIPanel panel = new OverlayedPanel();
  6. panel.setLayout(panelLayout);
  7. panel.add(new UILabel("Firstname"), panelLayout.getConstraints(0, 0));
  8. panel.add(new UITextField("John"), panelLayout.getConstraints(1, 0));
  9. panel.add(new UILabel("Lastname"), panelLayout.getConstraints(2, 0));
  10. panel.add(new UITextField("Doe"), panelLayout.getConstraints(3, 0));
  11. panel.add(new UILabel("Street"), panelLayout.getConstraints(0, 1));
  12. panel.add(new UITextField("Old R. Road"), panelLayout.getConstraints(1, 1, 3, 1));
  13. panel.add(new UILabel("ZIP"), panelLayout.getConstraints(0, 2));
  14. panel.add(new UITextField("11946"), panelLayout.getConstraints(1, 2));
  15. panel.add(new UILabel("Place"), panelLayout.getConstraints(2, 2));
  16. panel.add(new UITextField("Hampton Bays"), panelLayout.getConstraints(3, 2));
  17.    
  18. parentContainer.add(panel, UIBorderLayout.CENTER);

Notice that we can use it is any other panel (line #5) and simply add it to the parent (line #18). For a user of the API it is transparent as to whether there are more components or not, this is also visible in the created component hierarchy:

         UI                   Technology
---------------------    ----------------------
 UIPanel                  Panel
   \-OverlayedPanel         \-Panel
       |-UILabel                |-Label
       |-UITextField                \-Panel
       |-UILabel                    |-Label
       |-UITextField                |-TextField
       |-UILabel                    |-Label
       |-UITextField                |-TextField
       |-UILabel                    |-Label
       |-UITextField                |-TextField
       |-UILabel                    |-Label
       \-UITextField                |-TextField
                                    |-Label
                                    \-TextField

This makes it very easy to have containers which add additional components without the actual GUI noticing or caring.

Conclusion

Because of the way the JVx framework is designed, it is easy to access all layers of the GUI framework and also facilitate the usage of these layers to create custom components and allow easy access to the wrapped components, no matter on what layer or of what kind they are.

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!

JVx Reference, DataBooks

Let's talk about DataBooks, which allow access to data without any effort.

What is it?

DataBooks are an active model, which allow you to directly query and manipulate the data. Contrary to many other systems JVx does not map the data into objects, but instead allows you to directly access it in a table like fashion, exposing columns, rows and values.

One could say that it is like a three dimensional array, with these dimensions:

  1. DataPages
  2. DataRows
  3. Columns/Values

With DataPages containing DataRows, which itself contain the values and everything is referencing the RowDefinition, which outlines how a row looks like.

DataBook Architecture

RowDefinition

The RowDefinition defines what columns are available in the row and stores some additional information about them, like the names of the primary key columns. You can think of the RowDefinition as the headers of a table.

Its creation and usage is rather simple, and if you're working with RemoteDataBooks there is no need to create one at all, as it is automatically created when the DataBook is opened. A RowDefinition holds and manages ColumnDefinitions, which define the columns.

RowDefinition rowDefinition = new RowDefinition();
rowDefinition.addColumnDefinition(columnDefinitionA);
rowDefinition.addColumnDefinition(columnDefinitionB);
rowDefinition.addColumnDefinition(columnDefinitionC);

dataBook.setRowDefinition(rowDefinition);

ColumnDefinition

The ColumnDefinition defines and provides all necessary information about the column, like its DataType, its size and if it is nullable or not. You can think of it as one column in a table.

ColumnDefinition columnDefinition = new ColumnDefinition("NAME", new StringDataType());
columnDefinition.setNullable(false);

MetaData

Most of the ColumnDefinition is additional information about the column, like if it is nullable, the label of the column, default values, allowed values and similar information.

DataType

Of course we must define what type the value in the column has, this is done by setting a DataType on the ColumnDefinition. The DataType defines what kind of values the column holds, like if it is a String, or a Number or something else. We do provide the widest used DataTypes out of the box:

  • BigDecimal
  • BinaryData
  • Boolean
  • Long
  • Object
  • String
  • Timestamp

It is possible to add new DataTypes by simply implementing IDataType.

DataRow

The DataRow repesents a single row of data, it holds/references its own RowDefinition and of course provides access to the values of the row. Accessing the DataRow can be done either by column index or column name, and the methods do either return or accept Objects. Let's look at a simple usage example:

DataRow dataRow = new MemDataRow(rowDefinition);

String value = (String)dataRow.getValue("COLUMN_A");

dataRow.setValue("COLUMN_A", "New Value");

DataPage

The DataPage is basically a list of DataRows, it also holds its own RowDefinition which is shared with all the contained DataRows.

The main usage of DataPages is to allow paging in a master/detail relationship. If the master selects a different row, the detail databook does select the related DataPage.

DataBook

The DataBook is the main model of JVx, it provides direct access to its current DataPage and DataRow by extending from IDataRow and IDataPage.

By default, the DataBook holds one DataPage and only has multiple DataPages if it is the detail in a master/detail relationship.

Usage example

Here is a simple usage example of a MemDataBook, an IDataBook implementation which does only operate in memory:

IDataBook dataBook = new MemDataBook();
dataBook.setName("test");
dataBook.getRowDefinition().addColumnDefinition(new ColumnDefinition("ID", new LongDataType()));
dataBook.getRowDefinition().addColumnDefinition(new ColumnDefinition("COLUMN_STRING", new StringDataType()));
dataBook.open();

dataBook.insert(false);
dataBook.setValue("ID", Long.valueof(0));
dataBook.setValue("COLUMN_STRING", "VALUE");

dataBook.insert(false);
dataBook.setValue("ID", Long.valueof(1));
dataBook.setValue("COLUMN_STRING", "VALUE_A");

dataBook.saveSelectedRow();

dataBook.setSelectedRow(0);

dataBook.setValue("COLUMN_STRING", "VALUE_NEW");

dataBook.saveSelectedRow();

dataBook.setSelectedRow(1);

dataBook.delete();

Accessing the data with Strings

One of the major advantages of the DataBook concept is that there is no need to create new classes to represent each table, view or query result. One can always use the DataBook, directly and easily and model changes don't necessitate changes on the client side. The downside to this approach is that we lose compile time checks because we access the data dynamically. However, This can be mitigated by using EPlug, an Eclipse plugin which provides compile time checks and many more features.

No primitives, Objects only

We do not provide overloads to fetch primitives, that is because there are mainly three types of data inside a database:

  1. Numbers
  2. Text
  3. Binary Data

Text and Binary Data are both objects (arrays of primitives are Objects after all) and Numbers are either primitives or Objects. Most of the time if we deal with numbers inside a database we want them to be of arbitrary precision, which means we must represent them as BigDecimal. Supporting double or float in these cases would be dangerously, because one might write a float into the database which might or might not end up with the correct value in the database. To completely eliminate such problems, we do only support Objects, which means that one is "limited" to the usage of Number extensions like BigLong and BigDecimal, which do not suffer from such problems.

Where are the DataPages?

What is not clear from this example is how and when DataPages are used. As a matter of fact, most of the time there is no need to think about DataPages because they are managed directly by the DataBook, and if used this like there is only one DataPage. Multiple DataPages will be used if there is a Master/Detail relationship defined in which case the DataBook does select the correct DataPage automatically.

Master/Detail

Master/Detail is something that occurs in nearly every data model. It means simply that there is one master dataset which is referenced by one or multiple detail datasets. Or to express it in SQL:

SELECT
  *
FROM
  MASTER m
  LEFT JOIN DETAIL d ON m.ID=d.MASTER_ID;

We can of course express a Master/Detail relationship when using DataBooks. For that we just create a ReferenceDefinition and assign it to the Detail DataBook:

IDataBook masterDataBook = new MemDataBook();
masterDataBook.setName("master");
masterDataBook.getRowDefinition().addColumnDefinition(new ColumnDefinition("ID", new LongDataType()));
masterDataBook.open();

IDataBook detailDataBook = new MemDataBook();
detailDataBook.setName("detail");
detailDataBook.getRowDefinition().addColumnDefinition(new ColumnDefinition("ID", new LongDataType()));
detailDataBook.getRowDefinition().addColumnDefinition(new ColumnDefinition("MASTER_ID", new LongDataType()));
detailDataBook.setReferenceDefinition(new ReferenceDefinition(new Streing[] {"MASTER_ID"}, masterDataBook, new String[] {"ID"});
detailDataBook.open();

Let's assume the following data for illustration purposes:

MASTER              DETAIL
======        =================
  ID            ID  | MASTER_ID
------        ------|----------
     1             1|         1
     2             2|         1
     3             3|         2
                   4|         2
                   5|         2
                   6|         3
                   7|         3
                   8|         3

Now if we select the second row in the masterDataBook, the detailDataBook will just contain the rows with the corresponding MASTER_ID, so 3, 4 and 5.

MASTER              DETAIL
======        =================
  ID            ID  | MASTER_ID
------        ------|----------
     1             3|         2
S    2             4|         2
     3             5|         2

The detailDataBook is automatically adjusted according to the selection in the masterDatabook. Of course this can have an arbitrary depth, too.

Conclusion

The DataBook is the backbone of JVx, it provides a clean and easy way to access and manipulate data. At the same time, it is flexible and can be customized to specific needs with ease.