Enterprise Java Technologies Tech Tips
Tips, Techniques, and Sample Code
Welcome to the Enterprise Java Technologies Tech Tips for
September 23, 2004. Here you'll get tips on using enterprise
Java technologies and APIs, such as those in Java 2 Platform,
Enterprise Edition (J2EE).
This issue covers:
* Value and Method Binding Expressions in JavaServer
Faces Technology
* Persisting Model Components With Java Data Objects
These tips were developed using the Java 2, Enterprise Edition,
v 1.4 SDK. You can download the SDK at
http://java.sun.com/j2ee/1.4/download.html.
This issue of the Tech Tips is written by N. Alex Rupp,
a professional Open Source developer and software architect for
Open Technology Systems (http://www.open-techsys.com/).
You can view this issue of the Tech Tips on the Web at
http://java.sun.com/developer/EJTechTips/2004/tt0923.html.
See the Subscribe/Unsubscribe note at the end of this newsletter
to subscribe to Tech Tips that focus on technologies and products
in other Java platforms.
You can download the sample archive for these tips at
http://java.sun.com/developer/EJTechTips/download/ttsep2004.war.
Any use of this code and/or information below is subject to the
license terms at
http://developers.sun.com/dispatcher.jsp?uid=6910008.
For more Java technology content, visit these sites:
java.sun.com - The latest Java platform releases, tutorials, and
newsletters.
java.net - A web forum for collaborating and building solutions
together.
java.com - The marketplace for Java technology, applications and
services.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
VALUE AND METHOD BINDING EXPRESSIONS IN JAVASERVER FACES TECHNOLOGY
As indicated by its title, the March 24, 2004 Tech Tip
"Introducing JavaServer Faces Technology"
(http://java.sun.com/developer/EJTechTips/2004/tt0324.html#2)
introduced JavaServer Faces (JSF) technology, the new standard
framework for web-based user interfaces that use Java technology.
The following tip takes a closer look at JSF, focusing on value
and method binding expressions in the technology.
One of the aims of JavaServer Faces technology is to support
a role-based workflow for application development. The
technology is designed to address the unique concerns and needs
of page authors, user interface component designers, and
business model developers. As such, there are several ways that
a developer can approach the technology. This tip focuses on the
role of the page author, for whom binding expressions provide
a way to access the data model.
Value Binding Expressions
The two different types of binding expressions in JSF are value
binding expressions and method binding expressions. Value binding
expressions can be used inside of JSF components to:
o Automatically instantiate a JavaBean and place it in the
request or session scope.
o Override the JavaBean's default values through its accessor
methods.
o Traverse an object tree using an easy-to-learn DOM-style
notation.
o Quickly retrieve Map, List, and array contents from a JavaBean.
o Synchronize form contents with value objects across a number
of requests.
The syntax of binding expressions is based on the JavaServer
Pages (JSP) 2.0 Expression Language, which itself is based on
the object accessing syntax of JavaScript. In JSP, expressions
are delimited with "${}", but in JSF they are delimited with
"#{}". This is because in JSP 2.0, the JSP container evaluates
expressions before the page is executed. However, JSF needs to
be able to evaluate the expressions at a time of the view
component's choosing.
Page authors can use value binding expressions in combination
with the standard JSF user interface component library. In doing
that, page authors can easily create prepopulated forms in JSP
pages, and synchronize the contents of those forms with JavaBean
values in the conversational state of a servlet application. The
ability to bind expressions to public methods in arbitrary
objects, also allows page authors to easily trigger events on
the data model.
A good way to begin working with binding expressions is to look
at some examples. The sample WAR file that accompanies this
issue of the Tech Tips (ttsep2004.war) contains two JSP files:
index.jsp and viewInvoice.jsp. Each of these JSP files contains
examples of value and method binding expressions.
Here are some binding expression examples from the index.jsp file:
#{invoice.customerName}
#{invoice.date}
#{invoice.next}
The first two of these binding expressions are standard value
bindings for public accessor methods. The third binding
expression is a method binding expression (more about that
later). The equivalent expression in Java technology of the
first binding expression, #{invoice.customerName}, is
invoice.getCustomerName(). The second binding expression,
#{invoice.date}, differs from the first in that its initial
value is described in the faces-config.xml file in the WEB-INF
directory:
Represents an Invoice
invoice
com.alexrupp.ttsep2004.InvoiceBean
session
date
2004-09-06
The date string is initialized in the constructor of the
InvoiceBean:
public InvoiceBean() {
date = "2004-08-01";
...
The managed-property element in the faces-config.xml file
overwrites the initial date value before the bean is placed
into the session scope.
In addition to being able to read the initial value of a field
from an object, value binding expressions can also be used to
navigate maps, lists, or arrays. Here are some examples:
#{foo[bar]}
#{foo["bar"]}
#{foo[3]}
#[foo[3].bar}
#{foo.bar[3]}
Finally, you can use value binding expressions to write the
value of a field into an object prior to the object being
displayed. This is useful when you want to prepopulate form
fields with different values, depending on how the user first
arrives at the form. You can also use this technique to perform
limited mathematical calculations, as shown in the following
examples:
#{customer.status == 'VIP'}
#((city.farenheitTemp - 32) * 5 / 9}
Method Binding Expressions
The third binding expression listed previously, #{invoice.next},
is a method binding expression. Unlike a value binding, a method
binding does not represent an accessor method. Instead, a method
binding represents an activation method. If you're familiar with
Struts, then this should not surprise you. Which type of binding
expression is appropriate in any given user interface component
(such as a custom JSF tag) is determined by the tag author. In
certain cases, only value binding expressions are allowed. In
other cases, only method binding expressions are allowed. In
still others, either type of expression might be allowed. The
syntax of a method binding expression has two primary formats:
#{expr-a.value-b}
#{expr-a[value-b]}
The first format is a classic DOM-style object tree structure.
The second format can be used to call a method pointed to from
an object array, Map, or List. In the example code, a method
binding expression is used on the index.jsp page to resolve the
action of the enclosing form element. The method called is an
arbitrary method on the InvoiceBean object, but it doesn't need
to be. In the example, the method is required to return a String
value. That value is used by the JSF engine to determine the
next view component:
Navigation rules for "index.jsp".
/index.jsp
validated
/viewInvoice.jsp
Notice that the actual view component used (viewInvoice.jsp)
does not appear in the URL of the following page when the form
contents are submitted. This URL shadowing allows you to swap
out the underlying view components (or even change the entire
information architecture of the underlying site) without
upsetting the URL hierarchy. So what the public sees (and
perhaps bookmarks) remains consistent.
Forgiving syntax
The JavaServer Faces engine goes to considerable lengths to coax
meaning out of the values entered into binding expressions. For
instance, if a numeral is entered and a String is expected by
a method, the JSF engine coerces the numeral into a String in
the process of its evaluation. The JSF engine will look for
collection valued references, follow object trees, and even
instantiate new objects in the appropriate scope if none exist
that are capable of servicing the request. All of this leads to
a friendly user experience and higher productivity between page
authors and component developers.
For more information about JavaServer Faces technology, see the
JavaServer Faces Technology home page
(http://java.sun.com/j2ee/javaserverfaces/index.jsp).
----------------------------------------------------------------
PERSISTING MODEL COMPONENTS WITH JAVA DATA OBJECTS
The Java Data Objects (JDO) API provides a standard,
straightforward way of achieving object persistence in Java
technology. JDO uses a practical combination of XML metadata and
bytecode enhancement to ease development complexity and
overhead, as compared to other object binding technologies.
One of the strong points of JDO is the simplicity of its API.
All you need to learn are a few interfaces to use the technology.
The JDO API is standardized, and there is a range of
implementations from which to choose. The JDO Reference
Implementation and TCK are available at no cost on the JDO
Specification page
(http://jcp.org/aboutJava/communityprocess/final/jsr012/index2.html).
The Reference Implementation does not support relational
databases. For JDO implementations that support relational
databases, see JDOcentral.com (http://jdocentral.com).
JDO is distinct from other persistence technologies, such as
Enterprise JavaBeans technology, in that it allows you to work
with plain old JavaBeans. It doesn't force you to adhere to any
special APIs. JDO's careful use of post-compilation bytecode
enhancement provides an abstraction barrier between the
developer and the persistence container, that frees the
developer from the complexity of the surrounding environment. It
lets a developer focus on what really matters: the structure and
behavior of applications.
JDO distinguishes between the domain object model (the Java
classes that represent the persistent data) and the management
classes (the Java classes that are responsible for querying the
database, managing the life cycle of persistent instances, and
demarcating transactions). Persistent classes are not affected
by persistence, they simply implement the business logic
associated with the model. The management classes must be
persistence-aware, but JDO allows you to implement your
management classes without database-specific code.
Here are the steps in working with JDO:
o Download the JDORI jars and their dependencies.
o Define a simple model bean and create its metadata in a JDO
XML file.
o Compile and enhance the JavaBean.
o Construct a management facade for working with the persistent
store.
The sample web application for this issue of the Tech Tips
provides a simple example of using JDO. There are several books
and dozens of articles available that show how to use the JDO
API (see the resources at the end of this tip). So instead of
describing how to use JDO API, this tip focuses on the most
challenging part of getting started with JDO: setting up the
development environment and getting the first object to
verifiably persist. The sample web application illustrates how
to do that.
Download the JDO JARs and dependencies
The requisite JAR files have all been included in the example
WAR file (ttsep2004.war). You can find the JAR files in the
WEB-INF\lib directory. Here are the JAR files:
o jdo-1.0.1.jar (the JDO API JAR)
o jdori-1.0.1.jar (the Sun JDO implementation classes)
o jdori-enhancer-1.0.1.jar (bytecode enhancer package)
o btree-1.0.1.jar (bean tree JAR for handling the default file
object persistence)
o antlr-2.7.1.jar (required for parsing queries)
Configure the properties and set up the file database
The JDO reference implementation comes with a file-based data
storage mechanism called "FOStore". The web application uses
FOStore (this avoids the added complexity of integrating a
database). To set up FOStore, you must configure your system
properties. In the example, this is done in jdori.properties
file in the src/com/alexrupp/ttsep2004 directory. Here are the
file contents:
# jdori.properties file
javax.jdo.PersistenceManagerFactoryClass=
com.sun.jdori.fostore.FOStorePMF
com.sun.jdori.option.ConnectionCreate=true
javax.jdo.option.ConnectionUserName=jdotester
javax.jdo.option.ConnectionPassword=jdopassword
# The following property points to your local filesystem:
javax.jdo.option.ConnectionURL=fostore:C:/fostore
javax.jdo.option.Optimistic=false
javax.jdo.option.RetainValues=false
javax.jdo.option.RestoreValues=false
This configuration uses the FOStore PersistenceManager Factory.
It stores data files in the C:/ directory of a Windows machine.
Build, compile, and enhance the JavaBean
The web application uses the InvoiceBean object for persistence.
To prepare the InvoiceBean class for persistence, it must be run
through a bytecode enhancer. The bytecode enhancer injects an
interface and several important methods into the class, so that
the persistence container can work with it. This technique is
preferred over entering these methods manually. It's also
preferred over stub class and interface generation used in other
persistence technologies. There is a file named maven.xml in the
example that contains the necessary lines of code to enhance the
bytecode:
The goal element calls the com.sun.jdori.enhancer.Main class,
and passes it a line of arguments. The class uses the arguments
to identify and enhance the bytecode of the InvoiceBean class.
You can enter your own classes in addition to the InvoiceBean.
Retrieve a PersistenceManagerFactory using the system properties
The InvoiceManager servlet shows how to retrieve the
PersistenceManagerFactory class. It uses the JDOHelper class and
the imported properties file assembled earlier. After obtaining
a PersistenceManagerFactory, it's a simple matter to retrieve
a PersistenceManager and begin using the JDO API:
// ...
// get the JDO properties
Properties props = new Properties();
try {
props.load(CreateInvoice.class.getResourceAsStream
("jdori.properties"));
} catch (IOException e) {
e.printStackTrace();
}
// get the PMF
PersistenceManagerFactory fact =
JDOHelper.getPersistenceManagerFactory(props);
// get the persistence manager
PersistenceManager mgr = fact.getPersistenceManager();
//...
Although used in this example, this method of getting a
PersistenceManager is not the best practice. In a real
application, you should use a ServletFilter, where the init
method obtains the PersistenceManagerFactory once (it's an
expensive operation) and saves it as an instance variable in the
filter. Each invocation will pass through the filter, and store
the PersistenceManager as a property in the request.
Use the PersistenceManager to create a new persistent object
The final step is to build a class for managing the create,
read, update and delete processes of the InvoiceBean. You could
let the JavaBean class manage its own persistence, but it's
better to keep it as a passive data store and leave the active
role to another class. You'll find the modest beginnings of this
manager functionality in the InvoiceManager servlet. There is
enough code in this servlet to put an object in the data store.
The servlet then verifies the addition by counting the total
number of InvoiceBean objects contained in the store and
displaying that information to the screen:
// make the transaction
try {
mgr.currentTransaction().begin();
mgr.makePersistent(savingInvoice);
invoice.setPersistenceStatus(""
+ " Saved Successfully at "
+ System.currentTimeMillis());
/* Count all of the invoices. This is
* Okay for a demo, but in production you should
* Never use an unqualified query.
*/
Query query = mgr.newQuery(InvoiceBean.class);
Collection result = (Collection) query.execute();
invoice.setInvoiceCount("" + result.size());
query.close(result);
// commit the transaction.
mgr.currentTransaction().commit();
} catch (Throwable t) {
invoice.setPersistenceStatus(" Not Saved: " + t);
mgr.currentTransaction().rollback();
}
// forward to a view component
try {
res.sendRedirect("/ttsep2004/faces/viewInvoice.jsp");
} catch (IOException e) {
e.printStackTrace();
}
With a little time and effort, you can build a sophisticated
(but not complicated) invoice tracking system using a
combination of Java Data Objects for persistence and
JavaServer Faces technology for presentation. Each technology
reduces complexity and development overhead. Once you master
these technologies, you can dramatically increase productivity.
For more information about JDO, see the following resources:
o JDO Specification Page
(http://www.jcp.org/aboutJava/communityprocess/first/jsr012)
o JavaRanch Intro to JDO
(http://www.javaranch.com/newsletter/200401/IntroToJDO.html)
o ObjectDB (http://www.objectdb.com/database/jdo/manual/chapter1)
o OnJava
(http://www.onjava.com/pub/a/onjava/2002/02/06/jdo1.html?page=1)
o JDO Central (http://www.jdocentral.com)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
RUNNING THE SAMPLE CODE
Download the sample archive for these tips (from
http://java.sun.com/developer/EJTechTips/download/ttsep2004.war).
The application's context root is ttsep2004. The downloaded WAR
file also contains the complete source code for the sample.
The J2EE 1.4 SDK contains the Sun Java System Application Server
Platform Edition 8. You can deploy the Web archive
(ttsep2004.war) in Sun Java System Application Server
Platform Edition 8 by using the deploytool program or the admin
console. You can also deploy it using the asadmin command as
follows:
asadmin deploy install_dir/ttsep2004.war
Replace install_dir with the directory in which you installed
the war file.
You can access the application at http://localhost:8080/ttsep2004.
For a J2EE 1.4-compliant implementation other than Sun Java
System Application Server Platform Edition 8, use your J2EE
product's deployment tools to deploy the application on your
platform.
. . . . . . . . . . . . . . . . . . . . . . .
Please read our Terms of Use and Licensing policies:
http://www.sun.com/share/text/termsofuse.html
http://developers.sun.com/dispatcher.jsp?uid=6910008
PRIVACY STATEMENT:
Sun respects your online time and privacy (http://sun.com/privacy).
You have received this based on your e-mail preferences. If you
would prefer not to receive this information, please follow the
steps at the bottom of this message to unsubscribe.
* FEEDBACK
Comments? Send your feedback on the Enterprise Java Technologies
Tech Tips to:
http://developers.sun.com/contact/feedback.jsp?category=sdn
* SUBSCRIBE/UNSUBSCRIBE
Subscribe to other Java developer Tech Tips:
- Core Java Technologies Tech Tips. Get tips on using core
Java technologies and APIs, such as those in the Java 2
Platform, Standard Edition (J2SE).
- Wireless Developer Tech Tips. Get tips on using wireless
Java technologies and APIs, such as those in the Java 2
Platform, Micro Edition (J2ME).
To subscribe to these and other JDC publications:
- Go to the JDC Newsletters and Publications page,
(https://softwarereg.sun.com/registration/developer/en_US/subscriptions),
choose the newsletters you want to subscribe to and click
"Update".
- To unsubscribe, go to the subscriptions page,
(https://softwarereg.sun.com/registration/developer/en_US/subscriptions),
uncheck the appropriate checkbox, and click "Update".
- To use our one-click unsubscribe facility, see the link at
the end of this email:
- ARCHIVES
You'll find the Enterprise Java Technologies Tech Tips archives at:
http://java.sun.com/developer/EJTechTips/index.html
- COPYRIGHT
Copyright 2004 Sun Microsystems, Inc. All rights reserved.
901 San Antonio Road, Palo Alto, California 94303 USA.
This document is protected by copyright. For more information, see:
http://java.sun.com/developer/copyright.html
Enterprise Java Technologies Tech Tips
September 23, 2004
Trademark Information: http://www.sun.com/suntrademarks/
Java, J2SE, J2EE, J2ME, and all Java-based marks are trademarks
or registered trademarks of Sun Microsystems, Inc. in the
United States and other countries.