Tải bản đầy đủ - 0 (trang)
SOAP: The Cornerstone of Interoperability

SOAP: The Cornerstone of Interoperability

Tải bản đầy đủ - 0trang

www.it-ebooks.info

Java Web Services













Send and receive data transmissions across a network using either HTTP or SMTP1

Understand MIME encoding rules and base the means of constructing and

deconstructing binary attachments on those rules

Construct and deconstruct XML documents that conform to the enveloping and

encoding rules established by SOAP

Perform the required action, if an action is indicated in the SOAP document



Also, simple doesn't necessarily connotate "weak" or "lame." SOAP is powerful enough to

represent any datatype, object serialization, method invocation, or document exchange.

Simple does mean that SOAP is missing some important things, such as security, reliability,

routing, and rules of engagement for interaction among multiple parties. These items,

however, will be added eventually. Let's just conclude that in its infancy, SOAP was

"simpler" than its predecessors.



3.2 Object

The "O" in SOAP stands for "object" and has to do with its roots as a way of invoking COM

objects across the Internet. As with its close cousin XML-RPC, SOAP is fully capable of

describing a remote procedure call or method invocation. Here's a typical SOAP document

that describes a method invocation on a remote object:

POST /StockQuote HTTP/1.1

Host: www.example.org

Content-Type: text/xml; charset="utf-8"

Content-Length: nnnn

SOAPAction: "http://example.org/2001/06/quotes"






env:encodingStyle="http://www.w3.org/2001/09/soap-encoding"

xmlns:m="http://example.org/2001/06/quotes">

DIS









Section 3.5 discusses the details of this SOAP request. For now, it should suffice to say that

the two most important parts are the method name, GetLastTradePrice, and its parameter,

the ticker symbol DIS.



3.3 Access

A key feature of SOAP and web services is their accessibility. The initial developers of SOAP

intended for all SOAP conversations to be carried out via a "binding" to another lower-level

protocol, and that binding would most likely be HTTP or SMTP. These protocols were chosen

because they are almost universally available. Most firewalls have been trained to allow

HTTP sessions and SMTP exchanges, so SOAP conversations can easily cross corporate

boundaries.

1



Even this characterization is somewhat of a misnomer, as we will see when we talk about bindings and higher-level protocols built on top of SOAP.



29



www.it-ebooks.info

Java Web Services



It's possible to create a SOAP binding for almost any protocol—however, for the time being,

HTTP is the de facto binding (and most widely used). Other bindings, such as SOAP over

RMI, or SOAP over JMS (for improved reliability), are emerging.



3.4 Protocol

Put all these factors together and we have a protocol. SOAP is an XML based protocol used to

exchange information throughout a distributed environment.

3.4.1 Message-Based Document Exchange and RPC

SOAP has its roots in synchronous remote procedure calls over HTTP—although you

wouldn't know it by reading the specification these days. In fact, the specification seems to go

out of its way to distance itself from that association. Although special provisions are

available for performing synchronous RPC calls in SOAP, there is also an asynchronous,

message-based document exchange model. Actually, the document exchange model is the

default method of exchanging data between two endpoints. An RPC call is a specialized case

of combining multiple one-way asynchronous messages into a request-response.

The introduction to Section 2 of the SOAP 1.2 specification says it well:

SOAP messages are fundamentally one-way transmissions from a SOAP

sender to a SOAP receiver; however, SOAP messages are often combined to

implement patterns such as request/response.

SOAP implementations can be optimized to exploit the unique characteristics

of particular network systems. For example, the HTTP binding ... provides for

SOAP response messages to be delivered as HTTP responses, using the same

connection as the inbound request.2

Because SOAP can represent some fairly complex data structures in both the request and

response messages, the lines between the two models are blurred. This chapter presents the

information that is germane to either model first. The RPC-specific concepts built on the more

generic concepts are explained at the end. We use Apache SOAP 2.2 for our examples, which

follows a similar design.



3.5 Anatomy of a SOAP Message

The SOAP specification describes four major components: formatting conventions for

encapsulating data and routing directions in the form of an envelope, a transport or protocol

binding, encoding rules, and an RPC mechanism. The envelope defines a convention for

describing the contents of a message, which in turn has implications on how it gets processed.

A protocol binding provides a generic mechanism for sending a SOAP envelope via a lowerlevel protocol such as HTTP. Encoding rules provide a convention for mapping various

application datatypes into an XML tag-based representation. Finally, the RPC mechanism

provides a way to represent remote procedure calls and their return values. Throughout this

book, we'll refer to these four areas collectively as a SOAP message.



2



SOAP 1.2 Specification: http://www.w3.org/TR/2001/WD-soap12-part1-20011002/.



30



www.it-ebooks.info

Java Web Services



3.5.1 How XML Becomes SOAP

We start this discussion by focusing on the document exchange model. To clarify this topic,

we use a simple purchase order document, PO.xml. This document is overly simplified

because it contains only two things—a ship-to address and an item entry:







Joe Smith

14 Oak Park

Bedford

MA

01730







Candy Canes

444

1.68

I want candy!









PO.xml is not yet a SOAP document; it's just a vanilla XML document. What makes it

become a SOAP document is:















The wrapping of the XML inside of a SOAP body

The wrapping of the SOAP body within a SOAP envelope

The optional inclusion of a SOAP header block

Namespace declarations

Encoding style directives for the serialization of data

The binding of the whole thing to a protocol



As illustrated in Figure 3-1, a SOAP envelope contains two primary components: a header

and a body. Both the header and the body can contain multiple blocks of information.

Figure 3-1. Block structure of a SOAP envelope



The following listing shows PO.xml wrapped by an envelope to make it conform to SOAP:



31



www.it-ebooks.info

Java Web Services




xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"

xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"

xmlns:xsd="http://www.w3.org/1999/XMLSchema">



...









Joe Smith

14 Oak Park

Bedford

MA

01730







Candy Canes

444

1.68

I want candy!













3.5.2 The SOAP Envelope

The SOAP envelope declaration is simply the outermost XML tag that delineates the

boundaries of the SOAP document. The following envelope tag shows three required

attributes, which specify the namespace and the schema to be used for this envelope:


xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"

xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"

xmlns:xsd="http://www.w3.org/1999/XMLSchema">

...





Let's



examine



the



syntax



of



this



tag.



The



first

attribute,

xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/", is a namespace

declaration. The namespace declaration prevents tag name conflicts when XML fragments are

combined to form composite documents. It's analogous to the use of the package keyword in

Java.

At first, it may seem that "
special keywords. Actually, :Envelope and xmlns: are, but the use of the string SOAP-ENV is

completely arbitrary. What's really important is its relationship to the :Envelope and xmlns:

keywords. The URL http://schemas.xmlsoap.org/soap/envelope/ is a special URI reserved for

the namespace defined by SOAP. Its purpose in life is to be a unique string. A common

convention is to use a URI that represents a real URL owned by the organization that authors

the document. This convention ensures that the URI is globally unique. It could just as well

have looked like this:



32



www.it-ebooks.info

Java Web Services


xmlns:abbr="http://schemas.xmlsoap.org/soap/envelope/"

xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"

xmlns:xsd="http://www.w3.org/1999/XMLSchema">

...





In this version of the envelope element, xmlns:abbr declares a prefix that is an abbreviation

to

be

used

in

place

of

the

much

more

lengthy

"http://schemas.xmlsoap.org/soap/envelope/". The tag and the

closing tag indicate that this namespace is scoped to the entire envelope.

Next, the xmlns:xsi=http://www.w3.org/1999/XMLSchema-instance attribute declares

the XML schema instance namespace. The prefix, xsi, must be prepended to all elements and

attributes defined in this namespace. An example of such an attribute is xsi:type, which

specifies the type of an element for encoding purposes.

Finally, xmlns:xsd=http://www.w3.org/1999/XMLSchema is just another namespace

declaration, akin to xsi and SOAP-ENV. This declaration defines the XMLSchema namespace.

Elements from this namespace are used as values for the xsi:type attribute—for example,

xsd:string or xsd:boolean. The schema for the SOAP document is not referenced from the

SOAP envelope.

3.5.3 The SOAP Header

The SOAP header and body are syntactically similar. SOAP 1.1 and SOAP 1.2 have no

conventions for what is supposed to be in the header; it is simply a place to put directives to

the SOAP processor that receives the message. The sending and receiving parties need to

agree on which elements go there and what they mean. Higher- level protocols built on top of

SOAP, such as ebXML Message Service (MS), have formalized the use of the SOAP header

by defining specific elements such as a , which contains such specific

things as , , and . The SOAP body is intended for the actual data, or

message payload, to be consumed and processed by the ultimate receiver.

When using SOAP for RPC, the distinction between the header and the body is similar. The

is reserved purely for the method call and its parameters, and the
is used for

things targeted at the underlying infrastructure, such as a transaction ID. A transaction ID

clearly should not belong to the method signature; it's intended for the SOAP processor that

receives the message, which could very well be a J2EE server with a transaction manager.

Here's the syntactic form of a SOAP header:


xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"

xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"

xmlns:xsd="http://www.w3.org/1999/XMLSchema">





Me

You

9999

...





33



www.it-ebooks.info

Java Web Services





...







3.5.4 The SOAP Protocol Binding

At this point, we need to add only one thing to make PO.xml into a SOAP message: the

additional information needed by the protocol that it is bound to. The following listing shows

the HTTP header information that is prepended to the message when it is bound to the HTTP

protocol:

SOAPAction = "urn:soaphttpclient-action-uri"

Host = localhost

Content-Type = text/xml; charset=utf-8

Content-Length = 701




xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"

xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"

xmlns:xsd="http://www.w3.org/1999/XMLSchema">

...





The SOAPAction header is somewhat strange. In SOAP 1.1, it was a required part of the

HTTP protocol binding. Its intent was to allow something that does routing or dispatching to

make decisions without any knowledge of SOAP or the means to parse the SOAP envelope.

For example, a dumb CGI script or servlet whose only purpose is to route requests to other

processes shouldn't have to process the SOAP envelope to get routing information. This

concept is great, but it is tied to the HTTP protocol.

In SOAP 1.2, SOAPAction has become optional. It's not up to SOAP to dictate extensions to

an underlying protocol. Hindsight is 20/20. In this case, who can blame anyone for taking an

existing HTTP header such as Action and creating something like it called SOAPAction?

What's really needed is a generic mechanism for specifying sideband data independent of the

protocol. If such a thing existed, the people responsible for creating a standard mapping to

HTTP might just as well have chosen to have a SOAPAction header. However, the semantics

of the first mapping shouldn't dictate how the rest of the mappings are done.



3.6 Sending and Receiving SOAP Messages

We have seen the building blocks of a SOAP message. The next steps are to understand how a

message is built and how it is then communicated between two endpoints. To discuss these

topics, we present a simple SOAP sender and a SOAP receiver using Apache SOAP and the

Apache Tomcat servlet engine.3 You may find it refreshing to discover that the additional

pieces are not placed in the SOAP document by hand. The SOAP-ification is accomplished by

using APIs that take care of the dirty work.



3



While we use Apache SOAP, this chapter is not intended to be a tutorial on Apache SOAP or Tomcat. The intent is to talk about SOAP and its

behavior whenever possible. The installation and set up of Apache SOAP, Tomcat, and the example files are not discussed. Installation is covered by

the readme file included with the examples, which is available from http://www.oreilly.com/catalog/javawebserv/examples.



34



www.it-ebooks.info

Java Web Services



Before we look at the code of our first SOAP example, let's run it and observe its behavior.

This example consists of a simple HTTP sender class that reads an XML file, wraps it in

a SOAP envelope, and sends it to a URL destination. The destination is a simple HTTP

servlet that takes the contents of the message and dumps it to the screen. As we progress

through concepts such as dynamic headers, SOAP with Attachments, and SOAP-RPC, these

examples will become progressively more sophisticated. For now, lets run the simple one.

From the command line, run the command:

java SimpleGenericHTTPSoapClient -df ./PO.xml



If

this

command

doesn't

work,

make

sure

that

SimpleGenericHTTPSoapClient.class is on the classpath and PO.xml is

in the current directory.

You should see the following output:

_________________________________________________________

Starting SimpleGenericHTTPSoapClient:

host url

= http://localhost:8080/examples/servlet/SimpleHTTPReceive

data file = ./PO.xml

_________________________________________________________

Sent SOAP Message with Apache HTTP SOAP Client.

Waiting for response....

HTTP POST was successful.



In the command shell running the Tomcat servlet engine, you should see:

Received request.

----------------------SOAPAction = "urn:oreilly-jaws-samples"

Host = localhost

Content-Type = text/xml; charset=utf-8

Content-Length = 695

----------------------


xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"

xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"

xmlns:xsd="http://www.w3.org

/1999/XMLSchema">







Joe Smith

14 Oak Park

Bedford

MA

01730





35



www.it-ebooks.info

Java Web Services







Candy Canes

444

1.68

I want candy!











____________________________



3.6.1 The SOAP Sender

We will soon examine the source code and some of the APIs used to create and send this

message. But first, here is a listing of the simple SOAP sender in its entirety:

import java.io.*;

import java.util.*;

public class SimpleGenericHTTPSoapClient

{

//////////////

//Default values used if no command line parameters are set

private static final String DEFAULT_HOST_URL =

"http://localhost:8080/examples/servlet/SimpleHTTPReceive";

private static final String DEFAULT_DATA_FILENAME



= "./PO.xml";



private static final String URI = "urn:oreilly-jaws-samples";

//////////////

//Member variables

private String m_hostURL;

//data file that will be the body content of a soap envelop

private String m_dataFileName;

public SimpleGenericHTTPSoapClient(String hostURL, String dataFileName)

throws Exception

{

m_hostURL = hostURL;

m_dataFileName

= dataFileName;

System.out.println(



);



System.out.println("____________________________________________________");

System.out.println("Starting SimpleGenericHTTPSoapClient:");

System.out.println("

host url

= " + m_hostURL);

System.out.println("

data file

= " + m_dataFileName);

System.out.println("____________________________________________________");

System.out.println( );

}



36



www.it-ebooks.info

Java Web Services

public void sendSOAPMessage( )

{

try

{

// get soap body to include in the SOAP envelope

FileReader fr = new FileReader (m_dataFileName);

javax.xml.parsers.DocumentBuilder xdb =

org.apache.soap.util.xml.XMLParserUtils.getXMLDocBuilder();

org.w3c.dom.Document doc =

xdb.parse (new org.xml.sax.InputSource (fr));

if (doc == null) {

throw new org.apache.soap.SOAPException

(org.apache.soap.Constants.FAULT_CODE_CLIENT,

"parsing error");

}

//Create the SOAP envelope

org.apache.soap.Envelope envelope =

new org.apache.soap.Envelope( );

// create a vector for collecting the body elements

Vector bodyElements = new Vector( );

//obtain the top-level DOM element and place it into the vector

bodyElements.add(doc.getDocumentElement ( ));

//Create the SOAP body element

org.apache.soap.Body body = new org.apache.soap.Body(

body.setBodyEntries(bodyElements);



);



//Add the SOAP body element to the envelope

envelope.setBody(body);

// Build the Message.

org.apache.soap.messaging.Message msg

= new org.apache.soap.messaging.Message(



Client.");



}



);



msg.send (new java.net.URL(m_hostURL), URI, envelope);

System.out.println("Sent SOAP Message with Apache HTTP SOAP

// receive response from the transport and dump it to

// the screen

System.out.println("Waiting for response....");

org.apache.soap.transport.SOAPTransport st =

msg.getSOAPTransport ( );

BufferedReader br = st.receive ( );

String line = br.readLine( );

if(line == null)

{

System.out.println("HTTP POST was successful. \n");

}

else

{

while (line != null)

{

System.out.println (line);

line = br.readLine( );

}

}



37



www.it-ebooks.info

Java Web Services



}



catch(Exception e)

{

e.printStackTrace(

}



);



//

// NOTE: the remainder of this deals with reading arguments

//

/** Main program entry point. */

public static void main(String args[]) {



}



}



// not relevant ...



The main( ) method is responsible for parsing the command-line arguments, running

the constructor, and calling the sendSOAPMessage( ) method:

/** Main program entry point. */

public static void main(String args[]) {

...



...

}



// Start the HTTPSoapClient

try

{

SimpleGenericHTTPSoapClient soapClient =

new SimpleGenericHTTPSoapClient(hostURL, dataFileName);

soapClient.sendSOAPMessage( );

}



The constructor simply stores some local member variables and prints things on the screen.

All the real work happens in sendSOAPMessage( ). After reading the PO.xml document,

sendSOAPMessage( ) parses the document into a DOM tree. We get a parser by calling the

Apache getXMLDocBuilder( ) method, which returns a DocumentBuilder object. This

parser is represented by a javax.xml.parsers.DocumentBuilder interface, which is part of

the Java API for XML Processing (JAXP) package. While we chose to use the Xerces parser,

the actual parser could be any parser that implements the interface. Once a suitable parser is

obtained, the parser is invoked; it returns an org.w3c.dom.Document object:

public void sendSOAPMessage( )

{

try

{

// get soap body to include in the SOAP envelope

FileReader fr = new FileReader (m_dataFileName);

javax.xml.parsers.DocumentBuilder xdb =

org.apache.soap.util.xml.XMLParserUtils.getXMLDocBuilder(

org.w3c.dom.Document doc

= xdb.parse (new org.xml.sax.InputSource (fr));

if (doc == null) {

throw new org.apache.soap.SOAPException

(org.apache.soap.Constants.FAULT_CODE_CLIENT,

"parsing error");

}



);



38



www.it-ebooks.info

Java Web Services



Next, we need to create a SOAP envelope to hold everything and place the document into it.

To associate the document with the envelope, place the top-level DOM element into a

Vector, then attach the Vector to a Body object. Then place the body in the envelope using

the setBody( ) method. In this simple case, only one top-level element, the

tag, should be attached. The DOM parser has taken care of building and

attaching the nodes underneath the main PurchaseOrder element:

//Create the SOAP envelope

org.apache.soap.Envelope envelope = new org.apache.soap.Envelope();

// create a vector for collecting the body elements

Vector bodyElements = new Vector( );

//obtain the top-level DOM element and place it into the vector

bodyElements.add(doc.getDocumentElement ( ));

//Create the SOAP body element

org.apache.soap.Body body = new org.apache.soap.Body(

body.setBodyEntries(bodyElements);



);



//Add the SOAP body element to the envelope

envelope.setBody(body);



Now that the envelope is constructed, it needs to be sent to a destination. In Apache SOAP, a

Message object performs an asynchronous one-way send:

// Build the Message.

org.apache.soap.messaging.Message msg

= new org.apache.soap.messaging.Message(



);



msg.send (new java.net.URL(m_hostURL), URI, envelope);

System.out.println("Sent SOAP Message with Apache HTTP SOAP

Client.");



The Message.send( ) method takes three parameters: a URL that represents a destination, a

URI that represents the value for the SOAPAction header, and the SOAP envelope that we just

built. The SOAPAction URI is really part of the binding to HTTP. When we ran the example,

the value urn:oreilly-jaws-samples appeared as part of the HTTP header information that the

receiving servlet dumped. Later, we will see how to use the SOAPAction to map the request

into either an Apache MessageRouter service or a RPCRouter service. For now, it suffices to

say that this URI is used to determine which function or service is invoked when the message

reaches its destination.

The



Message interface is intended for asynchronous one-way communications;

Message.send( ) has a void return value. This value does not preclude it from being used in

a two-way synchronous conversation. When the Message interface is implemented over a

two-way transport protocol, such as HTTP, the SOAPTransport.receive( ) method can be



used to receive a response:

// receive response from the transport and dump it to the screen

System.out.println("Waiting for response....");

org.apache.soap.transport.SOAPTransport st =

msg.getSOAPTransport ();

BufferedReader br = st.receive ( );

String line = br.readLine( );



39



Tài liệu bạn tìm kiếm đã sẵn sàng tải về

SOAP: The Cornerstone of Interoperability

Tải bản đầy đủ ngay(0 tr)

×