Enterprise Java Technologies Tech Tips
Tips, Techniques, and Sample Code
Welcome to the Enterprise Java Technologies Tech Tips for
April 25, 2005. 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:
* An Introduction to SAAJ
* Improved Internationalization in the Java Servlet 2.4
API
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 staff member of java.sun.com.
You can view this issue of the Tech Tips on the Web at
http://java.sun.com/developer/EJTechTips/2005/tt0425.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 the Introduction to SAAJ
tip at
http://java.sun.com/developer/EJTechTips/download/ttapr2005saaj.jar.
You can download the sample archive for the Improved
Internationalization in the Java Servlet 2.4 API tip at
http://java.sun.com/developer/EJTechTips/download/ttapr2005-servlet.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 - Hot games, cool apps -- Experience the power of Java
technology.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
AN INTRODUCTION TO SAAJ
The SOAP with Attachments API for Java (SAAJ)
(http://java.sun.com/webservices/saaj/index.jsp) is an API you can use
to write direct SOAP messaging applications, that is, instead of
using the JAX-RPC APIs. By making method calls using SAAJ, you
can read and write SOAP-based XML messages, and you can
optionally send and receive these type of messages over the
Internet. This Tech Tip is largely based on information from
"Chapter 9: SOAP with Attachments API for Java"
(http://java.sun.com/j2ee/1.4/docs/tutorial/doc/SAAJ.html)
in the J2EE 1.4 Tutorial. It presents a high-level view of how
SAAJ messaging works within the SOAP framework. The tip assumes
that you are already familiar with the internal structure of
a SOAP message. If not, it may help to review the SOAP
specifications
(http://www.w3.org/TR/soap/).
There are two types of SOAP messages that you should be familiar
with: those with attachments, and those without attachments.
Each of these makes use of the classes inside of the
javax.xml.soap package. The simpler of these two are SOAP
messages without attachments.
SOAP Messages Without Attachments
A SOAP message that does not have attachments has a structure
made up of a SOAP part, a SOAP envelope, an optional SOAP header,
and a SOAP body.
There is a SAAJ class for the entire SOAP message, as well as
for each component of the structure. The
javax.xml.soap.SOAPMessage class represents a SOAP message,
the javax.xml.soap.SOAPPart class represents a SOAP part, the
javax.xml.soap.SOAPEnvelope interface represents the SOAP
envelope, and so on. When you create a new SOAPMessage object,
it automatically creates any subclasses that are required to be
in a SOAP message. For example, a new SOAPMessage object has
a SOAPPart object that, in turn, contains a SOAPEnvelope object.
The SOAPEnvelope object then automatically creates an empty
SOAPHeader object followed by an empty SOAPBody object.
The SOAPHeader object can include one or more headers that
contain metadata about the message (for example, information
about the sending and receiving parties). However, the
SOAPHeader object is optional -- it's created by default, but it
can be deleted if not needed.
The SOAPBody object, which always follows the SOAPHeader object
(if there is one), contains the message content. Another object
that may be included in the SOAP message structure is the
SOAPFault object. This object contains error and status
information. If there is a SOAPFault object, it must be in the
SOAPBody object.
SOAP Messages With Attachments
A SOAP message can include one or more attachment parts in
addition to the SOAP part. The SOAP part must contain only XML
content. As a result, if any content in a message is not in XML
format, it must be contained in an attachment part. For example,
if you want a SOAP message to contain a binary file, the message
must have an attachment part for it. An attachment part can
contain any kind of content, so it can contain data in XML
format as well.
SAAJ provides the javax.xml.soap.AttachmentPart class to
represent an attachment part of a SOAP message. If a SOAPMessage
object has one or more attachments, each AttachmentPart object
must have a MIME header to indicate the type of data it contains.
The AttachmentPart object can also have additional MIME headers
to identify it or to give its location. These headers are
optional, but can be useful when there are multiple attachments.
When a SOAPMessage object has one or more AttachmentPart objects,
its SOAPPart object may (or may not) contain message content.
Creating and Sending A Simple SOAP Message
The first step in creating a SOAP message is to invoke the
static newInstance() method of the MessageFactory object. SAAJ
provides a default implementation of the MessageFactory class
that makes it easy to get an instance of the class. The
following code fragment illustrates getting an instance of the
default message factory, and then using it to create a message:
SOAPMessageFactory messageFactory =
MessageFactory.newInstance();
SOAPMessage message = messageFactory.createMessage();
SOAPHeader header = message.getSOAPHeader();
SOAPBody body = message.getSOAPBody();
The four lines in the previous code fragment produce the
following XML message:
. . .
The next step is to add content to the body:
Name bodyName = soapFactory.createName("GetLastTradePrice",
"m", "http://wombat.ztrade.com");
SOAPBodyElement bodyElement = body.addBodyElement(bodyName);
And here is the XML it produces:
. . . .
In this case, GetLastTradePrice is the element's local name,
m is its namespace prefix, and http://wombat.ztrade.com is its
namespace URI. Now, let's add some details inside the
GetLastTradePrice element:
Name name = soapFactory.createName("symbol");
SOAPElement symbol = bodyElement.addChildElement(name);
symbol.addTextNode("SUNW");
Here is the XML it produces:
SUNW
Connections
All SOAP messages are sent and received over a connection. In
SAAJ, the connection is represented by a SOAPConnection object.
The connection that the SOAPConnection object represents goes
from the sender directly to its destination (typically using
an HTTP Post). This kind of connection is called
a point-to-point connection because it makes a one-way trip from
one endpoint to another endpoint. A typical message sent using
SAAJ is a request-response message. This type of message is sent
over a SOAPConnection object, using the call() method
(a request). The call blocks until it receives the reply
(a response).
Here is a simple example. The following code fragment creates
the SOAPConnection object connection, creates and populates
a message, and uses the connection object to send the message:
SOAPConnectionFactory factory =
SOAPConnectionFactory.newInstance();
SOAPConnection connection = factory.createConnection();
// create a SOAP request message and give it content
java.net.URL endpoint =
new URL("http://fabulous.com/gizmo/order");
SOAPMessage response = connection.call(request, endpoint);
The second argument to the call() method identifies where the
message is being sent. The argument can be a String object or
a URL object.
Any web service implemented for request-response messaging must
be able to handle HTTP Post requests, and must return a response
to a message it receives. The response must be a SOAPMessage
object, just as the request must be a SOAPMessage object. This
allows you to access the content of a response with the same
methods that you used to create the message. Note that some
messages might not require any response. The service that gets
such a message is still required to send back a response because
one is needed to unblock the call() method.
A connection can use a lot of resource, so it's a good idea to
close a connection as soon as you are finished using it. You can
close a connection as follows:
connection.close();
Resources
For more information about SAAJ, see "Chapter 9: SOAP with
Attachments API for Java"
(http://java.sun.com/j2ee/1.4/docs/tutorial/doc/SAAJ.html) in
the J2EE 1.4 Tutorial.
Sample Code
The sample code for this Tech Tip uses SAAJ to query a registry
for service organizations whose name matches the name pattern
"Federal Government Service". To run the sample code:
1. Download the sample archive (ttapr2005saaj.jar) for this Tech
Tip.
2. Download and install the Java Web Services Developer Pack
(Java WSDP) 1.5 from
http://java.sun.com/webservices/downloads/webservicespack.html.
3. Change to the directory where you downloaded the sample archive.
Uncompress the JAR file for the sample archive as follows:
jar xvf ttapr2005saaj.jar
4. Add the following Java WSDP 1.5 libraries to your CLASSPATH
environment variable. The locations are given relative to the
base directory (jwsdp-1.5):
saaj/lib/saaj-api.jar
saaj/lib/saaj-impl.jar
jaxp/lib/jaxp-api.jar
jaxp/lib/endorsed/xercesImpl.jar
jaxp/lib/endorsed/xalan.jar
jaxp/lib/endorsed/dom.jar
jaxp/lib/endorsed/sax.jar
jwsdp-shared/lib/mail.jar
jwsdp-shared/lib/activation.jar
5. Compile the SAAJMain.java file.
6. Run SAAJMain:
java SAAJMain
You should see the following results:
---- Request Message ----
Feder
al Government Service
Received reply from: http://uddi.ibm.com/beta/inquiryapi
---- Reply Message ----
Federal Government Serv
iceFederal Government ServiceFederal Government ServiceFederal Government Service
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
IMPROVED INTERNATIONALIZATION IN THE JAVA SERVLET 2.4 API
If you've used any of the internationalization features in
version 2.3 of the Java Servlet API, you likely had to pass
a java.util.Locale object to the setLocale() method of the
javax.servlet.ServletResponse interface. This meant that you
had to first create a Locale object. Alternatively, you might
have used the setContentType() method to pass both the content
type and the charset, such as:
setContentType('text/html; charset=UTF-8');
Using these methods was both inconsistent and unclear. In
version 2.4 of the Java Servlet API, there are two new
methods in the javax.servlet.ServletResponse interface that help
to more directly support internationalization:
o setCharacterEncoding(String encoding). This method sets the
response's character encoding. The method provides an
alternative to passing a charset parameter to setContentType(),
or passing a Locale to setLocale().
o getContentType(): This method returns the response's content
type. The method returns a String that can include a charset
parameter set by either setContentType(), setLocale(), or
setCharacterEncoding(). If no type was specified, the method
returns null.
Using setCharacterEncoding(), you simply specify the character
encoding as a String -- you don't need to first create a Locale
object as you did with the 2.3 version of the Java Servlet API.
However, for this method to have effect, it must be called
before the getWriter method, and before the response is
committed. The setCharacterEncoding() method pairs with the
preexisting getCharacterEncoding() method to provide an easy way
to manipulate and view the response's character encoding
(charset).
The second new method is getContentType(). This method returns
the content type used in the ServletResponse object, that is, as
a result of invoking the setContentType(), setLocale(), or
setCharacterEncoding() methods in the ServletResponse object.
The getContentType() method pairs with the preexisting
setContentType() method to expose the content type you assigned.
Before Servlet 2.4,, this wouldn't have been too interesting,
but now the type might be dynamically set with a combination of
setContentType(), setLocale(), and setCharacterEncoding() calls.
The getContentType method provides a way to view the generated
type string.
Does this mean that using setCharacterEncoding() is better than
using setLocale()? Well, it largely depends on the context. The
setLocale() method allows you to set a locale, such as "ja" for
Japanese. This, in turn, allows the container to determine an
appropriate charset implicitly. However, more than one charset
might work for a given locale, and using setLocale() doesn't
allow you to choose a specific charset. Consequently, the
setCharaceterEncoding() method provides an explicit way to
choose a specific charset. For example, it allows you to
override the container's choice of Shift_JIS with EUC-JP.
This helps to solve another problem: in some cases, web
applications set the response character encoding (which
corresponds to the charset value of the content type), but the
web page sent to the browser might be encoded in a different
encoding. This problem can occur when using a container based on
the Java Servlet 2.3 API together with the JavaServer Pages
Standard Tag Library(JSTL)
(http://java.sun.com/products/jsp/jstl/index.jsp). The sequence
of events that might occur is:
1. The application sets the content type including a charset
value. This sets the response character encoding.
2. The application uses a JSTL tag that accesses a resource
bundle.
3. JSTL sets the response locale to the locale that led to the
resource bundle found.
4. The container sets the response character encoding to an
encoding that's suitable for the response locale, but might
be different than the previously set character encoding.
This problem can be solved by distinguishing between explicit
and implicit character encoding specifications. Setting the
character encoding through the content type or by using the
setCharacterEncoding() are explicit specifications. By
comparison, determining the character encoding from a locale
setting is an implicit specification. Implicit specifications
cannot override explicit specifications, so event 4 above will
not occur.
Finally, note that if your application needs to be compatible
with containers based on older specifications, you must freeze
the character encoding.You can do this by calling
ServletResponse.flushBuffer() between the explicit character
encoding specification and the first use of custom actions that
might implicitly determine the character encoding.
Deployment Descriptor Changes for Servlet 2.4
The Java Servlet 2.4 API also introduces a new
element in the web.xml deployment
descriptor. This allows you to assign locale-to-charset
mappings. Each list consists of one or more
elements, where each mapping consists
of a element and a representative for that
:
ja
Shift_JIS
zh_TW
Big5
Using this deployment descriptor, any response assigned to the
ja locale uses the Shift_JIS charset, and any response
assigned to the zh_TW Traditional Chinese locale uses the Big5
charset.
Resources
For more information about Java Servlet Technology, see
"Chapter 11: Java Servlet Technology"
(http://java.sun.com/j2ee/1.4/docs/tutorial/doc/Servlets.html)
in the J2EE 1.4 Tutorial.
Sample Code
Download the sample archive for this tip
(ttapr2005-servlet.war). The application's context root is
ttapr2005-servlet. 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/ttapr2005-servlet.war
Replace install_dir with the directory in which you installed
the war file.
Alternatively, you can use the admin console of the Application
Server to deploy the WAR file.
You can access the application at
http://localhost:8080/ttapr2005-servlet
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.
Click on the link that says "Click here to see the example
servlet." This runs the i18n test servlet, which sets the
character encoding to the UTF-8 variant of Unicode and displays
the word "speak" in Arabic.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
TRY THE NEW SEARCH FACILITY
Sun is working on a new search facility for its developer sites.
The search facility is currently available as a beta release.
Try it out and provide your feedback. You can access the search
facility at
http://onesearch.sun.com/search/onesearch/index.jsp?col=developer-all&qt=java
. . . . . . . . . . . . . . . . . . . . . . .
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 2005 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
April 25, 2005
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.