Forms

The traditional way in which data is sent to the server in a non-TSA environment is via form submission (posting). Form submission is occasionally employed in TSA, e.g. in order to use existing authentication mechanisms, but it is the exception rather than the rule. The typical way in which data is sent to the server in TSA applications is via methods on client models. This can be done with or without the aid of an HTML form, depending on the application as well as your own personal preference. This document describes a few options available to the Project Avatar developer.

Sending Data Without Forms

Perhaps the simplest way to send data to a server is by intercepting a UI event and invoking a method in a client model using an EL expression. For example,

<script data-type="ItemModel" data-instance="item"
        data-url="data/items/#{this.key}"</script>

<label for="key">Item Key: </label>
<input id="key" data-value="#{item.key}"><br>
<button onclick="#{item.put()}">PUT</button>

This example intercepts the onclick event on an HTML button and invokes the put method on the REST model instance item, pushing the new data to the server every time the button is clicked.

Sending Data Using Forms

Alternatively, an HTML form can be used and its onsubmit event intercepted to invoke the model’s method as follows:

<script data-type="ItemModel" data-instance="item"
        data-url="data/items/#{this.key}"</script>

<form onsubmit="#{item.put()}">
    <label for="key">Item Key: </label>
    <input id="key" data-value="#{item.key}"><br>
    <button>PUT</button>
</form>

The invocation of put is moved from the button’s onclick event to the form’s onsubmit event. Note that in order to prevent form submission, and consequently a page reload, the value of the expression in the onsubmit attribute must return false. A value of undefined, returned by any void JavaScript function, is automatically converted to false by the Project Avatar runtime on all event handlers like onsubmit. Thus, the example above pushes the data to the server every time the button is clicked, without ever actually submitting the form given that by default the put method returns undefined.

Authentication

This document describes how to build a Project Avatar application that uses container-managed authentication on a Java EE application server such as Glassfish. In particular, it focuses on servlet-based authentication using form login and sessions. For more information about this type of authentication, the reader is referred to the Java EE Tutorial.

Form-based Authentication

In form-based authentication, a login page is provided for a user to type in a name and a password that are posted to a well-defined URL path, namely /j_security_check. Upon receiving this request, the servlet container and not the application, extracts the form parameters and verifies the credentials against a pre-configured realm. Successful verification results in a session being created and a token (or cookie) sent back to the browser for future requests. A request that comes with the aforementioned token is deemed as authenticated, and access is granted according the established authorization rules.

Application Structure

In order to expose login forms and protect other resources to un-authenticated users, a Project Avatar application must be broken down into at least two modules. The first module contains the login form and must be un-protected; the second, or in general the other modules, contain the application itself and are only accessible to authenticated users.

In what follows we will use the login sample in the Project Avatar distribution as guide on how to build applications with user authentication support. Here is the file structure for the login application:

    <html data-namespace="http://www.example.org/login/form">
        <head>
            <META http-equiv="Content-Type" content="text/html; charset=UTF-8">
            <title>Login</title>
        </head>
        <body>
            <div data-widget="view" id="login" data-title="Login" data-props="createHtml: true">
                <form method="POST" action="j_security_check">
                    <label for="user">Username: </label>
                    <input id="user" name="j_username"/><br>
                    <label for="pass">Password: </label>
                    <input id="pass" name="j_password" type="password"/><br>
                    <button type="submit">Login</button>
                </form>
            </div>
            <div data-widget="view" id="failed" data-title="Login" data-props="createHtml: true">
                <h3>Authentication failed, please try again</h3>
                <form method="POST" action="j_security_check">
                    <label for="userf">Username: </label>
                    <input id="userf" name="j_username"/><br>
                    <label for="passf">Password: </label>
                    <input id="passf" name="j_password" type="password"/><br>
                    <button type="submit">Login</button>
                </form>
            </div>
        </body>
    </html>
login
|-- WEB-INF
|   |-- glassfish-web.xml
|   `-- web.xml
|-- avatar.properties
|-- service
|   `-- src
|       `-- main.js
`-- view
    |-- org.example.login
    |   `-- src
    |       `-- app.html
    `-- org.example.login.form
        `-- src
            `-- form.html

This application consists of two modules: org.example.login and org.example.login.form. The former contains a single HTML file that defines the application itself and that must only be accessible to authenticated users; the latter defines views that will be used to generate two HTML pages for the login form and the failed login form. Let’s take a look at these now:

    <html data-namespace="http://www.example.org/login/form">
        <head>
            <META http-equiv="Content-Type" content="text/html; charset=UTF-8">
            <title>Login</title>
        </head>
        <body>
            <div data-widget="view" id="login" data-title="Login" data-props="createHtml: true">
                <form method="POST" action="j_security_check">
                    <label for="user">Username: </label>
                    <input id="user" name="j_username"/><br>
                    <label for="pass">Password: </label>
                    <input id="pass" name="j_password" type="password"/><br>
                    <button type="submit">Login</button>
                </form>
            </div>
            <div data-widget="view" id="failed" data-title="Login" data-props="createHtml: true">
                <h3>Authentication failed, please try again</h3>
                <form method="POST" action="j_security_check">
                    <label for="userf">Username: </label>
                    <input id="userf" name="j_username"/><br>
                    <label for="passf">Password: </label>
                    <input id="passf" name="j_password" type="password"/><br>
                    <button type="submit">Login</button>
                </form>
            </div>
        </body>
    </html>

First, the data-namespace attribute states that this page is defined in the namespace identified by http://www.example.org/login/form. Project Avatar uses a similar convention to JAXB and JAX-WS, and maps this URL to the org.example.login.form module. In a nutshell, the “www.” part is dropped, the rest of the host name components reversed and the paths appended from left to right. Second, the page defines two views, both of which set the createHtml attribute to true. This informs the Project Avatar compiler that a separate HTML must be generated for each view. We shall see the purpose of this command when we inspect the web.xml file for this application. Third, each of the views defines a similar HTML form that posts a user name (j_username) and a password (j_password) to the /j_security_check path for authentication purposes —the second view simply adds an error message to instruct the user to login again.

The objective of separating this application into two modules is to ensure that only the login forms are available to un-authenticated users. Which resources are protected, and which are not, can be defined in the file web.xml using the security-constraint element. Before diving into this file, let us review the file structure of the compiled Project Avatar application:

login
|-- WEB-INF
|   |-- glassfish-web.xml
|   `-- web.xml
|-- avatar.properties
|-- service
|   |-- bin
|   |   `-- main.js
|   `-- src
|       `-- main.js
`-- view
    |-- bin
    |   |-- org
    |   |   `-- glassfish
    |   |       `-- avatar.js
    |   |-- jquery
    |   |   |-- ...
    |   `-- org
    |       `-- example
    |           |-- login
    |           |   `-- form.js
    |           `-- login.js
    |-- css
    |   `-- avatar.css
    |-- failed.html
    |-- index.html
    |-- login.html
    |-- org.example.login
    |   `-- src
    |       `-- login.html
    `-- org.example.login.form
        `-- src
            `-- form.html

Focusing on the view modules, we see that module org.example.login is compiled in bin/org/example/login.js and that module org.example.login.form is compiled in bin/org/example/login/form.js. Hence, anything under bin/org/example/ should be protected and anything under bin/org/example/login/ should be unprotected to enable users to login into the application. Here is the web.xml file for this application:

<web-app ...>
    <display-name>Login Example</display-name>
    <description>A login example app</description>

    <session-config>
        <session-timeout>1</session-timeout>
    </session-config>

    <security-constraint>
        <web-resource-collection>
            <web-resource-name>protected</web-resource-name>
            <url-pattern>/*</url-pattern>
            <http-method>GET</http-method>
            <http-method>PUT</http-method>
            <http-method>POST</http-method>
        </web-resource-collection>
        <auth-constraint>
            <role-name>user</role-name>
        </auth-constraint>
    </security-constraint>

    <security-constraint>
        <web-resource-collection>
            <web-resource-name>unprotected</web-resource-name>
            <url-pattern>/images/*</url-pattern>
            <url-pattern>/css/*</url-pattern>
            <url-pattern>/bin/org/glassfish/*</url-pattern>
            <url-pattern>/bin/dojo/*</url-pattern>
            <url-pattern>/bin/jquery/*</url-pattern>
            <url-pattern>/bin/jquery.mobile/*</url-pattern>
            <url-pattern>/bin/org/example/login/*</url-pattern>
        </web-resource-collection>
    </security-constraint>

    <login-config>
        <auth-method>FORM</auth-method>
        <realm-name>file</realm-name>
        <form-login-config>
            <form-login-page>/login.html</form-login-page>
            <form-error-page>/failed.html</form-error-page>
        </form-login-config>
    </login-config>

    <security-role>
        <role-name>user</role-name>
    </security-role>
</web-app>

The first instance of security-constraint sets the default access as protected for every resource; the second instance of security-constraint sets the status as unprotected for every resource under bin/org/example/login/* as well as every other resource that is part of the Project Avatar runtime and is needed to render the login form. The login-config element defines the authorization method, the realm and the paths to the login forms. For a user to have access to the application, it must be registered in the Java EE container’s realm —the file realm in the example above.

The main application module is shown next. This is a simple application that retrieves a timestamp from the server via a REST model and corresponding service. There are two ways in which a session, and its corresponding token or cookie, can be invalidated: (i) via an explicit logout triggered by the user and (ii) as a result of a session timing out.

    <html data-main="true" data-namespace="http://www.example.org/login">
        <head>
            <META http-equiv="Content-Type" content="text/html; charset=UTF-8">
            <title>Login</title>
        </head>
        <body>
            <script data-model="rest">
                var NowModel = function() {
                    this.now = "";
                };
            </script>
            <script data-type="NowModel" data-instance="date" data-url="data/now"></script>

            <h2>Timestamp from Server</h2>
            <div>
                <span id="output">#{date.now}</span>
                <button onclick="#{date.get()}">Refresh</button>
            </div>
            <br>
            <div>
                <form method="POST" action="j_security_logout">
                    <button type="submit">Logout</button>
                </form>
            </div>
        </body>
    </html>

Project Avatar provides a convenient path /j_security_logout to trigger an explicit logout. In the example above, a Logout button is provided for the user to explicitly terminate the session. If a session expires while a user is still interacting with an application, accessing any REST resource from will redirect the browser to the login form again. Because of this reason, it is imperative to configure the caching policy correctly to avoid getting the login form as the value of the cached REST resource after the user is authenticated again. This can be done in the Project Avatar properties file as shown next:

# Configuration options
debug=true
cache.control=no-cache
debug.cache.control=no-cache

By setting cache.control and debug.cache.control (only needed in debug mode) to no-cache, the browser will not attempt to cache a REST resource and, thus, will not return the login form as the cached value of a REST resource that was accessed after a session expired.

Themes

An application’s theme can be set in two ways:

  1. The application avatar.properties file. Set the “theme” property to point to a theme. For example:
theme=smoothness
  1. The compile command line option. The –theme command line option will override the theme property in the avatar.properties file. For example:
avatar compile --theme=redmond  [application]

Using Provided Themes

Project Avatar comes bundled with a few themes. For jquery, the bundled themes are:

  • avatar (default)
  • redmond
  • smoothness

For dijit, the default theme is “claro” and is the only bundled theme.

Using Custom Themes

Besides the bundled themes, an application can use a custom theme. To use a custom jquery theme do the following:

  • Copy the theme directory to [application-dir]/view/bin/jquery/css. The theme css file should be named ‘jquery.ui.theme.css’. The jquery ui css corresponding to the theme should be named ‘jquery-ui.min.css’. For example, for a theme ‘foo’, the path to the theme css file is [application-dir]/view/bin/jquery/css/foo/jquery.ui.theme.css.
  • Set the theme using one of the mechanisms described above.

A popular set of themes for jquery can be found at ThemeRoller. To use one of the themes, for example, “dark-hive”, do the following:

  • Download the jquery themes from ThemeRoller and extract the “dark-hive” theme directory.
  • Copy this directory to your application at [application-dir]/view/bin/jquery/css/dark-hive.
  • Set the theme using one of the two methods described above.

Dojo

Project Avatar provides a pre-defined set of widgets based on the ‘dijit’ UI components from Dojo. These are packaged as an extension that can be downloaded and added to an existing Project Avatar installation.

Once installed, switching your application to use them is as simple as adding the following line to your avatar.properties file:

widgetLib=dijit

Download the extension jar and place it in the avatar-ext directory appropriate for your Project Avatar installation.

On GlassFish:

${AVATAR_HOME}/modules/avatar-ext

PhoneGap

PhoneGap is an open source framework that allows you to create mobile applications using standardized web APIs that take advantage of the HTML browser libraries available on iOS, Android, Blackberry and Windows.

Follow these steps to use PhoneGap in your Project Avatar application:

  • Create a Project Avatar application
    avatar new [application]
  • Download PhoneGap. This will be a zip file. Unzip the file and copy cordova-2.6.0.js in the avatar/view directory of your Project Avatar application.
  • Follow instructions at: Getting Started to setup a phone gap project for the desired platform. For Mac, this will be an XCode project. The project will contain a “www” directory.
  • Compile the Project Avatar application:
    avatar compile [application]
  • Copy the compiled Project Avatar application under the www directory of the PhoneGap project created in step 2.
  • Run the application on the PhoneGap simulator or actual device. Follow instructions at the PhoneGap website to run the application.

You can also take a look at the Using PhoneGap with Avatar blog for more information.

Back to top