Enterprise Java Technologies Tech Tips
Tips, Techniques, and Sample Code
Welcome to the Enterprise Java Technologies Tech Tips for
December 21, 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:
* Object Serialization with the JAXB Libraries
* Revisiting Timers with Enterprise Beans
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 Robert Eckstein,
a Java technology developer, editor, and author. Robert is
owner of Nexes Consulting, a Java consulting firm based in
Austin, Texas.
You can view this issue of the Tech Tips on the Web at
http://java.sun.com/developer/EJTechTips/2004/tt1221.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/ttdec2004-jaxb.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.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
OBJECT SERIALIZATION WITH THE JAXB LIBRARIES
XML is now a ubiquitous standard for representing data, and
there are a number of XML technologies that you can use to
serialize Java objects to XML. The two primary technologies that
Java developers are familiar with are the Simple API for XML
(SAX) and the Document Object Model (DOM) APIs. However, often,
programmers need technologies that are more targeted to the
immediate task. In this case, programmers might find themselves
wishing for simpler XML technologies for serializing object data.
Enter the Java API for XML Binding (JAXB). JAXB now comes
standard with the Java Web Services Development Pack
(http://java.sun.com/webservices/downloads/webservicespack.html),
JAXB allows you to perform a number of tasks, such as bind class
data from XML schema, and serialize object data to and from XML.
This Tech Tip introduces the JAXB APIs. It shows you how to
generate a set of Java classes from an XML Schema document using
the JAXB binding compiler. This tip also shows you how to
serialize an object to an XML file -- this is called marshalling
-- and how to do the opposite: serialize an object from an XML
file -- this is called unmarshalling.
You can run the examples as shown in this tip. However, before
you do that, you need to download the Java Web Services
Developer Pack. Then look in both the jaxb/lib and the
jwsdp-shared/lib directory of the distribution, and ensure that
each of the JAR files are explicitly included in your Java
classpath.
Alternatively, you can run the web application provided in the
WAR file that accompanies this tip. The source code shown in
the tip is included in the WAR file, however the source code is
slightly modified to use a servlet. To use the WAR file, you
need to download the Sun Java System Application Server
(http://java.sun.com/j2ee/1.4/download.html). Then download and
install the Java Web Services Developer Pack into it. Each of
the necessary libraries will then be present in the J2EE
environment. An Ant file is included to assist with compilation
and packaging.
The Binding Compiler
One of the first things to learn about JAXB is how to bind XML
schema to Java classes. Binding takes an XML schema and
generates a set of a Java interfaces that are capable of
representing the data model defined by the schema. The tool to
do this is called a binding compiler. The binding compiler
accepts a W3C XML schema and derives the proper interfaces and
classes from it.
Here is a simple schema that can be used to generate a JAXB
class.
You can find the schema, Birthdate.xsd, in the source code that
accompanies this tip. The schema defines a simple element named
Birthdate. The Birthdate element has an anonymous complexType
that defines three properties: month (a String), day
(an integer), and year, (another integer).
To bind this to a Java interface, invoke the XML binding
compiler. To do this you run the xjc command. You can find it in
the jaxb/bin directory of the Java Web Services Developer Pack
installation (you invoke the xjc.bat file in the Windows
environment, or the xjc.sh file in the Solaris Operating System
or other Unix environment). Use the following command-line
syntax:
xjc -p -d schema.xsd
where is the name of the package for the
generated files, is the directory in which the
generated files will be placed, and schema.xsd is the input XML
schema. So, for example, run the following command in the
directory that contains Birthdate.xsd:
xjc -p com.nexes.jaxb.test -d . Birthdate.xsd
In response, the binding compiler generates a set of Java source
classes, all of which need to be compiled with javac. The sample
code that accompanies this tip includes the source classes.
Here, for example, is the BirthdateType interface (comments have
been removed):
package com.nexes.jaxb.test;
public interface BirthdateType {
int getDay();
void setDay(int value);
int getYear();
void setYear(int value);
java.lang.String getMonth();
void setMonth(java.lang.String value);
}
The schema compiler, however, generates more than this. You can
divide the generated classes into three categories:
o A set of portable JavaBean-style getter/setter interfaces that
represent the data model defined by the schema.
o A set of concrete vendor-specific implementations of those
interfaces.
o Other supporting runtime classes.
Each of these classes assists with the serialized XML
representation of instance data for a Birthdate object. Here,
for example, is what a sample listing of an XML serialization of
a Birthdate object looks like:
January
1
1900
Typically, an XML document serializes (or unmarshals) directly
to a tree of classes known as a content tree. It's a tree
because each element in the XML contains one or more elements
that are themselves objects. In this example, the
element is a class, as is the element (a String).
Because String is a Java built-in type, JAXB does not have to
generate a class for it. For a more complex object, however,
many classes can be generated. After the XML instance document
has been turned into a class instance, a Java application can
recursively move down the content tree to any object that has
been created and access its value.
After the binding compiler generates the necessary classes, the
next step is to compile the generated classes with javac. Then
you can start working with JAXB serialization. As mentioned
earlier, the process of translating a Java object to a
serialized XML representation is called marshalling. The reverse
process, that is, translating from a serialized XML
representation to a Java object, is called unmarshalling. Let's
first look at unmarshalling.
Unmarshalling
Here is a code example that unmarshals data from an XML file to
a JAXB-generated instance:
import javax.xml.bind.*;
JAXBContext jc = JAXBContext.newInstance(
"com.nexes.jaxb.test");
Unmarshaller unmarshaller = jc.createUnmarshaller();
unmarshaller.setValidating(true);
Birthdate instance = (Birthdate)unmarshaller.unmarshal(
new File("birthdateInstance.xml"));
System.out.println("Month is: " + instance.getMonth());
System.out.println("Day is: " + instance.getDay());
System.out.println("Year is: " + instance.getYear());
The code creates a JAXBContext instance using the
com.nexes.jaxb.test package:
JAXBContext jc = JAXBContext.newInstance(
"com.nexes.jaxb.test");
This package contains the interfaces and classes that were
generated in the earlier example by the binding compiler from
Birthdate.xsd schema. The context object is then used to create
an Unmarshaller object:
Unmarshaller unmarshaller = jc.createUnmarshaller();
The Unmarshaller object performs most of the tasks associated
with translating the XML to a Java content tree. The code calls
the unmarshal() method of the Unmarshaller object, passing in
the name of the XML file that contains the instance data. Note
that you can use data sources and sinks other than files. The
example that comes with this tip saves the result in a String
and displays output to a servlet:
Birthdate instance = (Birthdate)unmarshaller.unmarshal(
new File("birthdateInstance.xml"));
The unmarshal() method returns an object that is an instance of
the class that was generated by the Schema compiler.
Notice the setValidating() method for the unmarshaller object:
unmarshaller.setValidating(true);
If setValidating() is set to true, the JAXB runtime API
validates the XML that contains the instance data against the
constraints specified by the XML schema that was submitted to
the binding compiler. If the data is invalid, the validation
fails and generates a runtime exception. JAXB providers do not
necessarily have to stop processing the data if a validation
error is found. However, they do have to report the runtime
exception to the invoker.
Marshalling
The opposite of unmarshalling is marshalling. Here is a code
example that marshals a Java content tree to an xml file:
import javax.xml.bind.*;
ObjectFactory objFactory = new ObjectFactory();
Birthdate birthdate = objFactory.createBirthdate();
birthdate.setMonth("January");
birthdate.setDay(1);
birthdate.setYear(1900);
JAXBContext jaxbContext = JAXBContext.newInstance(
"com.nexes.jaxb.test");
Marshaller marshaller = jaxbContext.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT,
new Boolean(true));
marshaller.marshal(birthdate, new FileOutputStream(
"birthdateInstance.xml"));
This code in this example is very similar to the source code for
the unmarshalling example. First, the code creates a JAXBContext
object, passing in the name of the package that has the binding
compiler generated files:
JAXBContext jaxbContext = JAXBContext.newInstance(
"com.nexes.jaxb.test");
Next, a Marshaller object is created using the
createMarshaller() method:
Marshaller marshaller = jaxbContext.createMarshaller();
The code then sets a property specifying that
JAXB_FORMATTED_OUTPUT should be written to the output file:
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT,
new Boolean(true));
Finally, the marshaller takes the current class instance and
writes it to a FileOutputStream. The FileOuputStream is mapped to
the file birthdateInstance.xml:
marshaller.marshal(birthdate, new FileOutputStream(
"birthdateInstance.xml"));
Optionally, you can validate an object you are serializing
against a JAXB-generated content tree. To do that, use the
Validator object as follows:
Validator validator = jaxbContext.createValidator();
Validator.validate(birthdate);
The JAXB specification does not require that a class instance
be validated before being marshalled to an XML representation.
You can try out marshalling and unmarshalling by running the
JAXB test servlet that accompanies this tip. For details, see
the section "Running the Sample Code."
For more information about JAXB, see the Java Architecture for
XML Binding (JAXB) page (http://java.sun.com/webservices/jaxb/). It
includes links to detailed specifications and articles on using
JAXB. Also see the document, "Java Architecture for XML Binding
(JAXB) Bindings Schema for JAXB"
(http://java.sun.com/xml/ns/jaxb/) to learn more about the
proper schema for XML binding. Also visit the jaxb project on
java.net (https://jaxb.dev.java.net/).
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
REVISITING TIMERS WITH ENTERPRISE BEANS
It's sometimes the case that a J2EE application needs to perform
a regularly scheduled back-end task. This naturally calls for a
timer. Prior to J2EE 1.4, creating timers for enterprise beans
typically meant creating a custom solution, reusing the J2SE
timer functionality, or going to a third-party product. However
J2EE 1.4 provides for a timer service -- one that containers
manage. This service maintains each of the registered timers,
and notifies Enterprise JavaBeans (EJB) technology components
(also known as enterprise beans) when the timer expires. If the
container crashes, the timers are recreated when the server
restarts. Any timers that have expired then notify the affected
enterprise beans.
The May 27, 2004 Enterprise Java Technologies Tech Tip titled
"The Enterprise Bean Timer Interface"
(http://java.sun.com/developer/EJTechTips/2004/tt0527.html#2)
presented a simple timer bean that cleans a log when the timer
expires. The term "expires" here means that the timer
counted down to zero and notified the enterprise bean that it
needs to do something. It does not mean that the timer has been
invalidated and discarded from the timer service -- this is
known as canceling the timer.
The following tip reviews the source code necessary to
implement a simple timer in a session bean. The tip builds on
the previous tip on timers by discussing some considerations
when working with timers. It assumes that you are familiar with
the EJB architecture, including both deployment and locally
exposing bean methods.
Reviewing the Timer Architecture
Let's review the basics: An enterprise bean can create any
number of timers, provided that the EJB environment in which the
bean is deployed allows it. Timers that are created by entity
beans are specific to the primary key identity of the bean. As
a result, there is one timer for each unique instance of the
entity bean. Timers that are created by stateless session beans
and message-driven beans are shared between instances in
a container pool.
Here are the four primary classes or interfaces used to create
timers in the EJB 2.1 architecture:
o javax.ejb.TimedObject. This interface specifies a method,
ejbTimeout(), that must be implemented by the enterprise bean
designer. The timer service calls the ejbTimeout() method when
each timer expires.
o javax.ejb.TimerService. This class is the container's timer
service object. A TimerService is obtained through the
getTimerService() method of the SessionContext.
o javax.ejb.Timer. This class allows the user to create timers
(as well as cancel them) pertaining to the current enterprise
bean. A Timer is created through the createTimer() method of
the TimerService object.
o javax.ejb.TimerHandle. This object provides a serializable
copy of the Timer. The copy can be used to store and retrieve
persistent timers. A TimerHandle is returned by the
getHandle() method of a Timer object.
Creating an EJB timer is quite simple, and consists of only two
steps:
1. Create an enterprise bean (that is, an entity, stateless
session, or message-driven bean) that extends the
javax.ejb.TimedObject interface. This interface requires that
a method called ejbTimeout() will be called by the timer
service when the timer expires.
2. Create the timer using the TimerService object. After you
have an instance of the TimerService object, use one of the
four createTimer() methods to put the timer into service.
The methods instantiate a timer inside the EJB container.
These four createTimer() methods are as follows:
o createTimer(long timeoutDuration, Serializable info). This
method creates a single-event timer. The timeoutDuration
parameter specifies the amount of time, in milliseconds, that
is allowed to pass before the timer expires and the
TimedObject's ejbTimeout() callback method is invoked.
o createTimer(Date firstDate, Serializable info). This method
works in a similar manner to the previous method. However,
instead of specifying a timeout, you provide a Date object
that specifies when the timer should fire.
o createTimer(Date firstDate, long timeoutInterval,
Serializable info). This method specifies an initial date
on which the timer should fire. It also specifies the interval
of time before each repeated firing of the timer.
o createTimer(long timeoutDuration, long timeoutInterval,
Serializable info). This method is similar to the previous
interval method, except that the initial firing is based on
a specified time duration, in milliseconds, from the current
system time.
Use the interval timer versions of the createTimer() method for
events that occur repeatedly at constant intervals. Use the
single event (that is, non-interval) versions of the method for
a timer that only needs to be fired once, and then will be
discarded. Notice that each createTimer() method includes a
Serializable parameter called info. This is used to pass in an
identification tag for the timer, typically a String, that can
be used to locate a timer instance at a later point if needed.
It can also be used to pass a reference to an object that might
be needed during timer callback processing. You can
set the parameter to null if it is not needed.
If you need to cancel a timer, you can use the cancel() method
on the target Timer object. The method cancels the current
timer.
Here are is an example of a stateless session bean that includes
methods that create and kill a timer.
public class TimerBean implements SessionBean, TimedObject
{
// EJB Framework Code Omitted
public void createTimer(
long startTime, long timeout, String id)
throws javax.ejb.EJBException, java.rmi.RemoteException
{
TimerService timerService =
sessionContext.getTimerService();
Timer timer =
timerService.createTimer(startTime, timeout, id);
}
public void killTimer(String id)
throws javax.ejb.EJBException, java.rmi.RemoteException
{
TimerService timerService =
sessionContext.getTimerService();
Collection timers = timerService.getTimers();
Iterator iterator = timers.iterator();
// Search through the collection, and find the timer
// that matches the given ID. For each instance
// that is found, call the cancel() method on it.
while (iterator.hasNext()){
Timer t = (Timer)iterator.next();
if (t.getInfo().equals(id))
t.cancel();
}
}
}
Considerations in Working With Timers
Here are some important things to consider when designing
enterprise beans that use timers.
o Entity beans, stateless session beans, and message-driven
beans can each have their own timer service. Stateful session
beans, however, cannot have a timer service. (However, if
a stateful session bean is passed an EJB timer from another
enterprise bean, it could invoke the javax.ejb.Timer
operations.)
o For entity beans, create timers in the ejbPostCreate()
method. This way, the timers can be attached to the specific
bean instance. For stateless-session beans, create timers in
a business method of the bean. For message-driven beans,
timers should be created whenever a message is received.
o Remember the serializable info parameter in each of the
createTimer() methods. The parameter is useful if you need to
create more than one timer in a bean (among other uses).
o You can use the getHandle() method of the Timer object to
serialize and restore a TimerHandle instance for later use.
After you deserialize a TimerHandle, use the getTimer() method
to reobtain an instance of the timer.
o It's often helpful to provide some means of canceling timers.
However, be aware that single-action timers are removed after
they successfully expire. Many applications rely on periodic
timers to continue firing. EJB timers associated with entity
beans are removed automatically when the entity bean (primary
key) is removed. In addition, all EJB timers are removed when
the application is undeployed.
o Entity beans typically have a timer for each of their
instances. Message-driven beans and stateless session beans
are associated with the type of bean, not the instance of
a particular bean. When the timer expires for a message-driven
bean or stateless session bean, the container calls the
ejbTimeout() method on a single TimedObject bean instance in
the instance pool. The container can pick any instance.
o Each call to createTimer() creates a new timer object inside
of the container. Be sure not to flood the application server
with timers if you can reuse one that is already processing.
If you want to guarantee exclusivity by checking for existing
timers, use the getTimers() method of the timer service. This
method is shown in the killTimer() method in the example above.
o If you use a timer with a transaction, you should give the
ejbTimeout() method a transaction attribute of RequiresNew.
Creating and canceling the timer should be done in the context
of the current bean. In that case, if the transaction needs to
be rolled back, the timer creation and cancellation is also
rolled back.
o A number of vendors now provide JMX MBeans for managing EJB
timers.
For more information on EJB Timer best practices, see the
section "Using the J2EE 1.4 Timer Service for Scheduling Actions"
(https://bpcatalog.dev.java.net/nonav/enterprise/timerservice/)
in the Java BluePrints Solutions Catalog. This is an excellent
resource on timer design considerations.
If you want to experiment with timers, download the sample
archive
(http://java.sun.com/developer/EJTechTips/download/ttmay2004.ear)
for the May, 27, 2004 Enterprise Java Technologies Tech Tip,
"The Enterprise Bean Timer Interface"
(http://java.sun.com/developer/EJTechTips/2004/tt0527.html#2).
Also, see the EJB 2.1 specification
(http://java.sun.com/products/ejb/docs.html).
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Running the Sample Code
Download the sample archive for these tips
(http://java.sun.com/developer/EJTechTips/download/ttdec2004-jaxb.war).
The application's context root is ttdec2004-jaxb. The
downloaded war file also contains the complete source code for
the sample.
You can deploy the sample archive on the J2EE 1.4 Application
Server using the deploytool program or the admin console. You
can also deploy it by issuing the asadmin command as follows:
asadmin deploy install_dir/ttdec2004-jaxb.war
Replace install_dir with the directory in which you installed
the war file.
You can access the application at
http://localhost:8080/ttdec2004-jaxb
For a J2EE 1.4-compliant implementation other than the J2EE 1.4
Application Server, use your J2EE product's deployment tools to
deploy the application on your platform.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Additional Resources
NetBeans IDE 4.0 is the first, free open source IDE to support
J2SE 5.0. NetBeans IDE 4.0 has the Tomcat server built in,
provides integrated profiling (JFluid), and a project system
based on Ant to meet all your development needs. You can
download NetBeans IDE 4.0 from the NetBeans IDE downloads page
(http://www.netbeans.org/downloads/).
. . . . . . . . . . . . . . . . . . . . . . .
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 Sun Developer Network - Subscriptions page,
(https://softwarereg.sun.com/registration/developer/en_US/subscriptions),
choose the newsletters you want to subscribe to and click
"Submit".
- To unsubscribe, go to the Subscriptions page,
(https://softwarereg.sun.com/registration/developer/en_US/subscriptions),
uncheck the appropriate checkbox, and click "Submit".
- 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
December 21, 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.