Login required
Download

Grails Vaadin Plugin

(11)
Author(s) Ondrej Kvasnovsky, Daniel Bell, Les Hazlewood
Current Release 1.4   (5 days ago)
Grails Version 1.1 > *
Tags ajax  rich client  vaadin 
Dependency
compile ":vaadin:1.4"
Last updated by gerades 1 week ago
grails install-plugin vaadin

It is recommended to follow this tutorial for installation of the latest version:

  • https://github.com/ondrej-kvasnovsky/grails-vaadin-plugin/wiki
Last updated by gerades 1 week ago
A plugin for creating a Vaadin applications on Grails.

Overview

Install:

grails install-plugin vaadin

After installing the plugin:

  1. Create a class in the grails-app/vaadin directory that extends com.vaadin.Application .
  2. Specify this class in the Vaadin configuration file ( grails-app/conf/VaadinConfig.groovy ).
  3. Remove any Grails URL mappings for the URL where you want to access the Vaadin UI (in grails-app/conf/UrlMappings.groovy )
  4. Run the application:
grails run-app

Usage

As of the plugin's 1.2 release, all Vaadin-related code should reside in the grails-app/vaadin directory. This directory is a normal source directory, and should contain packages and Groovy classes as expected (e.g. grails-app/vaadin/com/mycompany/vaadin/MyVaadinApplication.groovy ).

Placing the source in this directory allows the Grails environment to treat all Vaadin code as a special Grails artefact, enabling additional features, such as

  • auto-reload after a source code change (just hit browser refresh)
  • Spring dependency support, and
  • integration with Grails internationalization (i18n).

Spring Dependencies

The traditional way in Grails to wire up Spring dependencies is to simply declare the dependency as a property in your source code, for example, an AuditService used to keep track of what happens in an application. Note the 'def auditService' property:

//Ok for normal Grails artefacts, but NOT IDEAL FOR VAADIN UI COMPONENTS:
class VaadinApplication extends com.vaadin.Application {

def auditService

init() { auditService.log new ApplicationStartedEvent()

//set up window and buttons, etc. … } }

However, this is NOT recommended in your Grails-based Vaadin applications, for two reasons:

Reason 1: In order to support dependency injection across all of your Vaadin components (beyond the initial Vaadin com.vaadin.Application instance), you would be required to wire all of your Vaadin UI components in Spring, i.e. grails-app/conf/spring/resources.groovy .

You wouldn't be able to call Window window = new Window("My Window") in your code, and instead would need to acquire all instances from Spring, e.g. Window window = applicationContext.getBean("myWindow"); (and don't forget to make all of those UI beans prototype scoped!).

For even relatively simple UIs, this could quickly become difficult to manage.

(Note: If you still want to do this to achieve a templating type of mechanism where the spring bean definitions act as a sort of UI template, this is ok - but you must ensure that all beans have 'singleton = false' or scope = prototype'. Vaadin UI components cannot be application singletons - each user must get their own copy. Developer beware).

Reason 2: Perhaps the even more important reason requires understanding of Vaadin UIs: A Vaadin application runtime instance, and all of the objects that it reaches (children windows, buttons, etc) are bound to the HttpSession at runtime. Each user has their own Application instance, their own state. So what does this mean for Spring dependencies?

Spring beans in the runtime ApplicationContext , such as all of your
*Service implementations (UserService, DocumentService, etc) are usually stateless - unlike the Vaadin components. All Vaadin components that used traditional dependency injection ('def userService', etc) would retain a strong reference to each Service or any other bean in the ApplicationContext .

Why is this a problem? Session objects (and their contents, such as the Vaadin application and all of its children) might need to be serialized and paged to disk; the servlet container is free to store sessions in memory and then offload them to disk if memory becomes full. If you have a larger Vaadin application and thousands of users, the servlet container might need to do this. The same serialization could also happen if you use clustered sessions, or an enterprise caching framework that serializes Session data across a cluster.

If your Vaadin components retain strong references to stateless Spring beans that are application singletons, each serialized Session would also serialize the Spring beans! This makes the serialized object graph larger than it needs to be. Also, when deserialized, these beans would not be under Spring's control and would very likely fail to work.

Using Dependencies

So, based on the above reasons why it may not be ideal to use standard dependency injection, the Vaadin plugin adds two dynamic methods to all classes in grails-app/vaadin to support dependency acquisition:

getBean(String beanName)
getBean(Class beanType)

You can access any Spring bean as necessary by calling this method in any class under grails-app/vaadin . Here is the above Application example refactored to use this mechanism:

//Cleanly serializable implementation:
class VaadinApplication extends com.vaadin.Application {

init() { getBean(AuditService).log new ApplicationStartedEvent()

//set up window and buttons, etc. … } }

The above example uses the getBean(Class clazz) method to acquire the dependency by type. We could have just as easily looked up the bean by name: getBean("defaultAuditService") . These methods will always ask the Spring ApplicationContext for the dependency. Spring caches these references of course, so the call is extremely fast, but still serialization-safe.

(Aside: the 'getBean' approach is one way to solve the serialization problem. Another way is to dynamically replace all property definitions, e.g. 'def userService', with a runtime proxy: the proxy can be serialized safely, but when deserialized it would know how to look up the 'real' target bean from the Spring ApplicationContext at runtime. The current version of the Vaadin plugin does not support this dynamic proxy approach - please discuss on the dev list if you'd like to help make this happen!).

Internationalization (i18n).

Internationalization (i18n) is one of the things you have to do yourself when writing standard Vaadin applications - messing with Resource Bundles, MessageFormats, etc. But you don't have to worry about that when using the Grails Vaadin plugin!

All classes under grails-app/vaadin automatically receive dynamically added methods to 'hook' in to Grails I18N support:

i18n(String key, Collection args=null, Locale locale=LocaleContextHolder.getLocale())
i18n(String key, String defaultMessage, Collection args=null, Locale locale=LocaleContextHolder.getLocale())

The first method will throw an exception if there is no matching key. The second one will show the default message if the key doesn't exist.

All message keys should be defined in the standard Grails i18n location in grails-app/i18n/messages*.properties .

As you can see, the args and locale arguments are optional. so you can call the method in many permutations. If you don't specify a Locale (pretty common), it defaults to the one Grails sets up automatically for a request as defined in the Grails chapter on internationalization .

Some examples:

Window window = new Window(i18n("default.home.label"));

//button with label arguments:, e.g. "You have clicked {0} times since 2:15 pm!": Button button = new Button(i18n("button.click", [numClicked, sinceDate]));

window.addComponent button

..

Integrating client-side add-ons and using your own widgetset

Since version 1.4 of the plugin, it is now possible to use your own widgetset, which is very useful when using client-side Vaadin add-ons. Those add-ons require you to recompile your widgetset. But once you have recompiled your widgetset, you need to tell Vaadin servlet to use it. The plugin doesn't make it possible to recompile your widgetset yet, but there is a manual process to do it documented in this thread: http://vaadin.com/forum/-/message_boards/message/212322

Of course you don't need to modify the plugin anymore since this modification has now been integrated. So once you have recompiled your widgetset, all you need to do is to add the following line to VaadinConfig.groovy:

widgetset = "com.mycompany.myapp.MyWidgetset"

And replace the value with the path of your widgetset.

Note that if you don't specify a widgetset in VaadinConfig, the default one will be used as usual.

NB: I'm aware that widgetset compilation is still a cumbersome process and I will try to see if it cannot be simplified in a future version of the plugin.

Upgrading from 1.0 to 1.1

If you're upgrading from the 1.0 Vaading plugin, your old Vaadin configuration will not be automatically upgraded. You will want to use the following as a starting point in your grails-app/conf/VaadinConfig.groovy file:

vaadin {

//Your Vaadin application class that extends com.vaadin.Application: applicationClass = "com.mycompany.MyVaadinApplication"

//the context relative path where you want to access your Vaadin UI. Default to the context root. contextRelativePath = "/"

productionMode = false

googleAppEngineMode = false }

environments { production { vaadin { productionMode = true } } }

Release Notes

  • 1.5 - Possible to run it together with Grails 2.0.0. Vaadin updated to 6.7.4. Config option for custom servlet class name added. Automatic redeploy fixed (so you can do changes in Vaadin classes without restarting the application).
  • 1.4 - Added the possibility to specify your own widgetset to be used by Vaadin servlet, which is very useful for using add-ons
  • 1.3 - Simple Vaadin upgrade to version 6.5.1
  • 1.2 - Created new 'vaadin' artefact type - all Vaadin code should now reside in grails-app/vaadin . New features: Seamless integration with Grails Internationalization (i18n) as well as Spring bean lookup from any Vaadin component.
  • 1.1.2 - Upgraded to the latest stable Vaadin release (6.3.4), fixing these issues.
  • 1.1.1 - A minor point release that ensures compatibility with Grails 1.1 and higher. However, Groovy 1.7 language features (anonymous inner classes, etc) are only available in Grails 1.3+ environments (Groovy 1.7 is part of Grails 1.3+).
  • 1.1 - Latest stable Vaadin release (6.3.3). Ability to specify a path to your Vaadin UI other than the root context path (e.g. http://localhost:8080/myapp/vaadinUI). Environment-specific configuration support (production, development, etc. Custom environments too 'beta', 'uat', etc).
Last updated by admin 2 years ago
Last updated by oriental 1 year ago