Pieter Libin <pieter@emweb.be>

1. Introduction

JWt is a Java library for developing web applications. The library uses the standard Java Servlet infrastructure, and therefore, a JWt web application may be deployed in existing servlet containers or JEE web application servers.

The API is widget-centric, and inspired by existing Graphical User Interface (GUI) APIs: a widget is a self-contained class which encapsulates all event handling related to a user interface element. The library offers an abstraction of many web-specific implementation details, including event handling and graphics support. In this way, the library choses a rendering strategy based on the browser’s capabilities (AJAX are plain HTML). Still, the library supports the web semantics of URLs, bookmarks, and forward/backword navigation and therefore also search engine interopability.

2. Library overview

2.1. Widgets

The WWidget class represents a widget, which provides an abstraction of a visual entity. The entire user-interface is specified by creating a hierarchical structure of widgets, rooted at WApplication.getRoot(). By reacting to events related to these widgets, you can perform business logic, and manipulate the widget hierarchy to update the user interface.

Any descendent class of WWidget is a self-contained (reusable) class that encapsulates both the look and behaviour, enabling the design of the user interface in an orthogonal way.

2.1.1. Layout

Widgets are layed out (with a few exceptions) following their hierarchical structure. You have two main options for lay-out of children within a container. Either you use a CSS based layout, in which case the CSS style properties of the container and children together determine the result: each child manages its layout with respect to its sibling following a (rather complex) set of rules. Alternatively, JWt provides layout managers that may be used for layout.

CSS layout considers two important categories of layout. Text-like widgets (inline) flow with sibling inline widgets in lines, wrapping at the right edge of the parent container. In contrast, widgets displayed as a block stack vertically with respect to sibling widgets. Block widgets allow more control over their position and size than inline widgets, and may also float to the left or right border of the parent container.

Layout managers are implemented by classes that derive from WLayout and are used in conjunction with the WContainerWidget class. Due to limitations in CSS (and pedantic browser implementations), vertical layout is not possible without JavaScript.

2.1.2. Style

For visual markup of widgets, the recommended way is to use CSS style sheets. These allow the visual look to be defined seperately from the the rest of the application. External stylesheets may be loaded using WApplication.useStyleSheet() and the external stylesheet may be manipulated using WApplication.getStyleSheet().

In the stylesheets, you describe rules that are prefixed by CSS selectors. By setting matching style classes for your widgets using WWidget.setStyleClass(), these rules will be applied to your widgets. The recommended way for the visual response to events is by changing the style class for the widget.

In addition to style sheets, Wt also supports the direct manipulation of a widget’s style, using WWidget.getDecorationStyle().

2.1.3. Widget containers

With a few exceptions, all widgets are child of (and contained in) a container widget such as WContainerWidget or WTableCell. A widget is inserted into a +WContainerWidget by adding the widget to the container using WContainerWidget.addWidget(), or by passing the parent container as an argument to its constructor. You may also add a widget to a container using a layout manager.

2.2. Application URL(s)

A JWt application, like any other servlet, is deployed at a specific location (URL) within your servlet container/J2EE application server. This location is configured through the url-pattern defined in the servlet-mapping within your web.xml deployment descriptor, and the context at which the application is deployed. In this mode, a JWt application is a single page web application: the URL does not change.

A JWt application may also manage internal paths, which are URLs inside your application URL. To allow the servlet to handle all internal paths too, you need to set an url-pattern that ends with "/*". Then, the internal path may be set and read using WApplication.setInternalPath() and WApplication.getInternalPath(). When the internal path changes, this is reflected in the browser URL and an entry is added to the browser history, allowing the user to use the back and forward buttons to navigate through your application.

When AJAX is available, the library will always avoid rerendering the entire widget tree. To avoid rerendering only to change the URL, the internal path is indicated using a name anchor (#) after the deployment URL. For a plain HTML session, the session ID is appended to the URL to avoid the session from reloading when the user navigates using a WAnchor to a new internal URL.

To effectively change the internal path and obtain consistent behaviour with or without JavaScript, you should use a WAnchor to let the user navigate to a new internal path. The easiest way to do this is by using the WAnchor.setRefInternalPath(). This refers the anchor to a URL generated by WApplication.getBookmarkUrl() for the new internal path (handling the plain HTML case), and binds a JavaScript listener to its clicked() signal, which changes the internal path (handling the AJAX case).

Finally, you can listen for path changes using the WApplication.internalPathChanged() event to react to the user navigating through his history.

When your applications uses internal URLs, this has consequences for relative URLs to external resources (style sheets, images, JavaScript files, etc…), since these are resolved taking into account the current relative URL. All relative URLs that are known to the application (e.g. those set in WAnchor.setRef(), WImage.setImageRef(), WApplication.useStyleSheet(), etc…) are automatically replaced by JWt with an absolute URL that resolves these directly within the deployment location. You should use absolute URLs in CSS or XHTML for them to work within each internal path, since these cannot be fixed by JWt.

2.3. Startup, session management and request handling

JWt provides the abstract WtServlet class which implements the controller for an application. Every JWt application must extend this class and implement its createApplication() to return a new WApplication instance. This method is invoked by the library for every new session (which corresponds to a new user accessing your web application). The request arguments (as part of the WEnvironment object) are passed to this createApplication function, and may be used to customize the application or authenticate the user. See also Application bootstrap for details on the application bootstrap method.

At all times, the current WApplication instance is accessible using the static method WApplication.getInstance(), and is useful to inspect startup arguments and settings using getEnvironment(), to set or change the application title using setTitle(), to specify a locale using setLocale(), and many other application-wide settings. Access to this instance is implemented using thread local storage.

A session exits when the user browses away from the application, when WApplication.quit() is called, or when the servlet container is shut down. From this moment on, your widget tree will be waiting to be garbage collected. Therefore, you should release auxiliary resources held by your widgets or application in the finalize() method of these objects.

During the lifetime of a session, the controller implemented by WtServlet will handle and interpret requests, invoke event handling code, and render updates and changes to your widget tree. This is strictly an internal affair of the library, except that it allows you to scope the use of resources to a single request. To that extend, the library provides a central entry point for doing things like acquiring and releasing database connections and transactions, or have a single place for handling internal application errors. Each request is handled from within WApplication.notify(), and by reimplementing this method you may control resource usage during each request.

By default, servlet containers are configured to use cookies for session tracking. This configuration disables a user to have multiple concurrent sessions of the same application running in the same browser. In order to achieve such behaviour, you should configure your servlet container to use URL session tracking instead. This servlet container specific configuration can be found in your servlet container’s documentation. The examples distributed with JWt contain a configuration file for a number of servlet containers: Jetty (jwt-3.0.0/examples/hello/WebRoot/WEB-INF/jetty-web.xml), JBoss (jwt-3.0.0/examples/hello/WebRoot/WEB-INF/context.xml) and Tomcat (jwt-3.0.0/examples/hello/WebRoot/META-INF/context.xml).

2.4. Event handling

To respond to user-interactivity events, or in general to communicate events from one widget to any other, JWt uses a signal/listener system, which is a popular implementation of the Observer pattern.

Depending on the number of objects your signal propagates to listeners, you need to use Signal, Signal1, Signal2, …, Signal6 as a signal object.

Listeners implement the corresponding listener class, and can be added to a signal using addListener(). Because the listener interface only requires the implementation of a single method, it is convenient to use an anonymous inner class to implement it. The following example is taken from the hello example.

Adding a listener to a clicked() signal.
    nameEdit = new WLineEdit(getRoot());
    greeting = new WText(getRoot());

    WPushButton button = new WPushButton("Greet me.", getRoot());

    button.clicked().addListener(this, new Signal.Listener() {
        public void trigger() {
            greeting.setText("Hello there, " + nameEdit.getText());
        }
    });

The library defines several user-event signals on various widgets, and it is easy and convenient to add signals and listeners to widget classes to communicate events and trigger callbacks.

Event signals (EventSignal) are signals that may be triggered internally by the library to respond to user interactivity events. The abstract base classes WInteractWidget and WFormWidget define most of these event signals.

2.5. Server push

By default, updates to the user interface are possible only at startup, during any event (in a slot), or at regular time points using WTimer. This is the normal JWt event loop.

In some cases, one may want to modify the user interface from a second thread, outside the event loop. While this may be worked around by the WTimer, in some cases, there are bandwidth and processing overheads associated which may be unnecessary, and which create a trade-off with time resolution of the updates.

When "server push" (what is called comet in AJAX terminology) is enabled, widgets may then be modified, created or deleted outside of the event loop (e.g. in response to execution of another thread), and these changes are propagated by calling triggerUpdate().

For more information, please refer to the reference documentation of WApplication.enabledUpdates(), this function enables or disables server push.

Note that server push works only if your servlet container supports the Servlet 3.0 API. You can find a feature example on server push and a more elaborate simplechat example in the JWt source code.

2.6. Optimizing client-side event handling

By default, JWt performs all event processing server-side. Every connected event signal will cause the web browser to communicate with the servlet container in order to invoke the listener’s implementation, and visual changes will be updated in the web page.

However, JWt offers several options for incorporating client-side event handling. This may in general increase responsiveness of the application since the user gets an instant feed-back and the communication delay is avoided.

JWt provides a number of mechanisms to integrate JavaScript code with Java:

  • using JSlot, you can specify the JavaScript for a listener, when connected to an EventSignal Using

  • using JSignal, you can emit a Java signal from JavaScript code, using a JavaScript function Wt.emit(). Using

  • using WApplication.doJavaScript(), you can call JavaScript code directly as part of event handling.

2.7. Application bootstrap

A JWt application may support both plain HTML and Ajax-enabled user agents. When a first request is made for a new session, there is no way of knowing whether the agent supports Ajax (and has it enabled). The bootstrap procedure therefore has two strategies of making the choice between a plain HTML and Ajax-enabled application mode.

2.7.1. Default bootstrap

In the default bootstrap mode, for the normal case, a small bootstrap HTML file is served, which detects presence of AJAX (and various other environment properties such as presence of an internal path as an anchor, cookie support, and IE VML DPI setting). When no JavaScript support is available, it automatically redirects the user to a plain HTML version of the application.

In this mode, the application is not started until the library has determined AJAX support, which is made available in WEnvironment.hasAjax() which is passed to the application constructor.

In some special cases, this bootstrap is skipped and a plain HTML version is served. This is for user agents that are identified as spider bots, or user agents which are configured to not support AJAX (well), see the user agents configuration setting.

There are some draw-backs to this bootstrap method:

  • the redirection without JavaScript support may not be supported by all user agents. To handle this, the boostrap page also shows a link and a redirect message (see the redirect message configuration setting), which may confuse new users.

  • there is an additional round-trip before any contents is rendered.

  • for an AJAX user interface, all contents will be loaded through JavaScript. This has a draw-back that IE may delay applying external stylesheets after the contents has been rendered, which might cause some confusion, and some 3rd party JavaScript libraries do not support being loaded on-demand (with as most notable example, Google ads).

2.7.2. Progressive bootstrap

Since JWt 2.99.4, a new bootstrap method has been added (initially proposed by Anthony roger Buck). While the default bootstrap already honors the principle of graceful degradation, this bootstrap implements this using the principle of progressive enhancement (and quite literally so).

This bootstrap method may be enabled with the progressive bootstrap configuration setting.

This bootstrap method will initially assume that the user agent is a plain HTML user-agent and immediately create the application (with WEnvironment.hasAjax() always returning false). The initial response will contain the initial page suitable for a plain HTML user-agent.

JavaScript embedded in this page will sense for AJAX support and trigger a second request which progresses the application to an AJAX application (without repainting the user interface). To that extent, it will change WEnvironment.hasAjax() to return rue, and invoke WApplication.enableAjax() which in turn propagates WWidget.enableAjax() through the widget hierarchy. This upgrade happens in the back-ground, unnoticed to the user.

This mitigates disadvantages associated with the default bootstrap, but has the draw-backs of being a recent development in JWt, and it requires slightly more server-side processing.

2.8. Painting

JWt provides a vector graphics painting system which depending on the browser support uses one of three different methods to paint the graphics (inline SVG, inline VML or HTML 5 <canvas> element). Vector graphics has as benefit a lower bandwidth usage, which is indepedent of the image size and quality, and can be embedded within the HTML, avoiding an additional round-trip. To use the paint system, you need to specialize WPaintedWidget and use a WPainter to paint the contents of the widget inside its paintEvent().

The charting library is built on top of this painting infrastructure.

2.9. Deployment

JWt uses the Java Servlet API, and thus JWt applications are all compatible with commonly used servlet containers (Tomcat, Jetty, …) and JEE application servers (JBoss, Glassfish, …). The most common way to deploy a JWt application is by packaging the application as a war file and deploying it into a servlet container. Because JWt applications are plain Java applications, without the need for code generation or XML editing, JWt application development can be conveniently done from your favourite Java IDE. See the Getting Started section for hints on how to create war files and develop JWt applications from within Eclipse.

2.10. Configuration

JWt can be configured by changing values in the Configuration object accessible via the WtServlet.getConfiguration().

3. Getting started

In this section, we will go through the steps to download and install JWt, and deploy and run the examples that come bundled with it. We will detail the procedure for the ubiquitious Hello world example, but you can follow the same steps for each of the examples.

Tip
The examples that come with the library are each a self-contained project which only require the JWt library (and its dependencies) to get going. You could structure your own projects in the same way as each of these example projects, but it is up to you: the library does not enforce a particular layout of your web application, it simply acts as a library (rather than a framework).

We present two tracks for running your first JWt application: from within the Eclipse IDE or from the command line. You will need to download the JWt distribution which contains the library and its dependencies, from the homepage’s download section.

3.1. Hello world from within Eclipse

The library and all of the examples include a .project file which is used by Eclipse to manage the build process. For deploying the web application during development, we recommend using the run-jetty-run plugin.

3.1.1. Requirements

To run the Hello world example with Eclipse you will need to install the following softwares:

3.1.2. Importing into Eclipse

  1. Extract the JWt source distribution to a directory on your system.

  2. Start Eclipse.

  3. Right-click inside your Project Explorer and select ImportImport….

  4. Select GeneralExisting Projects into Workspace and click Next.

  5. Click Browse.

  6. Navigate to the directory where the JWt source distribution was extracted to. Select the examples/hello directory and click OK.

    Tip
    You can import multiple examples at once by selecting the examples directory instead, and selecting multiple projects in the next step.
  7. The hello project will be visible and selected, click Finish.

  8. The imported jwt-hello project becomes visible in the Project Explorer tree.

    There are however still build errors as the JWt library and dependencies are still missing.

    jwt-hello project tree

  9. We have provided an ant build script that copies the JWt library and dependencies in the lib folder and also builds a war file.

    Right-click on the build.xml, Run AsAnt Build. When this is your first example, the build script will also build the JWt library itself.

  10. Refresh your jwt-hello project. The example is now built and ready to be run.

3.1.3. Running

Below, we use the run-jetty-run plugin. You may also use any other JEE application server (with integration in Eclipse) to which you deploy the dist/jwt-hello.war file which has also been built by the ant tool.

  1. Open the RunRun Configurations… dialog.

  2. Create a new Jetty Webapp.

    Since this example does not require HTTPS, remove the HTTPS port value in the Ports section. Removing this value will disable all other HTTPS related settings.

  3. Click on the Browse… button in the Web Application section and select the WebRoot folder.

  4. Click Run (your configuration settings will be saved).

  5. The servlet container starts listening on port 8080

  6. Open your web browser and point it to http://localhost:8080/.

    The example in Firefox

3.2. Hello world from the command line using Ant

To build the library and examples, we will be using ant, and for deployemt we will use the light-weight Jetty servlet container.

3.2.1. Requirements

To run the Hello world example from the command line you will need to install the following softwares:

3.2.2. Building

  • Open you command line console.

  • Extract the JWt source distribution to a directory on your system, and navigate to this directory.

  • Enter the examples/hello directory and run ant:

    $ cd examples/hello
    $ ant

    This will build dist/jwt-hello.war, handling all of the dependencies including JWt itself.

3.2.3. Running

  • Copy the jwt-hello.war to jetty-install-dir/webapps/hello.war.

  • Start Jetty:

    • On Unix: jetty-install-dir/bin/jetty.sh start

    • On Windows: java -jar jetty-install-dir\start.jar

  • Open your preferred web browser and navigate to http://localhost:8080/hello/.

The example in firefox

3.3. A closer look at a JWt web application project structure

A JWt project is a setup does not involve much, since JWt acts as a Java library (on top of the Java servlet API). After running ant in the JWt source distrubition folder, all required jar files can be found in the jwt-3.0.0/dist folder. To use JWt in your project, you need only to include these 4 jar files into your project library path.

The start point of your application is defined by extending WtServlet which implements a Java servlet, and provides an entry point to a JWt application. An example of this is eu.webtoolkit.jwt.examples.hello.HelloMain.

To deploy the web application you need to provide a WebRoot/web.xml configuration file which binds the servlet to a context path:

3.4. Using server push requires the Servlet 3.0 API

Server push (used in the simplechat and serverpush feature example) relies on the asynchronous processing of requests, a feature which is only part of the Servlet API since version 3.0. Several servlet containers are currently implementing this new Servlet API, and no official releases exist. We were able to test our examples successfully on Tomcat 7.0.4 Beta.

A note when developing your own server push applications: make sure to include the servlet-api-3.0.jar during compilation, as demonstrated in the build.xml of the serverpush feature example (examples/features/serverpush).