.
.
developers.sun.com java.sun.com
   View this issue as simple text April 25, 2005    

In this Issue

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.

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. You can download the sample archive for the Improved Internationalization in the Java Servlet 2.4 API tip. Any use of this code and/or information below is subject to the license terms.

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) 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 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.

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.

SOAP message without attachments

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.

SOAP message with attachments

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:

   <SOAP-ENV:Envelope
    xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
     <SOAP-ENV:Header/>
     <SOAP-ENV:Body>
       . . .
     </SOAP-ENV:Body>
   </SOAP-ENV:Envelope> 

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:

   <m:GetLastTradePrice
    xmlns:m="http://wombat.ztrade.com">
    . . . .
   </m:GetLastTradePrice> 

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:

   <symbol>SUNW</symbol> 

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 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.

  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 ----

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/so
ap/envelope/"><SOAP-ENV:Header/><SOAP-ENV:Body><find_service gen
eric="2.0" maxRows="100" xmlns="urn:uddi-org:api_v2"><name>Feder
al Government Service</name></find_service></SOAP-ENV:Body></SOA
P-ENV:Envelope>

Received reply from: http://uddi.ibm.com/beta/inquiryapi

---- Reply Message ----

<?xml version="1.0" encoding="UTF-8" ?><Envelope xmlns="http://s
chemas.xmlsoap.org/soap/envelope/"><Body><serviceList generic="2
.0" xmlns="urn:uddi-org:api_v2" operator="private.uddi.operator" 
truncated="false"><serviceInfos><serviceInfo serviceKey="056b290
5-3999-4912-89de-fe79cbfedea0" businessKey="8cd1668c-64fa-4aa5-a
053-bd0be4bd53f5"><name xml:lang="en-US">Federal Government Serv
ice</name></serviceInfo><serviceInfo serviceKey="a70ad5a7-564a-4
acd-ac6a-b2bcf4b26a30" businessKey="3d686d3d-22d7-470c-b515-3264
28321566"><name xml:lang="en-US">Federal Government Service</nam
e></serviceInfo><serviceInfo serviceKey="ca5939ca-71ce-4e65-8b20
-d53f6ad52036" businessKey="f9aa37f9-c9f0-401b-8c0f-f2bd16f20f42
"><name xml:lang="en-US">Federal Government Service</name></serv
iceInfo><serviceInfo serviceKey="2b69352b-835d-4d5b-a51e-1af1e91
a1e44" businessKey="06b7a606-b5a5-452f-8df6-e8cdf5e8f6c6"><name 
xml:lang="fr-BE">Federal Government Service</name></serviceInfo>
</serviceInfos></serviceList></Body></Envelope>
.
.

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:

  • 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().

  • 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). 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 <locale-encoding-mapping-list> element in the web.xml deployment descriptor. This allows you to assign locale-to-charset mappings. Each list consists of one or more <locale-encoding-mapping> elements, where each mapping consists of a <locale> element and a representative <encoding> for that <locale>:

   <local-encoding-mapping-list>
     <local-encoding-mapping>
       <locale>ja</locale>
       <encoding>Shift_JIS</encoding>
     </locale-encoding-mapping>
     <locale-encoding-mapping>
       <locale>zh_TW</locale>
       <encoding>Big5</encoding>
     </locale-encoding-mapping>
   </locale-encoding-mapping-list>

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 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.

When you start the application, you should see a page that looks like this:

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.

You should see the following:

.
.

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 here.

.
.
Rate and Review
Tell us what you think of the content of this page.
Excellent   Good   Fair   Poor  
Comments:
If you would like a reply to your comment, please submit your email address:
Note: We may not respond to all submitted comments.
.
.

IMPORTANT: Please read our Licensing, Terms of Use, and Privacy policies:
http://developers.sun.com/berkeley_license.html
http://www.sun.com/share/text/termsofuse.html

Privacy Statement: Sun respects your online time and privacy (http://sun.com/privacy). You have received this based on your email preferences. If you would prefer not to receive this information, please follow the steps at the bottom of this message to unsubscribe.

Comments? Send your feedback on the Enterprise Java Technologies Tech Tips to: http://developers.sun.com/contact/feedback.jsp?category=newslet

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, choose the newsletters you want to subscribe to and click "Submit".
- To unsubscribe, go to the Subscriptions page, uncheck the appropriate checkbox, and click "Submit".


ARCHIVES: You'll find the Enterprise Java Technologies Tech Tips archives at:
http://java.sun.com/developer/EJTechTips/index.html


Copyright 1994-2006 Sun Microsystems, Inc. All rights reserved.
4150 Network Circle, Santa Clara, CA 95054 USA.


This document is protected by Copyright 1994-2006 Sun Microsystems, Inc. in the United States and other countries.

Sun Microsystems, Inc.
.
.