Enterprise Java Technologies Tech Tips
Tips, Techniques, and Sample Code
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:
* Document Handling Using JAX-WS Dispatch and Provider
APIs
* Using Multiple Databases in a Java Persistence
Application
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
(http://java.sun.com/javaee/glassfish/getit.jsp).
You can view this issue of the Tech Tips on the Web at
http://java.sun.com/mailers/techtips/enterprise/2006/TechTips_July06.html
You can download the sample archive for the tip Writing
a Handler in JAX-WS at
http://java.sun.com/mailers/techtips/enterprise/2006/download/ttjuly2006doc-disp.zip.
You can download the sample archive for the tip Using Multiple
Databases in a Java Persistence Application at
http://java.sun.com/mailers/techtips/enterprise/2006/download/ttjuly2006multdb.zip.
Any use of this code and/or information below is subject to the
license terms at
http://developers.sun.com/dispatcher.jsp?uid=6910008.
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
The JAX-WS 2.0 specification
(http://jcp.org/en/jsr/detail?id=224) 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"
(http://java.sun.com/developer/EJTechTips/2006/tt0527.html#2).
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
(http://java.sun.com/javaee/glassfish/getit.jsp). To build and
run the sample, you also need JDK 5.0, which you can download
from the J2SE 5.0 downloads page
(http://java.sun.com/j2se/1.5.0/download.jsp), 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
(http://java.sun.com/mailers/techtips/enterprise/2006/download/ttjuly2006doc-disp.zip)
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"
(http://www.w3.org/TR/wsdl).
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:
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 {
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 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, 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 {
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 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 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 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