Posts tagged: vaadinUI
Because I got some emails, here's the window shutter UI how it looks on my Wii U. Sure, the space is not perfectly used, but the UI wasn't optimized for Wii U. Also the agent name of the browser wasn't checked to optimize controls.
But it's ok and control just works
The pictures (phone cam):
It's about two years ago that I wrote about controlling window shutters. The system run for 2 years without problems but it was time to change "something" because it was vacation time and I thought it would be useful to showcase our vaadin UI
The old system was controled via (good old) SMS - without GUI. It had a lot of commands but only en/disable up/down were heavily used because the integrated public holiday and weekend automatism solved most use cases. The SMS contol was great and worked without problems but it was a problem if you didn't know the commands and syntax by heart!
Another consideration was a simple real-world showcase for our vaadin UI, the responsive feature and push support. Our application frame was already responsive and worked on desktop, tablet and smartphone browsers. I thought about using AngularJS or different "hypeware" but I didn't have weeks to research and implement. My new GUI had to be finished in few hours. And it should be maintainable for the next two (or more) years without problems.
I love researching hypeware... but simply read some articles if you want:
There are too many frameworks, everyone is different - no real standard APIs (didn't count HTML and CSS). You can't be sure that the framework is future-proof because developers love to change software to be incompatible with previous versions just to be state-of-the-art.
And why should a developer use 5 or more frameworks to create a simple application for desktop and mobile? You'll need more libs if your application needs DB and CRUD support.
C'mon we need simple and small frameworks and not what we have right now! The world is talking about microservices and what about "micro frameworks"?
Conclusio: I didn't find something comparable to JVx. Of course, it's my opinion and I'm JVx developer, but I'm a researcher and the technology isn't a problem if it makes sense to use it.
To be honest: Our Vaadin UI in combination with other JVx features is unbeatable for most application types. Of course, it's not recommended for web pages with custom layout requirements. If you need an "application style" solution with menu and screen/work area or form based - there's nothing comparable.
After I knew that my new GUI would be a JVx' vaadin solution, I had to think about the details. The whole application should be responsive to support every modern device and desktop browsers as well. The application server should be Jetty or Tomcat and it should run on the RasPi. The performance is not critical because the hardware is limited (but cheap).
Software stack: clear
Deployment type: clear
Next step was development. This was easy because I re-used existing classes and added some get/set methods to access internal members. The most important change was an event listener because every vaadin client should be updated immediate via push. It wasn't possible without notification mechanism. I thought about an event bus and played around with mbassador. It's a nice and small lib, fast and just works (recommendable).
To be honest: I didn't need it because I didn't need more than one listener and an event bus is not much more than a listener abstraction (with some extras).
After some hours developing and refactoring, everything was ready for a test.... The next decission: Jetty or Tomcat?
I worked with Tomcat for many years and didn't know much about Jetty, only that it's the number one for embedding into applications, supports SPDY and has websocket support. I played around with Jetty and got it running. The installation of my GUI worked like a charme and everything worked except push. I found solutions for embedded run mode but not for standalone Jetty. I'm pretty sure that I missed something, but I wasn't very patient and switched to Tomcat 8.
Not only because of my push problem but Jetty didn't handle requests as expected:
http://localhost/house/ didn't redirect to http://localhost/house/index.html automatically. I didn't have an index.html file in the public file area, anyway the request should be executed. Such requests work with Tomcat without additional configuration.
I'm not happy that my Jetty server didn't work but I'll retry it in the next days
Here's a simple screencast of my solution because it's easier to understand:
It took me less than one day to finish my GUI and the best: It's family safe.
I tried the GUI with PS4 and WiiU integrated browser and it was great to see shutters moving.
I've used a RaspberryPi, installed Tomcat 8 with Java8 and deployed my application as war file. The GUI is responsive and supports push via websockets and runs on every device in my house. It wasn't planned using gaming consoles
Oh, I forgot to mention: During my tests I found out that Android and iOS support custom Bookmark images for Desktop links but this needs additional tags in index.html (works without, but it's better to include the tags). Our VaadinUI now has built-in support for such images
The switch component is available in the Vaadin Directory.
For quite some time there has been the idea in our heads to run a stress test against a JVx/Vaadin installation to see if there are any major problems with performance and multithreading. We knew that Tomcat, Vaadin and JVx could serve a lot of users simultaneously, that's what all three were designed to do, that's what all three do well in many different environments, but we never really tried to stress it out. So we set out to change that.
Some weeks ago we started discussing and outlining how to perform such a stress test. After some research we came up with a plan:
- Design a test case using Selenium for the DemoERP application
- If necessary, design and create solutions to allow that
- Set up a Selenium Grid which can be used for testing
- Perform the actual test and fix anything that needs to be fixed
As simple as it sounds, it had quite some gotchas on the way and taught us some valuable lessons.
Name all the things
The first thing you need for automated testing are names, components need names so that they are easily identifiable by whatever you're using for testing. Already back in September we started to name components in a unique and easily recognizable fashion, our efforts are covered by ticket #1103. Of course you can still set your own names, if you want that, as the default names will only be applied if no other name is set.
In short, components are now receiving a name based on their position in the component tree. For example take this simple workscreen:
The naming starts with the "root" component and every child component does append it's name. So you can easily guess where a component is assigned to, simply from its name. Every name is guaranteed to be unique, either by its position in the tree or by incrementing a counter.
Additionally there are "special snowflakes" which are getting better names, like the name of a button which is only prefixed with the name of the workscreen and a "B" and then followed by the actions which are assigned to it, e.g.
public void initializeUI()
UIButton butUp = new UIButton("UP");
The button "butUp" will get the name Das-WV_B_DOUP. The prefix Das is the short name for the DashboardWorkScreen, followed by -WV which is like a prefix checksum/number. The letter B stands for Button and the action name DOUP is the last part.
With such a naming scheme in place, it's easy to create automated UI tests as every component is uniquely identifiable in the component tree. In the case of Vaadin the names are also used as ID's on the elements
The test case
For everyone who does not know our DemoERP application, it is a simple ERP application which features customer, product, offer and order management together with a nice statistic screen. All this can either be run as Swing application or (powered by a Tomcat Server) as Vaadin application directly in the browser.
The test case that we designed is rather simple:
- Load the application website and perform the initial login
- Open the customer management screen and add a new customer
- Open the offer management screen and search for an offer
- Switch to the order of said offer and edit it
- Open the statistic screen
This gives a nice workload for testing, as it touches close to all areas of the application, changes values nearly simultaneous and also adds data with every run. Also note that the testcase would perform these steps as fast as possible, without any artificial waiting in between.
Thanks to the Selenium IDE the test case was recorded within a matter of minutes, and quite fast copied into a unit test. The first round of testing happened with the Chromium WebDriver, which allowed us to watch the test case do its work and make tweaks wherever necessary to allow the test to succeed.
Setting up Selenium Grid
Selenium Grid (or Grid2) is a simple, scalable framework for distributed Selenium tests, allowing to control multiple browsers on different platforms. The central server is called a "hub" and the clients are called "nodes". The nodes are registering themselves at the hub, and from there a client (for example a unit test) can send a request to the hub and it will receive a node matching the requested requirements. On the client side this is happening by simply creating a new instance of a RemoteWebDriver provided by Selenium. It will automatically contact the hub, wait for a node to be ready for it and then forward all commands to that node.
This is useful if you want quickly test an application in multiple browsers on multiple platforms without leaving your IDE or to perform a simple stress test.
Setting it up is as easy as starting the hub on one machine, and starting the nodes on any other machines. We decided to go with PhantomJS as browser, as we intended to run many instances of said browser on one node and we also had a wide variety of machines, some without a GUI. PhantomJS does already have it's own built-in node, so we just needed to start PhantomJS on the machines and tell it where it can find the hub.
At the end of day we had 12 physical machines in place and we maxed them out to get a total of 82 nodes which can be used for our stress testing.
One thing we noticed very quickly was that lingering sessions can be a real issue and the timeouts really need to be tailored to your environment. While testing we quickly noticed that sessions kept lingering on, this was less an issue for the server and Tomcat, as more for our MariaDB installation because at some point it simply stopped accepting new connections. So we needed to reduce the amount of time a session would linger on to not clog our test server.
There are two important settings controlling the amount of time a session will linger on in such a setup:
- The timeout setting of the Tomcat server
- The heartbeat interval and closing of idle sessions in Vaadin
As said, these settings should be tailored to whatever environment the server is running in. In our test environment it didn't make any sense to keep sessions longer than a few minutes, because if the test case ended or was interrupted for some reason, the session would not resume. Armed with that knowledge we reduced the amount of time a session could linger on and we could finally start the real test.
Running the test
The server in our case would be a rather unspectacular laptop, with a Core-i7 (1.80GHz) and 16 GB of RAM. Tomcat 6 would deliver the application and the data would be provided by a local MariaDB/MySQL database (with an InnoDB engine).
The test itself, which ran several times for several hours, was rather boring to be honest. 82 clients swarmed the server as fast as it could answer requests without any noticeable effect on it's performance. The laptop, despite not being the typical server machine and for sure not intended as such, could easily handle the load that 82 clients produced. We did expect the application to stay in a usable state, however we did not expect that it wouldn't have any noticeable effect at all from a users perspective.
- CPU peaked at 60%, but stood most of the time between 40% and 50%
- Tomcat peaked at 4GB RAM, but would have been able to work with as little as 2GB
- Over 21.000 datasets were created during the test run
- The GUI was not noticeably slower during the test
Our setup could handle that amount of requests with ease. Unfortunately we could not get a hold of more machines to add further nodes for now.
We broke it, we fixed it
During the tests two nasty looking issues stood out, which kept happening in roughly 1% of all test runs with seemingly no pattern behind them.
The first was a simple NullPointerException which kept happening in UIImage, but that was fixed rather easily as certain methods where not synchronized and so destined to fail.
The second was a set of Exceptions which send us to our toes: NullPointerExceptions, "Object 'offer' was not found" and "Remote storage returned 15 value(s) but 22 were expected". Clearly there was something very wrong, and with the low volume with which these exceptions occurred, it could only be a race condition somewhere. Looking for possible causes send us to all corners of the codebase without any clue in sight what might cause them.
It only dawned upon us when we got a hold of the map which did not contain the object "offer", it only contained the objects "v_statistic_order_offer_year" and "v_statistic_order_offer_month". Looking at the lifecycle objects immediately showed the problem, the session did have a completely different lifecycle object. That did also explain the wrong amount of values, as two lifecycle objects happened to contain identical named objects. But how was that possible? We immediately checked the complete source code associated with creating a session, and in AbstractSession we found the culprit. Even though the complete code for creating a session was properly synchronized where necessary, one simple statement had slipped past:
private final Long lObjectId = Long.valueOf(++lSessionCount);
For everyone not seeing the problem, here is a simplified explanation. If an object is instantiated, the fields are initialized even before the constructor is run, this is not and can't be directly synchronized. A simple increment operation (++) is compiled to six operations:
- Load a reference to a variable onto the stack
- Put into that reference the value of the static field (in our case lSessionCount)
- Put the value "1" onto the stack
- Add both values on the stack together
- Duplicate the values
- Put the new value into the static field
Six instructions, a lot of time for two threads to overtake each other and cause problems. Instantiating two sessions at once had the potential to give both the same ID. Of course we immediately fixed it and applied some other optimizations.
Another run verified that this had fixed all three issues at once and the tests were running without any further incidents for hours.
We were not even close to pushing the limits of what a JVx application/server can handle, and judging from the performance of the server I can only call our test setup "humble". Still it gave us a good measure of what is for sure possible and showed us that we need a bigger setup to really push the limits.
During the tests we also created various utilities to aid us with testing, unfortunately they are in a rather barebone state and can not be released by now. Also there is now a more important project awaiting, one that we think you've been waiting for for far too long.
Vaadin supports "push" - since 7.1 - but JVx doesn't have an API for that. It's technology dependent and we usually not need it on client-side of an application. It would be useful for the server-side of JVx applications, but that's a different thing. I want to write about server-side push for UI changes.
With our next vaadin UI release, it's also possible to use server-side push of vaadin to update the client machine. It's very easy to use and also is technology independent, but we didn't introduce new APIs
How it works?
Create a new thread, through your factory and use invokeLater to update the UI. You always should use invokeLater to update the UI (no difference if you use swing or other desktop technologies).
public void run()
public void run()
label.setText("Push: " + iCount);
catch (InterruptedException ie)
If push is enabled, above code pushes the UI changes immediate to the client machines. To enable server-side push, simply add following to your servlet configuration in web.xml:
<param-value>automatic | manual</param-value>
It's also possible to use vaadin push without JVx' mechanism (pure vaadin). To see how this works, read following issue: Server-side refresh.
Our new vaadin UI is available. It's the first release and it's awesome.
Get the binaries from our project site. It's licensed under Apache 2.0 and free for all.
The installation is very simple:
- Download jvxvaadin-1.0.zip
- Unzip the archive
- Add all files to your existing JVx application
- Change Deployment descriptor (web.xml) and replace simpleapp with your application
This is an update of Project news.
We completely replaced our good old Java OnlineHelp (GXT version) with a new Vaadin implementation. It's based on Vaadin 7 and has some amazing new features, like full-text search. No worries, the new version supports the same file structure as our old version. The upgrade procedure is simple: Keep your structure directory and delete all other files. The binaries will be available in the next days.
We also removed all other GXT based projects because we switched the web technology. We think vaadin is the better choice and replaced our previous webUI with vaadinUI. Of course, it's not a 1:1 replacement but the first release is awesome. We'll release the binaries next week.
Our old webUI project is still alive because it contains our headlessUI. This project is still important and the base of our project JVx.mobile and some other projects that don't need a UI. This project makes it possible to start a JVx application on server-side. If you create REST or SOAP services, our headlessUI might be the right choice?
That's all for today!