New Technologies for Ajax and Web Application Development: Project Phobos

   
By Jennifer Ball, January 2007  

Articles Index

 

Contents
 
Phobos Architecture
What Is a Phobos Application?
Using a jMaki Widget in a Phobos Application
Using the Java Persistence API in a Phobos Application
Conclusion
For More Information


 

The goal of Project Phobos is to build a lightweight web application framework that runs on the Java platform but allows you to develop your entire application using a scripting language, such as JavaScript. As a result, you can take advantage of the many benefits that scripting languages offer but still leverage the power of the Java platform.

When you develop with Phobos, you will experience the many benefits of using scripting languages. For example,

  • You can deploy an application without compiling it.
  • You can write fewer lines of code.
  • You will be able to make changes to the application while it is running without redeploying it.

Phobos gives you what other scripting languages do not: access to the Java Platform, Enterprise Edition (Java EE) stack. As the first article in this series has pointed out, scripting languages and statically typed languages such as the Java programming language have their own strengths. When you use Phobos to create web applications, you can use scripting and Java technology in ways that take advantage of their strengths. And because Phobos runs on the Java EE platform, you can call into components of the Java EE stack. For example, from your Phobos application, you can call into the new and powerful Java Persistence API available as part of the Java EE platform.

Phobos also simplifies development in Ajax, a technology that includes but is not limited to Asynchronous JavaScript and XML. If you have JavaScript on the client, as you do with Ajax, and on the server, as you can with Phobos, you get all all the benefits of having the same scripting language on both the client and the server. This also means that no translation is required between one language on the server and another on the client. In addition, Phobos includes a set of convenience libraries specifically for Ajax, such as the jMaki framework and the Dojo toolkit.

This article first describes the Phobos architecture. It then uses a common calculator example to demonstrate the characteristics of a typical Phobos application. Next, it shows how to incorporate jMaki widgets into your Phobos application. Finally, it describes how to use the Java Persistence API with a Phobos application.

Phobos Architecture

From the Phobos user's perspective, Phobos consists of a set of scripting engines and a set of built-in scripting libraries. The scripting engines are compliant with JSR 223, Scripting for the Java Platform, and each one allows you to use a particular scripting language to develop your application. Currently, Phobos supports the JavaScript and JRuby engines. The scripting libraries add convenience JavaScript functions for performing such common tasks as request dispatching and rendering views, as well as more specialized ones such as integrating Ajax functionality into your application.

The application that you build with the Phobos framework adheres to a specific structure, which encourages building web applications according to the Model-View-Controller (MVC) design pattern. Every Phobos application consists of a set of controllers, a set of views, scripts for serving HTTP requests, and possibly other static content, such as style sheets and images.

Once you have written your application, the flexible Phobos architecture allows you to run it on one of a variety of platforms and in a variety of environments. You can run a Phobos application on the open-source GlassFish server or in any compliant servlet container. Phobos also lets you select a particular environment configuration depending on whether the application is in the development, testing, or production stage. For example, you can enable or disable certain optimizations based on their appropriateness for the current stage of development.

After you have deployed your application, it is live, meaning that you can make changes to the application while it is running and see the results instantaneously. There is no need to compile or redeploy the application.

Let's take a closer look at what a Phobos application looks like.

What Is a Phobos Application?

Every Phobos application includes an application directory, which in turn includes at least a controller, a script, and a view directory. Figure 1 shows the directory structure of the calculator example, which you can download from this Phobos samples download page.

Figure 1: Directory Structure of the Calculator Application
 

As you can see from Figure 1, the application directory contains the following subdirectories:

  • In the controller directory, you put the scripting code that creates a controller object and defines the functions that are called in response to user actions.
  • In the script directory, you can put any extra scripting code you use in the application. In the case of the calculator, the script directory contains a script file that redirects requests to particular pages of the application.
  • In the view directory, you put the files that represent the different pages of the application.

More complicated applications might need additional directories, such as a static directory, in which you can put static files, such as HTML pages and CSS style sheets. The " Overview of Phobos" document describes the directory structure in more detail.

As Figure 1 shows, the calculator application contains the following files:

  • The calculator.js file, which instantiates a controller object and invokes the appropriate methods to perform the arithmetic operations and redisplay the result.
  • The index.js file, which dispatches the first request for the application to the controller.
  • The calculator.ejs file, which is an embedded JavaScript file, an HTML file with JavaScript code embedded in it. This file represents the view or page of the application.

When the browser makes the first request for the page, the following happens:

  1. The index.js file redirects the request to the /calculator/show URL. The calculator part of the URL is a controller, and show is a function of it. The show function is defined in calculator.js.

  2. The Phobos runtime creates the Calculator controller and invokes the show function.

  3. The show function sets the initial values of the operands, sets the selected arithmetic operation to add, and renders the calculator.ejs view.

  4. The user enters two numbers, selects an operand, and clicks Compute.

  5. When the user clicks Compute, the compute function of calculator.js is called by way of an HTTP POST to the /calculator/compute URL.

  6. The compute function does the following:

    • Gets the values of the operands and the selected operation
    • Performs the appropriate calculation and saves the result into session
    • Redirects to the show function so that calculator.ejs is re-rendered

The line in index.jsp that redirects to the URL /calculator/show is the following, separated to fit on the print-friendly version of this page:

library.httpserver.sendRedirect(
                    

       library.httpserver.makeUrl("/calculator/show"));
                    

                  
 

This line uses the built-in httpserver JavaScript library that comes with Phobos to handle the initial request for the application. It invokes the show function of the Calculator controller, which renders the view. In the next two sections, we'll look more closely at the calculator example's controller and view, the key parts of the application.

The Controller

Every Phobos application needs at least one controller, which processes requests, makes changes to the model in response to requests, and renders the view. In the case of the calculator, the responsibility of its controller is to render the view, perform the arithmetic operations of the calculator, and pass the results to the view.

The calculator.js file contained in the application's controller directory does the work of creating the Calculator controller object and implementing the controller's functions. The calculator.js file defines and constructs the Calculator controller object using the prepackaged define function :

library.common.define(controller, "calculator", function() {
                    

    this.Calculator = function() {
                    

        ...
                    

    }
                  
 

Inside the calculator's constructor function, calculator.js defines the two functions implemented by the Calculator controller object: show and compute.

The show function stores the value of the calculation's result and the selected operation, such as add, into the session.   It uses the invocation.session object to save values into the session:

            var v = invocation.session.value;
                    

            if (v == undefined) {
                    

                v = 0;
                    

            }
                    

            var op = invocation.session.selectedOp;
                    

            if (op == undefined) {
                    

                op = "add";
                    

            }
                    

            model = { value: String(v), selectedOp: op };
                    

                  
 

As shown in the preceding code, the value of the result is set to zero because this is the first time the page is being requested. The operation is set to a default of add. Finally, a global variable, called model, is initialized with these values. Later, you'll see how the page accesses these values and passes them back to the controller.

The last thing the show function does is to display the page, not by writing HTML directly but by rendering a separate view, represented by calculator.ejs. It does this by using the render function from the view library:

library.view.render("calculator.ejs");
 

Notice that all you need to do is provide the name of the file, as long as you put the file in the appropriate directory.   Phobos is smart enough to know where to find the file. As a result, the render function resolves to /application/view/calculator.ejs.

The extension ejs stands for embedded JavaScript, to signify that the file is an HTML file with JavaScript statements and expressions embedded inside it. When the view is rendered, the embedded code is evaluated at the appropriate time. The next section describes how to create the calculator.ejs file.

But first, let's go over what the compute function does. This function gets the values and the operator from the request parameters and uses them to calculate a new result. After doing so, it saves the new values back into the session. Finally, it redirects to the show function so that the page is re-rendered with the new result. Here is the line, separated to fit on the print-friendly version of this page, that performs the redirect:

library.httpserver.sendFound(
                    

  library.httpserver.makeUrl("/calculator/show"));
                  
 

Now let's take a look at the view that is actually rendered.

The View

Every web application has a set of pages, or views. Figure 2 shows the view of the calculator application.  The user enters numbers in the Current Total and Second Operand fields, selects an operator from the set of radio buttons, and clicks Compute.  The application responds by displaying the total in the Current Total field.

Figure 2: Screen Capture of the Calculator Application
 

When developing a Phobos application, you create a view using an embedded JavaScript file. This file is an HTML file with embedded JavaScript statements, and so it is similar to a JavaServer Pages (JSP) technology page with HTML form elements mixed with scripting tags.

Following is the calculator.ejs file, with formatting tags removed: 

<script type="text/javascript">
                    

   window.onload = function() {
                    

     var selectedOp = "<%=model.selectedOp %>";
                    

     document.getElementById(selectedOp).checked = true;
                    

   }
                    

</script>
                    

<form action="/calculator/compute" method="post">
                    

   Current Total
                    

   <input type="text" size="20" name="value"
                    

    value="<%=model.value %>"/>
                    

   Second Operand
                    

   <input type="text" size="20" name="operand"/>
                    

   Operator
                    

   <input id="add" type="radio"
                    

     name="operator" value="add">+</input>
                    

   <input id="subtract" type="radio"
                    

          name="operator" value="subtract">-</input>
                    

   <input id="multiply" type="radio"
                    

      name="operator" value="multiply">*</input>
                    

   <input id="divide" type="radio"
                    

       name="operator" value="divide">/</input>
                    

   <input type="submit" value="Compute"/></td></tr>
                    

</form>
                  
 

Notice that when the user clicks the Compute button, the action of the form submission is the compute function, described in the previous section. Recall that the show and compute functions saved the values and selected operation into the model variable in session. Here, the calculator.ejs file uses JavaScript statements to retrieve the value and operation from the model variable. The script tag uses the <%=model.selectedOp%> statement to retrieve the selectedOp value in order to select the appropriate selected operation checkbox in the form. The Current Total text field uses the <%=model.value%> statement to get the calculation's current result.

As this section has shown, the architecture of a typical Phobos application conforms well to the familiar MVC design pattern.

Using a jMaki Widget in a Phobos Application

When developing a Phobos web application, you can do anything that you can do with a web application based on JSP technology, and that includes adding Ajax capabilities to your application. Currently, Phobos supports adding jMaki widgets to a Phobos application. In the future, as Phobos and Dynamic Faces mature, there might be more synergy between the two.

In the meantime, this section shows you how you can use the jMaki fisheye widget in a Phobos application.  Figure 3 showns a screen capture of the bioFisheyeWidget application, which you can download from this Phobos samples download page. This application allows a user to click on a photo to get biographical information about the person in the photo.

Figure 3: Screen Capture of the bioFisheyeWidget Example
 

The first task you must perform to get Phobos and jMaki working together is to download both projects and build them separately, as described in " Building a Phobos Distribution." After that, to include a jMaki widget into your application, just use the insert function of the jMaki JavaScript library provided by Phobos in your embedded JavaScript file, as shown here:

<% library.jmaki.insert({component: "dojo.fisheye", args:{items:[
                    

  {iconSrc:'JayashriVisvanathan.jpg',url:'fisheye/jayashri',
                    

  caption:'Jayashri', index:1},
                    

  {iconSrc:'chinnici.jpg',url:'fisheye/roberto',
                    

   caption:'Roberto',index:2},
                    

  {iconSrc:'blog_murray.jpg',url:'fisheye/greg',
                    

     caption:'Greg',index:3}]}}); %>
                    

                  
 

The preceding code uses the insert function to add the fisheye widget to a view. The arguments that you pass to this function are nearly the same as the attributes you would define for the equivalent ajax tag that you would include in a JSP page. The component argument tells the function which widget you are inserting into your page. The args argument identifies an array of icons that are included in the widget along with the properties for each of those icons.  One of the properties is url, which identifies a URL that must be accessed when the user clicks the photo that the icon represents.  Each URL points to a view that contains the appropriate biographical information.

To display the view with the biographical information, the view of the bioFisheyeWidget application includes a dcontainer widget that subscribes to a topic that gets the URL and will load it into the page:

<h3><div>
                    

<%library.jmaki.insert({component: "jmaki.dcontainer",
                    

   args:{topic:'/jmaki/dcontainer'}});%></div></h3>
                  
 

This is just one example of how you can use the publish and subscribe feature of jMaki to respond to widget events.  See the document " jMaki Glue" to learn how you can write your own topic listeners.

So that's how you include a prewrapped jMaki widget into your application. To include a custom jMaki widget that is not part of the jMaki distribution, you simply add the widget's component.js, component.htm, and component.css files to the application/static/resources directory of your application.

Using the Java Persistence API in a Phobos Application

As this article has mentioned previously, one of the advantages of using Phobos is that you have access to all the great features that the Java EE platform offers. One of the latest ease-of-use features included in Java EE 5 is the Java Persistence API, which provides developers with an object-relational mapping facility for managing relational data in Java technology-based applications.

The Java Persistence API allows you to represent an entity, which is typically a table in a relational database, with a Java class. The API also provides a set of classes for managing these entities:

  • Persistence Context: A persistence context is a set of managed entity instances that exist in a particular data store. The EntityManager interface defines the methods that are used to interact with the persistence context.
  • EntityManager: The EntityManager API creates and removes persistent entity instances, finds entities by the entity's primary key, and allows queries to be run on entities.
  • Persistence Unit: A persistence unit defines a set of all entity classes that are managed by EntityManager instances in an application. This set of entity classes represents the data contained within a single data store.

See chapters 24 through 27 of the Java EE 5 Tutorial for more information on the Java Persistence API.

Phobos provides a persistence JavaScript library that gives you the ability to access data from the views and scripts of your Phobos application using the Java Persistence API. The following simple code is from the jpaExample application, which you can download from this Phobos samples download page.  The code shows part of a script file that adds authors to a database and then displays those authors on the page. It represents the simplest way to publish this information in a web page.

response.setStatus(200);
response.setContentType("text/html");
writer = response.getWriter();

...
// Insert some authors.
...
var em;
...
em = library.persistence.getEntityManager("jpaExample1-pu");
...    
if (em != undefined) {
   // Insert some Authors if none are defined.
   var authors =
      em.createQuery("select a from Author a").
           getResultList().toArray();
   if (authors.length==0){
       var tx = em.getTransaction();
       tx.begin();

       var author = new Packages.jpaexample.Author();
       author.name =
             "Danny Goodman";  
             //equivalent to author.setName("Danny Goodman");
       author.organisation= "O\'Reilly";
       em.persist(author);
       writer.println("<br><br>created one author named "+ author.name);

       var author2 = new Packages.jpaexample.Author();
       author2.name= "Paul Wilton";
       author2.organisation ="Wrox Press Inc";
       em.persist(author2);
       writer.println("<br><br>created one author named "+ author2.name);

       tx.commit();
    }

    // List out the Authors that are available.
    authors = em.createQuery("select a from Author a").getResultList().toArray();
    writer.println("<h3>List of Authors as of "+ java.util.Date() +"</h3>")
    writer.println(
      "<table><tr><th>Id</th><th>Name</th><th>Organisation</th></tr>");
    for (var i in authors) {
        var a = authors[i];
        writer.println("<tr><td>" + a.authorId
        + "</td><td>" + a.name
        + "</td><td>" + a.organisation
        + "</td></tr>");
    }

    writer.println("</table>")
}

writer.println("</body></html>");
writer.flush();
 

Figure 4 shows a screen capture of the page generated by this code:

Figure 4: Screen Capture of jpaExample
 

As you can see from the code, the persistence library available with Phobos includes a function to get an EntityManager instance and store it into a simple JavaScript variable. From this variable, you can get a transaction, persist entities, and create queries in the same way you would if you were working in Java technology code. In addition, the Phobos persistence library can work with entity classes written in the Java programming language, which means that you can introduce entity classes you already have into a Phobos application.

Conclusion

The Phobos web application framework gives you the flexibility of developing a web application with a scripting language but still gives the application access to everything that the Java EE platform provides. As Phobos matures, it will give you a lot more capabilities, including more sophisticated database access and support for REST web services. To keep up-to-date on the progress of Phobos, visit the Project Phobos web site and join the project aliases.

For More Information

Previous articles in the "New Technologies for Ajax and Web Application Development" series:

JavaServer Faces Technology
JavaServer Pages (JSP) Technology
JavaScript Technology
Dojo Toolkit

About the Author

Jennifer Ball is a staff writer at Sun Microsystems. She writes about web application technologies that are part of the Java EE platform.

Rate and Review
Tell us what you think of the content of this page.
Excellent   Good   Fair   Poor  
Comments:
Your email address (no reply is possible without an address):
Sun Privacy Policy

Note: We are not able to respond to all submitted comments.