Web Services and JAX-WS

[b][list]
[*]Web Services and JAX-WS
[/list][/b]
In recent years, web services have emerged as a popular technology for remote method calls. Technically, a web service has two components:

A service that can be accessed with the SOAP transport protocol

A description of the service in the WSDL format

SOAP is an XML protocol for invoking remote methods, similar to the protocol that RMI uses for the communication between clients and servers. Just as you can program RMI applications without knowing anything about the details of the RMI protocol, you don't really need to know any details about SOAP to call a web service.

WSDL is an interface description language. It too is based on XML. A WSDL document describes the interface of a web service: the methods that can be called, and their parameter and return types. In this section, we generate a WSDL document from a service implemented in Java. This document contains all the information that a client program needs to invoke the service, whether it is written in Java or another programming language.

[b][list]
[*]Using JAX-WS
[/list][/b]
There are several toolkits for implementing web services in Java. In this section, we discuss the JAX-WS technology that is included in Java SE 6 and above.

With JAX-WS, you do not provide an interface for a web service. Instead, you annotate a class with @WebService, as shown in Listing 10-13. Note also the @WebParam annotation of the description parameter. It gives the parameter a humanly readable name in the WSDL file. (This annotation is optional. By default, the parameter would be called arg0.)

Listing 10-13. Warehouse.java
[quote]Code View:
1. package com.horstmann.corejava;
2. import java.util.*;
3. import javax.jws.*;
4.
5. /**
6. * This class is the implementation for a Warehouse web service
7. * @version 1.0 2007-10-09
8. * @author Cay Horstmann
9. */
10.
11. @WebService
12. public class Warehouse
13. {
14. public Warehouse()
15. {
16. prices = new HashMap<String, Double>();
17. prices.put("Blackwell Toaster", 24.95);
18. prices.put("ZapXpress Microwave Oven", 49.95);
19. }
20.
21. public double getPrice(@WebParam(name="description") String description)
22. {
23. Double price = prices.get(description);
24. return price == null ? 0 : price;
25. }
26.
27. private Map<String, Double> prices;
28. }[/quote]


In RMI, the stub classes were generated dynamically, but with JAX-WS, you run a tool to generate them. Change to the base directory of the Webservices1 source and run the wsgen class as follows:
[quote]
wsgen -classpath . com.horstmann.corejava.Warehouse[/quote]
[quote]
Note

The wsgen tool requires that the class that provides the web service is contained in a package other than the default package.[/quote]

The tool generates two rather mundane classes in the com.horstmann.corejava.jaxws package. The first class encapsulates all parameters of the call:

Code View:
[quote]public class GetPrice
{
private String description;
public String getDescription() { return this.description; }
public void setDescription(String description) { this.description = description; }
}[/quote]




The second class encapsulates the return value:

[quote]public class GetPriceResponse
{
private double _return;
public double get_return() { return this._return; }
public void set_return(double _return) { this._return = _return; }
}
[/quote]

Typically, one has a sophisticated server infrastructure for deploying web services, which we do not discuss here. The JDK contains a very simple mechanism for testing a service. Simply call the Endpoint.publish method. A server is started on the given URL—see Listing 10-14.

Listing 10-14. WarehouseServer.java
[quote]Code View:
1. package com.horstmann.corejava;
2.
3. import javax.xml.ws.*;
4.
5. public class WarehouseServer
6. {
7. public static void main(String[] args)
8. {
9. Endpoint.publish("http://localhost:8080/WebServices/warehouse", new Warehouse());
10. }
11. }[/quote]

At this point, you should compile the server classes, run wsgen, and start the server:

java com.horstmann.corejava.WarehouseServer


Now point your web browser to http://localhost:8080/WebServices/warehouse?wsdl. You will get this WSDL file:

Code View:
[quote]<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:tns="http://corejava.horstmann.com/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
targetNamespace="http://corejava.horstmann.com/" name="WarehouseService">
<types>
<xsd:schema>
<xsd:import schemaLocation="http://localhost:8080/WebServices/warehouse?xsd=1"
namespace="http://corejava.horstmann.com/"></xsd:import>
</xsd:schema>
</types>
<message name="getPrice">
<part element="tns:getPrice" name="parameters"></part>
</message>
<message name="getPriceResponse">
<part element="tns:getPriceResponse" name="parameters"></part>
</message>
<portType name="Warehouse">
<operation name="getPrice">
<input message="tns:getPrice"></input>
<output message="tns:getPriceResponse"></output>
</operation>
</portType>
<binding name="WarehousePortBinding" type="tns:Warehouse">
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"></soap:binding>
<operation name="getPrice">
<soap:operation soapAction=""></soap:operation>
<input><soap:body use="literal"></soap:body></input>
<output><soap:body use="literal"></soap:body></output>
</operation>
</binding>
<service name="WarehouseService">
<port name="WarehousePort" binding="tns:WarehousePortBinding">
<soap:address location="http://localhost:8080/WebServices/warehouse"></soap:address>
</port>
</service>
</definitions>[/quote]




This description tells us that an operation getPrice is provided. Its input is a tns:getPrice and its output is a tns:getPriceResponse. (Here, tns is the namespace alias for the target namespace, http://corejava.horstmann.com.)

To understand these types, point your browser to http://localhost:8080/WebServices/warehouse?xsd=1. You will get this XSL document:

Code View:
[quote]<xs:schema targetNamespace="http://corejava.horstmann.com/" version="1.0">
<xs:element name="getPrice" type="tns:getPrice"/>
<xs:element name="getPriceResponse" type="tns:getPriceResponse"/>
<xs:complexType name="getPrice">
<xs:sequence><xs:element name="description" type="xs:string" minOccurs="0"/></xs:sequence>
</xs:complexType>
<xs:complexType name="getPriceResponse">
<xs:sequence><xs:element name="return" type="xs:double"/></xs:sequence>
</xs:complexType>
</xs:schema>[/quote]

Now you can see that getPrice has a description element of type string, and getPriceResponse has a return element of type double.
[quote]
Note

The WSDL file does not specify what the service does. It only specifies the parameter and return types.[/quote]
[b][list]
[*]
[*]A Web Service Client
[/list][/b]
Let's turn to implementing the client. Keep in mind that the client knows nothing about the server except what is contained in the WSDL. To generate Java classes that can communicate with the server, you generate a set of client classes, using the wsimport utility.

[quote]Code View:
wsimport -keep -p com.horstmann.corejava.server http://localhost:8080/WebServices/warehouse?wsdl[/quote]




The -keep option keeps the source files, in case you want to look at them. The following classes and interfaces are generated:

[quote]GetPrice
GetPriceResponse
Warehouse
WarehouseService
ObjectFactory[/quote]


You already saw the GetPrice and GetPriceResponse classes.

The Warehouse interface defines the remote getPrice method:

[quote]Code View:
public interface Warehouse
{
@WebMethod public double getPrice(@WebParam(name = "description") String description);
}[/quote]




You only need to know one thing about the WarehouseService class: its getPort method yields a stub of type Warehouse through which you invoke the service—see Listing 10-15.

You can ignore the ObjectFactory class as well as the file package-info.java that defines a package-level annotation. (We discuss annotations in detail in Chapter 11.)

Note

You can use any convenient package for the generated classes. If you look closely, you will notice that the GetPrice and GetPriceResponse classes are in different packages on the server and client. This is not a problem. After all, neither the server nor the client know about each other's Java implementation. They don't even know whether the other is implemented in Java.



Listing 10-15. WarehouseClient.java
[quote]Code View:
1. import java.rmi.*;
2. import javax.naming.*;
3. import com.horstmann.corejava.server.*;
4.
5. /**
6. * The client for the warehouse program.
7. * @version 1.0 2007-10-09
8. * @author Cay Horstmann
9. */
10. public class WarehouseClient
11. {
12. public static void main(String[] args) throws NamingException, RemoteException
13. {
14. WarehouseService service = new WarehouseService();
15. Warehouse port = service.getPort(Warehouse.class);
16.
17. String descr = "Blackwell Toaster";
18. double price = port.getPrice(descr);
19. System.out.println(descr + ": " + price);
20. }
21. }[/quote]






Now you are ready to run the client program. Double-check that the server is still running, open another shell window, and execute

[quote]java WarehouseClient[/quote]


You will get the familiar message about the price of a toaster.

Note

You might wonder why there is no equivalent of a RMI registry. When you locate a remote object for RMI, the client need not know on which server the object is located. It merely needs to know how to locate the registry. However, to make a web service call, the client needs the URL of the server. It is hardwired into the WarehouseService class.



We used a network sniffer to see how the client and server actually communicate (see Figure 10-8). The client sends the following request to the server:

[quote]Code View:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:ns1="http://corejava.horstmann.com/">
<soapenv:Body>
<ns1:getPrice><description>Blackwell Toaster</description></ns1:getPrice>
</soapenv:Body>
</soapenv:Envelope>[/quote]




Figure 10-8. Analyzing SOAP traffic

[View full size image]


The server responds:

[quote]Code View:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:ns1="http://corejava.horstmann.com/">
<soapenv:Body>
<ns1:getPriceResponse><return>24.95</return></ns1:getPriceResponse>
</soapenv:Body>
</soapenv:Envelope>[/quote]




In this section, you have seen the essentials about web services:
[list]
[*]
[*]The services are defined in a WSDL document, which is formatted as XML.
[*]
[*]The actual request and response methods use SOAP, another XML format.
[*]
[*]Clients and servers can be written in any language.
[/list]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值