|
Articles Index
Contents
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:
-
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.
-
The Phobos runtime creates the Calculator
controller and invokes the show function.
-
The show function sets the initial values of the
operands, sets the selected arithmetic operation to add,
and renders the calculator.ejs view.
-
The user enters two numbers, selects an operand, and clicks
Compute.
-
When the user clicks Compute, the compute function
of calculator.js is called by way of an HTTP POST
to the /calculator/compute URL.
-
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
Ajax Developer
Resource Center
Ajax
Downloads
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.
|