You are receiving this e-mail because you elected to receive e-mail from Sun Microsystems, Inc. To update your communications preferences, please see the link at the bottom of this message. We respect your privacy and post our privacy policy prominently on our Web site http://sun.com/privacy/
  Welcome to the Enterprise Java Technologies Tech Tips.
Enterprise Java Technologies
TECHNICAL TIPS
June 22, 2005
View this issue as simple text
In this Issue
 
Here you'll get tips on using Enterprise Java technologies and APIs, such as those in Java 2 Platform, Standard Edition (J2SE).

This issue covers:

» JAX-RPC Binding Styles and Use Attributes
» The Java Application Verification Kit for the Enterprise

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.

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 where enthusiasts of Java technology can collaborate and build solutions together.

java.com - Hot games, cool apps -- Experience the power of Java technology.

JAX-RPC BINDING STYLES AND USE ATTRIBUTES
 
The May 24,2005 Tech Tip, Creating a Simple Web Service Using JAX-RPC discussed how to create a simple web service using the JAX-RPC API. The tip showed, among other things, how to create a service endpoint interface (SEI), and then used the wscompile tool to generate a Web Services Definition Language (WSDL) document. The WSDL document, written in XML, describes the method calls that can be made to the web service. Let's take a closer look at a WSDL document. Here is the definition of WSDL from Wikipedia:
The Web Services Description Language (WSDL) is an XML format... often pronounced "Whiz-Dull"... that describes the public interface to the web service. This is an XML-based service description on how to communicate using the web service; namely the protocol bindings and message formats required to interact with the web services listed in its directory. The supported operations and messages are described abstractly, and then bound to a concrete network protocol and message format.
So, in short, a WSDL document provides the interface (a generic "list of methods") and a set of instructions that describe how the service is bound to a messaging protocol.

The WSDL 1.1 specification distinguishes two different binding styles, as follows:
  • RPC Style: This style specifies that the <soap:body> contains an element with the name of the service method being invoked (the wrapper element). This element, in turn, contains an entry for each parameter and the return value of this method.

  • Document Style: In this style, there is no wrapper element. Instead, the message parts appear directly under the <soap:body> element. There are no SOAP formatting rules for what the <soap:body> contains. The <soap:body> contains what the sender and receiver agreed on as an XML document.
Within those styles, you can also have an encoded use or a literal use:
  • Encoded: In this use, each message part references an abstract type using the type attribute. The message is produced using an encoding specified by the encodingStyle attribute. The encoding most frequently used is SOAP Encoding, which is a set of serialization rules defined in SOAP 1.1. The rules specify how objects, structures, arrays, and object graphs should be serialized. In general, applications that use SOAP encoding focus on remote procedure calls, and likely use the RPC message style.

  • Literal: In this use, each part references a concrete schema definition using either the element or type attribute. In other words, data is serialized according to a given schema. In practice, this schema is usually expressed using W3C XML Schema.
To summarize, the binding style/use combinations are:
  • RPC/encoded
  • RPC/literal
  • Document/encoded
  • Document/literal
This tip will ignore the Document/encoded combination because it isn't WS-I compliant and is no longer used. To gain a clearer picture of the remaining three combinations, let's take the simple Java method, sayHello, that was used in the May 24, 2005 Tech Tip and add some parameters to it. Then, let's run wscompile and see what WSDL document is generated for each of the binding/use combinations.

JAX-RPC WSDL With RPC/Encoded

Here is the method declaration that was used in last month's Tech Tip, modified to include two additional parameters:
   public String sayHello(String s, int x, float y);
If you run wscompile as described in last month's tip on the SEI that contains the method declaration:
   wscompile -define -mapping build\mapping.xml -d build 
   -nd build -classpath build config-interface.xml
it will use the default style/use combination: RPC/encoded. Here's the WSDL that is generated:
   <?xml version="1.0" encoding="UTF-8"?>

   <definitions name="MyHelloService" 
    targetNamespace="urn:Foo" xmlns:tns="urn:Foo" 
    xmlns="http://schemas.xmlsoap.org/wsdl/" 
    xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
    xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/">
     <types/>
     
     <message name="HelloIF_sayHello">
       <part name="String_1" type="xsd:string"/>
       <part name="int_2" type="xsd:int"/>
       <part name="float_3" type="xsd:float"/></message>
     <message name="HelloIF_sayHelloResponse">
       <part name="result" type="xsd:string"/></message>

     <portType name="HelloIF">
       <operation name="sayHello" 
        parameterOrder="String_1 int_2 float_3">
         <input message="tns:HelloIF_sayHello"/>
         <output message="tns:HelloIF_sayHelloResponse"/>
       </operation>
     </portType>

     <binding name="HelloIFBinding" type="tns:HelloIF">
       <soap:binding 
        transport="http://schemas.xmlsoap.org/soap/http"
        style="rpc"/>
       <operation name="sayHello">
        <soap:operation soapAction=""/>
         <input>
           <soap:body encodingStyle=
            "http://schemas.xmlsoap.org/soap/encoding/" 
            use="encoded" namespace="urn:Foo"/>
         </input>
         <output>
           <soap:body encodingStyle=
            "http://schemas.xmlsoap.org/soap/encoding/" 
            use="encoded" namespace="urn:Foo"/>
         </output>
       </operation>
     </binding>
     
     <service name="MyHelloService">
       <port name="HelloIFPort" binding="tns:HelloIFBinding">
         <soap:address location="REPLACE_WITH_ACTUAL_URL"/>
       </port>
     </service>
     
   </definitions>  
Notice that the style attribute generated in the binding is "rpc" and the use attribute is "encoded". This is the default style and use that the wscompile tool generates for WSDL.

Here is an RPC/encoded SOAP message that invokes the method:
   <soap:envelope>
       <soap:body>
           <sayHello>
               <String_1 xsi:type="xsd:string">Duke</String_1>
               <int_2 xsi:type="xsd:int">5</int_2>
               <float_3 xsi:type="xsd:float">5.0</float_3>
           </sayHello>
       </soap:body>
   </soap:envelope>
The WSDL and SOAP message are straightforward. The service method invoked is <sayHello>, which appears as its own element. Within that element are the parameters: a String, an int, and a float.

The xsi:type attribute might not be needed, as the server can deduce what a legal value is for each message part. That's not a big problem. However, it's difficult to validate this message because <sayHello> is not defined in a schema, but is instead a WSDL definition. In addition, RPC/encoded is not WS-I compliant. This makes it difficult for other types of clients to read the WSDL and generate the appropriate stubs on the client side to call the service.

JAX-RPC WSDL With RPC/Literal

Let's change the use in the binding from encoded to literal. To do this add a -f:rpcliteral option to the wscompile argument:
   wscompile -f:rpcliteral -define -mapping build\mapping.xml 
   -d build -nd build -classpath build config-interface.xml
The generated WSDL looks now looks like this:
   <definitions name="MyHelloService" targetNamespace="urn:Foo" 
    xmlns:tns="urn:Foo" xmlns="http://schemas.xmlsoap.org/wsdl/" 
    xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
    xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/">
     <types/>
     
     <message name="HelloIF_sayHello">
       <part name="String_1" type="xsd:string"/>
       <part name="int_2" type="xsd:int"/>
       <part name="float_3" type="xsd:float"/></message>
     <message name="HelloIF_sayHelloResponse">
       <part name="result" type="xsd:string"/></message>
       
     <portType name="HelloIF">
       <operation name="sayHello" 
        parameterOrder="String_1 int_2 float_3">
         <input message="tns:HelloIF_sayHello"/>
         <output message="tns:HelloIF_sayHelloResponse"/>
       </operation>
     </portType>
     
     <binding name="HelloIFBinding" type="tns:HelloIF">
       <soap:binding 
        transport="http://schemas.xmlsoap.org/soap/http" 
        style="rpc"/>
       <operation name="sayHello">
         <soap:operation soapAction=""/>
         <input>
           <soap:body use="literal" namespace="urn:Foo"/>
         </input>
         <output>
           <soap:body use="literal" namespace="urn:Foo"/>
         </output>
       </operation>
     </binding>
     
     <service name="MyHelloService">
       <port name="HelloIFPort" binding="tns:HelloIFBinding">
         <soap:address location="REPLACE_WITH_ACTUAL_URL"/>
       </port>
     </service>
     
   </definitions>
And here is a SOAP message that invokes the method:
   <soap:envelope>
       <soap:body>
           <sayHello>
               <String_1>Duke</String_1>
               <int_2>5</int_2>
               <float_3>5.0</float_3>
           </sayHello>
       </soap:body>
   </soap:envelope>
Notice that the xsi:type encoding attributes have been removed from the SOAP. More important, RPC/literal is WS-I compliant, so other types of clients can read the WSDL and generate the appropriate stubs on the client side to call the service. However, it's still difficult to validate <sayHello> because it's a WSDL element, not a schema.

JAX-RPC WSDL With Document/Literal

To switch to document encoding, rerun the wscompile tool and use the -f:documentliteral option:
   wscompile -f:documentliteral -define 
   -mapping build\mapping.xml -d build -nd build 
   -classpath build config-interface.xml
Here is the resulting WSDL:
   <definitions name="MyHelloService" targetNamespace="urn:Foo" 
    xmlns:tns="urn:Foo" xmlns="http://schemas.xmlsoap.org/wsdl/" 
    xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
    xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/">
    
     <types>
       <schema targetNamespace="urn:Foo" xmlns:tns="urn:Foo" 
        xmlns:soap11-enc=
         "http://schemas.xmlsoap.org/soap/encoding/" 
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
        xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" 
        xmlns="http://www.w3.org/2001/XMLSchema">
        
         <complexType name="sayHello">
           <sequence>
             <element name="String_1" 
              type="string" nillable="true"/>
             <element name="int_2" type="int"/>
             <element name="float_3" type="float"/>
           </sequence>
         </complexType>
         
         <complexType name="sayHelloResponse">
           <sequence>
             <element name="result" type="string" nillable="true"/>
           </sequence>
         </complexType>
         
         <element name="sayHello" type="tns:sayHello"/>
         <element name="sayHelloResponse" 
          type="tns:sayHelloResponse"/>
       </schema>
     </types>
     <message name="HelloIF_sayHello">
       <part name="parameters" element="tns:sayHello"/>
     </message>
     <message name="HelloIF_sayHelloResponse">
       <part name="result" element="tns:sayHelloResponse"/>
     </message>

     <portType name="HelloIF">
       <operation name="sayHello">
         <input message="tns:HelloIF_sayHello"/>
         <output message="tns:HelloIF_sayHelloResponse"/>
       </operation>
     </portType>

     <binding name="HelloIFBinding" type="tns:HelloIF">
       <soap:binding 
        transport="http://schemas.xmlsoap.org/soap/http" 
        style="document"/>
       <operation name="sayHello">
         <soap:operation soapAction=""/>
         <input>
           <soap:body use="literal"/>
         </input>
         <output>
           <soap:body use="literal"/>
         </output>
       </operation>
     </binding>
     
     <service name="MyHelloService">
       <port name="HelloIFPort" binding="tns:HelloIFBinding">
         <soap:address location="REPLACE_WITH_ACTUAL_URL"/>
       </port>
     </service>
     
   </definitions>
Notice that the <types> elements in the WSDL are much larger this time. Also notice that two <element> elements are defined: one for sayHello, and one for sayHelloResponse.

Here is a SOAP message that invokes the method:
   <soap:envelope>
       <soap:body>
           <String_1>Duke</String_1>
           <int_2>5</int_2>
           <float_3>5.0</float_3>
       </soap:body>
   </soap:envelope>
As you can see, the SOAP message is similar to the one for RPC/literal. Notice that the SOAP message for Document/Literal does not include the <sayHello> element. The primary feature of document/literal, and its key benefit compared to RPC/literal, is the schema element declaration in the WSDL to describe the contents of . This means you can tell what the message body contains simply by looking at the schema. There is no need for additional rules. You can take the schema describing a document/literal message and use it to validate the message (something you can't do with RPC/literal).

The document/literal combination provides a great deal of portability when using JAX-RPC. It's also the binding/use combination supported by Java 2 Platform, Micro Edition (J2ME) clients, as specified by JSR 172: J2ME Web Services Specification. JSR 172 defines a remote method invocation API that is based on a subset of JAX-RPC 1.1. JSR 172 conforms to WS-I Basic Profile. JSR-172 doesn't support Encoded representation. Some reasons for this are to reduce demands on network bandwidth, save users time, and limit per-byte charges.

For more information about JAX-RPC binding styles and use attributes, see the technical article Patterns and Strategies for Building Document-Based Web Services.

Back to Top

THE JAVA APPLICATION VERIFICATION KIT FOR THE ENTERPRISE
 
The Java Application Verification Kit (AVK) for the Enterprise is a tool designed to help developers ensure that their applications use only features specified in the J2EE specification. This ensures the portability of applications across a wide variety of J2EE-compatible application servers. Given the large investment most businesses have in client-server applications, the J2EE platform can save companies a lot of development time and money by reducing the need to install and test across multiple application servers. With J2EE's portability features, there is little or no need to rewrite code for different servers.

The Java BluePrints program provides guidelines for building portable J2EE-based applications. However, it is still possible to inadvertently write non-portable applications. This is where the Java AVK for the Enterprise is useful.

The Java AVK works in two stages: static verification and dynamic verification.
  • Static verification determines if an application suite's deployment descriptors follow the specification, and that the suite contains no methods that are proprietary to a particular vendor. It also checks to see if the application code conforms to the J2EE specification. (For example, it checks if the remote interface of an EJB contains all RMI/IIOP-compliant parameter types.)

  • Dynamic verification determines the proportion of enterprise bean component methods, web services methods, and web components that are invoked by running the application.
This tip discusses how to perform static verification. It also covers some aspects of dynamic verification. The tip is based on information in the Java Application Verification Kit (AVK) for the Enterprise User's Guide. An online version of the User's Guide is available. You can also find the User's Guide in the docs directory of AVK distribution. The next issue of the Tech Tips will cover how to perform more advanced dynamic verification.

Using the Java AVK

If you haven't already done so, download the AVK distribution from the Java Application Verification Kit (AVK) for the Enterprise page, and install it.

To use the AVK, you need to define AVK tasks in an Ant file. (You do not have to have the Application Server running to use these tasks.) The AVK distribution includes a samples directory. In the samples directory, there is a build.xml file that defines two AVK tasks: source scanning and static archive testing. You can tailor the code in the build.xml file to suit your needs. (Note that in the future, the source scanning feature will be deprecated, and source scanning will be performed as part of static archive testing. However, because the source scanning feature is currently covered in the User's Guide, and the SourceScan task is in the sample build.xml file, this tip covers the source scanning feature).

Here are the two AVK tasks definitions in the build.xml file (note that each <taskdef> element is shown here on multiple lines for formatting purposes. Each <taskdef> element in the sample build.xml file is on one line):
   <taskdef name="SourceScan" 
   classname="org.apache.tools.ant.taskdefs.optional.sun.
   verification.SourceScan" 
   classpath="${cpath}"/>
   
   <taskdef name="ArchiveTest"
   classname="org.apache.tools.ant.taskdefs.optional.sun.
   verification.StaticArchiveTest" classpath="${cpath}" />
The build.xml file also includes the following <property> element that defines the classpath (this must appear in the build.xml file):
   <property name="cpath" value="${avk.home}/lib/javke-ant.jar"/>
where avk.home represents the directory in which you installed the Java AVK. The samples directory includes a build.properties file that defines the avk.home property. You can define this property in your own build.properties file or you can define the property in the build.xml file.

In addition to defining the AVK tasks, you also need to specify targets that use the tasks. The build.xml file in the samples directory specifies the following sample targets:
  • code-scan. This target uses the SourceScan task to find code that is proprietary to the application server that was used to generate the application.

  • static-archive-test. This target uses the ArchiveTest task to validate an archive file against the J2EE specifications.

  • translate-dd. This target uses the TranslateRuntimeDD task to convert deployment descriptors from other application servers into Sun Java System Application Server deployment descriptors.
Alternatively, you can define the targets in another xml file and point to that file from the build.xml file.

Scanning Code for Proprietary APIs

(As mentioned previously, the source scanning feature will be deprecated and will be performed as part of static archive testing. However it is covered here because the feature is currently covered in the User's Guide, and the SourceScan task is in the sample build.xml file.)

If you examine the sample build.xml file, you will notice that the first task defined in the file is the code scanning task (SourceScan). The Java AVK will perform this task first if it is used with this build.xml file. In general, it's a good idea to perform the SourceScan task first. That's because the task will alert you to any changes that need to be made in your source code (and the subsequent need to rebuild your application).

Use the SourceScan task to scan source code (in Java or JSP files) for proprietary APIs. For example, the following target in the sample build.xml file scans all Java and JSP files in a directory named nonportable for code specific to the BEA WebLogic 5 server:
   <target name="code-scan" description="scan source code tests">
     <SourceScan srcDir="${avk.home}/samples/nonportable"
                 srcServer="weblogic5" />
   </target>  
Both the srcDir and srcServer attributes are required in the target specification. The srcServer attribute specifies the server that was used to generate the application. See the Java Application Verification Kit (AVK) for the Enterprise User's Guide for the allowed application servers.

You can perform the SourceScan task in the sample by executing the following command:
   asant code-scan
In response, you should see the following result:
   Buildfile: build.xml

   code-scan:
        [echo] 
        See "C:\Sun\javke1.4.1\reporttool\scan\codeSummary.html" 
        for results.

   BUILD SUCCESSFUL
The codeSummary.html file named in the results lists the source files by type (Java files and JSP pages) that were scanned, and lists any nonportable APIs found in each file.

sourcescan

Static Archive Testing

Use the ArchiveTest task to ensure that your application modules comply with the J2EE specifications. This task identifies and reports problems with the module file components' method signatures and other static inconsistencies. It looks at all components of the file, and reports any inconsistencies with the API and deployment descriptors defined in the J2EE specifications.

The task also validates the packaging and structure of the modules. For example, the following target in the sample build.xml file scans the WAR file bookstore.war (note that the <target> and <ArchiveTest> elements are each shown here on multiple lines for formatting purposes. The <target> and <ArchiveTest> elements in the sample build.xml file are on one line):
   <target name="static-archive-test" 
   description="static archive tests for application containing 
   web components, reporting on all tests">
   <ArchiveTest 
   appName="${avk.home}/samples/bookstore/bookstore.war"
   reportingOpts="a" />
   </target>
The appName attribute is required. The value can be the path name of an EAR, JAR, WAR, or RAR file. If you use the task without defining any other attributes, it scans all modules in the archive and reports all failures and warnings. It also indicates where you can find the result.

You can perform the ArchiveTest task in the sample by executing the following command:
   asant static-archive-test
In response, you should see a result that looks similar to this:
   Buildfile: build.xml

   static-archive-test:
     ...
     
     [exec] INFO: 
     [exec] # of Failures : 0
     [exec] # of Warnings : 0
     [exec] # of Errors   : 0
     [exec] Nov 23, 2004 3:04:08 PM 
     com.sun.enterprise.tools.verifier.ReportHandler writeToConsole
     [exec] INFO: Look in file 
     "C:\Sun\javke1.4.1\reporttool\static\bookstore.war.txt" for 
     detailed results.
     [echo] 
     See "C:\Sun\javke1.4.1\reporttool\static\verifierSummary.html" 
     for results.

   BUILD SUCCESSFUL
You can change the value of the reportingOpts attribute to change the scope of the report (for example, to report only failures). You can also specify a partitionOpts attribute to limit the verification process to one or more component types (for example, to EJBs only). See the Java Application Verification Kit (AVK) for the Enterprise User's Guide for the allowed attributes and values.

The summary page from the static archive tests shows the failures, warnings, passes and nonapplicable test results for each of the modules of the J2EE platform contained in the application. Each result contains a link to detailed information, including a description of the test that was run, the assertion in the specification being tested, and the name of the test. In addition, the summary includes a section that lists any errors that the static archive tests encountered.

archivetest

Translating Deployment Descriptors

Every application server has its own runtime deployment descriptors that specify implementation-specific aspects of deployment. An application that previously ran on another J2EE server must convert its runtime deployment descriptors to work with the Sun Java System Application Server. The process of converting deployment descriptors with the Java AVK does not replace your original module or application. Instead it creates a new copy of the module or application with the new deployment descriptors.

Use the TranslateRuntimeDD task to generate the deployment descriptors. For example, the following target in the sample build.xml file converts the deployment descriptors for the EAR file named HelloWorld.ear from BEA WebLogic 6 deployment descriptors to Sun Java System Application Server deployment descriptors (note that the <target> and <TranslateRuntimeDD> elements are each shown here on multiple lines for formatting purposes. The <target> and <TranslateRuntimeDD> elements in the sample build.xml file are on one line):
   <target name="translate-dd" 
   description="translate runtime DD for deployment">
     <TranslateRuntimeDD 
     archiveName=
     "${avk.home}/samples/weblogic_6_x/HelloWorld/HelloWorld.ear"
     srcServer="weblogic6" />
Both the archiveName and the srcServer attributes are required. The srcServer attribute specifies the server that was used to generate the application. See the Java Application Verification Kit (AVK) for the Enterprise User's Guide for the allowed application servers.

You can perform the TranslateRuntimeDD in the sample by executing the following command:
      asant translate-dd
In response, you should see a result that looks like this:
   Buildfile: build.xml

   translate-dd:
     [echo] Some xml files may not have translated correctly.
     [java]       [war] Warning: selected war files include 
   a WEB-INF/web.xml which will be ignored (please use webxml 
   attribute to war 
   task)http://rhea.sfbay.sun.com/iw-cc/command/iw.ccpro.submit
     [java]       [ear] Warning: selected ear files include a 
   META-INF/application.xml which will be ignored (please use 
   appxml attribute to ear task)

     [java] BUILD SUCCESSFUL
     [java] Total time: 3 seconds
     [echo] See 
   "C:\Sun\javke1.4.1\reporttool\translate\translationSummary.html" 
   for results.
     [echo] We attempted to create an ear file even if minor 
   errors occurred. The application with translated deployment 
   descriptors is in a new .ear file located in 
   C:\Sun\javke1.4.1\reporttool\translate\Input_Archives\asmtbuild 

   BUILD SUCCESSFUL
Do not use the new EAR file created by the task. Instead, open the translationSummary.html file in a web browser. This file shows the locations of the new runtime descriptors. These locations begin with the prefix sun-. Add these descriptors to your original application. Note that the task also generates new standard descriptors (application.xml, ejb-jar.xml, web.xml). Do not add these to your application.

translatedd

For more information about the Java AVK, see the Java Application Verification Kit (AVK) for the Enterprise page. Also see next month's issue of ther Tech Tips for further coverage of dynamic verification.

Back to Top

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.
Comments? Send your feedback on the Tech Tips: http://developers.sun.com/contact/feedback.jsp?category=sdn

Subscribe to the following newsletters for the latest information about technologies and products in other Java platforms:
  • 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).
You can subscribe to these and other Java technology developer newsletters or manage your current newsletter subscriptions on the Sun Developer Network Subscriptions page

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

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

© 2005 Sun Microsystems, Inc. All Rights Reserved. For information on Sun's trademarks see: http://sun.com/suntrademarks
Java, J2EE, J2SE, J2ME, and all Java-based marks are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries.