1. Trang chủ
  2. » Công Nghệ Thông Tin

Teach Yourself J2EE in 21 Days phần 9 pptx

113 281 0

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Tiêu đề Using Rpc-Style Web Services With J2ee
Trường học Standard University
Chuyên ngành Computer Science
Thể loại Bài viết
Năm xuất bản 2002
Thành phố City Name
Định dạng
Số trang 113
Dung lượng 0,92 MB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

Figure 20.5 shows the operation of such a SOAP router.Note that the description of the Web Service is used by both the client and server to helpdetermine the correct mapping between Java

Trang 1

The other type of J2EE component in which application logic can be held is a servlet orJSP You may ask how you would wrap this functionality for use as a Web Service Well,the issue here is that many of the Web components in question are already acting aschannels to some form of client (as shown in Figure 20.4) Consequently, wrapping themmakes no sense What you should do is create a replacement for such a Web componentthat is targeted at Web Service clients rather than Web browsers If your Web compo-nents are well designed, you should be able to reuse the JavaBeans, servlet filters, andhelper classes (even servlets/JSPs that they use) as part of your Web Service implementa-tion If you already have servlets or JSPs that generate XML, you might be able tomigrate them to meet your Web Service needs or transform the generated XML as part ofthe solution

Using an RPC-style SOAP-Based Web Service

SOAP grew out of an effort to create an XML-based method invocation mechanism fordistributed objects (primarily Microsoft’s DCOM) As such, it is an ideal transport formethod calls made over Web Services

Browser Client

Mobile Client

HTML servlet

WAP servlet

Trang 2

RPC-Oriented Web Services

Remote Procedure Calls (RPCs) made over Web-based protocols are essentially no ferent from those made over other protocols, such as IIOP, DCOM, or JRMP The callsare usually synchronous (in other words, the client waits for the method to return beforecontinuing) Zero or more parameters of varying types are passed into the call to provideinformation to process, and zero or more return values are generated to deliver the out-puts of the remote method to the client The remote method calls are delivered to someform of dispatcher at the remote server that determines which method should be calledand arranges for the smooth flow of parameters and return values

dif-For RPC-style operation, SOAP implementations conform to the preceding description.The difference with SOAP (and other Web-based RPC mechanisms, such as XML-RPC)

is that it uses standard, general-purpose transports, such as HTTP, together with a based method call description in XML All of the parameters and return values areencoded in XML as part of the SOAP body, while information about the service andmethod to call are provided in the transport header and possibly the SOAP header Whensent over HTTP, the SOAP header and body are wrapped in another XML document—the SOAP envelope—and this envelope forms the body of an HTTP POST request

text-An HTTP-based SOAP message will be delivered to a SOAP router that takes the form

of an HTTP servlet (for a Java implementation) The SOAP router will examine theHTTP and SOAP header information and decide how it should forward the messagebody This will involve instantiating or calling a particular component or class that willreceive the message The SOAP router, or its helper classes, will also perform the con-version of the XML-based parameters into Java objects and primitives that can be passed

as part of the service invocation Figure 20.5 shows the operation of such a SOAP router.Note that the description of the Web Service is used by both the client and server to helpdetermine the correct mapping between Java and XML for method calls and parametertypes

This is all good, but why go to this effort? Why not use an existing RPC mechanism,such as RMI or just use HTTP itself?

The justification for not using RMI or CORBA relates to commonality and security.There are at least three different distributed object protocols (CORBA, RMI, andDCOM), each of which has its adherents The use of HTTP and XML provides a com-mon protocol that is not tied to any vendor Also, the protocols listed have great difficulty

in penetrating most firewalls (not surprising, given their ability to invoke random tionality) However, HTTP (and SMTP) have general right of access through most fire-walls, which makes it easier to integrate applications across organizational boundaries(after the security questions are sorted out)

Trang 3

Although raw HTTP is a good transport, it was created to exchange simple HTML sages This does not provide the sophistication required for a distributed invocation envi-ronment The use of a defined XML message format brings structure to this environmentand allows for the interoperability of Web Service clients and servers from different vendors—something that escaped CORBA until comparatively recently

mes-Now that you understand the architecture and motivation for RPC-style Web Services,you can install a Java-based Web Service environment and, through it, use and build yourown Web Services

Setting up Axis under Tomcat 4.0

The environment you will use for Web Service development in the first instance consists

of the Tomcat servlet engine and the Axis Web Service toolkit, both from the ApacheSoftware Foundation

F IGURE 20.5

A Java-based SOAP

router.

Web Service Proxy

EJBs

SOAP Router and Dispatcher

servlet

Web Service Client

Candidate Web Services

SOAP Request

SOAP Response

Java methods

Invoke target method

servlets

Java WSDL

From a developer’s perspective, one of SOAP’s greatest assets is its ability to penetrate firewalls However, from an administrator’s point of view, this pre- sents the same types of problem as traditional RPC, namely the ability to tar- get a random function call at an exposed server Although the principle of SOAP is only a small step on from the invocation of server-side functionality such as CGI, great care should be taken to ensure adequate security when exposing Web Services The overall security story for Web Services is still a work in progress.

Caution

Trang 4

You can download Tomcat 4.0 from the Apache Software Foundation at ta.apache.org/tomcat/or install it from the CD-ROM as follows:

http://jakar-1 Unzip the Tomcat 4.0 archive (jakarta-tomcat-4.0.1.zip) into an appropriatedirectory on your hard drive (an example from Windows would be C:\jakarta- tomcat-4.0.1)

2 In your personal or system environment, set the environment variable

CATALINA_HOMEto point to this directory

You can download Axis from the Apache Software Foundation or install it from the ROM as follows:

CD-• Unzip the Axis archive (xml-axis-alpha2-bin.zip) into an appropriate directory

on your hard drive (an example from Windows would be C:\axis-1_0)

• Copy the webapps\axisdirectory from the axis-1_0distribution into Tomcat’s

webappsdirectory ({CATALINA_HOME}\webapps)

You need to install XML support for Axis from the Fall 01 JAX Pack (available fromSun or on the CD-ROM) as follows:

• Unzip the JAX Pack archive (java_xml_pack-fall01.zip) into an appropriatedirectory on your hard drive (an example from Windows would be

C:\java_xml_pack-fall01)

• Copy crimson.jarand xalan.jarfrom the jaxp-1.1.3directory into INF\libunder Tomcat’s webappsdirectory ({CATALINA_HOME}\webapps)

axis\WEB-Tomcat and Axis are now installed with the appropriate XML support

In the next section, you will create a client for a simple helloWeb Service First, youmust install and test this simple Web Service as follows:

1 Install the class required for the HelloServiceby copying the webservicestory from the CD-ROM directory Day20\examples\HelloServiceto axis\WEB- INF\classesunder Tomcat’s webappsdirectory ({CATALINA_HOME}\webapps)

direc-2 Start Tomcat by running the startupscript/batch file in the {CATALINA_HOME}\bin

directory

3 To ensure that Tomcat and Axis are installed correctly, start a Web browser andpoint it at http://localhost:8080/axis/index.html You should see a welcomescreen from Axis

• Now deploy the hello server using the deployitbatch file in the CD-ROM directory Day20\examples\HelloService

Trang 5

Assuming that you had no errors, you have now deployed a simple Web Service called

MyHelloService In the long and distinguished tradition of curly-bracket-based guages, you will start with a variation on the Hello World!program

lan-Service Description Information

Your Web server now has a Web Service installed under it The next step is to access thatWeb Service However, before you can take advantage of the Web Service, you need thefollowing information:

• A definition of the service you are calling—This information corresponds to the

traditional interface definition for an RPC or RMI server The interface definitioncontains information about the methods available, the number and types of parame-ters, the type of any return values, and definitions of any complex types used asparameters

• The location of the service—This corresponds to the binding information used by

RPC and RMI servers This Web Service binding information lists the protocolsover which you can call the available Web Service methods For each supportedprotocol, there is also a URL indicating the location of a server that provides animplementation of that service for that protocol

As you may have surmised by now, all of this information is provided by a WSDLdescription of the service

Anatomy of a WSDL Document

The WSDL for MyHelloServiceis shown in Listing 20.1 It is worth taking a fewmoments to study this information because it provides a good insight into the way thatWeb Services work

L ISTING 20.1 WSDL for the Hello Service ( MyHelloService.wsdl )

1: <?xml version=”1.0” encoding=”UTF-8”?>

2:

3: <definitions 4: targetNamespace=”http://localhost:8080/axis/services/MyHelloService”

Trang 6

15: <part name=”sayHelloToResult” type=”xsd:string”/>

33: </input>

34: <output>

35: <soap:body use=”encoded”

36: encodingStyle=”http://schemas.xmlsoap.org/soap/encoding/” 37: namespace=”MyHelloService”/>

The document consists of the following sections:

• The XML prolog and root element (lines 1–8 and 48) The namespace declarations

on the root element (definitions) show that all unqualified elements and

attribut-es come from the WSDL schema The soapprefix denotes types from the SOAPschema, while the xsdprefix denotes types from the W3C XML Schema defini-tion There is also a namespace defined for this service that is associated with the

serviceNSprefix

L ISTING 20.1 Continued

Trang 7

• WSDL messagedefinitions (lines 10–16) These define two matched messages—arequest and a response The request (sayHelloToRequest) takes a single stringparameter and the response (sayHelloToResponse) also returns a single string

• WSDLportTypedefinitions (lines 18–23) A portTypeis the equivalent of aninterface definition It contains one or more operationdefinitions, which in turnare built from the messagedefinitions in the document In this case, there is a sin-gle operationdefined in the HelloServerPortTypecalled sayHelloTo This con-sists of the two messages,sayHelloToRequestand sayHelloToResponse, seen ear-lier

• Now that you have an interface (portType), you can define the protocols overwhich that interface can be accessed The binding element (lines 25–40) creates abinding, called HelloServerSoapBinding, between the HelloServerPortTypeandSOAP Within this WSDL binding, a SOAP binding (soap:binding) is defined

Because SOAP can work with a variety of underlying transports and it can work in

an RPC-centric or document-centric way, the attributes on the soap:bindingcate that it is an RPC-style binding that uses HTTP

indi-The WSDL operationis then mapped to a SOAP operationwith input and put soap:bodyelements defined to map the request and response

out-• Finally, an instance of the service is defined in the WSDL serviceelement (lines42–46) A WSDL servicecontains a list of WSDL portelements Each portele-ment defines a specific instance of a server that conforms to one of the WSDL

bindings defined earlier

Again, in the case of the simple Hello service, the serviceelement (named

HelloServer) contains a single WSDL port called HelloServerPort This fies that a server conforming to the HelloServerSoapBindingcan be found at thegiven SOAP address, namely

speci-http://localhost:8080/axis/service/MyHelloService.This is a very simple WSDL document defining a very simple service WSDL documentsare typically far longer and more complex Because of this, WSDL is largely intended formanipulation by tools and applications

Creating a Java Proxy from WSDL

Given the service description in Listing 20.1, the next step is to create a client that canuse this service The simplest way to do this is to have a tool generate a proxy for theservice This proxy will be a local object that will hide away a lot of the complexityassociated with the mechanics of calling methods on the service

You can apply the Apache Axis Wsdl2javatool to MyHelloService.wsdlas follows

java org.apache.axis.wsdl.Wsdl2java MyHelloService.wsdl

Trang 8

This will generate three Java files:

• HelloServerPortType.javais a Java interface that represents the remote interface(or portTypein WSDL terms) This is shown in Listing 20.2 Note that the inter-face looks like an RMI interface in that it extends java.rmi.Remote, and themethod is defined as throwing java.rmi.RemoteException The service proxyimplements this interface, and the client should use the interface type to referenceinstances of the service proxy

• HelloServer.javais a factory class that creates instances of the service proxy.This is shown in Listing 20.3 The client instantiates a factory and then calls the

getHelloServerPortmethod to obtain a service proxy Two forms of this methodare provided—one that allows the client to specify the endpoint at which the ser-vice resides and the other that takes no arguments The latter method will use thelocation information contained in the WSDL file when instantiating the serviceproxy

• HelloServerSoapBindingStub.javais the service proxy itself Note that by using

a separate interface to represent the portTypeand a factory for the creation of theproxy, the same client code can be used, regardless of the particular protocol bind-ing The code for HelloServerSoapBindingStub.javais not shown here because

it is very similar to the “raw” SOAP code you will see shortly

L ISTING 20.2 HelloServerPortType.java 1: /**

2: * HelloServerPortType.java 3: *

4: * This file was auto-generated from WSDL 5: * by the Apache Axis Wsdl2java emitter.

6: */

7: 7:

8: public interface HelloServerPortType extends java.rmi.Remote { 9: public String sayHelloTo(String arg0) throws java.rmi.RemoteException; 10: }

To run the tools and compile the files, you must have the JAR files from the

axis\WEB-INF\lib directory on your classpath, namely axis.jar , clutil.jar ,

crimson.jar , log4j-core.jar , wsdl4j.jar , and xalan.jar

Note

Trang 9

L ISTING 20.3 HelloServer.java

1: /**

2: * HelloServer.java 3: *

4: * This file was auto-generated from WSDL 5: * by the Apache Axis Wsdl2java emitter.

13: public HelloServerPortType getHelloServerPort() { 14: java.net.URL endpoint;

15: try { 16: endpoint = new java.net.URL(HelloServerPort_address);

17: } 18: catch (java.net.MalformedURLException e) { 19: return null; // unlikely as URL was validated in wsdl2java 20: }

21: return getHelloServerPort(endpoint);

22: } 23:

24: public HelloServerPortType

➥ getHelloServerPort(java.net.URL portAddress) { 25: try {

26: return new HelloServerSoapBindingStub(portAddress);

27: } 28: catch (org.apache.axis.SerializationException e) { 29: return null; // ???

30: } 31: } 32: }

You can now write a client application that uses these classes The code for such anapplication is shown in Listing 20.4 This application simply takes the name passed as aparameter and sends it to the sayHelloTomethod of the Web Service You can see thecreation of the HelloServerservice proxy factory on line 20 The client then calls the

getHelloServerPortmethod to obtain an instance of the service proxy (line 23)

The client can then call the sayHelloTomethod passing the given parameter (line 28)

This method invocation is wrapped in a try-catchblock to catch any potential

RemoteExceptionthat may occur

Trang 10

L ISTING 20.4 HelloServerClient.java Application That Uses Generated Service Proxy

11: System.out.println(“Usage: WebServiceSayHello <name>”);

12: System.exit(1);

13: } 14: else 15: { 16: name = args[0];

17: } 18:

19: // Instantiate the factory 20: HelloServer factory = new HelloServer();

29:

30: System.out.println(response);

31: } 32: catch(RemoteException ex) 33: {

34: System.out.println(“Remote exception: “ + ex);

35: } 36: } 37: }

To test out your client, you should:

1 Compile the client code

2 Ensure that the service is running (both Tomcat and the Axis server)

3 Run the client (with the appropriate classpath settings) as shown

prompt> java HelloServerClient Fred Hello Fred!

Trang 11

Calling the Web Service Through SOAP

You have now accessed the service through a service proxy based on WSDL However,you can access the service directly through SOAP, should that be necessary Indeed,some older toolkits may only provide a SOAP-level API and no WSDL-based tools, sothis section looks quickly at how you would achieve the same effect directly with SOAP

Listing 20.5 shows the code you would write under Apache SOAP 2.2 (the precursor toAxis) to call the Hello service using the SOAP API directly

L ISTING 20.5 SoapSayHello.java Using the Apache SOAP 2.2 API

8: private static String serviceUrn = “MyHelloService”;

9: private static String soapRouterUrl =

17: System.out.println(“Usage: SoapSayHello <name>”);

18: System.exit(1);

19: } 20: else 21: { 22: name = args[0];

23: } 24:

25: URL url = null;

26:

27: try 28: { 29: url = new URL(soapRouterUrl);

30: } 31: catch (MalformedURLException ex) 32: {

33: System.out.println(“Exception: “ + ex);

34: System.exit(1);

35: } 36:

Trang 12

37: Call call = new Call();

47:

48: Response response;

49:

50: try 51: { 52: response = call.invoke(url, “”);

53: } 54: catch (SOAPException e) 55: {

56: System.err.println(“Caught SOAPException (“ + 57: e.getFaultCode() + “): “ + 58: e.getMessage());

59: return;

60: } 61:

62: if (!response.generatedFault()) 63: {

64: Parameter retVal = response.getReturnValue();

65: Object value = retVal.getValue();

66:

67: System.out.println(value != null ? “\n” + value : “I don’t know.”); 68: }

69: else 70: { 71: Fault fault = response.getFault();

72:

73: System.err.println(“Generated fault: “);

74: System.out.println (“ Fault Code = “ + fault.getFaultCode()); 75: System.out.println (“ Fault String = “ + fault.getFaultString()); 76: }

77: } 78: }

The first thing to notice is that the endpoint URL is now split into the service name andthe SOAP router (lines 8 and 9) This SOAP router URL must be turned into a

java.net.URL(lines 25–35) for it to be used

L ISTING 20.5 Continued

Trang 13

A SOAP Callis then instantiated (line 37) and populated with the service name (line 39)and the method name (line 40) The parameters for the call must be encoded as

Parameterinstances, specifying the parameter name, Java class, and encoding required

A java.util.Vectorcontaining all of the parameters is then passed to the Callobject(lines 42–46)

The call is then made to the SOAP server using the invokemethod (line 52) This iswhere the SOAP router URLis passed in A SOAP Responseis returned from invoke.Now the result must be deciphered (lines 62–76) This involves checking for an error,retrieving the Parameterobject, extracting the actual returned object from it, and thencasting this returned object to the appropriate type

As you can see, the use of a proxy is preferable because it removes most of the ity This is why the Java APIs for creating and sending SOAP messages—JAX-RPC andJAXM—both work at a higher level than this The benefits of using the WSDL-basedproxy are that the client code is less complex, there is type safety by using the generatedJava interface, and the client developer needs to know very little about the SOAP-leveloperations or indeed about SOAP itself

complex-A Half-Way House

There is a compromise that can be made between service-specific calling using a proxyand the use of raw SOAP Axis provides a ServiceClientclass that performs much ofthe code shown in Listing 20.5 In fact, all of the code from line 25 on can be effectivelyreplaced by the following lines:

ServiceClient client = new ServiceClient(soapRouterUrl);

String response = (String)client.invoke(serviceUrn,

“sayHelloTo”, new Object [] { name });

The service address, method name, and the parameters are all passed into the invoke

method Note that the last argument in the code shown creates a new array of type

Objectand populates it with a single element, which is the Stringcontaining the nameprovided by the user

In this case, there is a lot more flexibility than with the WSDL proxy, because themethod name and parameter can be specified at runtime This allows for dynamic inter-action with discovered services However, the code shown is preferable to the SOAPcode in Listing 20.5 because the code surrounding the call setup has been largely simpli-fied

Dynamic calling will be examined further tomorrow in the discussion surrounding theuse of directory services

Trang 14

Debugging a SOAP Interaction

As with any distributed environment, debugging Web Service interaction is a challenge.One of the main issues is knowing precisely what is being sent and received To assistwith this, Axis provides a tool calledtcpmonthat will monitor and display SOAP traffic.The basic idea is that you target your client at a different port The tcpmonutility listens onthat port, logs the SOAP traffic arriving, and then passes it on to the real SOAP server port.SOAP traffic sent back is also logged If you cannot change the client configuration, youcould change the port on which the SOAP server listens The tcpmonutility can then listen

on the original SOAP server port and forward traffic on to the new port Figure 20.6 showshow an instance of tcpmoncan monitor inbound traffic from SOAP clients on port 8888,log the traffic, and then forward it on to the real SOAP router listening on port 8080

pass-Servlet Container

TCPMON

SOAP Message Router

SOAP Client

Port 8888

Port 8080

Graphical output

To start the tcpmonutility, type

java org.apache.axis.utils.tcpmon

This will start a GUI through which the traffic will be displayed When the GUI starts

up, you will be prompted for the port on which to listen and also the port and host towhich traffic should be forwarded Figure 20.7 shows a monitor session being started thatwill listen on port 8888 and forward all traffic received on to localhost:8080

The tcpmon utility allows you to set up multiple port/host/port mappings Each will be displayed in its own tabbed pane.

Tip

Trang 15

The request and response messages are displayed as pairs, as shown in Figure 20.8 Thisshows an interaction between the Hello service and a client that has been modified sothat its target port is configurable The client sends its request to port 8888 with a

SOAPActionof MyHelloService/sayHelloTo You can see the method invocation and thestring parameter in the SOAP body The response is shown in the right pane In theresponse, the SOAP body contains a sayHelloToResponsemessage encapsulating the

sayHelloToResultreturn value

SOAP request and

response to the Hello

service seen through

tcpmon

Trang 16

The tcpmonutility will retain a history of messages sent back and forth through a ular port You can then look back through a sequence of messages in your own time.

partic-Implementing an RPC-Style SOAP-Based Web Service

Now that you are familiar with writing a simple client for a Web Service, you will bly want to create your own Web Service in Java

proba-To deliver a Web Service, you must provide the following:

• The business logic

• A description of the Web Service, such as its name, the methods to be exposed and

so forth

• A router to receive SOAP calls and dispatch method calls to the business logicFollowing the same principles as EJBs, it would be good if most of the Web Service-related functionality was provided for you, leaving you to concentrate on the businesslogic Ideally, you would provide the business logic and some of the Web Servicedescription, leaving someone else to provide the rest Fortunately, as you will see, theAxis environment provides most of the Web Service plumbing, as do other Java-basedWeb Service containers

Wrapping up a Java class as a Web Service

To create a Web Service to run under Axis, all you need to do is supply a Java class andsome configuration information The Java class needs no specific code to make itselfWeb Service-aware, simply one or more public methods

As an example, consider the SimpleOrderServershown in Listing 20.6 This containsthe business logic to be wrapped Note that in this instance, the server is just a standardJava class Apart from the package name, there is no indication that this is intended to be

a Web Service Even the package name is there only to separate this example from otherclasses This class will be instantiated and its methods invoked by the Axis server.The Axis server takes the form of a servlet called, not surprisingly,AxisServlet Thisservlet acts as the router for all HTTP-based SOAP requests and also supplies WSDLdescriptions for deployed services, as you will see later The AxisServletcan be found

at http://localhost:8080/axis/servlet/AxisServlet

Trang 17

9:

10: receipt = “Thank you, “ + customerID + “\n”;

11: receipt += “You ordered “ + quantity + “ “ + productCode + “‘s\n”;

12: receipt += “That will cost you “ + (quantity * 50) + “ Euros”;

13:

14: return receipt;

15: } 16: }

Now that you have your business logic, you will need to provide some information forthe AxisServlet:

• The name under which the service is to be deployed—in this case, the name will

be SimpleOrderService

• The class that provides the functionality for the service—in this case, this is the

SimpleOrderServeras shown in Listing 20.6

• The names of the methods that should be exposed as part of the service—in thiscase, the single method submitOrder

This information is encapsulated in XML format, as shown in Listing 20.7 The

<service>element defines the name and the fact that this is an RPC-based service The

<option>elements define the class and method names

L ISTING 20.7 Deployment Descriptor for the SimpleOrderService

( deploy_simple_order.xml )

1: <admin:deploy xmlns:admin=”AdminService”>

2: <service name=”SimpleOrderService” pivot=”RPCDispatcher”>

3: <option name=”className” value=”webservices.SimpleOrderServer”/>

4: <option name=”methodName” value=”submitOrder”/>

5: </service>

6: </admin:deploy>

Trang 18

You are now ready to deploy your Web Service.

First, copy over the SimpleOrderServer.classfile to the Axis classes directory:

{TOMCAT_HOME}\webapps\axis\WEB-INF\classes\

This ensures that the class is on the Axis classpath so that the server can find it when youinvoke the submitOrdermethod Make sure that you retain the appropriate directoryhierarchy This means that because SimpleOrderServeris in the webservicespackage,

it should appear as webservices\SimpleOrderServer.classbelow the Axis classesdirectory

Next, use the ServiceManagerClientto deploy your Web Service according to thedeployment descriptor in Listing 20.7, as follows:

java org.apache.axis.client.AdminClient

➥ -lhttp://localhost:8080/axis/servlet/AxisServlet deploy_simple_order.xml

Assuming that you get no errors, you can list the services currently deployed, either bypointing your Web browser at the Axis services URL,http://localhost:8080/axis/ services?list, or by issuing the following command from the command line:

java org.apache.axis.client.AdminClient

➥ -lhttp://localhost:8080/axis/services list

The deployment descriptor syntax shown works with Axis alpha 2 However, there is a stated commitment that this syntax will migrate to a standard Web Service Deployment Descriptor (WSDD) syntax at a later date Although the syntax will differ, the principles will remain largely the same.

Note

The URL prefix /axis/services is simply a mapping for the /axis/servlet/ AxisServlet URL prefix, so they can be used interchangeably.

However, be aware that the web.xml mapping for the virtual directory services

is incorrect on Axis alpha 2 To list a service or obtain its WSDL, you must either update the web.xml file for the services mapping so that it looks as follows:

<servlet-mapping>

<servlet-name>AxisServlet</servlet-name>

<url-pattern>/services/*</url-pattern>

</servlet-mapping>

or always use the explicit AxisServlet URL:

http://localhost:8080/axis/servlet/AxisServlet/{service name and options}

Note

Trang 19

Whether you list the services through the Web browser or the tool, you should see a list

of services similar to the one in Listing 20.8 You can see the deployment information forthe SimpleOrderServicebetween lines 24–27, and that for MyHelloServicethat youused earlier between lines 29–32

L ISTING 20.8 List of Services Deployed under Axis

8: <chain flow=”JWSHandler,debug” name=”global.request”/>

9: <chain flow=”Authenticate,Authorize” name=”authChecks”/>

19: <service pivot=”MsgDispatcher” name=”AdminService”>

20: <option name=”methodName” value=”AdminService”/>

21: <option name=”enableRemoteAdmin” value=”false”/>

22: <option name=”className” value=”org.apache.axis.utils.Admin”/>

23: </service>

24: <service pivot=”RPCDispatcher” name=”SimpleOrderService”>

25: <option name=”methodName” value=”submitOrder”/>

26: <option name=”className” value=”webservices.SimpleOrderServer”/>

27: </service>

28: <service pivot=”JWSProcessor” name=”JWSProcessor”/>

29: <service pivot=”RPCDispatcher” name=”MyHelloService”>

30: <option name=”methodName” value=”sayHelloTo”/>

31: <option name=”className” value=”webservices.HelloServer”/>

32: </service>

Trang 20

33: <service pivot=”EchoHandler” name=”EchoService”/>

34: </services>

35: <transports>

36: <transport request=”URLMapper” name=”SimpleHttp”/>

37: <transport request=”HTTPAuth,URLMapper” name=”http”/>

38: <transport response=”LocalResponder” name=”local”/>

39: </transports>

40: </engineConfig>

A Client for Your Web Service

Now that you have successfully deployed your server, you can create a client for it asyou did for the MyHelloServiceearlier Again, you have the choice of directly using a

ServiceClientor generating a client-side service proxy based on the service’s WSDL.But wait, it is all very well to talk about generating a service proxy from WSDL, but theservice you have just deployed is just a Java class How do you get the WSDL for it?Well, once again the tools can help here The Axis environment will provide for you theWSDL description if you append the query string “?wsdl”onto the service URL Figure20.9 shows the WSDL for the SimpleOrderServicedisplayed in a Web browser You canthen simply save the page onto local disk as SimpleOrderService.wsdl

L ISTING 20.8 Continued

F IGURE 20.9

Obtaining the WSDL description of your service in a Web browser through Axis.

Trang 21

Other tools provide other ways of obtaining the WSDL from a Java-based service Forexample, IBM’s WSTK provides a graphical tool called wsdlgenthat allows you to selectthe Java methods that you want to expose as Web Service methods

After you have a WSDL file for your service, you can create a client as you did beforefor the MyHelloServiceby using Wsdl2javato generate client-side service proxy classes(SimpleOrderServer,SimpleOrderServerPortType, and

SimpleOrderServerSoapBindingStub, in this case)

It is a good idea to generate your service proxy classes in a different

directo-ry from your server Unless you are vedirecto-ry careful with your naming strategy, Wsdl2java can easily select the same name for its service proxy factory as you have for your server (SimpleOrderServer.java) Creating the client

in a different directory can save a lot of frustration.

Caution

The client code to use the SimpleOrderServerclient-side service proxy is shown inListing 20.9

L ISTING 20.9 SimpleOrderClient.java —Takes Parameters for the Customer ID, Product

Code, and Quantity and Submits the Order to the SimpleOrderService

7: String customerId = “unknown”;

8: String productCode = “Widget”;

9: int quantity = 1;

10:

11: if (args.length != 3) 12: {

13: System.out.println(“Usage: SimpleOrderClient <customerId>

➥ <productCode> <quantity>”);

14: System.exit(1);

15: } 16: else 17: { 18: customerId = args[0];

19: productCode = args[1];

20: quantity = Integer.parseInt(args[2]);

21: } 22:

23: // Intantiate the factory

Trang 22

24: SimpleOrderServer factory = new SimpleOrderServer();

25:

26: // Get a PortType that represents this particular service 27: SimpleOrderServerPortType service = factory.getSimpleOrderServerPort(); 28:

29: try 30: { 31: // Call the service 32: String response = service.submitOrder(customerId, productCode,

33:

34: System.out.println(response);

35: } 36: catch(RemoteException ex) 37: {

38: System.out.println(“Remote exception: “ + ex);

39: } 40: } 41: }

The following shows how you would run the client and the result returned:

prompt> java SimpleOrderClient Acme ACX-09387 37 Thank you, Acme

You ordered 37 ACX-09387’s That will cost you 1850 Euros

You have now created a complete Java Web Service client and server

Starting from WSDL

When a system is designed, the designers will create UML diagrams (or the like) to resent the system entities and interactions between them Tools can then generate pro-gramming artefacts, such as Java classes and interfaces based on this information If thesystem will be based on Web Services, such artefacts will include WSDL descriptions ofthe required services You, as a Java developer, may then be presented with a WSDLdescription that requires a Java implementation

rep-Rather than having to work out manually what sort of Java class would match thatWSDL description, the Java-based Web Service toolkits provide utilities that can producethe appropriate Java skeleton code from a given WSDL document Under Axis, the

Wsdl2javautility can be used to produce a skeleton Java Web Service as follows:

java org.apache.axis.wsdl.Wsdl2java skeleton SimpleOrderServer.wsdl

L ISTING 20.9 Continued

Trang 23

• SimpleOrderServerSoapBindingImpl.java The implementation class is the oneyou will fill with the business logic The skeleton provided is shown in Listing20.11 You can see the location for the business logic on line 14.

• deploy.xmland undeploy.xml Two XML deployment files are provided—one todeploy the service and one to undeploy it In Listing 20.12, you can see that theservice is deployed as SimpleOrderServerPortand calls the

SimpleOrderServerSoapBindingSkeletonclass to service requests You can usethis XML file together with AdminClientto deploy the Web Service

L ISTING 20.10 SimpleOrderServerSoapBindingSkeleton.java —A Server-Side Proxy for

the Given WSDL Service Description

1: /**

2: * SimpleOrderServerSoapBindingSkeleton.java 3: *

4: * This file was auto-generated from WSDL 5: * by the Apache Axis Wsdl2java emitter.

14: this.impl = new SimpleOrderServerSoapBindingImpl();

15: } 16:

17: public

➥ SimpleOrderServerSoapBindingSkeleton(SimpleOrderServerPortType impl) 18: {

19: this.impl = impl;

20: } 21:

22: public Object submitOrder(String arg0, String arg1, int arg2) 23: throws java.rmi.RemoteException 24: {

Trang 24

25: Object ret = impl.submitOrder(arg0, arg1, arg2);

26: return ret;

27: } 28: }

L ISTING 20.11 SimpleOrderServerSoapBindingImpl.java —A Skeleton Within Which to Implement Your Business Logic

1: /**

2: * SimpleOrderServerSoapBindingImpl.java 3: *

4: * This file was auto-generated from WSDL 5: * by the Apache Axis Wsdl2java emitter.

6: */

7:

8: public class SimpleOrderServerSoapBindingImpl 9: implements SimpleOrderServerPortType 10: {

11: public String submitOrder(String arg0, String arg1, int arg2) 12: throws java.rmi.RemoteException 13: {

14: throw new java.rmi.RemoteException (“Not Yet Implemented”); 15: }

16: }

L ISTING 20.12 deploy.xml —A Deployment Descriptor Automatically Generated from the SimpleOrderServer WSDL

1: <! > 2: <! Use this file to deploy some handlers/chains and services >

3: <! Two ways to do this: > 4: <! java org.apache.axis.utils.Admin deploy.xml >

5: <! from the same dir that the Axis engine runs > 6: <! or > 7: <! java org.apache.axis.client.AdminClient deploy.xml >

8: <! after the axis server is running > 9: <! This file will be replaced by WSDD once it’s ready > 10:

Trang 25

17: <option name=”methodName” value=” submitOrder”/>

18: </service>

19: </m:deploy>

Using Axis JWS files

As you have seen, most of the work on the server side is done for you by the tools andutilities that come with the toolkit All you have to really provide is a Java class andeverything else can be generated for you Given this, the Axis project has taken thingsone stage further and developed the concept of JWS (or .jws) files

JWS files (short for Java Web Service) provide a way of deploying a Java-based WebService in the simplest possible way All you do is take the Java class that would be thetarget for the Web Service deployment descriptor (the classoption under the <service>

element) and change its suffix to .jwsinstead of .java You then place this file where below the /axisdirectory and that’s it There is no need to create deploymentinformation or to use AdminClient

some-One thing to note is that if your classes belong to a package hierarchy, you will have toplace them in the appropriate subdirectory under the axis directory

As an example, consider creating a JWS service based on the SimpleOrderServer Takethe SimpleOrderServer.javafile and rename it as SimpleOrderServer2.java(andrename the class inside it to SimpleOrderServer2also, as shown in Listing 20.13) Thechange to the filename and classname will avoid any confusion with the original service

Then change the file extension from .javato .jwsand copy the file into the /axis

directory You can then access it as follows:

http://localhost:8080/axis/SimpleOrderServer2.jws

L ISTING 20.13 SimpleOrderServer2.jws —A JWS Version of the Simple Order Server

1: public class SimpleOrderServer2 2: {

3: public String submitOrder(String customerID, String productCode,

4: { 5: // Form up a receipt for the order 6: String receipt = “”;

7:

8: receipt = “Thank you, “ + customerID + “\n”;

9: receipt += “You ordered “ + quantity + “ “ + productCode + “‘s\n”;

10: receipt += “That will cost you “ + (quantity * 50) + “ Euros”;

11:

L ISTING 20.12 Continued

Trang 26

12: return receipt;

13: } 14: }

A JWS file is a fully-functioning Web Service, so you can obtain its WSDL by using theURL http://localhost:8080/axis/SimpleOrderServer2.jws?wsdl

The result of this is shown in Listing 20.14 As you can see, the names used reflect thename of the JWS file, such as SimpleOrderServer2as the name of the service on line

38 The SOAP address provided as part of the porttargets the JWS file, as you can see

on line 41 You can then use this WSDL information to create a client-side service proxyand call the service as you have done before

L ISTING 20.14 WSDL Generated from SimpleOrderServer2.jws 1: <?xml version=”1.0” encoding=”UTF-8” ?>

2: <definitions

➥ targetNamespace=”http://localhost:8080/axis/SimpleOrderServer2.jws”

3: xmlns:xsd=”http://www.w3.org/2001/XMLSchema”

4: xmlns:serviceNS=”http://localhost:8080/axis/SimpleOrderServer2.jws” 5: xmlns:soap=”http://schemas.xmlsoap.org/wsdl/soap/”

11: <part name=”arg0” type=”xsd:string” />

12: <part name=”arg1” type=”xsd:string” />

13: <part name=”arg2” type=”xsd:int” />

30: </input>

L ISTING 20.13 Continued

Trang 27

• All public methods on the JWS class are exposed; you have no fine-grained control

as you would with a deployment descriptor

• You cannot control the lifetime of the JWS class, so you cannot maintain sessionstate between invocations

This means that “serious” Web Services are likely to be deployed as Java classes (orwrapped EJBs) However, in the same way that JSPs provide a lightweight way of using

a servlet, JWS files provide a lightweight way of delivering Web Services Other factors,such as the ease of deployment and automatic compilation reinforce the similaritiesbetween these two models

Session Context and Web Services

As with servlets and JSPs, it is important to be able to maintain session state betweenmethod invocations on a particular Web Service To do this, Axis lets you control statemanagement policy at both the client and server side

If a server is intended to allow state to be maintained between method invocations, thisneeds to be specified in the deployment descriptor Listing 20.15 shows a variant of the

SimpleOrderServicethat maintains state between method invocations This class storesthe name of the last customer to call the submitOrdermethod (line 23) and checks thename of the next customer against this value (line 12) If the customer name is the same,the message in the receipt is different (lines 14–18) Obviously, if there is no sessionmaintained, the instance of the server class will be discarded after each method call

L ISTING 20.14 Continued

Trang 28

The only time that the “Hello again” greeting will be seen is if session state has beenmaintained between invocations.

L ISTING 20.15 SessionSimpleOrderServer.java —A Version of the Simple Order Server That Maintains Session State

14: receipt = “Hello again, “ + customerID + “\n”;

15: } 16: else 17: { 18: receipt = “Thank you, “ + customerID + “\n”;

19: } 20: receipt += “You ordered “ + quantity + “ “ + productCode + “‘s\n”; 21: receipt += “That will cost you “ + (quantity * 50) + “ Euros”;

To provide the ability to maintain session state between invocations, an option must beset in the deployment descriptor to indicate that the Web Service implementation shouldmaintain session state The deployment descriptor for the SessionSimpleOrderServerisshown in Listing 20.16, and you can see on line 6 that a new optionelement has beenadded to set the scopeoption to Session This indicates to the Axis server that the serverinstance should not be discarded until the user session has ended

L ISTING 20.16 Deployment Descriptor for the SessionSimpleOrderServer 1: <admin:deploy xmlns:admin=”AdminService”>

2: <service name=”SessionSimpleOrderService” pivot=”RPCDispatcher”>

Trang 29

3: <option name=”className”

➥ value=”webservices.SessionSimpleOrderServer” />

4: <option name=”methodName” value=”submitOrder” />

5: <option name=”scope” value=”Session”/>

L ISTING 20.17 Client Code Altered to Work with the SessionSimpleOrderServer to

Maintain Session State

7: String customerId = “unknown”;

8: String productCode = “Widget”;

9: int quantity = 1;

10:

11: if (args.length != 3) 12: {

13: System.out.println(“Usage: SessionSimpleOrderClient “ + 14: “<customerId> <productCode> <quantity>”);

15: System.exit(1);

16: } 17: else 18: { 19: customerId = args[0];

20: productCode = args[1];

21: quantity = Integer.parseInt(args[2]);

22: } 23:

24: // Intantiate the factory 25: SessionSimpleOrderServer factory = new SessionSimpleOrderServer();

L ISTING 20.16 Continued

Trang 30

32: stub.setMaintainSession(true);

33:

34: try 35: { 36: // Call the service 37: String response;

49: System.out.println(“Remote exception: “ + ex);

50: } 51: } 52: }

When the two consecutive calls to submitOrderare made (as seen on lines 39–45), theserver instance is not discarded between the calls, so the following output is seen:

prompt> java SessionSimpleOrderClient Fred ASX4220 15 Thank you, Fred

You ordered 15 ASX4220’s That will cost you 750 Euros Hello again, Fred

You ordered 15 ASX4220’s That will cost you 750 Euros

Maintaining state is particularly useful when building up information from a client orwhen expensive resources, such as EJB references, are required

L ISTING 20.17 Continued

In this context, the term “expensive” is used to denote that a large amount

of valuable connection time is wasted obtaining such a resource if it has to

be created or retrieved for every client call Ideally, the server-side mentation should be able to cache and recycle such resources between clients to make best use of them Failing that, you would certainly want to retain resources between client invocations that form part of the same workflow (or transaction).

imple-Issues surrounding resource recycling and scalability have already been cussed on Day 18, “Patterns.”

dis-Note

Trang 31

Wrapping Existing J2EE Functionality as Web Services

As noted earlier, many Web Service implementations will be used to wrap existing tionality If that functionality takes the form of JavaBeans (such as those used in combi-nation with servlets or JSPs), it is relatively simple to use these from the Web ServiceJava classes seen so far In this case, the Java class provided as the target for the WebService router will perform a similar role to the servlet or JSP in that it provides thefront-end interaction logic that will then draw on functionality in the JavaBeans asrequired This Java class is then acting in the role of a façade, as discussed on Day 18

func-The key question for J2EE applications is how Web Services will interact with the J2EEcontainer and server to provide access to J2EE resources, most notably EJBs The answer

is relatively simple, although there are some complications in the short term

As you have seen, the Web Service router takes the form of a servlet, such as the

AxisServlet Hence, your Web Service Java classes are the equivalent of JavaBeans orhelper classes being used by any other servlet This means that they are being invokedwithin the context of the servlet Because the Web Service router can run within a J2EEservlet container, it can be installed on a J2EE server This means that the router and anyclasses used by it can gain access to J2EE resources through the container, so your WebService Java classes can use the same code as your servlets and JSPs to access EJBs andother J2EE resources

All of this seems quite simple, but there are some issues with this model:

• To deploy your Web Services under J2EE, they must be bundled in a WARfile ThisWeb Application will contain mappings for the endpoint addresses used by yourclient applications, such as http://acme.com:8080/axis/services/MyService.The virtual directory mappings used here (/axisand /axis/services) can only beused by one Web Application in the server This means that any Web Services thatuse these endpoint addresses must be deployed as part of the same Web

Application Also, to comply with the J2EE model, all J2EE resources accessedfrom within this Web Application must be declared as part of the deploymentdescriptor

The end result of this is that your Web Service Java classes must be bundled intothe WARalongside the Axis classes Any change to any of your Web Services, or theaddition of any new Web Services, will require this WARto be re-built and re-deployed This is slightly inconvenient because it may cause the re-deployment ofcompletely unrelated services that are running quite happily The only alternative tothis involves deploying multiple copies of the Web Service router, each with differ-ent endpoint mappings Over time, as Web Services become incorporated into theunderlying J2EE platform, this issue should disappear

Trang 32

• To avoid the previous issue and provide a single Web Service router that is pendent of the Web Services themselves, you could use an external servlet contain-

inde-er, such as Tomcat, to house your Web Service router This would allow you todeploy Web Services simply by copying their classes into place and informing therouter of their existence In this case, you would need to access EJBs and otherJ2EE resources from this remote container In some respects, this is not a problembecause you can initialize your JNDI runtime to perform its resource lookups usingthe naming service on the remote J2EE server The following code shows how youcould look up an EJB deployed on the R2EE RI from Tomcat:

Hashtable env = new Hashtable();

env.put(“java.naming.factory.initial”,

➥”com.sun.jndi.cosnaming.CNCtxFactory”);

env.put(“java.naming.provider.url”, “iiop://localhost:1050”);

InitialContext ic = new InitialContext(env);

Object lookup = ic.lookup(agencyJNDI);

home = (AgencyHome)PortableRemoteObject.narrow(lookup, AgencyHome.class);

However, there is a problem with this in that the calling container must be able topropagate the appropriate security and transaction context to the remote EJB con-tainer Because such propagation can still be the source of interoperability issuesbetween J2EE servers, the configuration of an out-of-server EJB client can becometricky As a result, this is not an ideal solution at present

• The previous two issues are largely technical in nature and can generally be come by the application of suitable mechanisms However, there is a more centralissue here Regardless of where the Web Services are deployed or invoked, you stillhave to write a Web Service Java class to expose the business logic in your EJBs

over-In some cases, this may be desirable in that you want to apply extra constraints onWeb Service-based users of these EJBs However, if the EJB is a Session EJB con-taining the business logic you want to expose, you would want a way of automati-cally creating the intervening Web Service Java class After all, the EJB interface isjust a list of Java methods similar to those on the Web Service Java class

The ability to expose EJB methods automatically as Web Services is provided inAxis and its predecessor, Apache SOAP The “pluggable provider” mechanismallows you to use an EJB provider rather than a Java class-based one You thenspecify this in the deployment descriptor, and the SOAP engine will then target thegiven EJB when a SOAP call arrives Similarly, the IBM WSTK provides a graphi-cal way of wrapping up EJBs as Web Services, although as of October 2001, thiswould only work with EJB-JAR files conforming to the EJB 1.0 specification Inboth cases, there is still the issue of ensuring the correct context propagation to thetarget J2EE server

Trang 33

As you can see, these issues make the creation and deployment of J2EE-based WebServices slightly awkward at the moment However, the primary purpose of J2EE 1.4 isthe incorporation of Web Services into the core J2EE platform This should mean thatcreating and deploying a Web Service that uses J2EE resources becomes as easy as creat-ing a servlet or EJB

Parameter Types and Type Mapping

So far, the Web Services you have seen have used simple parameters, such as strings andintegers However, in the real world, most systems will need to pass complex types such

as arrays, classes, and data structures During the rest of today, you will look at how suchcomplex types can be mapped between Java and SOAP/WSDL and create an order ser-vice that uses these types

Mapping Between Java and SOAP/WSDL Types

For simple types, SOAP and WSDL use the representations defined in “XML SchemaPart 2: Datatypes” that is part of the W3C XML Schema standard There is a straightmapping for all Java primitive types except for char There is also a straight mapping forthe Java Stringclass

If you were to define a Web Service with the following (unlikely) method:

public void test(byte byteArg, short shortArg, int intArg, long longArg,

float floatArg, double doubleArg, char charArg, boolean boolArg, String stringArg)

this would map into WSDL as follows:

<part name=”arg0” type=”xsd:byte”/>

<part name=”arg1” type=”xsd:short”/>

<part name=”arg2” type=”xsd:int”/>

<part name=”arg3” type=”xsd:long”/>

<part name=”arg4” type=”xsd:float”/>

<part name=”arg5” type=”xsd:double”/>

<part name=”arg6” type=”ns1:char”/>

<part name=”arg7” type=”xsd:boolean”/>

<part name=”arg8” type=”xsd:string”/>

</message>

Trang 34

Notice that all of the arguments except charare mapped to a type using the xsdprefix,which refers to the http://www.w3.org/2001/XMLSchemanamespace.

However, when you start to work with arrays and complex Java types, such as your ownclasses, more effort must be put into the representation of these mappings Consider what

is done by RMI when you pass Java objects between a client and server:

• RMI uses the Java serialization mechanism to convert the contents of the objectinto a byte stream that can be sent across the network

• Both client and server must have a definition for the type being passed (or must beable to get hold of one)

• The remote interface definition uses standard Java syntax to indicate where objectsare used as parameters or return values

When using complex Java types as part of a Web Service, you must address the sameissues However, there is the added complication that you must do this in a platform andlanguage-independent way Therefore, the following is needed to pass complex parame-ters as part of a Web Service method:

• Provide a mechanism to marshal and unmarshal the contents of a complex Javatype into an XML format that can be used as part of a SOAP message

• Deliver the marshalling and unmarshalling mechanism on both the client and theserver

• Indicate in the WSDL definition that certain parameters or return values are plex types, and provide a mapping between the complex types and their associatedmarshalling/unmarshalling code

com-Consider also the situation where you are provided with WSDL that has been generatedfrom a non-Java Web Service, such as a Web Service implemented using Microsoft NETcomponents This may also contain definitions for complex types that must be mappedinto Java types to use that Web Service from Java

Somebody has to do this mapping, and it is not necessarily straightforward Sometimes itcan be done using automated tools, while at other times it may require custom code

Mapping Complex Types with Serializers

The JAX-RPC specification defines a serialization framework that can be used to mapbetween complex Java types and their XML representations in WSDL and SOAP Youwill define serializer and deserializer classes for each complex type that will be called on

by the Web Service runtime to perform this conversion (See Figure 20.10.)

Trang 35

Serializers fall into three types:

• A set of standard serializers are provided as part of the Java Web Service work These include serializers for arrays and common classes, such as

frame-java.util.Date

• Given a JavaBean, a generic serializer can use its getters to extract its data whenmarshalling, and the associated deserializer can use the setters to populate a newinstance when unmarshalling

• A custom serializer can be written to create an XML representation of any Java class

Obviously, the creation of a custom serializer is not a trivial task Therefore, it is best totry to keep to standard classes and JavaBeans

To see how complex type mapping works, consider how you could improve the

SimpleOrderServerseen previously The submitOrdermethod took three parameters—

customerId,productCode, and quantity A more realistic service would take a variety

of customer information together with a list of line items, each of which would describe a product and the quantity required of that product The productCodeand

quantitycan form the basis of a simple line item to start improving the order service

SOAP Transport

SOAP Transport

<XML>

Serializer

Complex types

SOAP Server

<XML>

Deserializer

Complex types

Trang 36

The LineItemBeanformed from these is shown in Listing 20.18 As you can see, thisprovides getters and setters for both the product code and the quantity.

It is important that the JavaBean has a no-argument constructor and the full compliment of getters and setters Failure to provide all of these can lead to exceptions when trying to marshal or unmarshal these types.

5: private String _productCode;

6: private int _quantity;

14: public LineItemBean() 15: {

16: } 17:

18: public String getProductCode() 19: {

20: return _productCode;

21: } 22:

23: public void setProductCode(String productCode) 24: {

25: _productCode = productCode;

26: } 27:

28: public int getQuantity() 29: {

30: return _quantity;

31: } 32:

33: public void setQuantity(int quantity) 34: {

35: _quantity = quantity;

36: } 37: }

Trang 37

The server-side code can then be altered to use this JavaBean, as shown in Listing 20.19

L ISTING 20.19 BeanOrderServer.java —Using the LineItemBean

7: String receipt = “Thank you, “ + customerID + “\n”;

8: receipt += “You ordered “ + item.getQuantity() + “ “ +

Before you can deploy this updated class, you need a way to tell the Axis server how itcan unmarshal an instance of a LineItemBean If you do not do this, an exception willoccur when the server attempts to service a call to submitOrder

Given that the LineItemBeanis a JavaBean, the Axis BeanSerializercan be used tomarshal and unmarshal its contents You instruct the Axis server to use this serializer bydefining a bean mapping in the deployment descriptor Listing 20.20 shows an updatedform of the order service deployment descriptor containing a bean mapping betweenlines 5–7 The bean mapping associates an XML qualified name (a tag name and associ-ated namespace) with a particular Java class On line 9, the tag LineItemfrom the name-space urn:com-acme-commerceis defined as representing the Java class

webservices.LineItemBean

L ISTING 20.20 Defining a Bean Serializer for Use with the BeanOrderService

1: <admin:deploy xmlns:admin=”AdminService”>

2: <service name=”BeanOrderService” pivot=”RPCDispatcher”>

3: <option name=”className” value=”webservices.BeanOrderServer”/>

4: <option name=”methodName” value=”submitOrder”/>

Trang 38

All name-to-class mappings contained within the <beanMappings>element will be formed by the BeanSerializer After you have deployed the BeanOrderService, a list-ing of the deployed Axis services will reveal a full type mapping for the bean, as shown

per-in the followper-ing (you may need to restart your Web server for this mappper-ing to show up):

<service pivot=”RPCDispatcher” name=”BeanOrderService”>

<option name=”methodName” value=”submitOrder”/>

<option name=”className” value=”webservices.BeanOrderServer”/>

it with the namespace urn:com-acme.commerceas defined by the bean mapping in thedeployment descriptor

<definitions

targetNamespace=”http://localhost:8080/axis/services/BeanOrderService” xmlns:xsd=”http://www.w3.org/2001/XMLSchema”

xmlns:serviceNS=”http://localhost:8080/axis/services/BeanOrderService” xmlns:ns1=”urn:com-acme-commerce”

xmlns:soap=”http://schemas.xmlsoap.org/wsdl/soap/”

xmlns=”http://schemas.xmlsoap.org/wsdl/”>

<message name=”submitOrderRequest”>

<part name=”arg0” type=”xsd:string”/>

<part name=”arg1” type=”ns1:LineItem”/>

</message>

The mapping is now set up on the server side You can now call this service, confidentthat the correct unmarshalling will take place All that remains is to call the service from

a client The code shown in Listing 20.21 shows a client for the BeanOrderService

L ISTING 20.21 A Client for the BeanOrderService 1: import java.rmi.RemoteException;

2: import java.net.MalformedURLException;

3:

4: import org.apache.axis.AxisFault;

Trang 39

16: String customerId = “unknown”;

17: String productCode = “Widget”;

18: int quantity = 1;

19: ServiceClient client = null;

20:

21: try 22: { 23: Options options = new Options(args);

24: client = new ServiceClient(options.getURL());

25: args = options.getRemainingArgs();

26: } 27: catch (MalformedURLException ex) 28: {

29: System.err.println(“Option error: “ + ex);

30: System.exit(2);

31: } 32: catch (AxisFault ex) 33: {

34: System.err.println(“Option error: “ + ex);

35: System.exit(2);

36: } 37:

38: if (args == null || args.length != 3) 39: {

40: System.out.println(“Usage: SimpleOrderClient -l<endpoint>” + 41: “<customerId> <productCode> <quantity>”);

42: System.exit(1);

43: } 44: else 45: { 46: customerId = args[0];

47: productCode = args[1];

48: quantity = Integer.parseInt(args[2]);

49: } 50:

51: LineItemBean lineItem = new LineItemBean(productCode, quantity);

52:

53: QName lineItemAssociatedQName = new QName(“urn:com-acme-commerce”,

L ISTING 20.21 Continued

Trang 40

60:

61: String receipt;

62: try { 63: receipt = (String)client.invoke(“BeanOrderService”, 64: “submitOrder”,

65: new Object[] { customerId, lineItem }); 66: } catch (AxisFault fault) {

67: receipt = “No receipt”;

68: System.err.println(“Error : “ + fault.toString());

69: } 70:

71: System.out.println(receipt);

72: } 73: }

The main interest begins at line 51 where the LineItemBeanis instantiated Followingthis (line 53), an org.apache.axis.utils.QNameis created containing the XML quali-fied name that will represent the LineItemBeanas it is passed across the network Thevalue of this QNameis the one shown in the WSDL generated from the server, namely thetag name LineItemin the namespace urn:com-acme-commerce

A BeanSerializeris then created that will actually perform the mapping This serializermust know which particular type of JavaBean it is supposed to map Consequently, it isgiven the class type (webservices.LineItemBean.class) as a constructor parameter.Scrolling back to line 24, you can see that the client will be using a ServiceClienttoinvoke the Web Service method This is initialised with the service URL (http://

localhost:8080/axis/services/BeanOrderService) On lines 57–59, the serializer andthe QNameare passed to the addSerializermethod of the ServiceClient, together withthe JavaBean type, so that the ServiceClientknows for which type this serializer isintended

Finally, the Web Service method itself is invoked on lines 63–65, and the LineItem

instance is passed as the second parameter The client-side runtime will then invoke theserializer you have associated with LineItemwhen that parameter is marshalled into theSOAP message

L ISTING 20.21 Continued

Ngày đăng: 13/08/2014, 08:21

TỪ KHÓA LIÊN QUAN