Sun Java Solaris Communities My SDN Account Join SDN
 
Enterprise Java Technologies Tech Tips

Document Handling Using JAX-WS Dispatch and Provider APIs and Using Multiple Databases in a Java Persistence Application

 
In This Issue

Welcome to the Enterprise Java Technologies Tech Tips for July 29, 2006. Here you'll get tips on using enterprise Java technologies and APIs, such as those in Java Platform, Enterprise Edition (Java EE).

This issue covers:

These tips were developed using an open source reference implementation of Java EE 5 called GlassFish. You can download GlassFish from the GlassFish Community Downloads page.

You can download the sample archive for the tip Writing a Handler in JAX-WS.

You can download the sample archive for the tip Using Multiple Databases in a Java Persistence Application.

Any use of this code and/or information below is subject to the license terms.

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.

Document Handling Using JAX-WS Dispatch and Provider APIs
By Deep Singh  

The JAX-WS 2.0 specification provides two new APIs which make it possible for web services to operate at the XML message level. In working with web services and XML, programmers use an implementation of the Service Endpoint Interface (SEI) to provide a Java level abstraction that hides the details of converting between Java methods and corresponding XML. However, sometimes developers want to work directly with XML rather than with Java abstractions. The new APIs provide an alternative to the SEI approach. This Tech Tip shows the APIs in use in a sample application.

The two new APIs are javax.xml.ws.Provider and java.xml.ws.Dispatch. Both are generic APIs. Provider is a server-side API, while Dispatch is a client-side API. These APIs require services to work with messages or message payloads. Because of that, the APIs need to know specifics about the message's structure or the payload structure. The generic nature of the APIs allows them to be used with a variety of message object types. The JAX-WS specification requires that implementations support at least javax.xml.transform.Source, javax.xml.soap.SOAPMessage, javax.activation.DataSource, and JAXB objects. The sample application in this tip uses the javax.xml.transform.Source and javax.xml.soap.SOAPMessage objects in distinct implementations.

The sample application: using Dispatch and Provider

The sample application for this tip is an update to the sample application from the May 27, 2007 tip Document Handling in Web Services Applications. The sample application in the previous tip emulated credit card authorization and used an SEI to implement the web service. The sample application for this tip provides the same service using the Provider interface to implement the web service. The client uses a SOAPMessage object to send messages, and a Source object to send message payloads. The sample uses synchronous callback service invocation mode. In synchronous callback mode, the service's invoke method blocks further processing until the remote operations complete and return a result. The sample application also uses JAXB on both the client and server.

Setting up your environment

The sample for this tip uses an open source reference implementation of Java EE 5 called GlassFish. If you haven't already done so, download GlassFish from the GlassFish Community Downloads page. To build and run the sample, you also need JDK 5.0, which you can download from the J2SE 5.0 downloads page, and Apache Ant 1.6.5, which is in the GlassFish bundle (in Windows, it's in the lib\ant subdirectory).

Installing the sample application

Download the sample package and unzip its contents. The root directory for the sample is techtip. Change the current directory to the techtip directory. Edit the script env.sh (for UNIX) or env.bat (for Windows) to reflect your build environment. For example, change the value of the JAVA_HOME environment variable in the script to the location of JDK 5.0 on your system. Then execute the script to set up your environment.

Building the web service

The sample builds a web service using a WSDL file. The steps involved in doing this are:

  1. Create a WSDL file based on XML schemas.
  2. Write an endpoint implementation class.
  3. Generate portable artifacts for web service execution.
  4. Compile the web service, package it as a WAR file, and deploy it.

Let's look at these steps and files a little closer.

Create a WSDL file based on XML schemas

A WSDL file is packaged with the sample. You can find the WSDL file, CreditCardService.wsdl, in the conf directory. The WSDL file exposes web service operations that authorize credit card payments. For more information about WSDL, see Web Services Description Language (WSDL) 1.1.

Schema files

The two schema files that the WSDL file imports are CreditCardAuthorization.xsd and CreditCardServiceException.xsd. CreditCardAuthorization.xsd defines the structure of the XML document that a client can send to the web service. The elements in the schema that are pertinent to credit card authorization requests are:

   <element name="AuthorizationRequest">
       <complexType>
            <sequence>
                <element name="CreditCard" 
                   type="tns:CreditCard" nillable="true"/>
                 <element name="CardUser" 
                   type="tns:CardUser" nillable="true"/>
            </sequence>
        </complexType>
   </element>            

Similar elements are defined and used for returning authorization status.

CreditCardServiceException.xsd defines the structure of an XML document for returning an error message, that is, when the web service cannot process the request.

Generate portable artifacts

You can find the ant tasks for the sample application in the build.xml file in the techtip directory. The sample uses the wsimport tool and the packaged WSDL to generate portable artifacts such as the service class, JAXB classes, and exception classes. In the sample this is done in an ant task that has the target name generate-server. The ant task uses an external binding file, config-server.xml, which you can find in the conf directory.

After the artifacts are generated, they're compiled using the javac compiler. In the sample, this is done using an ant task with the target name compile-server.

Write an endpoint implementation class

The sample provides two endpoint implementation classes, CreditCardServiceUsingPAYLOAD.java and CreditCardServiceUsingMESSAGE.java. Only one can be deployed as a service at a time. Which one gets deployed depends on an environment variable for the service mode. The environment variable is set by the script you executed earlier. For example, the env.sh script includes the following setting of the environment variable for the service mode:

   # possible values for service_mode are MESSAGE or PAYLOAD
   service_mode=PAYLOAD; export service_mode.

The CreditCardServiceUsingPAYLOAD.java class implements the Provider interface for payload-oriented synchronous callback mode. The CreditCardServiceUsingMESSAGE.java class implements the Provider interface for message-oriented synchronous callback mode.

Here is the implementation using Payload:

   @WebServiceProvider
   @ServiceMode(value=Service.Mode.PAYLOAD)
   public class CreditCardServiceUsingPAYLOAD 
       implements Provider<Source>    {
  
      public Source invoke(Source request) {
          Source response = null;
          try {
              response = authorizePayment(request);
              ...

The JAX-WS specification requires the Provider implementation class contain a @WebServiceProvider annotation. The @ServiceMode annotation defines which callback mode to use. The code for CreditCardServiceUsingPAYLOAD.java specifies Service.Mode.PAYLOAD mode. This indicates that the Provider implementation works with message payloads only.

The class implements the Provider<Source> interface. The type Source can be used only with payload mode. For synchronous callback, the implementation defines an invoke method. This method is called by the client. For an interface of type Provider<Source>, the input and output parameters of the invoke method are Source objects. In the sample, the authorizePayment method is a utility method used to authorize charges on the credit card.

   public Source authorizePayment(Source request) 
       throws Exception {
   Source response = null;
   try {
       String requestXML = getXMLFromSource(request); 
       String responseXML = authorizePaymentSTAX(requestXML); 
       response = getSourceFromXML(responseXML);
       ...

The authorizePayment method converts the input Source to a string. It uses StAX reader and writer APIs to read the input XML and construct output XML, respectively. Recall that the sample in the May 2006 tech tip used the method authorizePaymentSTAX to process the XML document using StAX.

Now, let's look at the service implementation using Message:

   @WebServiceProvider
   @ServiceMode(value=Service.Mode.MESSAGE)
   public class CreditCardServiceUsingMESSAGE 
       implements Provider<SOAPMessage>    {
  
   public SOAPMessage invoke(SOAPMessage request) {
       SOAPMessage response = null;
  
       try {
           Source req = util.getSourceFromSOAPMessage(request);
           Source res = authorizePayment(req);

           ...

As before, the class has WebServiceProvider and ServiceMode annotations. The notable difference is that the mode is now Service.Mode.MESSAGE. The Provider interface supports methods of type SOAPMessage. The invoke method is a synchronous callback method with input and output parameters for soap messages. The utility method getSourceFromSOAPMessage returns a Source object. The utility method authorizePayment is similar to the one defined in the payload example.

The Provider implementation can also use JAXB with the payload or message service modes. The details of using JAXB are beyond the scope of this tip. The sample however does include code that demonstrates the use of JAXB (more about that a little later in the tip).

Compile the web service, package it as a WAR file, and deploy it

You need to compile the service implementation class as well as the portable artifacts for the web service that were generated earlier. Run wsimport on CreditCardService.wsdl to compile the service implementation class and the generated artifacts. Next, you need to package the classes into a WAR file along with the deployment descriptor for web services, sun-jaxws.xml. The packaging is performed in the sample through an ant task that has the target build. The server performs the build based on the service mode you set in the environment. To test the different modes, change the service_mode environment variable in the env.sh or env.bat script, and rebuild the server and client.

Building the client

Here are the steps to build the web service client:

  1. Write the client class.
  2. Generate portable artifacts for web service execution.
  3. Compile the client.
Write the client class

A standalone web service client, CreditCardServiceTest.java, is packaged with the sample. You can find it in the src\client directory. The client calls the credit card web service to authorize payment on a credit card provided by the customer. The client sends credit card and card holder information contained in an XML document to the server.

Here's the method in CreditCardServiceTest that invokes the web service:

   public void testAuthorizePayment(String url, 
          String authrequestXMLfile, Service.Mode mode) 
          throws Exception {
       try { 
           Service service = Service.create(
                  wsdlLoc, serviceName);
           service.addPort(portName, 
                  SOAPBinding.SOAP11HTTP_BINDING, url); 
  
           if(mode.equals(Service.Mode.PAYLOAD)) {
               Dispatch<Source> disp = service.createDispatch(
                      portName, Source.class, mode);
               ...
                      
               Source response = disp.invoke(xmlSource);
            ...

The testAuthorizePayment method creates a service using the url for the WSDL located on the server and the service QName identifying the wsdl:service element. Next, the method adds a port to be used with Dispatch. The added port does not contain information about wsdl:port -- it can be used only with Dispatch instances. The portName is QName for the new web service port, and the url is the endpoint address for the web service. The port uses SOAP1.1/HTTP binding.

If the service mode selected is PAYLOAD, the Dispatch instance is created using an object of type Source. The Dispatch instance invokes the service method using the Source object as input and gets output of type Source.

If the service mode selected is MESSAGE, the Dispatch instance is created using an object of type SOAPMessage:

           if(mode.equals(Service.Mode.MESSAGE)) {
               Dispatch<SOAPMessage> disp = 
                      service.createDispatch(
                             portName, SOAPMessage.class, mode);
               ...
           
                SOAPMessage response = disp.invoke(message);
            ...

For MESSAGE mode, the Dispatch instance calls the invoke method using a SOAPMessage object, and gets a SOAPMessage object in response.

As mentioned earlier, this tip does not describe how to use JAXB with the payload or message service modes. However the following lines of code in class CreditCardServiceTest.java use JAXB to test the payment authorization:

           JAXBContext jc = 
                  JAXBContext.newInstance("creditcard");
           Unmarshaller u = jc.createUnmarshaller();
            
               AuthorizationRequest request =
                   (AuthorizationRequest)u.unmarshal(
                   new FileInputStream(authrequestXMLfile));
           ...
           
               Dispatch<Object> disp = 
                   service.createDispatch(portName, jc, mode);
               AuthorizationStatus response = 
                   (AuthorizationStatus)disp.invoke(request);
           ...
Generate portable artifacts and compile the client

Generate client-side portable artifacts using the WSDL on the server. This is done in the sample using an ant task with the target build. Actually, when you call ant target build, it compiles both the server and client classes, including the generated artifacts. It also builds a deployable WAR file. Note that the client uses a JAXB binding configuration file, config-client.xml. The client is built based on the service mode you set in the environment. To test the different modes, change the service_mode environment variable in the env.sh or env.bat script, and rebuild the server and client.

Running the sample

After running the script to set up your environment, you can run the sample as follows:

  1. Start GlassFish by entering the following command:
    %J2EE_HOME%/bin/asadmin start-domain domain1

    Ensure that the J2EE_HOME environment variable is set to the GlassFish install directory.

  2. Build the web service, the client, and needed artifacts, and package it into a WAR file by entering the following command:
    ant build
  3. Deploy the application by entering the following command:
    ant deploy
  4. Run the application by entering the following command:
    ant run
    The command runs the application using all three XML handling technologies. You should see output that looks something like this:
          run:
               [java] Calling Credit Card Service with MESSAGE...
               [java] Response from Credit Card Service:
               [java] <?xml version="1.0" encoding="UTF-8"?>
               <soapenv:Envelope xmlns:soapenv=
               "http://schemas.xmlsoap.org/soap/envelope/">
               <soapenv:Body><ns0:AuthorizationStatus xmlns:ns0=
               "urn:CardService"><ns0:authorizationToken>49235677
               </ns0:authorizationToken><ns0:authorized>true
               </ns0:authorized><ns0:errorCode>0</ns0:errorCode>
               </ns0:AuthorizationStatus></soapenv:Body>
               </soapenv:Envelope>
    
  5. Undeploy the application by entering the following command:
    ant undeploy
  6. Delete all classes and the WAR file generated for the application by entering the following command:
    ant clean

About the Author

Deep Singh is a staff member of the Java Performance Engineering group at Sun Microsystems.

Using Multiple Databases in a Java Persistence Application
By Rahul Biswas  

The June 24, 2006 Tech Tip Inheritance and the Java Persistence API was the first Enterprise Java Technologies Tech Tip about the new Java Persistence API. This tip is second in the series. Here you'll examine a sample application that uses the Java Persistence API to persist entities in multiple databases.

The sample application

A sample application accompanies this tip. The application displays information about about orders. A user can view basic information about an order:

The user can also display more details about an order:

To display this information, the application loads and displays entities (that is, persistent objects) that map to two separate databases. One entity maps to data in a database that contains basic information about an order such as the order identification and description. Another entity maps to a database that contains further details about the order such as the configuration description.

The application has four types of components:

  • An HTML page: index.html
  • A JavaServer Page (JSP): viewOrder.jsp
  • A stateless session bean (SessionStateless.java) and its local interface (SessionStatelessLocal.java)
  • Entities (Order.java and Configuration.java)

The JSP uses the stateless session bean to access the entities. For example, when a user selects an order in the drop down menu of the index.html page and then clicks the View Order button, it loads the viewOrder.jsp page. The JSP page then uses the stateless session bean to access the Order entity. Here's a snippet of code from viewOrder.jsp that accesses the Order entity:

   <% 
      Order order = null;
      String orderID=request.getParameter("orderID");
      String action = request.getParameter("action");
      
      order = stateless.loadOrder(orderID); 
   %>

Notice that the viewOrder.jsp page calls the loadOrder method in the stateless session bean. Here's what the loadOrder method looks like:

   @TransactionAttribute(TransactionAttributeType.REQUIRED)
   public Order loadOrder(String id){
       return em1.find(Order.class, id);
       }

em1 in the loadOrder method is an entity manager. The session bean uses entity managers to load entities from a database. In the loadOrder method, em1 is used to load the Order entity from a database. If the user requests additional details about an order, the JSP page calls another method, loadConfiguration, in the session bean. That method uses another entity manager to load a Configuration entity from a second database. The Configuration entity that is loaded is based on the configID that's stored in the Order entity. The Order and Configuration entities have the following attributes:

   public class Order implements Serializable {
       
       private String id;
       private String description;
       private String configID;
       
       
   public class Configuration implements Serializable {
        
       private String id;
       private String description; 

The configID attribute of the Order entity is the primary key of the Configuration entity in a separate database.

Using Multiple Databases

If you look at the build.xml file in the setup directory of the sample, you'll see an ant task with the target setup. That task creates two Derby databases: sun-appserv-samples-db1 and sun-appserv-samples-db2 (the database names are specified in the build.properties file in the sample directory). The setup task also creates two sets of transactional JDBC data sources (jdbc/SamplesDB and jdbc/SamplesDB2) and JDBC connection pools on the application server. One connection pool points to the sun-appserv-samples-db1 database and the other points to the sun-appserv-samples-db2 database.

The JDBC resources and JDBC connection pools need to map to persistence units. The Java Persistence API allows you to define multiple persistence units, each of which can map to a separate database. If you look at the persistence.xml file in the src\conf directory you'll see persistence units specified for sample-db1 and sample-db2:

   <persistence version="1.0">
    <persistence-unit name="sample-db1">
     <provider>
      oracle.toplink.essentials.ejb.cmp3.EntityManagerFactoryProvider
     </provider>
     <jta-data-source>jdbc/SamplesDB</jta-data-source>
     <non-jta-data-source>jdbc/SamplesDB__nontx
     </non-jta-data-source>
    </persistence-unit>
    <persistence-unit name="sample-db2">
     <provider>
      oracle.toplink.essentials.ejb.cmp3.EntityManagerFactoryProvider
     </provider>
     <jta-data-source>jdbc/SamplesDB2</jta-data-source>
     <non-jta-data-source>jdbc/SamplesDB2__nontx
     </non-jta-data-source>
    </persistence-unit>
   </persistence>
   

The sample-db1 persistence unit maps to the jta-data-source with a JNDI name of SamplesDB. The sample-db2 persistence unit maps to the jta-data-source with a JNDI name of SamplesDB2.

The sample-db1 and sample-db2 persistence units are used to create and inject the appropriate entity managers into the stateless session bean. Here is the code in the session bean that injects the entity managers with a transactional persistence context on which the session bean has a dependency:

   @PersistenceContext(unitName="sample-db1", 
          type=PersistenceContextType.TRANSACTION)
   private EntityManager em1;
       
   @PersistenceContext(unitName="sample-db2", 
          type=PersistenceContextType.TRANSACTION)
   private EntityManager em2;
   

em1 is the entity manager for the sample-db1 persistence context. This means that when the viewOrder.jsp JSP calls the method loadOrder, the method uses the entity manager for the sample-db1 persistence context to load the Order entity from the sun-appserv-samples-db1 database.

em2 is the entity manager for the sample-db2 persistence context. This means that when the viewOrder.jsp JSP calls the method loadConfiguration, the method uses the entity manager for the sample-db2 persistence context to load the Configuration entity from the sun-appserv-samples-db2 database.

Summary

As you can see, the Java Persistence API makes it easy to store persistent entities in multiple databases.

For more information about the Java Persistence API, see the article The Java Persistence API - A Simpler Programming Model for Entity Persistence.

Running the Sample Code

To install and run the sample code that accompanies this tip:

  1. If you haven't already done so, download GlassFish from the GlassFish Community Downloads Page, and install it.

  2. Set the following environment variables:

    • GLASSFISH_HOME. This should point to where you installed GlassFish.

    • ANT_HOME. This should point to where ant is installed. Ant is included in the GlassFish bundle that you downloaded. (In Windows, it's in the lib\ant subdirectory.)

    • JAVA_HOME. This should point to the location of JDK 5.0 on your system.

    Add $JAVA_HOME/bin, $ANT_HOME/bin, and $GLASSFISH_HOME/bin to your PATH environment variable.

  3. Download the sample package and extract its contents. You should now see the newly extracted directory as <sample_install_dir>/ttjuly2006multdb , where <sample_install_dir> is the directory in which you installed the sample package. The sample directory below ttjuly2006multdb contains the source files and other support files for the sample.

  4. Change to the sample directory and edit the build.properties file as appropriate. For example, if the admin host is remote, change the value of admin.host from the default (localhost) to the appropriate remote host. Also, make sure that the javaee.server.passwordfile location is correct.

  5. Start GlassFish:
    $GLASSFISH_HOME/bin/asadmin start-domain domain1


  6. Start the database server. From the sample directory enter the following command:
    ant setup
    In response you should see output similar to this:
         ...
               
          start-db:
               [exec] Database started in Network Server mode on 
               host ... and port ...
                
               [exec] Starting database in the background.  Log 
               redirected to ...
               [exec] Command start-database executed successfully.
    


  7. Build and deploy the sample application. From the sample directory enter the following command:
    ant all
    In response you should see output similar to this:
          compile:
                
                [javac] Compiling ... source files to ...
                ...\sample\build\classes
                
                package-ejb:
                ...
                [jar] Building jar: ...\sample\build\ejb\sample.jar
                
                package-war:
                ...
                [zip] Building zip: ...\sample\build\sample.ear
                
                tools:
                
                deploy:
                [exec] Command deploy executed successfully.  
    


  8. Start the application. Open your browser to http://<host>:8080/sample/index.html, replacing <host> with your host name (for instance, localhost). You should see the home page of the application.


About the Author

Rahul Biswas is a member of the Java Performance Engineering group at Sun. He is currently involved in the development of a generic performance benchmark for Java Persistence and the performance improvement of the persistence implementation in GlassFish.

Rate and Review
Tell us what you think of the content of this page.
Excellent   Good   Fair   Poor  
Comments:
Your email address (no reply is possible without an address):
Sun Privacy Policy

Note: We are not able to respond to all submitted comments.