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

Posts tagged: JVx

Page Navigation

Plain JVx Vaadin applications don't have page navigation as known from e.g. JSF applications. If you press "back" in your browser, the whole application is lost and "forward" will create a new application. Same problem with "reload".

It has nothing to to with JVx because it's a technology restriction. Isn't it?
Not necessarily!

You should know that vaadin has support for Browser Navigation, but this feature has no standard implementation because every application is different and has different requirements. If you create your own Vaadin application, you'll have to implement your own Navigation. It's not tricky but you should know how it works. A good starting point can be found in the book of vaadin. The main thing is that you should create your application with different views. A view is more or less a page. The navigator supports navigation between views. If you have different views, it's easy to use the Navigator.

But our generic application is a little bit different to plain Vaadin applications because JVx has work-screens. A work-screen is like a View or a page, but technology independent. A work-screen can be used for desktop applications and web applications without code changes. A desktop application usually doesn't offer Navigation as known from web browsers. So it's a good idea to have work-screens because it's independent of the used GUI technology and platform features.

If you use a JVx application as web application with Vaadin UI, you'll miss page navigation - for sure. We made some experiments with vaadin' page Navigation and are happy to present an awesome solution for this problem.

We did a generic implementation in our application frame and now it's possible to navigate between work-screens - out-of-the-box. It's implemented once in our application frame. Simply use it and page navigation works!

Here's a short demonstration:

Browser Navigation


Responsive Web Application

We have a great new feature in our generic web application. It's now responsive and supports big and small devices like smartphones, without additional coding. Everything will work out-of-the-box.

The application is generic which means that it's an application frame that can be used for you own requirements. We have a simple demo application for our internal tests.

Have a look:

JVx application with Vaadin UI


The menu changes the position and size. Also padding and margin are different if there's not enough space.

A DropboxStorage as X-mas present

Merry X-mas :)

We have a little present for you. It's a connector for Dropbox.

The source code is available here.

It's a full IStorage implementation and allows CRUD operations to your Dropbox account. We use it for sharing dynamicly created reports and as document archive. It's very useful because your application doesn't need a mobile client to exchange data with the backend.

If your secretary creates the management report (Word, Excel or Pdf), simply modify or read it via Dropbox. It's really simple because Word and Excel are available for mobile devices. Both tools have a built-in Dropbox support and thus makes it easy to access files.

How to use the storage?

Currently, we don't have a pre-compiled lib, but simply clone the repository and use the ANT build to create your own lib.

It's simple to integrate the storage in your application:

public DropboxStorage getFiles() throws Exception
{
    DropboxStorage storage = (DropboxStorage)get("files");

    if (storage == null)
    {
        storage = new DropboxStorage();
        storage.setAccessToken(SessionContext.getCurrentSessionConfig().
                                   getProperty("/application/dropbox/accessToken"));
        storage.setFileType(FileType.All);
        //use "flat" style
        storage.setRecursive(true);
        storage.open();

        put("files", storage);
    }

    return storage;
}

Before the storage will work, prepare your dropbox account to get an access token. It's not tricky and everything is documented.

There are some examples available as JUnit tests.

A simple Dropbox screen could look like this one:

Dropbox access with JVx

Dropbox access with JVx

JVx with Java6

JVx was based on Java5 and all releases, including 2.1, were built with JDK 1.5. We thought it could be the time for a change and Java5 is not popular nowadays. With JVx 2.2 we'll switch to Java6. It wasn't important for us because JVx has no specifics that need Java6, but some 3rd party libs like RESTlet need Java6. The client-side code of JVx will probably work with Java5 but we'll build our releases with target 1.6.

We made an update to RESTlet 2.2.3 because of some useful changes and also for the side-project JVx.mobile. So we had to switch to Java6 as well. Our repository is already based on Java6 and we started migration of dependent projects and build tasks.

Because of some changes in DBAccess regarding DataSource support, it was also a good idea to use new JDBC drivers and most new drivers are not available for Java5. So we hope you understand why Java6 was a good idea.

The current nightly build was created with Java6. Give it a try.

JVx Update 2.1.1

We had some problems with our JVx 2.1 release. It had a bug in server-side processing of BLOB columns because of #987. It was not a problem on client-side, but standard CRUD operations failed.

The other problem was the reopen mechanism of connections. It was an unused feature till 2.1 and wasn't well tested. It worked but not in all circumstances. We refactored the implementation and made tests.

Both fixes are included in JVx 2.1.1.

JVx 2.1 is in da house

Happy birthday :) JVx is 2.1

It's another great release today and ~ 6 month after 2.0. We have soo many cool features for you and of course some bugfixes.
The complete changelog is available on our sourceforge project site.

I want to highlight some features for you

  • Configuration via JNDI or Classpath

    It's now possible to have custom configuration files without our recommended directory structure. We still recommend our structure for multi-application deployments, but it's not important for single deployments or complex enterprise deployments. Find more details about loading strategy in the corresponding ticket #1126.

  • Server-side plugin support

    We introduced IServerPlugin. It allows adding plugins and changing server handling on demand. It's easy to write custom protocol recorder or configure session management via plugin.

  • ServerContext and HttpContext

    We introduced HttpContext and ServerContext. The HttpContext allows live access to servlet request and response (if an application server is in use). It makes no difference if you use REST or standard communication. We set the right instances into the context and your application will work without specific technology checks. We also use HttpContext for JVx.mobile.

    The ServerContext is comparable with SessionContext, but it's earlier in the execution process, because it offers access to sessions directly after creation or detection. It's useful for e.g. plugins.

  • Tab/Focus Index

    We introduced set/getTabIndex in IComponent. This API change allows user-defined component navigation via tabulator or Enter key.

  • CommunicationException details

    It's now possible to find out the connection which throwed a CommunicationException.

  • Alignment for IEditor (API change)

    It's now possible to set the alignment on IEditors instead of the cell editors. Small but very useful API change.

  • Autolink with storages

    It's now possible to create automatic link references with other storage. We had this feature already in 2.0 but only for simple storages without conditions - only from clause was used. Now it's possible to configure custom storages with user-defined sort in the same LCO and set this storages as automatic link reference to other storages in the same LCO.

  • Server side bean processing boost

    We change and improved server side bean handling of our AbstractStorage. Here are some numbers for you:

    ....................... Before | After

    Insert Object[] ... Beans: 200 |   0
    Update Bean ....... Beans: 900 | 200
    Update T .......... Beans: 900 | 400
    Fetch Bean ........ Beans: 600 | 200
    Fetch Object[] .... Beans: 300 |   0
    Update Object[] ... Beans: 500 |   0
    Insert Bean ....... Beans: 400 | 100
    Delete Object[] ... Beans: 300 |   0
    Delete Bean ....... Beans: 600 | 200
    Delete T .......... Beans: 600 | 300
    Insert T .......... Beans: 400 | 200

    Created Beans after processing 100 records.
    The current solution is a performance boost and using Object[] is always faster than everything else.

  • Lazy blob loading

    We don't load Blobs immediate. We load it on request. This doesn't need any actions on client side but be aware of server-side handling because the value of a blob column will be RemoteFileHandle instead of byte[]. You should run your unit tests for your business logic. It's possible to disable lazy fetching, per storage with

    setLazyFetchEnabled(boolean);

    It's also possible to define the threshold for loading immediate or loading lazy. Check

    setLargeObjectLimit
    setDefaultLargeObjectLimit

    of DBAccess.

    This is an awesome new feature because is speeds up data transfer.

  • Custom UI properties

    UIResource got:

    public Object getObject(String pObjectName)
    public Object putObject(String pObjectName, Object pObject)

    It's possible to add custom objects per UI instance, e.g. save custom states.

  • REST services refactored

    We refactored our REST services. The implementation now works without problems and is easier to use becasue we don't need full qualified java names in the URL. We try to find the class via accesscontroller. The accesscontroller got a new method for this.

  • Unique component names

    For all lovers of automated UI tests. We have unique names for all our components. It's easy to create GUI tests with tools like Selenium (web tests) or FEST (swing tests) or whatever you use :)

We have about 107 tickets in this release and it's not possible to explain every change in this blog posting, but be sure - it's great!

The Maven archetype should be available in the next few days, because sonatype archetype listings are not live.

Next VisionX and JVx releases

The last official JVx release was in May and last VisionX version was released in July. We think it's time to update both and planned the release of JVx 2.1 and VisionX 2.1 for the end of November. Currently, we are in time and shouldn't have any delays.

There are some open tickets for JVx and VisionX, but the planned features are done. The open tickets are nice to have and favoured from the 2.2' release.

Especially VisionX 2.1 will be an awesome new release because it contains soo many new features. The new solution store, the styling of mobile and web applications, the new GUI designer, PDF reporting, IDE integration, subscription based licensing and many more. The release will be the first with full Oracle Forms migration support. It has all known features of Oracle Forms like Repeating Frames, Focus order, Popup Menu configuration.

The release will contain solutions for over 200 tickets.

And what's in JVx 2.1?

We've some cool changes, e.g. great support for automatic tests (unique component names), reduced metadata caching, JNDI support for configuration files, Replacement and StrictIsolation annotations, REST refactoring and many more.

Stay tuned :)

Responsive Web Design

Hurray, we have a new buzzword: Responsive.

It's not brand new, but nowadays it's important because we use applications on different devices and the same application should work on different screen sizes/resolutions.

What does responsive mean?

Wikipedia:

Responsive web design (RWD) is a web design approach aimed at crafting sites to provide an optimal viewing experience—easy reading and navigation with a minimum of resizing, panning, and scrolling—across a wide range of devices (from mobile phones to desktop computer monitors).

My opinion:

Don't waste space for unnecessary information.

If you have big menus and toolbars in your application, you should reduce the used space dependent of the available space.

We did some experiments with our vaadin UI and have some impressions for you:

App full space

App full space

 
App with limited space

App with limited space

The application on the right has a small menu without additional text and with small padding. All gaps are smaller than in the orginal application on the left.

We used custom css and source code to change the UI because not everything was possible with CSS e.g. set tooltips instead of button text. A set of instructions was posted from Matti Tahvonen.

We made some smaller changes in our Vaadin UI to support technology independent handling of resize changes.

It will be possible to do following:

launcher.eventComponentResized().addListener(this, "doLauncherResized");

...

public void doLauncherResized(UIComponentEvent pEvent)
{
    IDimension dim = ((ILauncher)pEvent.getSource()).getSize();
   
    if (dim != null)
    {
        int iWidth = dim.getWidth();
       
        if (iWidth < 800)
        {
            layoutMode = LayoutMode.Small;
        }
        else
        {
            layoutMode = LayoutMode.Full;
        }

        resizeMenu();
    }
}

One application, different styles

Impressions

The first image shows the legacy mode of our standard application style (check last image). It turns a SDI application to MDI - without coding or re-deployment. Simply awesome :)

The second image doesn't use a toolbar and the third one is without a menubar. Not all applications need multiple navigation elements, known from desktop applications.

The fourth image shows, what we prefer.

Legacy mode (MDI)

Legacy mode (MDI)

 
Legacy mode (no toolbar)

Legacy mode (no toolbar)

Legacy mode (no menubar)

Legacy mode (no menubar)

Modern mode (SDI with popups)

Modern mode (SDI with popups)

One more ;-)

Modern style (menu right)

Modern style (menu right)

[Update]

The same application with Swing UI

Swing UI

Swing UI

Next big feature - Automate your GUI Tests

It's not a problem to automate GUI tests, nowadays. There are different approaches and tools. A nice tool overview is available on wikipedia.

The tools have different techniques to perform tests. On technique is sending/simulating mouse clicks to components. The problem is that the GUI shouldn't be changed between tests and you should use a special test environment/system. Another technique is tricky but there's a nice implementation from MIT. It works with image recognition. And finally there's a solution based on unique component identifiers.

We like the last technique, based on unique component identifiers because it allows changing the UI without changing test cases - we love flexibility. The only problem with JVx was that we didn't have unique identifiers and a developer won't set an identifier for every component. We didn't have a mechanism to create unique identifiers... BUT now... we have.

With upcoming JVx releases, it will be possible to test GUIs automatically based on unique identifiers. This identifiers will be available also for VaadinUI. Another advantage for VaadinUIs will be that the id could be used for styling via CSS.

There are still some todos for us but we're happy to be able to show you some examples.

We made some test-cases with different test tools. To test our VaadinUI, we use Selenium together with PhantomJS.

The source code might look like this one:

public class TestCaseB
{
    private static final int TIMEOUT_IN_SECONDS = 10;
   
    private static final String TIMEOUT_IN_MILLISECONDS_AS_STRING =
                        Integer.toString(TIMEOUT_IN_SECONDS * 1000);

    private WebDriver driver;
    private Selenium selenium;
   
    @Before
    public void setUp()
    {
        driver = configureDriver(createPhantomJsDriver());
       
        String baseUrl = "http://localhost:8080/";
       
        selenium = new WebDriverBackedSelenium(driver, baseUrl);
        selenium.setTimeout(TIMEOUT_IN_MILLISECONDS_AS_STRING);
    }
   
    @Test
    public void testDemoerptest()
    {
        selenium.open("/VisionX.Server/app/web/ui/DemoERP/");
        waitForPage();
       
        selenium.type("id=UserName", "admin");
        selenium.type("id=Password", "admin");
        selenium.click("id=OK");
        waitForPage();
       
        selenium.click("id=DemoERP_P1_P1_P2_B1");
        waitForPage();
        selenium.click(
          "//div[@id='NavigationTable']/div[2]/div/table/tbody/tr[2]/td[2]/div");
        selenium.click(
          "//div[@id='NavigationTable']/div[2]/div/table/tbody/tr[3]/td[2]/div");
        selenium.click(
          "//div[@id='NavigationTable']/div[2]/div/table/tbody/tr[2]/td[2]/div");
        selenium.click(
          "//div[@id='NavigationTable']/div[2]/div/table/tbody/tr/td[2]/div");
       
        selenium.click("id=DemoERP_P1_P1_P2_B2");
        waitForPage();
        selenium.click(
          "//div[@id='NavigationTable']/div[2]/div/table/tbody/tr[2]/td/div");
        selenium.click(
          "//div[@id='NavigationTable']/div[2]/div/table/tbody/tr[3]/td/div");
        selenium.click(
          "//div[@id='NavigationTable']/div[2]/div/table/tbody/tr[4]/td/div");
       
        selenium.click("id=DemoERP_P1_P1_P2_B3");
        waitForPage();
       
        selenium.click("xpath=(//button[@type='button'])[7]");
        waitForPage();
    }
   
    @After
    public void tearDown()
    {
        driver.quit();
        selenium.stop();
    }
   
    private WebDriver configureDriver(WebDriver pWebDriver)
    {
        pWebDriver.manage().timeouts().implicitlyWait(TIMEOUT_IN_SECONDS,
                                                      TimeUnit.SECONDS);
        pWebDriver.manage().timeouts().pageLoadTimeout(TIMEOUT_IN_SECONDS,
                                                       TimeUnit.SECONDS);
        pWebDriver.manage().timeouts().setScriptTimeout(TIMEOUT_IN_SECONDS,
                                                        TimeUnit.SECONDS);
        pWebDriver.manage().window().setSize(new Dimension(1920, 1080));
       
        return pWebDriver;
    }
   
    @SuppressWarnings("unused")
    private WebDriver createChromeDriver()
    {
        ChromeOptions options = new ChromeOptions();
        options.addArguments("-incognito");
       
        return new ChromeDriver(options);
    }
   
    private WebDriver createPhantomJsDriver()
    {
        DesiredCapabilities capabilities = new DesiredCapabilities();
        capabilities.setCapability(
                 PhantomJSDriverService.PHANTOMJS_EXECUTABLE_PATH_PROPERTY,
                 "D:\\opt\\phantomjs\\phantomjs.exe");
       
        return new PhantomJSDriver(capabilities);
    }
   
    private void waitForPage()
    {
        selenium.waitForPageToLoad(TIMEOUT_IN_MILLISECONDS_AS_STRING);
    }
}

We use FEST (doc) for Swing UIs. The library is old (like Swing) but still works!

A very simple example with FEST:

public class TestUI extends FestSwingTestCaseTemplate
{
    private FrameFixture window;
   
    @After
    public void cleanItUp()
    {
        super.cleanUp();
    }
   
    @Before
    public void setUp()
    {
        super.setUpRobot();
       
        UIFactoryManager.getFactoryInstance(SwingFactory.class);
       
        WorkScreenCreatingGuiQuery query = new WorkScreenCreatingGuiQuery();
        Frame frame = GuiActionRunner.execute(query);
       
        window = new FrameFixture(robot(), frame);
        window.show();
       
        query.afterShow();
    }
   
    @Test
    public void testTheUIStuff()
    {
        // Check if the editor does have the correct value.
        // The WorkScreen does select the first line for us.
        Assert.assertEquals("John Smith",
                            window.textBox("UITWS_E_TESTDATABOOK_NAME").text());
       
        // Select the next line in the table.
        window.table("UITWS_T_TESTDATABOOK").selectRows(1);
        Assert.assertEquals("Ian McIrish",
                            window.textBox("UITWS_E_TESTDATABOOK_NAME").text());
       
        // Select the tab that has that TextField-Button-Label combo on it.
        window.tabbedPane("UITWS_TP1").selectTab(1);
        window.tabbedPane("UITWS_TP1_P2_TP1").selectTab(2);
       
        // Enter something into the textfield, press the button and the label
        // should now have the same text.
        window.textBox("UITWS_TP1_P2_TP1_P3_P1_TF1").setText("This is an automated test.");
        window.button("UITWS_TP1_P2_TP1_P3_P1_B1").click();
        Assert.assertEquals("This is an automated test.",
                            window.label("UITWS_TP1_P2_TP1_P3_P1_L2").text());
    }
   
    private static final class WorkScreenCreatingGuiQuery extends GuiQuery<Frame>
    {
        private UIFrame frame;
       
        private WorkScreen workscreen;
       
        void afterShow()
        {
            // Important so that everything gets a name.
            // There is a window constructed, but outside of the JVx scope.
            frame.addNotify();
            workscreen.notifyRepaint();
        }
       
        @Override
        protected Frame executeInEDT() throws Throwable
        {
            frame = new UIFrame();
            workscreen = new UITestingWorkScreen();
           
            frame.add(workscreen);
           
            return (Frame) frame.getResource();
        }
       
        private String dumpStructure()
        {
            return dumpStructure(frame, 1);
        }
    }
}