Table of Contents |
---|
Developing a Service using JAX-WS
...
- Start with a WSDL contract and generate Java objects to implement the service.
- Start with a Java object and service enable it using annotations.
For new development the preferred path is to design your services in WSDL and then generate the code to implement them. This approach enforces the concept that a service is an abstract entity that is implementation neutral. It also means you can spend more time working out the exact interface your service requires before you start coding.
However, there are many cases where you may need to service enable an existing application. While JAX-WS eases the process, it does require that you make some changes to source code of your application. You will need to add annotations to the source. It also requires that you migrate your code to Java 5.0.
...
File | Description |
---|---|
| The SEI. This file contains the interface your service implements. You should not edit this file. |
| The endpoint. This file contains the Java class your clients will use to make requests on the service. |
| The skeleton implementation class. You will modify this file to implement your service. |
| A basic server |
...
portTypeName.java
is the service interface(SEI) for the service._portTypeName_Impl.java
is the class you will use to implement the operations defined for the service.
...
You provide the business logic for your service's operations by completing the stub methods in _portTypeName_Impl.java
. For the most part, you use standard Java to implement the business logic. If your service uses custom XML Schema types, you will need to use the generated classes for each type to manipulate them. There are also some CXF specific APIs that you can use to access some advanced features.
...
For example, an implementation class for a service that defined the operations sayHi
and greetMe
may look like #Example1the following:
Anchor | ||||
---|---|---|---|---|
|
Code Block | ||
---|---|---|
| ||
package demo.hw.server; import org.apache.hello_world_soap_http.Greeter; @javax.jws.WebService(portName = "SoapPort", serviceName = "SOAPService", targetNamespace = "http://apache.org/hello_world_soap_http", endpointInterface = "org.apache.hello_world_soap_http.Greeter") public class GreeterImpl implements Greeter { public String greetMe(String me) { System.out.println("Executing operation greetMe"); System.out.println("Message received: " + me + "\n"); return "Hello " + me; } public String sayHi() { System.out.println("Executing operation sayHi\n"); return "Bonjour"; } } |
Java First Development
To create a service starting from Java you need to do the following:
Create a Service Endpoint Interface (SEI) that defines the methods you wish to expose as a service.
Tip tiletitle Tip You can work directly from a Java class, but working from an interface is the recommended approach. Interfaces are better for sharing with the developers who will be responsible for developing the applications consuming your service. The interface is smaller and does not provide any of the service's implementation details.
- Add the required annotations to your code.
Generate the WSDL contract for your service.
Tip title Tip If you intend to use the SEI as the service's contract, it is not necessary to generate a WSDL contract
- Publish the service.
...
The service endpoint interface (SEI) is the piece of Java code that is shared between a service and the consumers that make requests on it. When starting with a WSDL contract, the SEI is generated by the code generators. However, when starting from Java, it is the up to a the developer to create the SEI.
There are two basic patterns for creating an SEI:
Green field development
You are developing a new service from the ground up. When starting fresh, it is best to start by creating the SEI first. You can then distribute the SEI to any developers that are responsible for implementing the services and consumers that use the SEI.Note title Note The recommended way to do green field service development is to start by creating a WSDL contract that defines the service and its interfaces.
- Service enablement
In this pattern, you typically have an existing set of functionality that is implemented as a Java class and you want to service enable it. This means that you will need to do two things:- Create an SEI that contains only the operations that are going to be exposed as part of the service.
Modify the existing Java class so that it implements the SEI.
Note title Note You can add the JAX-WS annotations to a Java class, but that is not recommended.
...
Tip | ||
---|---|---|
| ||
JAX-WS defines an annotation that allows you to specify methods that are not exposed as part of a service. However, the best practice is to leave such methods out of the SEI. |
#Example2 The below shows a simple SEI for a stock updating service.
Anchor | ||||
---|---|---|---|---|
|
Code Block | ||
---|---|---|
| ||
package org.apache.cxf; public interface quoteReporterQuoteReporter { public Quote getQuote(String ticker); } |
...
Because the SEI is a standard Java interface, the class that implements it is just a standard Java class. If you started with a Java class you will need to modify it to implement the interface. If you are starting fresh, the implementation class will need to implement the SEI.
#Example3 The below shows a class for implementing the above interface in #Example2.
Anchor | ||||
---|---|---|---|---|
|
Code Block | ||
---|---|---|
| ||
package org.apache.cxf; import java.util.*; public class stockQuoteReporterStockQuoteReporter implements quoteReporterQuoteReporter { ... public Quote getQuote(String ticker) { Quote retVal = new Quote(); retVal.setID(ticker); retVal.setVal(Board.check(ticker));[1] Date retDate = new Date(); retVal.setTime(retDate.toString()); return( retVal); } } |
Annotating the Code
JAX-WS relies on the annotation feature of Java 5. The JAX-WS annotations are used to specify the metadata used to map the SEI to a fully specified service definition. Among the information provided in the annotations are the following:
- The target namespace for the service.
- The name of the class used to hold the request message.
- The name of the class used to hold the response message.
- If an operation is a one way operation.
- The binding style the service uses.
- The name of the class used for any custom exceptions.
The namespaces under which the types used by the service are defined.
Tip title Tip Most of the annotations have sensible defaults and do not need to be specified. However, the more information you provide in the annotations, the better defined your service definition. A solid service definition increases the likely hood that all parts of a distributed application will work together.
...
Property | Description |
---|---|
name | Specifies the name of the service interface. This property is mapped to the name attribute of the |
targetNamespace | Specifies the target namespace under which the service is defined. If this property is not specified, the target namespace is derived from the package name. |
serviceName | Specifies the name of the published service. This property is mapped to the |
wsdlLocation | Specifies the URI at which the service's WSDL contract is stored. The default is the URI at which the service is deployed. |
endpointInterface | Specifies the full name of the SEI that the implementation class implements. This property is only used when the attribute is used on a service implementation class. Note: Not allowed on the SEI |
portName | Specifies the name of the endpoint at which the service is published. This property is mapped to the |
Tip | ||
---|---|---|
| ||
You do not need to provide values for any of the |
...
The SEI requires that you add the @WebService
annotation. Since the SEI is the contract that defines the service, you should specify as much detail as you can about the service in the @WebService
annotation's properties.
#Example4 The code below shows the interface defined in #Example2 above with the @WebService
annotation.
Anchor | ||||
---|---|---|---|---|
|
Code Block | ||
---|---|---|
| ||
package com.ionamycompany.demo; import javax.jws.*; @WebService(name="quoteUpdater", targetNamespace="http:\\//cxf.apache.org", serviceName="updateQuoteService", wsdlLocation="http:\\//somewhere.com\/quoteExampleService?wsdl",) public interface QuoteReporter { portName="updateQuotePort") public interface quoteReporter { public public Quote getQuote(@WebParam(name="ticker") String ticker); } |
The @WebService
annotation in #Example4 above does the following:
- Specifies that the value of the name attribute of the
wsdl:portType
element defining the service interface isquoteUpdater
. - Specifies that the target namespace of the service is {{
http:
//cxf.apache.org
}}.Specifies that the value of the name of thewsdl:service
element defining the published service isupdateQuoteService
. - Specifies that the service will use the pre-defined WSDL contract which is published at
http:\\//somewhere.com\/quoteExampleService?wsdl
. - Specifies that the value of the name attribute of the
wsdl:port
element defining the endpoint exposing the service isupdateQuotePort
.
The @WebParam annotation is necessary as java interfaces do not store the Parameter name in the .The @WebParam annotation is necessary as java interfaces do not store the Parameter name in the .class file. So if you leave out the annotation your parameter will be named arg0.
...
In addition to annotating the SEI with the @WebService
annotation, you also have to annotate the service implementation class with the @WebService
annotation. When adding the annotation to the service implementation class you only need to specify the endpointInterface
property. As shown in #Example5 below the property needs to be set to the full name of the SEI.
Anchor | ||||
---|---|---|---|---|
|
Code Block | ||
---|---|---|
| ||
package org.apache.cxf; import javax.jws.*; @WebService(endpointInterface="org.apache.cxf.quoteReporter"), public class stockQuoteReporter implements quoteReporter { public Quote getQuote(String ticker) { ... targetNamespace="http://cxf.apache.org", portName="StockQuotePort", serviceName="StockQuoteReporter", ) public class StockQuoteReporter implements QuoteReporter { public Quote getQuote(String ticker) { ... } } |
Optional Annotations
While the @WebService
annotation is sufficient for service enabling a Java interface or a Java class, it does not provide a lot of information about how the service will be exposed as an endpoint. The JAX-WS programming model uses a number of optional annotations for adding details about your service, such as the binding it uses, to the Java code. You add these annotations to the service's SEI.
Tip | ||
---|---|---|
| ||
The more details you provide in the SEI, the SEIthe easier it will be for developers to implement applications that can use the functionality it defines. It will also provide for better generated WSDL contracts. |
...
Property | Values | Description |
---|---|---|
style |
| Specifies the style of the SOAP message. If |
use |
| Specifies how the data of the SOAP message is streamed. |
parameterStyle |
| Specifies how the method parameters, which correspond to message parts in a WSDL contract, are placed into the SOAP message body. A parameter style of |
#Example6 shows an An SEI that uses rpc/literal SOAP messages .is as follows:
Anchor | ||||
---|---|---|---|---|
|
Code Block | ||
---|---|---|
| ||
package org.eric.demo; import javax.jws.*; import javax.jws.soap.*; import javax.jws.soap.SOAPBinding.*; @WebService(name="quoteReporter") @SOAPBinding(style=Style.RPC, use=Use.LITERAL) public interface quoteReporterQuoteReporter { ... } |
Defining Operation Properties with Annotations
...
Note | ||
---|---|---|
| ||
The |
The @OneWay
annotation
...
FixMe: |
The @Oneway
annotation
The @Oneway
annotation is defined by the javax.jws.Oneway
javax.jws.OneWay
interface. It is placed on the methods in the SEI that will not require a response from the service. The @OneWay
@Oneway
annotation tells the run time that it can optimize the execution of the method by not waiting for a response and not reserving any resources to process a response.
Example
#Example7 The below shows an SEI whose methods are annotated.
Anchor | ||||
---|---|---|---|---|
|
Code Block | ||
---|---|---|
| ||
package org.apache.cxf; import javax.jws.*; import javax.xml.ws.*; @WebService(name="quoteReporter") public interface quoteReporterQuoteReporter { @WebMethod(operationName="getStockQuote") @RequestWrapper(targetNamespace="http://demo.ionamycompany.com/types", className="java.lang.String") @ResponseWrapper(targetNamespace="http://demo.ionamycompany.com/types", className="org.eric.demo.Quote") public Quote getQuote(String ticker); } |
...
The method parameters in the SEI coresspond correspond to the wsdl:message
elements and their wsdl:part
elements. JAX-WS provides annotations that allow you to describe the wsdl:part
elements that are generated for the method parameters.
...
Property | Values | Description |
---|---|---|
name |
| Specifies the name of the parameter as it appears in the WSDL. For RPC bindings, this is name of the |
targetNamespace |
| Specifies the namespace for the parameter. It is only used with document bindings where the parameter maps to an XML element. The defaults default is to use the service's namespace. |
mode |
| Specifies the direction of the parameter. |
header |
| Specifies if the parameter is passed as part of the SOAP header. |
partName |
| Specifies the value of the name attribute of the |
...
Property | Description |
---|---|
name | Specifies the name of the return value as it appears in the WSDL. For RPC bindings, this is name of the |
targetNamespace | Specifies the namespace for the return value. It is only used with document bindings where the return value maps to an XML element. The defaults is to use the service's namespace. |
header | Specifies if the return value is passed as part of the SOAP header. |
partName | Specifies the value of the name attribute of the |
Example
#Example8 The next example shows an SEI that is fully annotated.
Anchor | ||||
---|---|---|---|---|
|
Code Block | ||
---|---|---|
| ||
package org.apache.cxf; import javax.jws.*; import javax.xml.ws.*; import javax.jws.soap.*; import javax.jws.soap.SOAPBinding.*; import javax.jws.WebParam.*; @WebService(name="quoteReporter") @SOAPBinding(style=Style.RPC, use=Use.LITERAL) public interface quoteReporterQuoteReporter { @WebMethod(operationName="getStockQuote") @RequestWrapper(targetNamespace="http://demo.ionamycompany.com/types", className="java.lang.String") @ResponseWrapper(targetNamespace="http://demo.ionamycompany.com/types", className="org.eric.demo.Quote") @WebResult(targetNamespace="http://demo.ionamycompany.com/types", name="updatedQuote") public Quote getQuote( @WebParam(targetNamespace="http://demo.iona.com/types", name@WebParam(targetNamespace="stockTickerhttp://demo.mycompany.com/types", name="stockTicker", mode=Mode.IN) String ticker ); } |
Generating WSDL
Once you have annotated your code, you can generate a WSDL contract for your service using the java2wsdl command.
Example
#Example9 The next example shows the WSDL contract generated for the SEI shown in #Example8. above:
Anchor | ||||
---|---|---|---|---|
|
Code Block | ||
---|---|---|
| ||
<?xml version="1.0" encoding="UTF-8"?> <wsdl:definitions targetNamespace="http://demo.eric.org/" xmlns:tns="http://demo.eric.org/" xmlns:ns1="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:ns2="http://demo.eric.org/types" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"> <wsdl:types> <xsd:schema> <xs:complexType name="quote"> <xs:sequence> <xs:element name="ID" type="xs:string" minOccurs="0"/> <xs:element name="time" type="xs:string" minOccurs="0"/> <xs:element name="val" type="xs:float"/> </xs:sequence> </xs:complexType> </xsd:schema> </wsdl:types> <wsdl:message name="getStockQuote"> <wsdl:part name="stockTicker" type="xsd:string"> </wsdl:part> </wsdl:message> <wsdl:message name="getStockQuoteResponse"> <wsdl:part name="updatedQuote" type="tns:quote"> </wsdl:part> </wsdl:message> <wsdl:portType name="quoteReporter"> <wsdl:operation name="getStockQuote"> <wsdl:input name="getQuote" message="tns:getStockQuote"> </wsdl:input> <wsdl:output name="getQuoteResponse" message="tns:getStockQuoteResponse"> </wsdl:output> </wsdl:operation> </wsdl:portType> <wsdl:binding name="quoteReporterBinding" type="tns:quoteReporter"> <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/> <wsdl:operation name="getStockQuote"> <soap:operation style="rpc"/> <wsdl:input name="getQuote"> <soap:body use="literal"/> </wsdl:input> <wsdl:output name="getQuoteResponse"> <soap:body use="literal"/> </wsdl:output> </wsdl:operation> </wsdl:binding> <wsdl:service name="quoteReporterService"> <wsdl:port name="quoteReporterPort" binding="tns:quoteReporterBinding"> <soap:address location="http://localhost:9000/quoteReporterService"/> </wsdl:port> </wsdl:service> </wsdl:definitions> |