Integrating JavaScript libraries into GWT using JSNI

From time to time when developing GWT applications, I reach the point where the functionality I needed is already perfectly implemented by a JavaScript library. Currently I needed some kind of user friendly non-blocking notification system that displays warnings/errors/.. in the form colored overlays depending on the notification message level. The first match in Google (toastr) seemed like a perfect fit:

toastr is a Javascript library for Gnome / Growl type non-blocking notifications. jQuery is required. The goal is to create a simple core library that can be customized and extended. so in this post I will show the key points that need to be done to use a JavaScript library from GWT (Java) code using toastr as an example.

Including the needed resources

The first step is that the JavaScript library itself (and often accompanying cascading stylesheets) need to be available in the HTML page hosting the GWT application. Of course placing the *.js and *.css files in the GWT module public folder and then using them in the page using <stylesheet ..> and <script ..> is a perfectly feasible solution I prefer to inject the needed resources into to page because when you wrap an external JavaScript library, the GWT module wrapping the library tends to get reused in other contexts and injecting the resources can be done in the modules entrypoint so the developer using your module does not need to modify the applications page an can start using your wrapper right away.

In the case of toastr we need the sources for toastr itself toastr.min.js, the stylesheet toastr.min.css and of course JQuery jquery-1.11.2.min.js. GWT provides the ClientBundle interface which apart from providing an aggressive caching strategy comes with compile time sanity checks. The first sentence of the documentation sums it up nicely:

The resources in a deployed GWT application can be roughly categorized into resources to never cache (.nocache.js), to cache forever (.cache.html), and everything else (myapp.css). The ClientBundle interface moves entries from the everything-else category into the cache-forever category.

So to actually uses the resource in a ClientBundle extend the ClientBundle interface and point it to the needed files:

now instantiate this interface using the GWT.create(...) method:

now you can read the actual file contents via:

Inject the resources

The next step is to inject the resources into the page. GWT provides injectors for JavaScript and CSS that take care of injecting the script/styles into the right parts of the DOM tree:

Call the “native” JavaScript functions

Now that our JavaScript library is available, we can start using it. Interaction with native code from Java is done using the Java native interface (JNI) or in this case the JavaScript Native Interface (JSNI) as it is called in GWT. The contract is, that in the native method declaration everything written between /*-{ and }-*/ is treated as JavaScript by the GWT compiler. When writing JavaScript you have to keep in mind that the script runs in a nested frame and hence window and document are not directly accessible, but GWT guarantees that they are available in $wnd and $doc. To call the warning function toastr offers the Java method looks like this:

You always have to keep in mind, that the JavaScript code you write in native methods is not checked by the compiler, so you will not notice an errors until it is actually used during runtime. There are also some (smaller limitations) on the argument types (especially concerning varargs and long types) that are summed up on the documentation page for JSNI.

By |January 27th, 2015|development, gwt, Uncategorized|

GWT star rating widget

Of course there are numerous GWT implementations of the ubiquitous star based rating widget that is used on nearly every website. For some reason none of them hat the exact features I needed, so based on the approach shown by Austin in this post I created a reusable rating widget for GWT.

The widget comes in two flavors, first a widget where only full stars can be selected, and another one that lets you chose half stars:

mango_gwt_commons_rating1

full star example

The full star widget implements the HasValue<Integer> interface for the selected ratings.

mango_gwt_commons_rating2

half star example

To support semi-star ratrings, the half star widget implements the HasValue<Float> interface.

mango_gwt_commons_rating3

using other images example

The used images, can be altered by providing a resource containing your own images, three image sets are already provided (standard, large and small)

mango_gwt_commons_rating4

mango_gwt_commons_rating5

More example are available in the mango-gwt-commons build artifacts, sourcecode as always on GitHub.

By |January 23rd, 2015|development, gwt|

GWT inline editing (editable label)

I started to extract some smaller GWT parts from my current project that may be reusable in other situations into an independent project to eliminate dependencies on internal structures and ease up reusability.

A functionality that I needed and was unable to find in other libraries was an inline edit control for simple labels (like the X-Editable project for jQuery)

Currently three types (String, Boolean and Integer) are supported. If the value of the control is empty an (configurable) empty string is displayed, the following screenshot shows editable labels of all three types without content.

editable_label1

Clicking on the underlined label opens the inline editor, here for example the editor to input an ordinary string:
editable_label2

The next screenshot show the editor show an editor for an integer with an invalid value (the editor wont close with an invalid value):
editable_label3

And finally the editor for boolean values:
editable_label4

Usage is as follows (the editable controls all support GWTs HasValue interface):

All CSS styles can be altered to suite your needs:

The three editable label types can be seen in action in the Mango showcase (Administration -> Properties), source code is available on GitHub.

By |January 19th, 2015|development, gwt, mango|

New Feature: Inherited label/width from datatype

A little new feature that can help to reduce the noise in the model is the support for inherited with/label definitions from the datatype. Before the change the width for an control had to be defined in each control (inheritance from other controls was supported, but not from datatypes). This lead to errors especially if an datatype was used in several dictionaries:

The above example can now be expressed like this:

The width is only defined once in the datatype and the controls fall back to this width if they don’t contain an width definition. The same rules now apply for labels, see the documentation for common datatype and controls attributes here and here.

By |January 15th, 2015|development, gwt, mango, Uncategorized|

New Feature: Styling for table rows

A new hook type IBaseTableHook provides facilities to style the rows of all tyble types that are available in Mango (simple table, editable table, result table, …).

row style hook example

with the corresponding CSS style

row style hook example (css)

results in a different color for all rows matching the criteria in the hook:

base_table_hook1

See the hook documentation for more.

By |January 7th, 2015|development, gwt, mango, Uncategorized|

Mango Documentation – Labels

After the exhausting holiday season I found some time to continue my work on Mangos documentation. The latest addictions try to throw some light on how Mangos displays entity in the UI and the possibilities to alter this behavior for dictionaries and entities.

By |January 7th, 2015|development, gwt, mango, Uncategorized|

Injecting JNDI datasource from AWS Beanstalk RDS

When deploying web applications that rely on JNDI based datasources to an Amazon webservices beanstalk environment you will soon run into the problem of how to create an JNDI datasource for beanstalks Tomcat instances (because it doesn’t provide one by itself). The method described in this post has the disadvantage that you have to alter your WAR file in order to include the resource definition in your ware file, making your WAR file dependent on the target environment. To avoid repacking my WAR files I slightly altered my approach and came up with the following solution:

I created a ServletContextListener that looks for amazons well known environment variables that are available when you define an RDS (relational database service or in short terms: a database). The AwsRdsMysqlJndiInjector then collects the information for database access, creates a BasicDataSource based datasource and connects it with the JNDI context name given by the environment defined in the beanstalk configuration (which has to match the datasource you defined in your web application.

Lets assume a standard Spring configuration referencing a JNDI datasource:

and a Amazon Beanstalk configuration using a mysql engine based RDS:

mango_demo_beanstalk_rds_config

To make this RDS available as a JNDI link with the name java:comp/env/jdbc/mangodemo configure the trailing name of the JNDI link as environment variable in your Beanstalk software configuration:

mango_demo_beanstalk_softwarE_config2

so it looks like this:

mango_demo_beanstalk_softwarE_config1

the following class will pick up this information an create an accordingly named JNDI link:

as last step add the class as servlet context listener to your web.xml:

Success or error messages should show up in your Tomcats catalina.log. For updates sourcecode see AwsRdsMysqlJndiInjector.java

By |December 22nd, 2014|development|

Functional logging with Mango

To support the everyday need of functional logging a new logging feature was added to Mango. The goal is not to supersede logging via log4j and its companions but to provide functional logging for the application itself.

The logger can easily be injected via spring and can be used in two ways. The first usecase of course is traditional logging if messages with a log level:

a log viewer is provided an can be added to your navigation tree as follows:

Log viewer example

log_module_ui

It is also possible to log events that are specific to a single business object, for example an entity:

The above example attaches the log messages to an instance of CountryVO. They can be viewed when showing/editing the said CountryVO using an editor.

Editor log viewer example editor_log_viewer

For more information see the documentation

By |December 8th, 2014|development, mango|

Using Amazon Elastic Beanstalk with JNDI resources

During the migration of the Mango Live Demo from a homegrown salt configuration management based deployment approach to Amazon Elastic Beanstalk I (as many others) came across the problem to provide a JNDI datasource for my web application which isn’t really straightforward in Beanstalk so here is my solution:

First of all, the Tomcat started inside your Beanstalk application has to be configured with a JNDI datasource. Because messing with the /etc/tomcat7/server.xml would risk messing with the Beanstalk configuration I opted for providing a context.xml inside the META-INF folder of my web application (which is extracted anyways to be deployable via git aws.push.

Beanstalk provides environment variables for the configured RDS (Relational Database Service) instance of your Beanstalk application, which can directly be used in the META_INF/context.xml

META_INF/context.xml

Now the environment has needs two additional jar files for this to work, for once the Commons DBCP library for managing the DataSource and of course the MySQL Connector/J providing the driver class com.mysql.jdbc.Driver.
The default Beanstalk environments can be customized via special YAML based configuration files, that have to be placed inside the folder .ebextensions. The files can create users, install packages and like in our case, simply create files, so create the file .ebextensions/server-update.config with the following content.

server-update.config

This configuration will download the two needed jar files an place them in the Tomcat 7 lib folder.
To finally active the configuration add the config file:

git add .ebextensions/server-update.config && git commit -am "JNDI configuration"

and deploy everything to Beanstalk as usually:

git aws.push

By |November 30th, 2014|development|

Endless scrolling using GWTs DataGrid

Sometimes when you have to display large amounts of constantly growing, ordered data a simple DataGrid using a pager isn’t enough, because

  • you do not (not even approximately) know how many data you have
  • new data constantly gets added

Imagine looking at a certain timespan of a logfile (red marked area). As you are looking, new log entries are added (on the left side). On the right side there may be thousands of old log entries. Because all log entries are ordered by it’s timestamp it should easily be possible shifting the red area to the left or right.

endless_datagrid1 (1)

To support this usecase I created EndlessDataGrid which is basically a plain DataGrid using a ListDataProvider which represents the actually displayed section of the ordered data. A MouseWheelHandler registered on DataGrids internal ScrollPanel intercepts mousewheel up/down events and dispatches them to a callback handler that can be registered on the EndlessDataGrid. The data grid then calls onPageUp(…) respectively onPageDown(…) when the first/last entry of the table is reached. Due to GWTs asynchronous nature, calls made inside the callbacks methods will almost certainly be asynchronous, so when the calls return with their data they have to call the appropriate methods (pageUpFinished(…), pageDownFinished(…). Because different methods are called when data is returned, the newly arrived data (in the case you scrolled upwards) can visually be marked, so that it is easier to distinguish from already loaded data. Dialing the mousewheel fires a lot of events and to prevent the EndlessDataGrid from hammering your backend, it waits some time before the callback is called again (default is 200ms, can be altered via setCallbackQuietPeriod(int).

Example of newly retrieved entries endless_datagrid1

Usage example

Full sourcecode is available at Github, for a working Demo see http://mango-demo-dev.elasticbeanstalk.com/DemoClient/DemoClient.html (Administration -> Log)

By |November 30th, 2014|development, mango|