JWIG User Manual

Anders Møller & Mathias Schwarz
{amoeller,schwarz}@cs.au.dk

Last update: February 11 2011

JWIG User Manual

Contents:

1.
What is JWIG?
2.
Hello World!
3.
Web applications, web methods, and web sites
4.
Generating responses
5.
Requests and parameters
6.
Caching
7.
Session state
8.
Client side programming
9.
Configuration
10.
Persistence with Hibernate
11.
Miscellaneous convenience features
12.
Features under development
13.
The JWIG program analysis suite
14.
Examples
(hover mouse to see subsections)

Contents

1.
What is JWIG?
2.
Hello World!
3.
Web applications, web methods, and web sites
4.
Generating responses
4.1
XML generation using Xact
4.2
Response redirection
4.3
Links to web methods
5.
Requests and parameters
5.1
Mapping from URLs to code
5.2
Web service programming
5.3
Filters and user authentication
5.4
Forms
6.
Caching
6.1
Page regeneration
6.2
Invalidating cached pages
7.
Session state
8.
Client side programming
8.1
Automatic view updates
8.2
HTML events
9.
Configuration
10.
Persistence with Hibernate
10.1
Setting up your database connection and dialect
10.2
Setting up username and password
10.3
Persistable objects
10.4
Querying
10.5
Mapping objects
10.6
Taking persistable parameters
10.7
Database cache
11.
Miscellaneous convenience features
11.1
Error reporting and logging
11.2
Returning plain text
11.3
Low-level servlet input/output
11.4
Cookies
11.5
Sending emails
11.6
Debugging applications
12.
Features under development
12.1
Session threads
12.2
HTML extension libraries
13.
The JWIG program analysis suite
14.
Examples
14.1
QuickPoll
14.2
Example: MicroChat
14.3
Example: GuessingGame

1. What is JWIG?

JWIG is a Java-based web application programming system. JWIG is being developed to explore high-level language design and program analysis support for web programming.

Highlights of JWIG 2.0:

NOTE: This is work in progress. Feedback is appreciated!

This document describes the design and capabilities of JWIG and is intended to make it possible for others to play with the system. JWIG has many interesting connections to other web programming frameworks; however those connections are not the focus of this document. The JWIG 2.0 implementation builds upon Tomcat 6 and other widely used Java tools, such as Ant, Hibernate, log4j, and JavaMail. The version of JWIG described here supersedes all previous releases of JWIG and is not designed to be directly backward compatible (although the main ideas from previous releases are still present).

The javadoc JWIG API documentation supplements this user manual by describing more details of all the classes and method in the JWIG API.

2. Hello World!

For instructions on how to install JWIG, go to the JWIG web page at
http://www.brics.dk/JWIG/
and download either the kickstart file (which contains a basic JWIG application) or the full JWIG source package (open source, LGPL licence), and then read the INSTALL file.

We naturally begin with the JWIG variant of the ubiquitous Hello World program:

Main.xact - a tiny JWIG program
import dk.brics.jwig.*;
import dk.brics.xact.*;

public class Main extends WebApp {

  public XML hello() {
    return [[
      <html>
        <head><title>JWIG</title></head>
        <body>Hello World</body>
      </html>
    ]];
  }
}

(In the following examples, we omit the import declarations.) Compile and deploy (for example with ant compile and ant deploy using the Ant build file from kickstart.zip). Note that this source file contains Xact syntax, so it must be compiled by the Xact compiler (see Section 4). Then direct your browser to

  http://HOST:PORT/TOMCAT-APP/hello
where HOST, PORT, and TOMCAT-APP should be be replaced by the name and port of your web server and the Tomcat application name, according to the configuration in jwig.properties and build.xml. You should now see the Hello World message. This tiny example application demonstrates a number of basic features in JWIG, as explained in the following sections.

3. Web applications, web methods, and web sites

A program written in JWIG is a class named Main (default package). In the example above, Main extends WebApp and is called a web application. When the JWIG runtime system starts, one instance of the web application is created.

Each public method in the web application class is a web method that can be accessed via a HTTP GET request, as in the Hello World example above. Since web method are associated to GET requests, they should be safe and idempotent, as required by the HTTP specification.

The Main class can alternatively extend WebSite, which is used for a web site that consists of multiple web applications. Example:

Main.java - a web site consisting of two web applications
public class Main extends WebSite {

  public void init() {
    add(new examples.GuessingGame());
    add(new examples.QuickPoll());
  }
}

When a web site is started, its init method is invoked. In this method, each web application is created and added to the web site using the add method. Web methods are, using the default configuration, invoked as

  http://HOST:PORT/TOMCAT-APP/WEBAPP-CLASS/WEBMETHOD
where HOST, PORT, and TOMCAT-APP are as before. WEBAPP-CLASS is the web application class name with '/' instead of dots (e.g. examples/GuessingGame in the example above), and WEBMETHOD is the web method name. The mapping from URLs to web methods can be configured as explained in Section 5.

4. Generating responses

Web methods typically produce XHTML output, which is sent to the client to be shown in a browser window. A key constituent of JWIG is the Xact XML transformation language. The following section provides a short introduction to Xact.

4.1 XML generation using Xact

Xact is a general tool for transforming XML data. We here focus on its capabilities for constructing XHTML documents dynamically.

For more information about Xact, see http://www.brics.dk/Xact/.

An XML template is a fragment of an XML document that may contain unspecified pieces called gaps. These gaps can be filled with strings or other templates to construct larger templates and complete XML (typically XHTML) documents. XML templates are represented in the JWIG program by values of the XML type. XML values are immutable, that is, all operations that manipulate XML templates create new values without modifying the input values. XML template constants are written as plain XML text enclosed in double square brackets. For example, the following line declares a variable to contain XML template values and initializes it to a simple constant value:

An XML variable and a simple template constant
XML hello = [[Hello <i>World</i>!]];

XML template constants must be well-formed, that is, the tags must be balanced and nest properly. Implicitly, the default namespace is set to http://www.w3.org/1999/xhtml (the XHTML 1.0 namespace).

A code gap in an XML template is written using the syntax <{code}> where the content is a Java expression:

XML template with code gaps
String title = "JWIG";

XML getMessage() {
  return [[Hello <b>World</b>]];
}

XML hello = [[
  <html>
    <head><title><{title}></title></head>
    <body>
      <{getMessage()}>
    </body>
  </html>
]];

These gaps can be placed within text and tags, as if they were themselves tags. Gaps placed like this are called template gaps. When executed, the code in the code gaps is evaluated, and the resulting values are inserted in place of the gaps.

Code gaps can also be placed as the values of attributes. For example, <a href={foo()}> is an anchor start tag whose href attribute has a value obtained by invoking some method foo(). Gaps placed like this are called attribute gaps.

A named gap is written using the syntax <[name]>. The gap name must be a legal Java identifier. Named gaps can also be placed inside tags, as the values of attributes. The syntax for this is to write the name of the gap enclosed in square brackets where you would normally write an attribute value enclosed in single or double quotes. For example, <a href=[LINK]> is an anchor start tag whose href attribute is a gap named LINK.

Named gaps are filled using the plug operator:

Building XML templates using plug
XML hello1 = [[<p align=[ALIGNMENT]>Hello <[WHAT]>!</p>]];
XML hello2 = hello1.plug("WHAT", [[<i><[THING]></i>]]);
XML hello3 = hello2.plug("THING", "World").plug("ALIGNMENT", "left");

After executing this code, the values of the variables will be:

  hello1:  <p align=[ALIGNMENT]>Hello <[WHAT]>!</p>
  hello2:  <p align=[ALIGNMENT]>Hello <i><[THING]></i>!</p>
  hello3:  <p align="left">Hello <i>World</i>!</p>

As can be seen from the example, both strings and XML templates can be plugged into template gaps. Attribute gaps, however, can of course only contain strings. When plugging in a string, characters that have a special meaning in XML (e.g. < and &) are automatically escaped. As a shorthand, the plug operator allows the plugging of any object or simple value. If the value being plugged in implements the ToXMLable interface, its toXML() method is first invoked for converting it to an XML template; otherwise toString() is invoked for converting it to a string. When an XML template is returned from a web method, all remaining template gaps are replaced by empty strings. For all remaining attribute gaps, the whole attribute is removed.

The JWIG program analyses (see Section 13) can check - at compile time - that the XML documents being generated dynamically using Xact are always valid XHTML 1.0.

A common use of named gaps in XML templates is for avoiding redundancy in dynamic XML construction, for example when many XHTML pages use the same overall structure:

XHTML wrapper
XML my_xhtml_wrapper = [[
  <html>
    <head><title><[TITLE]></title></head>
    <body>
      <h1><[TITLE]></h1>
      <[BODY]>
    </body>
  </html>
]];

XML page1 = my_xhtml_wrapper.plug("TITLE", "one")
  .plug("BODY", [[This is <b>one page</b>]]);

XML page2 = my_xhtml_wrapper.plug("TITLE", "two")
  .plug("BODY", [[This is <b>another page</b>]]);

Instead of being written inlined in the JWIG program, an XML template constant can be placed in an external file and loaded into the program at runtime using, for example, XML.parseTemplateResource(name) where name is a resource name.

Because of the non-Java syntax, files containing XML template constants [[...]] must be desugared using the Xact compiler. Note that such files typically have extension .xact instead of .java.

One way to invoke the compiler is like this:

  java -classpath xact.jar dk.brics.xact.compiler.Main *.xact
See also the Ant build file build.xml in the JWIG kickstart file.

4.2 Response redirection

One alternative to returning XML data is to redirect to another web resource by returning a URL. As an example, when invoking the following web method, the response is a redirection to the given URL:

Response redirection
public URL redirect() {
  return new URL("http://www.brics.dk/JWIG/");
}

4.3 Links to web methods

Often, redirection is to another web method within the same web site. The method makeURL makes it easy to construct such URLs:

Response redirection to another web method
public URL redirect2() {
  return makeURL("hello");
}

public XML hello() {
  return [[
    <html>
      <head><title>JWIG</title></head>
      <body>Hello World</body>
    </html>
  ]];
}

The method name is optionally qualified by a web application class name, either by prepending the qualified name of the class to the method name or by supplying the Class object of the web app as the first argument. Parameters (see Section 5) can be added simply as extra arguments to the makeURL method. To control whether the generated URL should use https (secure connection), see the variant of makeURL that takes an extra boolean argument.

5. Requests and parameters

Web methods can receive parameters, such as form data fields, that arrive using the most common encodings (application/x-www-form-urlencoded and multipart/form-data). Parameters often occur in connection to form submission, as explained in Section 5.4.

The following example shows a web method with a single parameter named x:

HelloWorld3.java - web method parameters
public class HelloWorld3 extends WebApp {

  public XML hello(String x) {
    return [[
      <html>
        <head><title>JWIG</title></head>
        <body>
          The value of the parameter <tt>x</tt> is: <{ x }>
        </body>
      </html>
    ]];
  }
}

We can invoke this web method by e.g.

  http://HOST:PORT/TOMCAT-APP/HelloWorld3/hello?x=John+Doe

Other data types than strings can also easily be received:

• Any class that implements valueOf(String)
(this includes wrapper classes such as Integer and Boolean) - where valueOf is then used for creating a value from its string representation, and an absent field results in null.
• Primitive types (int, boolean, etc.)
- parsed in the usual way.
FileField
- for file uploads (which requires method="post" and enctype="multipart/form-data" in the form tag, as usual), see Section 5.4.
XML
- Xact values, parsed via XML.parseDocument.
Persistable
- see Section 10.
• Arrays (of the above kinds)
- for receiving multiple parameters of the same name (the array may be empty but is never null).
• Collection<E> or subclasses where E is of the above kinds. The E type must correspond to a class or interface
For receiving multiple parameters of the same name
Parameters
- matching any collection of parameters. If a web method declares an argument of type Parameters all request parameters that are not matched by the preceding arguments on the list of formal method parameters are represented using this parameters object.

To make the parameter names of web methods accessible by the JWIG runtime system, either

  1. the code must be compiled with debug information, i.e. with option -g,
  2. the @ParamName annotation must be used on each parameter of the method, or
  3. the @ParamName annotation can be used on some parameters and the code must be compiled with debug information to find the rest of the parameter names.

5.1 Mapping from URLs to code

The mapping from URLs to web applications, web methods and parameters can be configured using the @URLPattern annotation, which allows "REST-style" URLs:

Configuring URL to code mapping
@URLPattern("app4")
public class HelloWorld4 extends WebApp {

  @URLPattern("h/$x")
  public XML hello(String x) {
    return [[
      <html>
        <head><title>JWIG</title></head>
        <body>
          The value of the parameter <tt>x</tt> is: <{ x }>
        </body>
      </html>
    ]];
  }
}

The hello method can now be invoked by e.g.

  http://HOST:PORT/TOMCAT-APP/app4/h/117
whereas the default mapping described in Section 3 would require
  http://HOST:PORT/TOMCAT-APP/HelloWorld4/hello?x=117
In general, the pattern of a web application class is just a string and a number of web applications parameters. These web application parameters are passed transparantly among methods in the same web application, and they may be given as a map from names to values to the makeURL method. For a web method, the pattern is a set of choices, separated by '|'. Each choice is a sequence of steps, separated by '/'. A step can be:
a string (not containing a separator)
- matching that string
*
- matching any string not containing '/'
**
- matching any string (which may contain '/')
$foo
- matching any string not containing '/' and binding the string to the request parameter named foo
Request parameters specified using $p are merged with those supplied using the ordinary query string and request body mechanisms.

5.2 Web service programming

JWIG support all HTTP methods for JWIG web methods and Xact can easily be used to generate any kind of XML. This allows web methods to implement REST web services in a straightforward manner. Web methods are simply annotated with @GET, @POST, @PUT, @DELETE etc. to indicate to JWIG what requests a web method should respond to. More than one HTTP method annotation may be set on a single web method and if no annotations are set, JWIG defaults to @GET. Consider the following example:

Web service example
@PUT
public URL store(String s) {
    //implementation omitted
}
JWIG will invoke this web method (only) if a matching PUT request is sent from the client.

5.3 Filters and user authentication

Multiple web methods may match a request URL. In this case, the @Priority annotation determines the order. The next method passes control to the next web method in the list. A filter is a web method with return type void. The default priority of a filter is higher than that of the cache method, which means that filters are processed before the caching mechanism explained in Section 4 is applied. By default filters answer to the same request types as normal web methods, but they may be annotated to respond to any request type. This is typically used for authentication. The following filter matches all request URLs (using @URLPattern) and returns an error an insecure connection is used (that is, without SSL/TLS) and a HTTP Basic authentication "authorization required" message if the right user credentials are not provided:

HTTP Basic authentication
@URLPattern("**")
public void accessBasic() {
  if (!isSecure)
    throw new AccessDeniedException("Connection is insecure!")
  User u = getUser();
  if (u == null || !u.getUsername().equals("smith") || !u.getPassword().equals("42"))
    throw new AuthorizationRequiredException("JWIG examples");
  next();
}

Section 11 describes the use of exceptions (and also cookies, which may be used for another kind of user authentication).

5.4 Forms

Ordinary web methods react on HTTP GET requests, as explained earlier. The response can be an XHTML page containing a form that uses GET or POST. By using a SubmitHandler as form action, the program code that produces the form becomes tightly coupled with the code that receives the field values. Here is an example of a web method that produces a form and receives a text field and an uploaded file:

Upload.xact - a file upload form
public class Upload extends WebApp {

  XML wrapper = [[
    <html>
      <head><title>Upload</title></head>
      <body>
        <[BODY]>
      </body>
    </html>
  ]];

  public XML upload() {
    return wrapper.plug("BODY", [[
      <form method="post" enctype="multipart/form-data" action=[ACTION]>
        Enter some text: <input type="text" name="t"/> <br/>
        Upload a file: <input type="file" name="f"/> <br/>
        <input type="submit" value="Go!"/>
      </form>
    ]].plug("ACTION",
      new SubmitHandler() {
        public XML run(String t, FileField f) {
          return wrapper.plug("BODY", [[
            Your text: <{ t }> <br/>
            Size of your file: <{ f.getSize() }>
          ]]);
        }
    });
}

The SubmitHandler contains a run method that processes the form field values. The response of this method is either

XML
- (as in the example above) an XML value that is sent directly back to the client,
URL
- resulting in a redirection to the given location using the POST-redirect-GET pattern, or
void
- resulting in a redirection to the URL of the web method that led to the SubmitHandler.

The latter case is useful in combination with the ability of modifying an existing web page, as shown in the example application GuessingGame.

SubmitHandlers are subject to regeneration. See Section 6.1.

6. Caching

Response from web methods is automatically cached. HTTP ETag and Last-Modified headers are inserted to support client-side caching. Additionally, a built-in web method (cache) handles server caching and conditional GET requests. Since web methods are associated with GET requests, a cached page can always safely be regenerated by executing the web method again (although this may, of course, lead to different page content).

6.1 Page regeneration

When event handlers (such as submit handlers) are added to a page this event handler object is stored in the cache along with the generated XML page itself. When the client interacts with the server, and a request is sent to one of the handlers on the page, the page must therefore be retreived from the cache to find the appropriate handler. There are two situations where this may fail

In these situations, JWIG will attempt page regeneration and generate the original page again make the submit handler available for the new request. Reconstruction is attempted by regenerating the original page by sending a request to the same URL that originally made the handler available. A JWIG response must therefore be reconstructable in the sense that a request to a specific URL must always return the same set of event handlers.

6.2 Invalidating cached pages

Occasionally, the programmer needs to invalidate a cached pages because data has been changed. In JWIG an explicit representation of the relationship between data objects and cached pages is used to enable this invalidation.

JWIG holds a dependency map from data objects to pages that depend on them. To add a dependency for the current page on an object, use the addResponseInvalidator method, When the data object is changed the update method must be called for JWIG to invalidate all cached pages depending on the object. JWIG represents this relationship efficiently.

The database system integrates with this such that when a data object is taken as a parameter to a web method addResponseInvalidator is automatically called with this object and when an object is updated in the databasae the update update method is called.

The example application QuickPoll shows how to use addResponseInvalidator.

example?

See also in Section 5.3 how to disable the cache web method in relation to user authentication.

7. Session state

The class Session makes it easy to encapsulate session state and identifying it by IDs that can be passed as parameters to web methods.

A common way of using sessions is to write a subclass of Session containing the actual session state, such as shopping cart contents, create an instance in one web method, and then pass that around to other web methods that need access to the session state:

Sessions
class UserState extends Session {
  List<Item> shopping_cart; // contains user state
}

public URL entry() {
  UserState s = new UserState();
  ... // initialize the new session
  return makeURL("shopping", s);
}

public XML shopping(UserState s) {
  ... // s contains the session state
}

Session data is thus passed explicitly between web methods and represented in a type-safe manner avoiding all the pitfalls of traditional String-to-Object session maps that are never cleaned up and are prone to name clashes (for example if a user runs through the page using two tabs simultaniously). Furthermore, when adding the session id to the URL it is ensured that each URL represents a single resource in that two different sessions will have two different URLs.

A session management thread keeps track of the mapping from session IDs to session objects (via toString and valueOf; see Section 5) and automatically garbage collects session objects that have not been accessed in some time (as configured in the Session constructor). If jwig.auto_refresh_sessions is set (see Section 9), session objects are automatically being refreshed regularly as long as some user is viewing a page holding the session object. (This means that it is in most cases unnecessary to write things like "this session will timeout after N minutes, make sure the form data is submitted before then".)

The example application GuessingGame demonstrates the use of Sessions.

8. Client side programming

While the JWIG framework is server-based and all computation takes place on the server side, it is possible to create dynamic applications in JWIG by using two primitives, namely the ability to update a page on the client side and the ability to capture client side events. This model allows the programmer to build user interfaces using little or no JavaScript.

8.1 Automatic view updates

JWIG makes it possible to update the XML contents of a page being shown. These updates are automatically propagated to the clients using a Comet/AJAX system implemented for JWIG.

An XMLProducer is responsible for generating a fragment of the XML that may be updated and propagated to the client at any time. The XMLProducer is specific to the objects that is used to generate its contents and thus the same XMLProducer can be used in multiple places. The XMLProducer must implement a run method that is used to generate its content. This method can be called any number of times and is specifically called again when the data that the XMLProducer depends on is changed. The XMLProducer can take an observable object as argument and is thus notified by this object when a change has happened. It may also simply rely on the cache system to tell that an object has changed. In that case nothing is required for the XMLProducer to work. Everything is inferred from the context. See the section on caching for details.

This example shows a page with a highscore for some game. Whenever the highscore is changed, the database system notifies the XMLProducer to invalidate its current value. The XMLProducer is then executed again and the new value is sent to the client.

XMLProducer example
public void ajaxy() {
    XML page = ...;
    page = page.plug("NAME", new XMLProducer() {
        public XML run() {
            HighScore highscore = Game.getCurrentGame().getHighScore();
            return highscore.getName();
        }
     });
}

8.2 HTML events

The EventHandler class is used to respond to client side HTML events. It can be attached to any where in the code where an event handler is expected. The EventHandler must contain a run method that is responsible for handling the event on the server side. This run method is able to take parameters just like a SubmitHandler. The EventHandler is plugged into a place where an event handler can be attached and it will respond to that event. For example consider an EventHandler that responds to an onClick event:

EventHandler example
XML x = [[...<input type="button" value="Click me" onClick=[HANDLER] >...]]
  .plug("HANDLER", new EventHandler() {
    public void run() {
        log.info("User clicked the button");
    }
});

EventHandlers are subject to regeneration. See Section 6.1.

9. Configuration

JWIG uses a common configuration system that allows properties to be specified declaratively in a separate file and operationally at runtime. First, properties can be written in the file jwig.properties, as this example:

  jwig.base_url = http://services.brics.dk/java
  jwig.base_url_secure = https://services.brics.dk/java
  jwig.hibernate = true

  hibernate.connection.username = jdoe
  hibernate.connection.password = ToPsEcReT
  hibernate.connection.url = jdbc:mysql://mysql.cs.au.dk/jdoe

  mail.transport.protocol = smtp
  mail.host = cs.au.dk
Second, properties can be set (typically during initialization of the WebSite or WebApp) using setProperty. Properties for the WebSite are shared for all web applications and can be overridden locally in each WebApp. To read a property, use getProperty. The names of JWIG specific properties all begin with jwig. Note that reasonable defaults have been selected for all properties, so simple JWIG applications can be created without explicitly setting any configuration.

The jwig.properties file should be placed in the base folder of the classloader (I.e. in the folder that holds the classes that belong to the default package) at runtime.

A complete list of JWIG configuration properties is available in the API documentation of the WebSite class.

10. Persistence with Hibernate

This section is by no means meant as a complete guide to the Hibernate framework. It is only meant as a reference about how to enable Hibernate for use in JWIG programs.

While Hibernate is a powerful framework that requires some work to master, the basics can be learned quickly. See the Hibernate Getting Started document at http://www.hibernate.org/152.html

Most web applications need to store data externally. For this purpose JWIG integrates closely with the Java ORM framework Hibernate. To enable Hibernate you will need a Database server and a JDBC driver for the database. Furthermore mappings between objects and database table must be specified and based on this Hibernate basically generates SQL for the database server. All popular databases have their own SQL dialect so Hibernate needs to be set up to use the right one. Make sure that your database in on the list of list of supported databases, it most probably is.

10.1 Setting up your database connection and dialect

JWIG defaults to MySQL, so if you use MySQL as your database, you will not need to set the dialect. The dialect classes for the most popular databases can be found on this list:

DatabaseDialect
PostgreSQLorg.hibernate.dialect.PostgreSQLDialect
Microsoft SQL Serverorg.hibernate.dialect.SQLServerDialect
Oracle 9i/10gorg.hibernate.dialect.Oracle9Dialect
For the full list, please the refer to the Hibernate documentation

To set the database dialect, set the property 'hibernate.dialect' in either jwig.properties or using the setProperty method on WebSite. Please refer to Section 9 for details on configuration.

Second you will have to set the class name for your JDBC driver. Again this is done for MySQL. If you use another database, please set the property 'hibernate.connection.driver_class' in the same way as above to the qualified name of you driver class. This class name can be found on the web site of the JDBC driver.

10.2 Setting up username and password

Finally you will need to set the following properties in the JWIG configuration (see Section 9):

PropertyContents
hibernate.connection.usernameYour database username
hibernate.connection.passwordYour database password
hibernate.connection.urlConnection URL for you database, for example jdbc:mysql://mysql.cs.au.dk/schwarz
jwig.hibernateSet this to 'true' to enable Hibernate support

10.3 Persistable objects

The heart of the JWIG-Hibernate bridge is the Persistable interface. To enable persistence of a class this class must implement the Persistable interface. The only thing that has to be implemented is that the object must have an Id property of type Integer. An implementation is provided as AbstractPersistable, extending this class will give your class the required field, getter, and setter. The Id must of course be unique for the given object like always with a database. This allows JWIG to refer to persistable objects by their Id in URL etc. Below we will assume that such a class called User exists.

More advanced queries can be made using the standard Hibernate framework. The session factory can be obtained using the static method HibernateQuerier.getSessionFactory() and Hibernate sessions can be obetained through the getCurrentSession() method of this object. It is beyond the scope of this manual to explain how queries in general work in Hibernate so please refer to the Hibernate manual and tutorials.

10.4 Querying

The other central interface is the Querier interface. This interface gives an instance of a persistable given its class and its Id. You can get the active querier from WebSite.getQuerier(). This is also the method you want to override if you need to define your own querier. Using this an object can be queried from the database like this:

Object querying
        User u = getWebSite().getQuerier().getObject(User.class,1);
        
This will return the user from the database with Id 1 or null if no such user exists. The Hibernate implementation of the Querier is called HibernateQuerier, and if Hibernate is not enabled, a place holder querier is active which will fail when queried.

10.5 Mapping objects

Creating database mappings for your classes are done entirely using the Hibernate framework. A good place to start is to look at the users manual and the swarm of Hibernate tutorials on the web. When you have created the mappings, load them from your web app contructor. This is done using the HibernateQuerier class like this:

Loading a mapping
            HibernateQuerier.getConfig().addClass(User.class);
          
where User is a class that has a hibernate mapping in a file called User.hbm.xml in the same folder as User.class.

10.6 Taking persistable parameters

Persistable objects can be used as parameters to web methods just like classes with a valueof(String) method. The difference is that persistable object will be serialized not by their toString() method, but by their getId() method. JWIG then queries the object from the database when needed.

Example of persistable parameter passing
public XML viewUser(User user) {
    //User (as mapped above) is automatically queried from the database and passed as parameter
}

//Furthermore, makeURL can create URLs to such methods
public URL gotoUser(User user) {
    return makeURL("viewUser", user);
}

10.7 Database cache

For performance reasons the database can cache the objects that are created to represent database entities. Caching is enable by spefifying a <cache> element in the mapping file of the entity you want to cache. JWIG is set up so a cache is available and ready to use, but for performance reasons in a real world setting, you should replace it with the EHCache framework by putting this line in your jwig.properties:

EHCache install
hibernate.cache.provider_class=org.hibernate.cache.EhCacheProvider
Furthermore you should create an ehcache.xml configuration file. Read more here.

11. Miscellaneous convenience features

11.1 Error reporting and logging

A built in web method with maximal priority takes care of catching all exceptions thrown by the ordinary web methods and reporting errors to the users. The following exceptions are particularly relevant:

JWIGException
- base class for all JWIG runtime exceptions (results in "500 Internal Server Error")
AccessDeniedException
- thrown when the client is denied access to a requested resource ("403 Forbidden")
AuthorizationRequiredException
- thrown when the client should resend the request with HTTP Basic authentication information ("401 Unauthorized"), see Section 5.3
BadRequestException
- thrown when the HTTP request contains errors ("400 Bad Request")
ServerBusyException
- thrown when the server is overloaded ("503 Service Unavailable")
PersistenceException
- thrown if the persistence system is misconfigured ("500 Internal Server Error"), see Section 10
SessionDefunctException
- thrown when trying to fetch a non-existing session from the session state manager ("410 Gone")

JWIG uses log4j for logging, and the JWIG runtime system automatically logs many internal events. A Logger object for logging application specific events can be obtained by using the factory method on Logger like this:

Obtaining a logger
Logger log = Logger.getLogger(WEBAPP.class);

where WEBAPP is the name of your web app class. See also the configuration properties (Section 9) whose name start with log4j. The following example writes a message to the log with level INFO:

Writing to the log
log.info("10-4 Rubber Duck");

In some cases it can be expensive to create the string that is printed to the log. In that case, test if the log is enabled for the relevant level before generating the string:

Testing log level
if(log.isInfoEnabled())
    log.info(getComplicatedStringThatTakesALongTimeToCompute());

Log4j can give fine-grained control of what loggers print. It can be configured at class or package (including sub-package) level so that different log levels are used for different program parts. The standard JWIG configuration is to set the log level to print all log statements of at least level INFO to System.out. If you want better control of the output you should initialize Log4j yourself this in your Main class. See this Log4j tutorial for more information.

11.2 Returning plain text

Web methods can return plain text (media type text/plain) instead of XML or redirecting, simply by returning a string instead of an XML value or a URL:

HelloWorld2.java - returning plain text
public class HelloWorld2 extends WebApp {

  public String hello() {
    return "Hello World";
  }
}

11.3 Low-level servlet input/output

In the rare case that you need access to the underlying HttpServletRequest or HttpServletResponse object, these can be obtained using getServletRequest and getServletResponse. To avoid interfering with the JWIG system, only use getServletResponse with filter web methods (see Section 5.3). One use of this is for generating binary output by streaming directly to the servlet output stream.

To generate URLs to web application resources, see the methods getURL, makeURL, getWebSiteURL, and getWebAppURL.

11.4 Cookies

The method getCookies returns a (non-null) array of cookies occurring in the request, and addCookie adds a cookie to the response.

The following example shows how to use cookies for authentication:

Cookie authentication
@URLPattern("restricted/**")
public void accessCookie() {
  String key = null;
  for (Cookie c : getCookies())
    if (c.getName().equals("key"))
      key = c.getValue();
  if (key == null || !key.equals("87"))
    throw new AccessDeniedException("You shall not pass!")
  next();
}

Here, accessCookie is a filter web method that checks in every request matching restricted/** whether a cookie named key with value 87 is provided.

11.5 Sending emails

JWIG uses JavaMail for sending emails:

Emails
import javax.mail.*;
import javax.mail.internet.*;
import dk.brics.jwig.*;

public class EmailTest extends WebApp {

  public String send() throws MessagingException {
    Email e = new Email();
    e.setText("This is a test!");
    e.setSubject("JWIG email test");
    e.setSender(new InternetAddress("amoeller@cs.au.dk"));
    e.addRecipients(Message.RecipientType.TO, "amoeller@cs.au.dk");
    SendFailedException ex = sendEmail(e);
    if (ex == null)
      return "Email sent!";
    else
      return ex.toString();
  }
}

Configuration properties (see Section 9) whose name start with mail. are used by JavaMail. In jwig.properties set (if you are at our department at University of Aarhus):

 mail.transport.protocol = smtp
 mail.host = cs.au.dk

11.6 Debugging applications

You can attach a remote debugger to your JWIG program by starting Tomcat with the following options:
 -Xdebug
 -Xnoagent -Xrunjdwp:transport=dt_socket,address=127.0.0.1:8000,server=y,suspend=n
(On Windows, edit the Java Options in 'configure Tomcat'.) You may want to use a different value of address. Set your IDE to use the same address for remote debugging (in Eclipse start the debugger with a Remote Java Application), and you can now use the debugger while Tomcat is running.

12. Features under development

The features described below are only partially implemented or merely being considered for future releases of JWIG. Comments and suggestions are welcome!

12.1 Session threads

A central feature in the first version of JWIG was session threads, as explained in the article Extending Java for High-Level Web Service Construction, by Christensen, Møller, and Schwartzbach, ACM Transactions on Programming Languages and Systems, 25(6), 2003. Our new notion of SubmitHandlers has largely made session threads obsolete, though.

12.2 HTML extension libraries

In preparation.

13. The JWIG program analysis suite

The design of JWIG allows some specialized program analyses to be performed, such that the programmer can check - at compile time - that certain kinds of errors cannot occur at runtime. The JWIG analyzer considers the following properties for a given program:

Additionally, the program analysis can produce a global control-flow graph of a web application to visualize its structure.

NOTE: The program analyses are not completed in the current version of JWIG. (For now, see the earlier publications on JWIG and Xact.)

Examples

14.1 QuickPoll

Example: QuickPoll
    package quickpoll;

    import dk.brics.jwig.*;
    import dk.brics.xact.*;

    @URLPattern("quickpoll")
    public class QuickPoll extends WebApp {

      XML wrapper = [[
        <html>
          <head><title>QuickPoll</title></head>
          <body>
            <h1>QuickPoll</h1>
            <[BODY]>
          </body>
        </html>
      ]];

      class State {
        String question;
        int yes;
        int no;
      }
  
      State state = new State();
  
      @URLPattern("")
      public XML index() {
        return wrapper.plug("BODY", [[
          <ul>
            <li><a href={makeURL("init")}>Initialize</a> (access control)</li>
            <li><a href={makeURL("vote")}>Vote</a></li>
            <li><a href={makeURL("results")}>View results</a></li>
          </ul>
        ]]);
      }
  
      @URLPattern("init")
      public void authenticate() {
        User u = getUser();
        if (u != null && u.getUsername().equals("jdoe") && u.getPassword().equals("42")) 
          next();
          else
            throw new AuthorizationRequiredException("QuickPoll");
      }
  
      public XML init() {
        return wrapper.plug("BODY", [[
          <form method="post" action=[INIT]>
            What is your question?<br/>
            <input name="question" type="text" size="40"/>?<br/>
            <input type="submit" value="Register my question"/>
          </form>
        ]]).plug("INIT", new SubmitHandler() {
          XML run(String question) {
            synchronized (state) {
              state.question = question;
              state.yes = state.no = 0;
            }
            update(state);
            return wrapper.plug("BODY", [[
              Your question has been registered.
              Let the vote begin!
            ]]);
          }
        });
      }

      public XML vote() {
        if (state.question == null)
          throw new AccessDeniedException("QuickPoll not yet initialized");
        addResponseInvalidator(state);
        return wrapper.plug("BODY", [[
          <{state.question}>?<p/>
          <form method="post" action=[VOTE]>
            <input name="vote" type="radio" value="yes"/> yes<br/>
            <input name="vote" type="radio" value="no"/> no<p/>
            <input type="submit" value="Vote"/>
          </form>
        ]]).plug("VOTE", new SubmitHandler() {
          XML run(String vote) {
            synchronized (state) {
              if ("yes".equals(vote))
                state.yes++;
              else if ("no".equals(vote))
                state.no++;
            }
            update(state);
            return wrapper.plug("BODY", [[
              Thank you for your vote!
            ]]);
          }
        });
      }
  
      public XML results() {
        return wrapper.plug("BODY", new XMLProducer(state) {
          XML run() {
            synchronized (state) {
              int total = state.yes + state.no;
              if (total == 0)
                return [[No votes yet...]];
              else
                return [[
                  <{state.question}>?<p/>
                  <table border="0">
                    <tr><td>Yes:</td><td><{drawBar(300*state.yes/total)}></td><td><{state.yes}></td></tr>
                    <tr><td>No:</td><td><{drawBar(300*state.no/total)}></td><td><{state.no}></td></tr>
                  </table>
                ]];
            }
          }
        });
      }
  
      private XML drawBar(int length) {
        return [[<table><tr><td bgcolor="black" height="20" width={length}></td></tr></table>]];
      }
    }

14.2 Example: MicroChat

Example: QuickPoll
    package microchat;

    import java.util.*;
    import dk.brics.jwig.*;
    import dk.brics.xact.*;

    @URLPattern("microchat")
    public class MicroChat extends WebApp {

        class Messages {
          List<String> ms = new ArrayList<String>();
      
          void add(String msg) {
            ms.add(msg);
            update(this);
          }
      
          void reset() {
            ms.clear();
            update(this);
          }
        }
    
        Messages messages = new Messages();

        @URLPattern("")
        public XML run() {
            return [[
              <html>
                <head>
                  <title>MicroChat</title>
                </head>
                <body>
                  <{ 
                    new XMLProducer(messages) {
                      XML run() {
                          if (!messages.ms.isEmpty()) 
                              return [[
                                <ul>
                                  <{ [[<li><[MSG]></li>]].plugWrap("MSG", messages.ms) }>
                                </ul>
                              ]];
                        else
                              return [[]];
                        }
                    } 
                  }>
                  <form method="post" action=[SEND]>
                    <input type="text" name="msg"/>
                    <input type="submit" value="Send!"/>
                    <p/>
                    <input type="button" value="Reset" onclick=[RESET]/>
                  </form>
                </body>
              </html>
            ]]
            .plug("SEND", new SubmitHandler() {
                void run(String msg) {
                messages.add(msg);
              }
            })
            .plug("RESET", new EventHandler() {
                void run() {
                messages.reset();
              }
            });
        }
    }
        
  

14.3 Example: GuessingGame

...