Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Professional Java.JDK.5.Edition (Wrox)

.pdf
Скачиваний:
31
Добавлен:
29.02.2016
Размер:
12.07 Mб
Скачать

Chapter 11

<td>26.11519 and Rising</td> </tr>

</table>

</body>

</html>

Now, what if you wanted to write a computer program to access this same repository of information. It’s easy enough as a user to enter the Web address, type in your zip code, and view the weather forecast. Writing a program to do the same thing, though, is a tedious task and easy to break. These types of dynamic sites intermingle the presentation format of the data (encoded in HTML) with the data itself. If a program were to attempt to access this information (and it is possible), it would have to know what parameters the server needed (in this case, the name of the zip code variable and that it is an HTTP GET request), and then know exactly what format the HTML generated will be in. A parser would have to be written that knows exactly where the high temperature and the low temperature reside in the Web page, parse them out, and then do something with the data. This is not only tedious, painful, and difficult, but it is extremely prone to breakage. If random-weather.org decided to change how it presented the data, your parser would have to be rewritten. If they modified almost any aspect of either HTML page, some part of your program would have to be rewritten. This just does not make sense. Separating data from its presentation is a key principle in any software design, and in the continuing evolution of the Web, may someday become a ubiquitous reality. Web services were mainly designed to help this process. Web services allow these types of Web queries for information to occur in a structured format, using XML, that can be easily parsed and read by computer programs. Google is offering a sample Web services API so developers can programmatically access the Google search engine. Developers could then write applications that integrate the Google search engine easily into their applications. Other sites are playing around with various Web services APIs. Amazon.com offers an API to allow developers to search their product catalog. Any site that offers dynamic content could expose useful Web services to developers (should they so desire).

Platform Independent RPC

Web services are an implementation of platform independent remote procedure calls. Think of each individual Web service as a remote method. An XML-encoded request is sent to a server, and an XMLencoded response is returned. Normally, Web services are sent over the HTTP protocol via the HTTP POST operation. XML is posted to the Web server, and XML is returned from the HTTP POST operation. Since XML was built to be a data description language, any form of data can be encoded. Though some would call XML a bloated data format, since it stores information in plaintext, no one argues with the robustness of the XML parsers available to developers. Since XML is plaintext and the rules are not overly complicated (XML specification designers originally wanted the spec to be simple enough that any graduate-level computer science student could implement a parser in about two weeks), it is easy to write parsers. The XML specification is simple and clear enough that different parsers do not have a problem interoperating. A sample XML request/response posted via HTTP is diagrammed in the following Figure 11-16.

526

Communicating between Java Components and Components of Other Platforms

HTTP Server

HTTP Post

Figure 11-16

There are other advantages to implementing RPC via XML over HTTP. HTTP is another rock-solid protocol, again because of its simplicity. Earlier in this chapter, you easily implemented part of the specification. Technologies such as RMI or CORBA have specifications that are orders of magnitude more complex than either HTTP or XML. These protocols are also binary protocols, which makes them more efficient over the wire as more information can be encoded in less space. Debugging these protocols, though, is no simple task. Some would argue that distributed objects themselves are just too complex of a technology and not worth the considerable amount of design and development time required to truly implement a server-side application consisting entirely of distributed objects. By taking the simple route, Web services have ensured their ease of implementation. Ease of implementation is one of the single most critical elements to a cross-platform technology.

XML Web services do not have certain features built into them out of the box. They do not support sessions (since HTTP does not truly support sessions). They do not support procedure callbacks. They have no understanding of a distributed object. They are not at all object oriented, in fact. Security, transactions, and scalability — no, no, and no again. They are not meant to be a pillar supporting a mission-critical application. They merely enable current Web technologies to support a new generation of applications.

527

Chapter 11

Web Services Description Language (WSDL)

The Web Services Description Language is the Web services equivalent of CORBA IDL — in the sense that it is an interface document. It describes how to communicate with a particular Web service. Some would say you can be more descriptive with data you are passing; since all data is defined in XML, you are not limited to primitive data types and particular classes like you are in CORBA IDL. Web services described in WSDL can have the following pieces of information attached to them:

Types. The XML data types are defined here.

Messages. The content of Web services messages is described here.

Port Types. Specifies input and/or output messages for a particular operation or method.

Binding. Specifies the underlying communications protocol and transport protocol the Web services run over.

WSDL itself is described in XML and the complete specification for its format can be found at the following URL:

http://www.w3.org/TR/wsdl

Apache AXIS is an open-source Java project for Web service development and hosting. It ships with a couple of sample Web services. One simply returns the current version of the AXIS server. This section will later discuss in more detail about how to use AXIS. Here is a sample WSDL document from the Apache Version service. Note how messages, port types, and bindings are defined. There are no custom types; this WSDL document simply describes one service (WSDL documents can describe one or more Web services). The one service returns a string, just the version string of the AXIS server:

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

<wsdl:definitions targetNamespace=”http://localhost:8080/axis/services/Version” xmlns:apachesoap=”http://xml.apache.org/xml-soap” xmlns:impl=”http://localhost:8080/axis/services/Version” xmlns:intf=”http://localhost:8080/axis/services/Version” xmlns:soapenc=”http://schemas.xmlsoap.org/soap/encoding/” xmlns:wsdl=”http://schemas.xmlsoap.org/wsdl/” xmlns:wsdlsoap=”http://schemas.xmlsoap.org/wsdl/soap/” xmlns:xsd=”http://www.w3.org/2001/XMLSchema”>

<!--WSDL created by Apache Axis version: 1.2beta Built on Mar 31, 2004 (12:47:03 EST)-->

<wsdl:message name=”getVersionResponse”>

<wsdl:part name=”getVersionReturn” type=”soapenc:string”/> </wsdl:message>

<wsdl:message name=”getVersionRequest”> </wsdl:message>

<wsdl:portType name=”Version”> <wsdl:operation name=”getVersion”>

<wsdl:input message=”impl:getVersionRequest” name=”getVersionRequest”/> <wsdl:output message=”impl:getVersionResponse” name=”getVersionResponse”/>

</wsdl:operation>

</wsdl:portType>

<wsdl:binding name=”VersionSoapBinding” type=”impl:Version”> <wsdlsoap:binding style=”rpc”

transport=”http://schemas.xmlsoap.org/soap/http”/>

528

Communicating between Java Components and Components of Other Platforms

<wsdl:operation name=”getVersion”> <wsdlsoap:operation soapAction=””/> <wsdl:input name=”getVersionRequest”>

<wsdlsoap:body

encodingStyle=”http://schemas.xmlsoap.org/soap/encoding/” namespace=”http://axis.apache.org” use=”encoded”/>

</wsdl:input>

<wsdl:output name=”getVersionResponse”> <wsdlsoap:body

encodingStyle=”http://schemas.xmlsoap.org/soap/encoding/”

namespace=”http://localhost:8080/axis/services/Version” use=”encoded”/> </wsdl:output>

</wsdl:operation>

</wsdl:binding>

<wsdl:service name=”VersionService”>

<wsdl:port binding=”impl:VersionSoapBinding” name=”Version”> <wsdlsoap:address location=”http://localhost:8080/axis/services/Version”/>

</wsdl:port>

</wsdl:service>

</wsdl:definitions>

We will not be going into too much depth for the actual details of WSDL — that is better left to books or chapters dedicated solely to WSDL. In CORBA or RMI, you generate stub classes to use distributed objects transparently in code. WSDL allows the same sort of functionality for Web services. There are toolkits and compilers for WSDL in a number of languages. This chapter will later examine how to generate Java classes from WSDL and then use them in code. You never even need to know what goes on under the hood, but it certainly helps in understanding. Since Web services, boiled down to their core, are really just XML posted via HTTP, you could use an XML API and an HTTP API and write Web services. This is almost always not the best way to go about using Web services though. Bindings generated from WSDL provide far more accurate implementations (and are much more likely to be bug free). Because of the simplicity of Web services, there is no real speed or efficiency advantage to reinventing the wheel either. This chapter will look more at code generation from WSDL and generating WSDL from Java methods that you wish to expose as Web services.

Simple Object Access Protocol (SOAP)

Every RPC system needs a communications protocol. RMI uses either JRMP or IIOP. CORBA uses IIOP. Web services use the Simple Object Access Protocol, or SOAP. SOAP is a message format defined in XML. SOAP is inherently platform independent because it is based entirely on XML. Like WSDL, SOAP is also a W3C standard, and its specification can be found at the following URL:

http://www.w3.org/TR/soap/

Every SOAP message has the following structural attributes:

Envelope. The entire XML message has as its root element the SOAP Envelope — all content of the message is contained here.

Headers. XML Data can be placed in the header of a SOAP message away from the actual content — keeping things like usernames and passwords (if required) separate from the actual content of the message.

Body. The XML content delivered in a SOAP message is contained in the body.

529

Chapter 11

SOAP is a fairly straightforward protocol, assuming you understand XML and XML namespaces. An example SOAP message for the AXIS version service is listed below:

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

<soapenv:Envelope xmlns:soapenv=”http://schemas.xmlsoap.org/soap/envelope/” xmlns:xsd=”http://www.w3.org/2001/XMLSchema” xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”>

<soapenv:Body>

<ns1:getVersion soapenv:encodingStyle=”http://schemas.xmlsoap.org/soap/encoding/” xmlns:ns1=”http://axis.apache.org”/>

</soapenv:Body>

</soapenv:Envelope>

The SOAP message returned from this version request looks like:

<?xml version=”1.0” encoding=”utf-8”?>

<soapenv:Envelope xmlns:soapenv=”http://schemas.xmlsoap.org/soap/envelope/” xmlns:xsd=”http://www.w3.org/2001/XMLSchema” xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”>

<soapenv:Body>

<ns1:getVersionResponse

soapenv:encodingStyle=”http://schemas.xmlsoap.org/soap/encoding/”

xmlns:ns1=”http://axis.apache.org”> <getVersionReturn xsi:type=”soapenc:string”

xmlns:soapenc=”http://schemas.xmlsoap.org/soap/encoding/”>Apache Axis version: 1.2beta

Built on Mar 31, 2004 (12:47:03 EST)</getVersionReturn> </ns1:getVersionResponse>

</soapenv:Body>

</soapenv:Envelope>

Notice how both messages are rooted with the XML element envelope. There are no headers for these messages, and the Body for each is straightforward. This text will not go into any further depth describing SOAP. Most of its details are not as important. Learning the ins and outs of WSDL is probably more worth your while; the exact syntax of SOAP is not as big of an issue, since most Web service toolkits will handle it all for you (much the same way as you wouldn’t think of knowing how JRMP or IIOP work).

Sadly, perhaps one of the most exciting elements of SOAP is that Microsoft has made it a key part of its new .NET platform. SOAP is here to stay, and will hopefully continue to provide the cornerstone protocol for enabling Web service communication.

Underlying Transport Protocols

SOAP can be transported over a variety of protocols. The normal course of action is over HTTP, which is over TCP/IP. However, SOAP messages can also be sent over:

Straight TCP/IP (no HTTP)

Simple Mail Transport Protocol (SMTP)

Java Messaging Service Protocols

The real power of SOAP lies with HTTP over TCP/IP though. Web services become normal Web requests, can be sent through firewalls, and are just structured data requests from Web servers.

530

Communicating between Java Components and Components of Other Platforms

Weather Web Site Example

Going back to the random-weather.org site from before, this section will take a look under the hood of how it is currently implemented. After looking at its current implementation, you will enable it for Web services. In addition to finding out your local random weather forecast from your Web browser, developers can programmatically access this same information. Your weather Web site has a particular class that does most of the work, WeatherGetter. WeatherGetter randomly generates a weather forecast for a certain zip code. This forecast changes daily and randomly. If you ran a real Web site, you could think of WeatherGetter as providing accurate weather information, maybe from a database, probably conglomerated from local weather stations. Your weather forecasts will consist of four items:

High Temperature

Low Temperature

Weather Description

Barometer and Description

You develop a JavaBean, Weather, to hold these properties:

package book;

public class Weather { private String description;

private int lowTemp; private int highTemp;

private float barometer;

private String barometerDescription;

public float getBarometer() { return barometer;

}

public void setBarometer(float barometer) { this.barometer = barometer;

}

public String getBarometerDescription() { return barometerDescription;

}

public void setBarometerDescription(String barometerDescription) { this.barometerDescription = barometerDescription;

}

public String getDescription() { return description;

}

public void setDescription(String description) { this.description = description;

}

531

Chapter 11

public int getHighTemp() { return highTemp;

}

public void setHighTemp(int highTemp) { this.highTemp = highTemp;

}

public int getLowTemp() { return lowTemp;

}

public void setLowTemp(int lowTemp) { this.lowTemp = lowTemp;

}

}

The WeatherGetter class is also straightforward. This section will not go into detail explaining exactly how the forecasts are generated; if you are curious, though, look at the java.util.Random class in the JDK. The code listing is important later on so you can see how to expose it as a Web service. Here is the code listing:

package book;

import java.util.Calendar;

import java.util.GregorianCalendar; import java.util.Random;

public class WeatherGetter {

private Random random;

public WeatherGetter() { this.random = new Random();

}

public Weather getWeather(int zipCode) { Calendar cal = new GregorianCalendar(); // changes the weather value daily

random.setSeed(zipCode + cal.get(Calendar.DAY_OF_YEAR) + cal.get(Calendar.YEAR));

Weather w = new Weather();

int x = random.nextInt(100); int y = random.nextInt(100);

if (x >= y) { w.setHighTemp(x); w.setLowTemp(y);

}else { w.setHighTemp(y); w.setLowTemp(x);

532

Communicating between Java Components and Components of Other Platforms

}

w.setBarometer(25 + random.nextFloat() * 8); if (random.nextBoolean()) {

if (random.nextBoolean()) { w.setBarometerDescription(“Rising”);

} else w.setBarometerDescription(“Falling”);

}else w.setBarometerDescription(“Holding Steady”);

String adjective;

String noun;

if (random.nextBoolean()) { adjective = “Partly”;

} else adjective = “”;

if (random.nextBoolean()) { noun = “Sunny”;

} else noun = “Cloudy”;

if ((“Partly”.equals(adjective) || “Cloudy”.equals(noun)) && random.nextBoolean()) {

noun += “, Chance of “; if (w.getLowTemp() < 32)

noun += “snow”; else noun += “rain”;

}

w.setDescription((adjective + “ “ + noun).trim());

return w;

}

}

The weather Web application is fairly straightforward. There is one Java Server Page (JSP) that handles incoming weather requests and outputs the current random forecast for that zip code (like the screen shots and HTML code from earlier). The JSP uses WeatherGetter to generate the weather requests. This is a standard way to build dynamic sites — JSPs backed by Java classes that access data (or in this simple case, generate data). See Chapter 7, “Developing Web Applications Using the Model 1 Architecture,” and Chapter 8, “Developing Web Applications Using the Model 2 Architecture,” for more information on building Web applications with Java. You will now look at how to have this same functionality exposed as a Web service, using Apache AXIS.

Apache AXIS

Apache AXIS is an implementation of SOAP and is a rewrite of the original Apache SOAP project. It is also the most used Java toolkit for developing Web services. One of the primary goals of the AXIS project is to work well with other SOAP implementations. It works seamlessly with Microsoft’s .NET platform. AXIS provides a strong toolkit for any developer wishing to implement Web services. It includes:

Web application archive (WAR file) to deploy and manage Web services in standard Java Web containers

WSDL2Java and Java2WSDL toolsets — converts WSDL to Java classes and generates WSDL from existing Java classes

533

Chapter 11

TCPMon — the TCP Monitoring utility you looked at earlier in this chapter

Rich set of sample Web services

Since AXIS includes a Web application, it is complemented perfectly by Apache Tomcat, a servlet container and HTTP server. Combing these two open-source projects yields a production quality environment for deploying Web services and Web applications.

The main alternative in the Java world to using AXIS is Sun’s Java Web Services Developer Package (JWSDP). The current version at the time of this writing is 1.3, though 1.4 is due out soon, and will probably be the current version when you are reading this. Either AXIS or JWSDP can be used, although I have personally found AXIS to be simpler to use, and used more widely in production. The remainder of the “Web Services” section will discuss AXIS.

Setting up the Environment

There are four main steps to making your environment Web services ready:

1.Download and install Apache Tomcat.

There is a windows installer distribution of Apache Tomcat that makes installation a breeze (there are also zip files and tar.gz files — for those, simply unpack them, they are ready as is). This file can be downloaded from the following URL:

http://jakarta.apache.org/site/binindex.cgi

This site lists all of the products the Jakarta Project offers, so you’ll have to scroll down to find the .exe file for Tomcat.

2.Download the Apache AXIS source distribution, build it (as per its instructions), and place the AXIS Web application in the Tomcat’s directory for deploying Web applications.

AXIS can be downloaded from the following URL:

http://ws.apache.org/axis/index.html

After downloading and unzipping AXIS, go under the <AXIS_HOME>/webapps directory to find the AXIS Web app. Copy this directory and all of its contents to the <TOMCAT_HOME>/webapps directory. The next time you start up Tomcat, you will be able to go to the local URL:

http://localhost:8080/axis/

From here you can view the status of the AXIS installation and see what Web services have been deployed.

3.Download the Java Activation Framework and install activation.jar to the lib directory of the AXIS Web application.

You’ll need to download the Java Activation Framework from the following URL:

http://java.sun.com/products/javabeans/glasgow/jaf.html

After downloading and unpacking the file, you’ll find activation.jar. Copy this file to the

<TOMCAT_HOME>/webapps/axis/WEB-INF/lib directory.

534

Communicating between Java Components and Components of Other Platforms

4.Modify the web.xml configuration file of the AXIS Web application to enable the administration servlet.

To be able to deploy Web services, you have to enable the AXIS administration servlet. Modify the <TOMCAT_HOME>/webapps/axis/WEB-INF/web.xml file to uncomment the administration servlet (note the comments around the servlet-mapping element below). The next time you start Tomcat, your Web services environment will be ready:

...

<!-- uncomment this if you want the admin servlet --> <!--

<servlet-mapping> <servlet-name>AdminServlet</servlet-name> <url-pattern>/servlet/AdminServlet</url-pattern>

</servlet-mapping> -->

...

Deploying a Service

Getting back to your random-weather.org Web site, suppose you want to expose the following method of WeatherGetter as a Web service:

public Weather getWeather(int zipcode) {...}

Doing so would enable client programmers, functionality of your random-weather.org

as well as normal Web-browsing end users, to access the Web site.

AXIS makes it easy to expose the method as a Web service — all you need is a Web Services Deployment Descriptor, which is an AXIS-specific file type used for deploying a Web service. This text will not go into too much detail regarding the actual format for this file; see the AXIS documentation for more information. Here is what your deployment descriptor, desploy.wsdd, looks like:

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

<deployment xmlns=”http://xml.apache.org/axis/wsdd/” xmlns:java=”http://xml.apache.org/axis/wsdd/providers/java”>

<service name=”Weather” provider=”java:RPC”> <parameter name=”allowedMethods” value=”getWeather”/>

<parameter name=”className” value=”book.WeatherGetter”/> <beanMapping qname=”ns:weather” xmlns:ns=”http://randomweather.org”

languageSpecificType=”java:book.Weather”/>

</service>

</deployment>

Notice how the service definition in the deployment descriptor defines the Java class and methods exposed as the Web service. Any class used as a service in this manner by AXIS must have a default, noargument constructor, so the AXIS engine can create instances of it. Since the type Weather is not a primitive type, there is some extra configuration necessary for AXIS to be able to properly serialize and deserialize the class to and from XML. There are powerful predefined mechanisms in AXIS for defining exactly how to serialize and deserialize data. If a predefined serializer cannot be found to properly serialize a nonprimitive Java type, custom serializers can be written for the utmost control over the serialization process. Since the Weather type follows JavaBean conventions, the easiest mechanism in your case

535

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]