X

Building An Ajax-Enabled Web Application Using Phobos and jMaki

Guest Author

by Roberto Chinnici

Phobos is a lightweight, scripting-friendly, web application
environment that runs on the Java platform. Using Phobos, you can take advantage of the benefits offered by
scripting languages and leverage the power of the Java platform. Being scripting-friendly, Phobos provides
a programming environment that fosters rapid application development. The primary language supported by Phobos is JavaScript,
which Phobos supports using the Mozilla Rhino scripting engine.

Scripting languages can be powerful and convenient. They also enable an interactive form of development in which
you can progressively refine the behavior of an application until it is ready for deployment and use. This is especially
important in developing Ajax-enabled web applications. These applications typically require a lot of
interactive in-browser testing and refinement. In addition to enabling an interactive mode of development, Phobos allows
scripting developers to call into any Java code at any time. As a scripting developer, you can reuse APIs,
libraries, and frameworks that run on the Java platform. Using Phobos offers a "best of both worlds" approach,
in which you can write "soft" -- often changing code -- in a scripting language, and write
"hard" -- rarely modified code -- in a compiled language such as the Java programming language.

In this tip, you'll use Phobos and jMaki to create a simple Ajax-enabled web application. The jMaki framework
is a lightweight framework for creating Web 2.0 applications using standards-based technologies such as
CSS, HTML, and JavaScript. For an introduction to jMaki, see the January 27, 2007 Tech Tip
Introduction to jMaki.

You will build the application using the NetBeans IDE and
deploy the application to the GlassFish application server.
The tip assumes that you have NetBeans IDE 6.1
and the
GlassFish v2ur2 application server
installed. You can install them together by installing the
Web & Java EE
version of NetBeans IDE 6.1
.

A
package
that contains the code for the sample application accompanies the tip.
The code examples in the tip are taken from the source code of the sample (which is included in the package).

The Phobos Framework


The key to understanding how a Phobos application works is to become familiar with the underlying framework.

In Phobos, whenever a request comes in to the servlet container, the container invokes the Phobos servlet. The Phobos
servlet then delegates the handling of the request to the Phobos framework, which is written in JavaScript. The framework
attempts to match the request URI with a certain number of predefined patterns. When a match is found, the framework
invokes the script or controller associated with that pattern.

In Phobos there are many ways to handle a HTTP request. The simplest way is by writing a plain script which has access
to two predefined variables called request and response. These variables hold a reference to
the HttpServletRequest and HttpServletResponse that the servlet container creates. The
user-written script can then perform the appropriate request-handling logic and produce a response.

Although scripts are in principle sufficient to cover every task, it is better to follow a more structured
approach based on the MVC (model-view-controller) pattern. In Phobos, all three components are written in JavaScript.
The controller is a JavaScript class hosted inside a script whose name must match that of the controller. The view is an
Embedded JavaScript (EJS) file, that is, a file that contains HTML with embedded JavaScript statements and expressions.
The definition of the model is left to the application. Typically, the model consists of a mix of JavaScript and Java
objects.

To learn more about the Phobos framework, see
An Overview of Phobos.

The Application

This tip uses Phobos to reimplement the PHP application that Ludovic Champenois presented in the
June 16, 2008 Tech Tip
Using jMaki with
PHP on OpenSolaris
.
See "The Sample Application" section of that tip for a description of the application.
Figure 1 shows a web page displayed by that application.













A Web Page from the PHP Application

Figure 1. A Web Page from the PHP Application



Notice that the PHP application uses MySQL as the database. However, the Phobos version of the application uses
JavaDB, rather than MySQL. You'll find the Java DB database bundled with GlassFish v2ur2.

Install the Phobos Plugins in NetBeans IDE 6.1

Before building the application, you need to add support for Phobos to the NetBeans 6.1 IDE. This support
is provided by Phobos-related plugins which include functionality such as a new Phobos project type
and a syntax-aware editor for EJS pages

To install the Phobos plugins:


  1. Select Plugins in the Tools menu of the IDE. This opens the Plugins window.
  2. Click the Available Plugins tab if it's not already selected.
  3. Check the checkboxes for the EJS and NetBeans 6 Phobos support plugins in the Phobos category
    as shown in Figure 2.













    Selecting the Phobos Plugins

    Figure 2. Selecting the Phobos Plugins




  4. Click the Install button. If it is not already installed, NetBeans will also install the jMaki Ajax Support plugin.

Configure the Java DB Database

Next, let's create a new database for the application.


  1. Start Java DB as follows:
    • Click the Services tab in the NetBeans IDE.
    • Expand the databases node. You should see Java DB in the list of databases.
    • Right-mouse click on Java DB and select Start Server.

  2. Create a Java DB database as follows:
    • Right-mouse click on Java DB and select Create Database. This will open a Create Java DB Database window.
    • Enter the database name, data. This is the database name preconfigured in Phobos.
      (See the section Connecting to the Database for more information about database
      configuration parameters that are predefined in Phobos.) Also, enter a user name, APP, and a password,
      APP.
      (These parameters, as well as the type of database to access, are fully configurable and customizable.
      You can specify different parameters or a different database type when you develop the application or later
      when the application is deployed.)
    • Click the O.K. button.

  3. Expand the Drivers node. You should see a driver for jdbc:derby://localhost:1527/data as shown
    in Figure 3. This is the driver for the data database.













    Driver list

    Figure 3. Driver List





Create a Project for the Web Application

Now that you have added the Phobos plugins to the NetBeans IDE and created and configured a Java DB database, it's time
to create the application. Start by creating a new project in the NetBeans IDE, as follows:


  1. Select New Project in the File menu of the IDE. This opens the New Project window.
  2. Select Web for the category and Web Application for the project in the New Project window
    and click the Next button. This opens the Name and Location panel.
  3. Enter PhobosSample in the name field and select an appropriate location for the project.
    Then click the Next button. This opens the Server and Settings panel.
  4. Ensure that GlassFish V2 is selected as the server and Java EE 5 as the Java EE version.
    Then click the Next button. This opens the Frameworks panel.
  5. Select jMaki Ajax Framework and Phobos Runtime as a Web Application Extension in the
    Frameworks field. When you select the jMaki Ajax framework, the panel displays a CSS Layout section. Choose
    No CSS Style in the CSS Layout section, as shown in Figure 4.













    Selecting the Phobos and jMaki Frameworks

    Figure 4. Selecting the Phobos and jMaki Frameworks




  6. Click the Finish button to create the project.
  7. Expand the new PhobosSample project in the Projects tab. Figure 5 shows that
    in addition to familiar elements that comprise a web application project, such as web pages and configuration files, the
    PhobosSample project includes Phobos-specific elements that reside in the Phobos Application folder.













    PhobosSample Project

    Figure 5. PhobosSample Project




Customize the Scripts for the Application

A Phobos application contains a set of scripts that are executed in response to web requests. Additionally, it contains
EJS pages that are used as views. These pages contain code snippets written in JavaScript that are
executed when the page is rendered. This allows dynamic content to be generated.

The application you created contains a predefined model/view pair. If you run the application as it currently exists,
you will see the web page displayed in Figure 6. You can see this default page by right-clicking
PhobosSample in the Projects tab and selecting Run.












Default Page Displayed by a Phobos Application

Figure 6. Default Page Displayed by a Phobos Application


You need to customize the model and view to produce the results you want for the application. That requires you to
update a number of pregenerated scripts. In addition, you need to create some other scripts to do things such as
connect to the database. The remainder of the tip focuses on these scripting actions.


Connect to the Database

For the application to work, it needs to connect to the database. In Phobos, you implement the connection using a startup
script. This is a special script that the Phobos runtime executes when the web application is initialized. The script
initializes the database layer, connects to the database, and checks that the table required by the application exists. If
the table does not exist, the script creates it.

Note that these actions were performed by the setup.php page in the PHP version of the application.
In the Phobos version of the application, there is no need to manually point the browser to a setup page because the
application will do that automatically at startup.

To create the startup script:


  1. Right-mouse click on the module package under Phobos Application and select New then Other. This open a New File
    window.
  2. Select Scripting as the category and Phobos Script as the file type, then click the Next button.
    This opens a Name and Location panel.
  3. Enter application as the script file name. Ensure that the full name of the resource in
    the Created File field is

    web/WEB-INF/application/module/application.js.
  4. Click the Finish button to create the script file. You will see the new file, application.js,
    added under the module package.
  5. Open the application.js file.Replace the contents of the application.js file with the following:

       library.common.define(module, "application", function() {
    this.onStartup = function() {
    application.options.database.preferred = "client";
    library.db.initialize(application.datasource.client);
    var sql = new library.db.SqlHelper();
    library.db.using(sql, function() {
    try {
    var result = sql.query({query: "SELECT COUNT(\*) FROM products"});
    }
    catch (e) {
    // must create the table
    sql.execute("CREATE TABLE products (" +
    "id int NOT NULL GENERATED ALWAYS AS IDENTITY PRIMARY KEY," +
    "name varchar(15) NOT NULL," +
    "category varchar(20) NOT NULL," +
    "price varchar(20) NOT NULL)");
    }
    });
    }
    });




     



The library.common.define function call that wraps the code below it is the Phobos way of creating a package.
You can think of that line as being equivalent to the statement package module.application; in the Java
programming language.
The JavaScript language does not have a native package construct. Because of that , Phobos (and any other JavaScript library)
had to define its own construct.

The body of the package defines and exports the onStartup function. That function is invoked by the Phobos
runtime when the application starts up. The onStartup function selects the client database as the preferred
database and initializes it. Its configuration parameters are predefined in Phobos as follows:



   application.datasource.client = {
dataSourceClassName: "org.apache.derby.jdbc.ClientConnectionPoolDataSource",
username: "APP",
password: "APP",
properties: {
serverName: "localhost",
portNumber: "1527",
connectionAttributes: ";create=true",
databaseName: "data"
}
}




 

As you can see, the databaseName is data, which matches the name of the database you created
earlier in the NetBeans IDE. If you want to use a different database, you need to copy the code shown above, paste it into
the application module, and edit it to suit your needs.

The rest of the code in the application.js script tries to connect to the database and execute a SQL query.
If it fails, it executes an SQL CREATE statement to create the table that holds the product information. This code
uses the Phobos db library (library.db), which wraps JDBC inside a more JavaScript-friendly layer. You can get
more details about this library in the
Phobos Library Documentation.

Run the application again to ensure that the added code is correct and to test that the application can connect to
the database. If everything is correct, you'll see the same page as before -- the contents of the page won't change until
you modify the main controller for the application. In case of an error, you should see a Phobos error page with a complete
stack trace.

Change the Main Page

If the application can connect to the database, it's time to start implementing the rest of the code, starting with the main
page. This page is the equivalent of the index.php page in the PHP version of the application.
However, there are some notable differences. Unlike PHP, Phobos uses a full MVC framework, so the application logic is split
between view and controller.

Let's update the view first -- it's the main.ejs file in the view package under Phobos Application in the
project. The contents of the view are similar to those of the index.php page in the PHP version. The main
difference is that instead of using PHP snippets inside the <?php ?> sections, the view uses JavaScript snippets
enclosed within <% %>.

Replace the code in the main.ejs file with the following:



   <html>
<head>
<title>Phobos Sample Application</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<link rel="stylesheet" href="style.css">
</head>
<body>
<br>Using the following form, you can add products that will be inserted in
a JavaDB database, and displayed using the jMaki Ajax framework in the table below.<br>
<br><br>
<form action="#" >
Product Name : <input id="name" name="name" type="text"><br>
Product Category :<input id="category" name="category" type="text"><br>
Product Price : <input id="price" name="price" type="text"><br>
</form>
<%
library.jmaki.insert({
component: "yahoo.button",
value: { label : 'add a product' }
});
%>
<br>
<b><center>List of Products:</center></b><br><br>
<%
library.jmaki.insert({
component: "yahoo.dataTable",
args: {columns : [
{ 'label' : 'name', 'id' : 'name'},
{ 'label':'category', 'id' : 'category'},
{ 'label': 'price ', 'id' : 'price'}
]},
service: library.httpserver.makeUrl("/main/listProducts")
});
%>
</body>
</html>




 

As you paste the contents into the file, the NetBeans IDE highlights the JavaScript sections (by default, it uses a
light-green color) to point out that the sections render dynamic content. This differentiates these sections from
the rest of the page, which is rendered as entered.

Notice the library.jmaki.insert function in the main.ejs file. This function is used in Phobos to
insert jMaki widgets. If you compare the function to the
addWidget function in the index.php file of the PHP version of the application, you'll see that
the arguments to both are similar. They also resemble the arguments that the jMaki JSP tag library expects. This makes the
transition from PHP to Phobos straightforward.

One important difference between the way the Phobos version and the PHP version use jMaki widgets is that in Phobos the
values and arguments (args) passed to the widget are real JavaScript objects, not strings. This highlights
one of the most interesting features in Phobos. The client (that is, the scripts running inside the browser) and the
server share a common language, JavaScript. This makes it easier to share data between the two tiers and eliminates a lot
of translation work. In particular, JavaScript Object Notation (JSON) becomes a native format supported by both tiers,
and so, is a particularly appealing data format.

Another thing to point out in the EJS page is the call to the library function,
library.httpserver.makeUrl("/main/listProducts"). Phobos views are stored in a separate directory tree
from static content, so that referencing other resources or even controllers from a view is error-prone. The
library.httpserver.makeUrl function helps here because it allows you to specify an absolute URL as an argument.
The URL is then replaced with the correct URL at runtime. In the example, the URL points to the main controller and
triggers invocation of the listProducts method when it is accessed.

Add jMaki Glue

Because the application uses jMaki, you need to create a jMaki Glue file, glue.js, that "glues"
the widgets on the page together using a publish-subscribe event model. Replace the contents of the glue file,
resources/glue.js, which you can find under Web Pages in the project, with the following:



   // uncomment to turn on the logger
jmaki.debug = false;
// uncomment to show publish/subscribe messages
jmaki.debugGlue = false;
// map topic for the add Product button
jmaki.subscribe("/yahoo/button/onClick", function(args) {
// get the values of the 3 fields in the form:
var name= document.getElementById("name").value;
var category= document.getElementById("category").value;
var price= document.getElementById("price").value;
//do an ajax request to the add server side logic, with the correct params:
jmaki.doAjax({
url : "addProduct",
method : "POST",
content : {
name : name,
category : category,
price : price
},
callback: function(req) {
//in this call back, we just add a new row to the local jMaki table
if (jmaki.trim(req.responseText) == "OK")
jmaki.publish ('/yahoo/dataTable/addRow', {
value: {
name : name,
category : category,
price : price
}
});
else
alert ("error adding a row: "+req.responseText);
}
});
});




 

Update the Controller

The modified view relies on some additional behavior from the controller, the listProducts action, which
you need to implement. However, first, let's rewrite the generated
controller code to use more stylish, easier to read JavaScript. Replace the code in the
main.js file in the controller package below Phobos Application with the following:



   library.common.define(controller, "main", function() {
function Main() {
}
Main.prototype.show = function() {
model = {};
library.view.render("main.ejs");
}
// export the controller class
this.Main = Main;
});




 

Notice the similarity between this code and the code in the application.js file defined earlier. A controller
is itself a module, but defined under the controller node in the project. A controller module defines
a controller class, represented
in JavaScript by a constructor function -- in this case Main. In addition, a controller class has one or more
action methods, which in JavaScript are usually defined using the constructor prototype. The entire code is idiomatic,
so it may appear strange at first.

You modified some code, so let's test it by running the application again. When you run the application, you should see
the page displayed in Figure 7. Although part of the page renders properly, it also displays some error
messages.












The Application Page Displaying Errors

Figure 7. The Application Page Displaying Errors


The reason for these errors is that the application is trying to insert some jMaki widgets into the page, but the resources
for those widgets are not in the application. The easiest way to fix the problem is to do the following:


  1. Open the main.ejs view.
  2. Open the jMaki palette in the NetBeans IDE.
  3. Expand the jMaki Yahoo item in the jMaki palette.
  4. Drag and drop the jMaki Yahoo Button and Data Table widgets onto the page.

Figure 8 shows the part of the code generated by the drag and drop.













Code Generated by Dragging and Dropping jMaki Yahoo Widgets

Figure 8. Code Generated by Dragging and Dropping jMaki Yahoo Widgets


The jMaki palette automatically inserts some JavaScript snippets that call the library.jmaki.insert function.
You can safely delete these snippets because the page already contains that code. A side benefit of dragging and dropping
the widgets is that the necessary resources are added to the project. You can find the added resources
under the Web Pages/resources/yahoo folder in the project.

Run the application again. As Figure 9 shows, the resource-related error messages have disappeared
and the button near the top of the page is rendered correctly. However, at the bottom of the page, where the table should
be, there is still an error message.













The Application Page Displaying a Failed to Load Data Error

Figure 9. The Application Page Displaying a Failed to Load Data Error


The error message is an indicator that the listProducts method in the controller has not yet been defined.
Define it now by adding the following code inside the main.js script:



   Main.prototype.listProducts = function() {
library.httpserver.sendJSON({rows: module.persistence.fetchProducts()});
}




 

Add a Persistence Layer

In keeping up with the incremental nature of development in Phobos, let's now implement a persistence layer. This allows
you to test the listProducts functionality in the browser. To do this, create a persistence.js
module. You can follow the same process you did to create the application.js module, that is, the
startup script.

After you create the persistence.js module, replace its contents with the following code:



   library.common.define(module, "persistence", function() {
this.fetchProducts = function() {
var sql = new library.db.SqlHelper();
var products = [];
library.db.using(sql, function() {
products = sql.select({table: "products",
columnMapping: columnMapping});
});
return products;
};
this.addProduct = function(product) {
var sql = new library.db.SqlHelper();
library.db.using(sql, function() {
sql.insert({table: "products",
values: product,
propertyMapping: propertyMapping,
prepare: true});
});
};
var columnMapping = {
ID: "id",
NAME: "name",
CATEGORY: "category",
PRICE: "price"
};
var propertyMapping = {
id: "ID",
name: "NAME",
category: "CATEGORY",
price: "PRICE"
};
});




 

As is the case in the startup script, the persistence module uses the Phobos db library to avoid having to directly
interact with JDBC. The fetchProducts and addProducts functions are exported from the module
by adding them to this object, which in this context is the module itself. The code to add a new product is simple.
The code does not validate the input data. Neither does it handle exceptions, which are simply passed back
to the caller. A production application would include many more checks to make sure no illegal or malicious data is sent to the
database.

The two mapping objects at the bottom deserve an explanation. Because Java DB converts all column names to uppercase,
if you retrieve data from the database you would find properties with the names NAME, CATEGORY, and PRICE. But if you
examine the main.ejs page, you'll notice that it expects properties called name, category and price, respectively.
It is easier to do the conversion in the database layer by specifying two mappings of column names to
property names and back. This approach is also useful when you want to map names written in camel case that are commonly
used in JavaScript, for example, streetAddress, to underscore-rich names that database professionals typically use,
such as STREET_ADDRESS.

Now that the persistence layer is completed, you can test the addProducts controller action by pointing the browser
to the URL http://localhost:8080/PhobosSample/main/listProducts. You should see the following text in the browser:

{rows:[]}.

This is an expected result because the database table is currently empty.

Add the Products

When a user of the application clicks on the add a Product button to add a product, the application sends an Ajax POST
request to the
addProduct method of the main controller. It's now time to implement this method by adding the following
code to the main.js controller script:



   Main.prototype.addProduct = function() {
var params = library.httpserver.parseRequestParameters();
if (params.name) {
module.persistence.addProduct({name: params.name, category: params.category, price: params.price});
library.httpserver.sendOk();
}
else {
library.httpserver.sendNotFound();
}
}




 

This function uses the parseRequestParameters library function to parse the body of the POST request into
a JavaScript object. The function then extracts the data from that object and passes it to the database layer.
Here, because all the property names match, the function could have been designed to pass the params object
directly. However, in general, it is safer to insulate the web-facing layer from the database layer. This avoids
exposing the database to attacks by malicious clients.

Test the Application

The application is complete and ready for testing. Run it and try adding a few products. You should see the updates
immediately reflected in the UI as shown in Figure 10.













Adding Products to the Database

Figure 10. Adding Products to the Database


You can also directly point the browser to the listProducts action at http://localhost:8080/PhobosSample/main/listProducts.
This will display the data in JSON format:



   {"rows":[{"id":"1","category":"car","price":"15000","name":"fiat"},{"id":"2","category":"car","price":"18000","name":"subaru"}]}




 

Summary

This tip showed you how to build an Ajax-enabled application using Phobos and jMaki with the help of the NetBeans IDE.

For persistence, the application used a simple JDBC wrapper library provided with Phobos. If the data model were more complex,
the application could have used a full-featured Java persistence library such as the Java Persistence API (JPA) or
Hibernate. Because of the excellent interoperability between JavaScript and the Java programming language, developers can
use the language most appropriate for each task without compromising productivity.

Further Reading


About the Author

Roberto Chinnici is a senior staff engineer at Sun Microsystems. He currently serves as the specification lead for the
Java Platform, Enterprise Edition (Java EE) 6. Roberto is a long-standing advocate of scripting and dynamic languages
on any platform and the creator of Phobos.

Join the discussion

Comments ( 3 )
  • imad Wednesday, September 10, 2008

    excellent idea


  • Vladimir Tuesday, September 23, 2008

    This is very interesting for me and to start use Phobos I need to know a little bit more. Here is my questions:

    if there are some performance issues comparing with typical web java oriented application?

    My application using JPA and is it possible instead of java entity classes to use pure javascript entity classes?

    To understand better the last question let put it another way:

    Is it possible for simple CRUD oriented application to create and modified persistence entity classes on the fly in real-time (interactive mode) without even redeployment of the application?

    Thank you very much for your excellent article.


  • Adi Saputra Monday, November 24, 2008

    This is a good articel,

    would U like To give me a book for study me at Home.(offline.), about this.. :)

    Thank's


Please enter your name.Please provide a valid email address.Please enter a comment.CAPTCHA challenge response provided was incorrect. Please try again.