Java API for XML Web services (JAX-WS) is a technology designed to simplify the construction of web services and web service clients in Java. Before looking at the API’s and features offered in the JAX-WS stack, let’s understand the need for a web service stack.
As web services uses SOAP as the communication protocol, web service clients interacting with web services needs to formulate the soap request message, which comprises of soap body containing the payload. On the server side, where the web service is deployed, the server (typically referred to as web service container) must accept the soap request, parse the soap request and look at which method to invoke on the web service implementation. The server must also convert the soap request message into the input object accepted by actual method implementation for the web service. Similarly once the method is executed; the server must convert the response into a soap message before sending the response back to client. The client must than convert the soap response into the required response output object.
You definitely need a framework for these tedious low level tasks of generating or parsing SOAP messages by client and server, converting objects to and from soap messages and tasks like handling soap attachments. JAX-WS provides a complete web service stack which eases above task of developing a deploying web services. JAX-WS supports the WS-I Basic Profile 1.1, which ensures the web service developed using the JAX-WS stack can be consumed by any clients developed in any programming language which adheres to WS-I Basic Profile standard. JAX-WS also includes the Java Architecture for XML Binding (JAXB) and SOAP with Attachments API for Java (SAAJ).
JAXB provides data binding capabilities by providing a convenient way to map XML schema to a representation in Java code. The JAXB shields the conversion of XML schema messages in soap messages to Java code without having the developers to know about XML and SOAP parsing. JAXB specification defines the binding between Java and XML Schema. SAAJ provides a standard way of dealing with xml attachments contained in soap message.
JAX-WS also speeds up web service development by providing a library of annotations to turn plain old Java classes into web services and specifies a detailed mapping from a service defined in WSDL to the Java classes that will implement that service. Any complex types defined in the WSDL are mapped into Java classes following the mapping defined by the Java Architecture for XML Binding (JAXB) specification.
Note: JAX-WS was previously bundled with Java Platform, Enterprise Edition 5 (Java EE 5) platform. JAX-RPC an earlier web service offering was renamed JAX-WS. JAX-WS 2.0 speciation is developed under JSR 224 of the Java Community Process (JCP).
Developing Web services
You can develop a web service using one of two approaches:
- Contract-First : Start with a WSDL contract and generate Java class to implement the service.
- Code-First: Start with a Java class and use annotations to generate both a WSDL file and a Java interface.
The Contract-First wsdl approach requires a good undertanding of WSDL and XSD (XML Schema Definition) for defining message formats. It’s a good idea to start with Code-First if you are fairly new to web services. Later you will look at how to start web service development using the Contract-First approach.
Code-First Web service
Using the Code-First approach, you start with a Java class, or classes, that implement features you want to expose as services. Code-First approach is particularly useful where Java implementations are already available and you need to expose implementations as services. The complete source code for the application is available here.
Developing a Order Processing Web Service
You will create a Order processing web service. The Order processing web service accepts order and shipping information , along with ordered items and generates a confirmation id as response. The code for the Order processing service is provided below. A dummy implementation is provided which prints the customer id and number of items at the console and returns back a dummy order id “A1234”.
package com.nb.beginjava6.service; import javax.jws.WebMethod; import javax.jws.WebService; import javax.jws.soap.SOAPBinding; import com.nb.beginjava6.service.bean.OrderBean; //JWS annotation that specifies that the port Type name of the Web Service is //"OrderProcessPort", the service name is "OrderProcess", and the targetNamespace //used in the generated WSDL is "http://nb.com/beginjava6/orderprocess" @WebService(serviceName = "OrderProcess", portName = "OrderProcessPort",targetNamespace = "http://nb.com/beginjava6/orderprocess") //JWS annotation that specifies the mapping of the service onto the SOAP message //protocol. In particular, it specifies that the SOAP messages are document-literal. @SOAPBinding(style=SOAPBinding.Style.DOCUMENT,use=SOAPBinding.Use.LITERAL) public class OrderProcessService { @WebMethod public OrderBean processOrder(OrderBean orderBean) { //Do processing... System.out.println("processOrder called for customer" + orderBean.getCustomer().getCustomerId()); //No of items ordered System.out.println("Number of items is " + orderBean.getOrderItems().length); //Process Order. //Set the Order Id. orderBean.setOrderId("A1234"); return orderBean; } }
Code: The code listing for order process service.
Note: The JAX-WS annotations used are part of the Web Services Metadata for the Java Platform specification (JSR-181).
The starting point for developing a JAX-WS web service is a Java class annotated with the javax.jws.WebService annotation. As you have noticed the OrderProcessService is annotated with WebService annotation. The WebService annotation defines the class as a web service endpoint.
Note: A Java interface mapped from a WSDL port type is called a Service Endpoint Interface.
The OrderProcessService class (class with @ javax.jws.WebService annotation) implicitly defines a Service endpoint interface (SEI) which delares methods that a client can invoke on the service. All the public methods defined in the class, unless the method is annotated with a @WebMethod annotation with the exclude element set to true gets mapped to WSDL operations. The @WebMethod annotation is optional and used for customizing the web service operation. Apart from the exclude element, the javax.jws.WebMethod annotation provides the operation name and action elements which are used to customize the name attribute of the operation and soap action element in WSDL document. Alternately if the OrderProcessService had implemented an interface, you can specify an explicit interface by adding the endpointInterface element to the WebService annotation. In the Contract First Web Service section you will look at how to use the endpointInterface annotation. Similar to endpointInterface, you can define the target namespace and port name for the web service using the targetNamespace and portName respectively. These values defined are mapped to the generated WSDL definition, like serviceName property value gets mapped to the WDSL service name, port name property value gets mapped to WSDL port name. These properties are optional; if undefined, default values will be derived from the class name.
Note: There is a certain set of requirements for creating a valid JAX-WS endpoint implementation. For instance, the implementing class must be annotated by @WebService or @WebServiceProvider annotation, methods needs to be exposed using @WebMethod and must have JAXB compatible parameters and return types for converting XSD schema to Java objects. Please look at JAX-WS 2.0 specification JSR 224 for detailed requirements.
Next you specify the optional @SOAPBinding annotation at the class level which specifies binding associated with the web service. You had looked at the two soap communication style RPC or Document in Web Service SOAP Communication Style section, you specify those settings in the @SOAPBinding annotation. The default propety values for SOAPBinding attributes are listed below.
Attributes | Possible Values | Default Value |
Style | SOAPBinding.Style.RPC SOAPBinding.Style.DOCUMENT |
SOAPBinding.Style.DOCUMENT |
Use | SOAPBinding.Use.LITERAL SOAPBinding.Use.ENCODED |
SOAPBinding.Use.LITERAL |
parameterStyle | SOAPBinding.ParameterStyle.BARE SOAPBinding.ParameterStyle.WRAPPED |
SOAPBinding.ParameterStyle.WRAPPED |
The style attribute specifies the soap binding style and maps to style atribute on the soap:binding and soap:operation elements in the WSDL Document . The use attribute maps to the use attribute on the soap:body in the WSDL Document. The soap prefix mentioned here refers the soap namespace defined in the WSDL, which typically is bound to the URL “http://schemas.xmlsoap.org/wsdl/soap/”. For WS-I complaint web services the style can be Document or RPC, while use needs to be Literal. Document literal style is preferred way of web service communication.
The parameterStyle is used with conjunction with document style attribute and defines how the web service request/reponse messages needs to be interpreted by a Web service provider/consumer.The SOAPBinding.ParameterStyle.WRAPPED tells the web service provider that the root element represents the name of the operation and child element following the root element represents the pay load.The SOAPBinding.ParameterStyle.WRAPPED is useful where you have defined different methods with same signature, and the web service container uses the operation name (which is root element in SOAPBinding.ParameterStyle.WRAPPED) to invoke the corresponding method on the web service. In case of SOAPBinding.ParameterStyle.BARE the entire payload will be passed to the service method, there will be no root element which wraps the payload. Hence in case of SOAPBinding.ParameterStyle.BARE, you can’t have different methods processing the same message, for instance methods like processOrder (OrderBean orderBean) and getOrderStatus (OrderBean orderBean) unless the web service provider (the web service container) handles this in some way.
Note: As per the WS-I specifications an endpoint (which maps to a class in Java) that supports multiple operations (maps to methods in Java) must unambiguously identify the operation being invoked based on the input message that it receives. This is only possible if all the operations specified in the wsdl:binding associated with an endpoint have a unique operation signature (methods with different signature).
Based on the parameterStyle, the schema artifact generated with WSDL (which you will look in next section) contains the payload or a root wrapper element which wraps the payload. Let’s understand this concept in detail by publishing the web service and looking at the generated schema and WSDL artifact.
Note: The WS-I Basic Profile requires that operations within a wsdl:portType have unique values which imply overloaded methods are not supported. Hence while designing web services one should not expose overloaded methods.
Publishing the Order Process Web Service
Once the web service is implemented , you need to generate any artifacts required by service to deploy the service , package the web service as a deployed artifact , typically a a Web Archive (war) and deploy the war file to any compliant sever which supports JAX-WS 2.0 specification.
Note: The Open source application server GlassFish Application Server from Sun, Tomcat with Java WSDP (Web services developer pack) and Sun Java Application Server are some of the compliant servers for JAX-WS deployments.
For testing purpose, Java 6 bundles a light weight web server to which web service can be published by invoking a Simple API call. You will look at how to test your web services using this approach.
Publish the Order Process Web Service
You will generate the JAX-WS portable artifacts for the Order Process web service by runing the wsgen tool. The wsgen tool generates JAX-WS portable artifacts used in JAX-WS web services. The tool reads a web service endpoint implementation class (SEI) and generates all the required artifacts for web service deployment, and invocation. The wsgen tool will generate the WDSL file and XSD schema for the web service, which needs to be published to the outside world.
For generating the JAX-WS artifacts , run the following command.
Run the following command from source folder to compile the Java files and place the class
files into their respective folders:
javac com\nb\beginjava6\service\*.java com\nb\beginjava6\service\bean\*.java com\nb\beginjava6\service\publish\*.java
After compiling the project , run the following command:-
wsgen -cp . com.nb.beginjava6.service.OrderProcessService –wsdl
Note: Before running the wsgen tool, make sure you have included the JAVA_HOME\bin folder in the environment PATH variable.
wsgen tool provides lot of options , like generating the WSDL and shema artifact for the service by providing the –wsdl option.
As per the JAX WS specification, if you have specified the document wrapped parameter style, each method (annotated with @WebMethod) in your service is converted to two wrapper Java bean classes: one for the method input and one for the method output. The input wrapper bean holds the input parameter and output wrapper bean holds the output parameter. Also the name of input Java wrapper bean must same as the method name, while the output wrapper bean must be same as method name with a ‘Response’ suffix.
As discussed earlier for document wrapped style, the web service request consists of root element which represents the name of the operation and child element following the root element represents the pay load, hence the wrapper Java elements are generated in case of document wrapped parameter style where the root element name maps to the method name. Let’s analyze the Java wrapper bean generated for processOrder() method.
Note: The javax.xml.ws.RequestWrapper and javax.xml.ws.ResponseWrapper annotations can be used to customize the name of the generated wrapper bean classes.
For the OrderProcessService, as there is one method processOrder, hence two Java classes ProcessOrder (input) and ProcessOrderResponse (output) gets generated in com.nb.beginjava6.service.jaxws package. The generated source code for ProcessOrder is providing below.
<strong>@XmlRootElement(name = "processOrder", namespace = "</strong> <strong>http://nb.com/beginjava6/orderprocess")</strong> @XmlAccessorType(XmlAccessType.FIELD) @XmlType(name = "processOrder", namespace = " http://nb.com/beginjava6/orderprocess") public class ProcessOrder { @XmlElement(name = "arg0", namespace = "") <strong>private com.nb.beginjava6.service.bean.OrderBean arg0;</strong> //Gettter and Setter }
Code: The code listing for generated request wrapper class.
As you see in the above code, the ProcessOrder holds the OrderBean and provides JAXB annotations on top of it. The @Xml specific annotations represents the JAXB meta data, which is used by JAXB to map Java classes to XML Schema constructs. JAX-WS uses this mapping to generate XML Schema named type and global element declarations that are referred to from within the WSDL message constructs generated for each operation. For instance, the @XmlType annoation specfies the ProcessOrder will be mapped to complex XSD element type “processOrder”which contains an element “arg0” which is of type “orderBean”. All these is transparently carried out behind the scenes with the JAXB framework.
Once the artifacts are generated , you will publish the Order Process Web Service by running the following web service publisher client.
java com.nb.beginjava6.service.publish.OrderWebServicePublisher
This will publish the Order Web Service at location http://localhost:8080/OrderProcessWeb/orderprocess .You can verify if the web service is running by displaying the Web Services Definition Language (WSDL) generated of the Order Process web service by opening the browser and navigating to the following location:
http://localhost:8080/OrderProcessWeb/orderprocess?wsdl
Before we start analyzing the WSDL and Schema artifacts, let’s analyze the code for the OrderWebServicePublisher. Following provides the source code of the OrderWebServicePublisher client.
package com.nb.beginjava6.service.publish; import javax.xml.ws.Endpoint; import com.nb.beginjava6.service.OrderProcessService; public class OrderWebServicePublisher { public static void main(String[] args) { Endpoint.publish("http://localhost:8080/OrderProcessWeb/orderprocess", new OrderProcessService()); } } Code: The code listing for publishing order process web service.
The Endpoint.publish () method provides a convenient way to publish and test the JAX-WS web service. The publish() takes two parameter, location of the web service and the JAX-WS web service implementation class. The publish() methods creates a light weight web server at the URL specified , in this case local host and port 8080 and deploys the web service to that location. The light weight web server is running in the JVM and can be terminated by calling the endpoint.stop() conditionally or terminating the OrderWebServicePublisher client .
Analyzing the Generated WSDL
To view the generated Order Process web service WSDL, type in the following URL location in the browser: http://localhost:8080/OrderProcessWeb/orderprocess?wsdl
Let’s analyze some important WSDL aspects and look at how the WSDL and schema artifacts were generated based on JAX-WS metadata.
We will start off with analyzing the XSD generated. The XSD generated is imported in WSDL file using the xsd:import tags as shown below, the schemaLocation specfied the location of XSD.
<types> <xsd:schema> <xsd:import schemaLocation="http://localhost:8080/OrderProcessWeb/orderprocess?xsd=1" namespace="http://nb.com/beginjava6/orderprocess" /> </xsd:schema> </types>
Type the schemalLocation (http://localhost:8080/OrderProcessWeb/orderprocess?xsd=1) in the browser and you will see the schema definitions in browser. Let’s analyze the important definitions. The schema definition starts off with targetNamspace and tns declaration, which maps to the tagetNamespace ‘http://nb.com/beginjava6/orderprocess” that we have defined in the @WebService annotation for OrderProcessService.
<xs:schema xmlns:tns=”http://nb.com/beginjava6/orderprocess” xmlns:xs=”http://www.w3.org/2001/XMLSchema” targetNamespace=”http://nb.com/beginjava6/orderprocess” version=”1.0″>
Based on the two wrapper bean classes ProcessOrder and ProcessOrderResponse generated by wsgen tool that was discussed earlier, the following schema elements are generated. The element “processOrder” is of type “processOrder” which represents a complexType containing one element whose name is “arg0” and type “orderBean”. You can see a one to one mapping between the ProcessOrder class and processOrder complex type.
Similarly the element ‘processOrderResponse” is of type “processOrderResponse” whose definitions maps to class ProcessOrderResponse.
<xs:element type="tns:processOrder" /> <xs:element name="processOrderResponse" /> <xs:complexType name="processOrder"> <xs:sequence> <xs:element name="arg0" minOccurs="0" /> </xs:sequence> </xs:complexType>
The orderBean type definition illustrated below maps to the OrderBean class. The orderBean type definition comprises of customer element whose type is customer, orderId whose type is String , orderItems (which is an array as it specifies maxOccurs attribute as “unbounded”) whose type is orderItem and shippingAddress whose type is address.
<xs:complexType name="orderBean"> <xs:sequence> <xs:element name="customer" minOccurs="0" /> <xs:element name="orderId" minOccurs="0" /> <xs:element nillable="true" maxOccurs="unbounded" type="tns:orderItem" minOccurs="0" /> <xs:element name="shippingAddress" minOccurs="0" /> </xs:sequence> </xs:complexType>
Similarly the rest of the schema definitions for customer, orderItems and address are defined which maps to Customer, OrderItem and Address Java bean respectively.
With the schema definitions analyzed, let’s revisit the message definitions in WSDL. The WSDL message definitions are listed below. The WSDL specifies the messages “processOrder” and “processOrderResponse” whose part elements are processOrder and processOrderResponse that we have looked in scheme definitions. The portType specifies the operation ‘processOrder” whose input message is “processOrder” and output message and “processOrderResponse”.
<message name="processOrder"> <part element="tns:processOrder" /> </message> <message name="processOrderResponse"> <part element="tns:processOrderResponse" /> </message> <portType name="OrderProcessService"> <operation name="processOrder"> <input message="tns:processOrder" /> <output message="tns:processOrderResponse" /> </operation> </portType>
Next the WSDL bindings are defined, which defines the soap:binding style as “document” and soap:body use tag as “literal” for input and output message formats for operation ‘processOrder”. The WSDL definitions generated maps to @SOAPBinding annotation that you had defined on OrderProcessService class.
<binding name="OrderProcessPortBinding" type="tns:OrderProcessService"> <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http" /> <operation> <soap:operation soapAction="" /> <input> <soap:body use="literal" /> </input> <output> <soap:body use="literal" /> </output> </operation> </binding>
Next the WSDL service are defined, which specifies the port and corresponding binding type , along with actual location of the service , which is typically a http location, which in this case is http://localhost:8080/OrderProcessWeb/orderprocess
<service name="OrderProcess"> <port binding="tns:OrderProcessPortBinding"> <soap:address location="http://localhost:8080/OrderProcessWeb/orderprocess" /> </port>
With this we have analyzed the generated WSDL and Schema artifacts. The following listing illustrates a sample soap request message sent by web service client when it invokes the processOrder operation.
&lt;/pre&gt; &lt;?xml version="1.0"?&gt; &lt;soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://nb.com/beginjava6/orderprocess" xmlns:xsd="http://www.w3.org/2001/XMLSchema"&gt; &lt;soapenv:Body&gt; &lt;ns1:processOrder&gt; &lt;arg0&lt;/strong&gt;&gt;&lt;customer&gt;&lt;customerId&gt;A123&lt;/customerId&gt;&lt;firstName&gt;John&lt;/firstName&gt;&lt;lastName&gt;Smith&lt;/lastName&gt;&lt;/customer&gt;&lt;orderItems&gt;&lt;itemId&gt;11&lt;/itemId&gt;&lt;qty&gt;11&lt;/qty&gt;&lt;/orderItems&gt;&lt;/&lt;strong&gt;arg0&gt; &lt;/ns1:processOrder&gt; &lt;/soapenv:Body&gt; &lt;/soapenv:Envelope&gt; &lt;pre&gt;
As you see in the above listing , the soap body contains the wrapper root element “processOrder” which maps to the method name “processOrder” in the OrderProcessService web service. This is how the web service container identifies which method to invoke in case of document-literal style. The child element (arg0) following the root element represents the soap payload which maps to the input parameter (OrderBean) of processOrder method in OrderProcessService class. The web service container behinds the scenes convert the soap payload to OrderBean class using JAXB and invoke the method processOrder. Once the method is invoked, the response object (OrderBean) from the method is converted to required soap response transparently by the web service container before transmitting the response back to web service client.
Creating Web Service Clients
You will now look at how to create web service clients from WSDL. JAX-WS comes with a tool called wsimport which is used for generating JAX-WS portable artifacts form WSDL. The portable artifacts typically generated are:
- Service Endpoint Interface (SEI)
- Service
- JAXB generated classes from schema types
- Exception class mapped from wsdl:fault (if any) .
The artifacts generated are used by clients to invoke the web service. The web service clients don’t need to deal with any soap format, like creating or parsing soap messages. This is handled by the artifact code which is generated. The web service client in turn deals with Java object (the JAXB generated classes) which eases developing web service clients and invoking operations on the web service.
Creating Web Service Client
You will generate the JAX-WS artifacts from the OrderProcess WSDL using the wsimport tool. You will then create a web service client, which uses artifact code generated to invoke the Order process web service.
For generating the JAX-WS artifacts , navigate to bin directory which contains all the compiled class files and run the following command.
Note: Before running the wsimport command, make sure you have published the web service by running the OrderWebServicePublisher.
wsimport -keep -p com.nb.beginjava6.service.client
http://localhost:8080/OrderProcessWeb/orderprocess?wsdl
The –keep option signifies to keep the genrated files and –p option specifies the package name where the artifact needs to be genrated. The http://localhost:8080
/OrderProcessWeb/orderprocess?wsdl specfies the location of the WSDL file.
Note: wsimport provides lot of options for customization, for detail options type in wsimport at command prompt.
The following artifacts get generated from OrderProcesService WSDL
- JAXB Classes (Address, Customer, OrderBean and OrderItem): These are generated by reading by reading the schema definitions defined in OrderProcesService WSDL.
- The RequestWrapper and ResponseWrapper classes (ProcessOrder and ProcessOrderResponse): The Wrapper classes are discussed earlier, to wrap the input and output for document literal wrapped style.
- Service class (OrderProcess): This is the class that your clients will use to make requests to the web service.
- Service Interface (OrderProcessService): This class contains the interface your service implements.
You will now look at the how to create a web service client using the above generated artifact. A sample reference code is provided in com.nb.beginjava6.service.client package. The code for web service client is provided below.
package com.nb.beginjava6.service.client; import java.net.MalformedURLException; import java.net.URL; import javax.xml.namespace.QName; public class OrderClient { final QName qName = new QName("http://nb.com/beginjava6/orderprocess", "OrderProcess"); public static void main(String[] args) { if (args.length != 1) { System.out .println("Specify the URL of the OrderProcess Web Service"); System.exit(-1); } URL url = getWSDLURL(args[0]); OrderClient client = new OrderClient(); client.processOrder(url); } private static URL getWSDLURL(String urlStr) { URL url = null; try { url = new URL(urlStr); } catch (MalformedURLException e) { e.printStackTrace(); throw new RuntimeException(e); } return url; } public void processOrder(URL url) { OrderProcess orderProcessingService = new OrderProcess(url, qName); System.out.println("Service is" + orderProcessingService); OrderBean order = populateOrder(); OrderProcessService port = orderProcessingService.getOrderProcessPort(); OrderBean orderResponse = port.processOrder(order); System.out.println("Order id is " + orderResponse.getOrderId()); } private OrderBean populateOrder() { OrderBean order = new OrderBean(); Customer customer = new Customer(); customer.setCustomerId("A123"); customer.setFirstName("John"); customer.setLastName("Smith"); order.setCustomer(customer); // Populate Order Item. OrderItem item = new OrderItem(); item.setItemId("11"); item.setQty(11); order.getOrderItems().add(item); return order; } }
Code: The code listing for order process web service client.
The web service client code listed above does the following
- Creates an instance of OrderProcess class by passing in WSDL URL of the OrderProcess Web Service, along with QName of the service.
- Creates an instance of OrderBean and populates order information in the populateOrder() method
- Retrieves a proxy to the service, also known as a port, by invoking getOrderProcessPort() on the service. The port implements the service interface defined by the service.
- Invokes the port’s processOrder method, passing the OrderBean instance created in Step 2.
- Gets the OrderBean reponse from the service , and prints the Order ID.
Note: Before running the OrderClient, make sure you have published the web service by running the OrderWebServicePublisher.
Compile the client class and then execute the web service client by providing the WSDL URL for the OrderProcess Web Service using the following command.
java com.nb.beginjava6.service.client.OrderClient
http://localhost:8080/OrderProcessWeb/orderprocess?wsdl
When the web service client is executed, you will see the following output at the console, where the OrderWebServicePublisher is running.
processOrder called for customer A123
Number of items is 1
At the console where the web service client is executed, you will receive the following output.
Order id is A1234
As you see in the client code, you don’t deal with any soap or xml based format for invoking web service operation, instead you deal with generated JAXB classes for inputs and outputs messages and use the service interface and service class objects which acts as stubs for web service invocation. The stubs are responsible for creating soap requests from JAXB annotations and converting soap response back to Java object.
You have now successfully created and published your web service and executed it via web service client. In next part, I will describe how to create contract first web services using the same example.