In this section, we take a closer look at each of the WSDL elements. To illustrate the discussion, we'll use examples from the WSDL document that describe the JAX-RPC book service that you saw in Chapter 2. That particular web service was developed by starting with Java interface definitions, rather than from a WSDL file. If you already have a distributed application written in Java (perhaps using RMI) that you need to convert to a web service, this is the natural path to follow. However, in order to make the service generally available, you must create and publish a WSDL document. Fortunately, the wsdeploy utility provided with the JAX-RPC reference implementation generates a WSDL file from the information provided in its jaxrpc-ri.xml file together with the class files for the Java interfaces, thus saving you the trouble of trying to build one manually.
|
The WSDL file for the JAX-RPC book service, which is called BookQuery.wsdl, can be found in the web archive at chapter2\bookservice\Books.war relative to the installation directory for this book's example source code. If this file is missing, you can recreate it by making chapter2\bookservice your working directory and typing the command:
ant web-package
Throughout this chapter, we'll show extracts from this file, slightly reformatted for better readability. A complete listing can be found in the Appendix.
Although it is very likely that the majority of WSDL files will be both created and consumed by software tools, it is still extremely useful to be able to read and understand a WSDL document so that you can see the operations provided by a web service that you need to interact with before using the stub and tie code (created by tools like wscompile and wsdeploy) to create a client for the service or to create your own implementation of it.
The root element of every WSDL file must be a definitions element, which has two attributes:
The WSDL specification describes this attribute as lightweight documentation for the content of the file. It is typically not used by software that parses WSDL files with the intent of generating code. In particular, this attribute does not provide the name of the web service, which is obtained instead from the service element.
The value of this attribute is a URI that becomes the XML namespace for the elements used to describe the services, ports, messages, and bindings defined in the file. It is not necessary (or possible) to explicitly state the namespace when declaring these objects, because they will automatically be associated with the target namespace.
As a typical example, the definitions element from the WSDL file generated for the book service is shown in Example 5-2.
<?xml version="1.0" encoding="UTF-8"?> <definitions name="BookService" targetNamespace="urn:jwsnut.chapter2.bookservice/wsdl/BookQuery" xmlns:tns="urn:jwsnut.chapter2.bookservice/wsdl/BookQuery" xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:ns2="urn:jwsnut.chapter2.bookservice/types/BookQuery" xmlns:ns3="http://java.sun.com/jax-rpc-ri/internal"> <!-- All nested elements omitted --> </definitions>
Here, the target namespace is urn:jwsnut.chapter.bookservice/wsdl/BookQuery, which is also associated with the namespace prefix tns so that it can be conveniently referred to throughout the file. In the case of a WSDL file generated by wsdeploy, the URL from this namespace is obtained by combining the typeNamespaceBase attribute of the webServices element in the jaxrpc-ri.xml file, and the name attribute of the endpoint element for the service in the same file, as described in Section 2.2.7.5 in Chapter 2. Prefixes for other namespaces that will be referenced are also typically defined within this element. The default namespace in this example, as in most WSDL files, is the namespace associated with WSDL itself rather than the target namespace, since most of the elements in the document will be WSDL elements.
The data types that are used in the messages exchanged by a web service and its clients are defined using the WSDL types element, and are referenced from the message elements that will be described later in this chapter.[2] The schema document for WSDL allows this element to contain arbitrary content, although in practice it will contain type definitions described using a schema language, plus an optional documentation element. The WSDL specification recommends the use of XML schema as the preferred schema language, and existing software tools that parse WSDL, including wscompile, currently expect to find XML schema elements here.
[2] It is possible to use type definitions found in external schema documents instead of (or as well as) defining types within the WSDL document itself. See Section 5.2.9 at the end of this chapter for details.
If you intend to manually build WSDL documents, you need a good understanding of XML schema to create the content of the types element. XML schema is a large and complex subject that is well beyond the scope of this book but is fully covered in Eric van der Vlist's book, XML Schema (O'Reilly). Fortunately, XML schemas are slightly easier to read than they are to write, as you can see from Example 5-3, which shows the types element in the WSDL document generated by wsdeploy for the book web service.
<types> <schema targetNamespace="urn:jwsnut.chapter2.bookservice/types/BookQuery" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tns="urn:jwsnut.chapter2.bookservice/types/BookQuery" xmlns:soap-enc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns="http://www.w3.org/2001/XMLSchema"> <complexType name="ArrayOfBookInfo"> <complexContent> <restriction base="soap-enc:Array"> <attribute ref="soap-enc:arrayType" wsdl:arrayType="tns:BookInfo[]"/> </restriction> </complexContent> </complexType> <complexType name="BookInfo"> <sequence> <element name="editor" type="string"/> <element name="author" type="string"/> <element name="price" type="double"/> <element name="title" type="string"/> </sequence> </complexType> <complexType name="BookServiceException"> <sequence> <element name="message" type="string"/> </sequence> </complexType> </schema> <schema targetNamespace="http://java.sun.com/jax-rpc-ri/internal" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tns="http://java.sun.com/jax-rpc-ri/internal" xmlns:soap-enc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns="http://www.w3.org/2001/XMLSchema"> <complexType name="hashMap"> <complexContent> <extension base="tns:map"> <sequence/> </extension> </complexContent> </complexType> <complexType name="map"> <complexContent> <restriction base="soap-enc:Array"> <attribute ref="soap-enc:arrayType" wsdl:arrayType="tns:mapEntry[]"/> </restriction> </complexContent> </complexType> <complexType name="mapEntry"> <sequence> <element name="key" type="anyType"/> <element name="value" type="anyType"/> </sequence> </complexType> </schema> </types>
The first thing to note is that there are two XML schema declarations here. This is necessary because they are declaring types within different namespaces (as defined by the targetNamespace attribute), and a single schema element can only refer to one namespace. The first schema contains the data types that appear in the Java interface definitions for the book web service, whereas the second is added by wsdeploy to allow the use of HashMap as a method return value.
The namespace for the first schema is obtained by combining the typeNamespaceBase attribute of the webServices element in the jaxrpc-ri.xml file supplied to wsdeploy with the name attribute of the endpoint element in the same file. It is good practice to use separate namespaces for the type definitions and the definitions of the messages, port types, etc. that also appear in the WSDL document, which you can achieve by supplying different values for the typeNamespaceBase and targetNamespaceBase attributes of the
webServices
element. It is permissible, as shown here, to have more than one namespace within the type element.
For reference, here is the definition of the remote interface supported by the book web service, from which the WSDL document was generated:
public interface BookQuery extends Remote { public abstract int getBookCount( ) throws RemoteException; public abstract String getAuthor(String name) throws RemoteException; public abstract String getEditor(String name) throws RemoteException; public abstract double getPrice(String name) throws BookServiceException,RemoteException; public abstract BookInfo[] getBookInfo( ) throws RemoteException; public abstract HashMap getBookMap( ) throws RemoteException; }
Most of the methods in this interface have arguments and return values that are either Java primitives or of type String. These types do not require definitions in the type section, because they can be represented directly by predefined XML schema elements such as xsd:int and xsd:string. Therefore, the schema section for the book web service declares a type for the BookServiceException class, the BookInfo class, and another that represents an array of BookInfo objects.[3] Data types can be defined as abstract types, using the XML schema complexType and simpleType elements, or they can be defined as elements that are either instances of predefined types or custom types, possibly with restrictions or extensions added. We'll examine these two possibilities separately.
[3] The schema section does not include a declaration for HashMap, since this type is not defined by the book web service � it is provided by the JAX-RPC reference implementation and is actually defined in the second schema section in the WSDL file.
Without delving too deeply into XML schema, it should be obvious that the following extract from the schema definitions shown in Example 5-3 declares a type called BookInfo that has four fields, three that contain strings and another that holds a double:
<complexType name="BookInfo"> <sequence> <element name="editor" type="string"/> <element name="author" type="string"/> <element name="price" type="double"/> <element name="title" type="string"/> </sequence> </complexType>
The name used to declare a type, in this case BookInfo, cannot be explicitly namespace-qualified. It is automatically assigned to the targetNamespace of the enclosing schema element, which is urn:jwsnut.chapter2.bookservice/types/BookQuery. The attributes of the schema element also associate this namespace with the prefix tns (see Example 5-3) so that the fully qualified name of the BookInfo type can be used in the schema definition for an array of BookInfo objects:
<complexType name="ArrayOfBookInfo"> <complexContent> <restriction base="soap-enc:Array"> <attribute ref="soap-enc:arrayType" wsdl:arrayType="tns:BookInfo[]"/> </restriction> </complexContent> </complexType>
Without the explicit namespace qualifier, BookInfo would be incorrectly taken as a name in the XML schema namespace.
A type that represents an array of objects of type Foo is usually given the name ArrayOfFoo. This convention is suggested in the WSDL specification and is honored by wsdeploy. In the rather terse definition just shown, the restriction element together with its base attribute specify that an ArrayOfBookInfo type is an Array, as defined by the SOAP specification (and described in Chapter 3), in which the arrayType attribute has the value tns:BookInfo[]. In other words, the array may contain an unspecified number of BookInfo objects.
|
The second schema element in Example 5-3 is generated as a result of the use of a HashMap as the return value of the getBookMap( ) method in the BookQuery interface. The schema essentially defines a new type called hashMap, which extends a private type called map and consists of an array of key/value pairs in which both the key and the value are described by the XML schema type anyType. This type should be used wherever an object of any kind is valid � in other words, wherever you would use java.lang.Object in a Java method definition. Both hashMap and map appear in the private namespace http://java.sun.com/jax-rpc-ri/internal, which is not likely to be understood by non-JAX-RPC implementations; therefore, the use of HashMap (or any of the Java collection classes) may lead to interoperability issues with web service platforms that are not based on the JAX-RPC reference implementation.[4]
[4] As a side issue, it might have been better if the namespace http://java.sun.com/jax-rpc-ri/internal contained schema definitions for the Java collection classes so that this extra schema element did not need to be added to the WSDL file by wsdeploy. This would not, of course, remove the interoperability problem, but it would simplify the WSDL document a little.
The complexType element is used to define a type that can contain other objects, such as the BookInfo object or the ArrayOfBookInfo array. A simpleType element, by contrast, declares a type that does not contain any other objects, such as integers and strings. It is not necessary to define new types in cases where the object can be represented directly using an XML schema primitive type. However, the simpleType element can be used to qualify the use of another simple type by applying restrictions to it. For example, consider the following:
<simpleType name="BookType"> <restriction base="string"> <enumeration value="paperback"/> <enumeration value="hardback"/> </restriction> </simpleType>
This schema extract defines a simple type called BookType that must have a string value that is either "paperback" or "hardback". Note, however, that while this constraint is useful as documentation for a human reader, it is not guaranteed that automatically generated code will check that BookType values received in messages actually satisfy the constraint.
For further information on the XML scheme complexType and simpleType elements, see XML Schema, by Eric van der Vlist.
The complexType and simpleType elements define data types, not actual data elements. The distinction between these two is analogous to the difference between a class and an instance of that class. Put another way, given the definitions shown in the schema in Example 5-3, you would not expect to find a BookInfo element in a message sent by the book web service, but you could define an element with the characteristics of the BookInfo type by using an XML schema element called (appropriately enough) element, referring to the BookInfo type:
<element name="BookInfoElement" type= "BookInfo"/>
With this definition in place, an item of book information could be encoded like this:
<BookInfoElement> <editor>Robert Eckstein</editor> <author>Kim Topley</author> <price>29.95</price> <title>J2ME in a Nutshell</title> </BookInfoElement>
An element can also simply be a redefinition of a simple type, as in:
<element name="author" type="xsd:string"/>
or it can have an associated but anonymous type declaration:
<element name="BookTypeElement"> <simpleType> <restriction base="string"> <enumeration value="paperback"/> <enumeration value="hardback"/> </restriction> </simpleType> </element>
Having defined the types that a web service will use, the next step is to describe the messages that the service expects to receive or send to its clients. Each message is represented by a message element, which may contain any number of part elements. Example 5-4 shows some of the message elements generated for the book web service.
<message name="BookQuery_getAuthor"> <part name="String_1" type="xsd:string"/> </message> <message name="BookQuery_getAuthorResponse"> <part name="result" type="xsd:string"/> </message> <message name="BookQuery_getBookInfo"/> <message name="BookQuery_getBookInfoResponse"> <part name="result" type="ns2:ArrayOfBookInfo"/> </message> <message name="BookQuery_getBookMap"/> <message name="BookQuery_getBookMapResponse"> <part name="result" type="ns3:hashMap"/> </message> <message name="BookServiceException"> <part name="BookServiceException" type="xsd:string"/> </message>
You'll notice that the message elements are paired � for example, BookQuery_getAuthor is matched with BookQuery_getAuthorResponse. Based on their name attributes, you would probably guess that these messages represent the set of arguments passed to a JAX-RPC method call and the values to be returned from that call, respectively. This is correct, although the only way to be sure that this is actually the case is to check the operation elements that actually associate the messages with the service's method calls.
The value of a message element's name attribute must be unique within the WSDL document. Apart from this constraint, there is no requirement to follow any specific pattern when choosing a name, although tools that generate WSDL from programming language code are likely to use a convention similar to the one defined by JAX-RPC and illustrated in Example 5-4:
The name of the message that supplies the arguments for a JAX-RPC method call is formed from the name of the service endpoint interface (such as BookQuery) and the method name (such as getBookInfo).
The name of the message that represents the return values from a method call is the name of the corresponding request message with the word Response appended.
The name of a message that represents the content of an exception thrown in response to a method call is the same as the name of the exception itself.
In the case of an overloaded method name, a number is appended in order to create a unique value for the name attribute so that, for example, if the getBookInfo( ) method had a second variant that required an argument, then the request message for this method is assigned the name BookQuery_getBookInfo2 and the response message is called BookQuery_getBookInfo2Response. Again, this is a convention used by the JAX-RPC reference implementation that may not be followed by other tools that generate WSDL.
The value of the name attribute is used to refer to the element from the operation element or elements that use it, as described next.
The part elements represent an item of data that is part of the message. Since a message element provides only an abstract description of the data that it is associated with, the order of part elements does not in any way determine how that data is represented within the message at runtime. That information is provided using binding elements, as described later in this chapter. That said, however, in practice it is quite common for there to be a direct relationship between part elements and the fields in the XML message that will be constructed when a method call is made or a response is to be returned.
JAX-RPC uses a single part element for each method call parameter or return value. The BookQuery_getAuthor message, for example, supplies a string value that is actually the title of the book for which the author name is required. Methods that do not require any arguments, such as BookQuery_getBookInfo, are represented as message elements with no parts. The name attribute of a part element must be unique within its surrounding message but is otherwise arbitrary.[5] By convention, the part that corresponds to the return value of a JAX-RPC method call uses the name result.
[5] For an RPC-style web service in which a part element represents a method argument, it is natural to use the name of the argument to name the element itself. Tools that create WSDL documents from programming language definitions may not always be able to follow this convention, however. In particular, since argument names are not preserved in Java class files, wsdeploy uses the Java type of the argument (followed by a numeric value to make it unique) rather than its name when creating the corresponding part object, as illustrated by the part name String_1 in Example 5-4.
For web services that are not RPC-based (i.e., document-based web services, such as the book image service created in Chapter 3 using the SAAJ APIs), message elements are used in the same way as they are for an RPC service to represent the logical content of the messages exchanged by the client and server. For document-based services, however, there are no naming conventions to be concerned with, since there is no mapping to the elements of a programming language. SAAJ, being a low-level API, is not WSDL-aware; therefore, there are no tools to create WSDL from the SAAJ code used to construct a SOAP message and vice versa. However, as will be shown in Chapter 6, you can use JAX-RPC instead of SAAJ to build a document-based web service from an existing WSDL description.
The data type associated with a part is declared using either a type or an element attribute, only one of which may be specified. When the type attribute is used, several examples of which are shown in Example 5-4, its value is the namespace-qualified name of the type that describes the item. This could be a standard type defined by a schema language (such as xsd:anyType, xsd:string, or xsd:int), a user-defined type to be found in the types section of the WSDL document (such as ns2:ArrayOfBookInfo), or could be imported into it from an external source, as described in Section 5.2.9, later in this chapter. If the element attribute is used instead, then it must refer to an element element in the types section (see Section 5.2.2.2 earlier in this chapter for details) or in an imported schema document.
The operations that a web service provides are represented, not surprisingly, by operation elements. These operations are grouped together as child elements of a portType element. You can think of a portType as corresponding to the service endpoint interface, and therefore to the Java interface when the service is implemented in Java. An operation is equivalent to a Java method within that interface.
The portType and operation elements generated for the BookQuery endpoint interface in the book web service are shown in Example 5-5.
<portType name="BookQuery"> <operation name="getAuthor" parameterOrder="String_1"> <input message="tns:BookQuery_getAuthor"/> <output message="tns:BookQuery_getAuthorResponse"/> </operation> <operation name="getBookCount" parameterOrder=""> <input message="tns:BookQuery_getBookCount"/> <output message="tns:BookQuery_getBookCountResponse"/> </operation> <operation name="getBookInfo" parameterOrder=""> <input message="tns:BookQuery_getBookInfo"/> <output message="tns:BookQuery_getBookInfoResponse"/> </operation> <operation name="getEditor" parameterOrder="String_1"> <input message="tns:BookQuery_getEditor"/> <output message="tns:BookQuery_getEditorResponse"/> </operation> <operation name="getPrice" parameterOrder="String_1"> <input message="tns:BookQuery_getPrice"/> <output message="tns:BookQuery_getPriceResponse"/> <fault name="BookServiceException" message="tns:BookServiceException"/> </operation> <operation name="getBookMap" parameterOrder=""> <input message="tns:BookQuery_getBookMap"/> <output message="tns:BookQuery_getBookMapResponse"/> </operation> </portType>
The portType element must supply a name attribute whose value is unique over all of the portTypes in the WSDL document. The wsdeploy command in the JAX-RPC reference implementation uses the Java interface name for the value of this attribute when creating a WSDL file. In Example 5-5, therefore, the portType element is assigned the name BookQuery.
Each operation element within a portType has a required name attribute, the value of which is required to be unique within its enclosing portType. Since an operation element maps to a Java method in an RPC-style web service, it would be natural to use the name of the method as the value of the name attribute. In the case of an overloaded method name, as with the message element, wsdeploy generates a unique name by appending a numeric value for the operation elements generated for the second and subsequent methods. When manually creating a WSDL file for such a case, any approach can be used to ensure a unique name.
A web service operation, whether it is RPC- or document-based, requires some or all of the following:
A message containing input values
A message containing output values
A message containing error information, in the event that the operation did not complete properly
The messages associated with a given operation are listed as nested elements of type input, output, and fault, respectively. Each of these elements refers to a message element defined elsewhere in the WSDL document. Each operation element may have zero or one input element, zero or one output elements, and any number of fault elements (including none). Which of these elements is present, and the order in which they occur, depends on the type of the operation, as shown in Table 5-2.
Type |
Elements and ordering |
Description |
---|---|---|
input |
The client sends a message to the server, to which there is no reply. This maps the asynchronous mode supported by JAXM. One-way calls can also be made by JAX-RPC clients using the dynamic invocation mechanism that will be covered in Chapter 6. |
|
input output Zero or more fault elements, as required |
The operation consists of a message sent from the client to the server, followed by either a response message from the server or a message that reports one of several possible error conditions. If SOAP is used as the underlying messaging system, the fault elements used to link to the definitions of the message sent as a result of error condition are normally mapped to SOAP fault elements. Request-response operations are directly supported by both JAX-RPC and SAAJ. |
|
output input Zero or more fault elements, as required |
The same as request-response, except that the first message is sent by the server to the client, thus reversing their roles. These operations are not supported by either JAX-RPC or SAAJ. |
|
output |
A notification is a message sent from the server to the client, to which there is no reply. Such an operation might be used to report an event within the server that the client might need to be aware of. This is not supported by either JAX-RPC or SAAJ. These operations can be supported by using the asynchronous facilities provided by JAXM, as described in Chapter 4. |
Note that although you can construct an operation element that describes a solicit-response or a notification operation, the concrete bindings described in the WSDL 1.1 specification do not provide a way to map these operations onto existing network protocols. Therefore, in practice, only one-way and request-response operations can be used.
In Example 5-5, the getAuthor operation corresponds to the getAuthor( ) method in the BookQuery interface, which is defined as follows:
public String getAuthor(String name) throws RemoteException;
This is obviously a request-response operation, and the operation element reflects this through the presence and ordering of both input and output elements:
<operation name="getAuthor" parameterOrder="String_1"> <input message="tns:BookQuery_getAuthor"/> <output message="tns:BookQuery_getAuthorResponse"/> </operation>
Although the getAuthor( ) method can throw a RemoteException, no fault element is required, since this exception is generated by the underlying communication layers rather than as a result of an error message to be returned by the server.
The input and output elements refer to message definitions using the message attribute, the value of which is the name assigned to the message using its own name attribute, qualified by its namespace. The input and output messages for this operation are defined as follows:
<message name="BookQuery_getAuthor"> <part name="String_1" type="xsd:string"/> </message> <message name="BookQuery_getAuthorResponse"> <part name="result" type="xsd:string"/> </message>
These definitions state that the message sent to the server consists of a single string, which will represent the method argument. The reply message also contains a string. It so happens that the string in the reply message will become the return value of the method call, but you cannot tell this from the message definitions (although the use of the name result for the message element is a useful hint). To see how the method arguments and return values are mapped to the values in the input and output messages, you need to refer back to the operation element itself:
<operation name="getAuthor" parameterOrder="String_1">
RPC method arguments are of three types:
These arguments are sent in the input message but do not change as a result of the method invocation. This is a direct mapping of the pass-by-value semantics of arguments in Java method calls.
These arguments appear in the method signature, but their value is not sent with the input message. However, a new value for the argument may appear in the response message and, if so, the argument is modified from the returned value. Java method calls do not directly support out arguments; instead, JAX-RPC uses holder classes to allow the argument value to be modified, as described in Chapter 2.
The value of an in/out argument is sent in the input message and is modified from the reply message. An in/out argument is therefore both an in and out argument, and is supported by JAX-RPC using holder classes.
Parts that appear in the parameterOrder attribute of the operation element represent method arguments and must reflect the order in which the arguments appear in the original method signature. This attribute and the input and output messages are then used as follows:
Parts that appear in the input message but not in the output message represent in arguments.
Parts that appear in the output message but not in the input message represent out arguments.
Parts that appear in both the input and output messages are assumed to represent in/out arguments.
If the output message contains a single part that does not appear in the parameterOrder attribute, then it represents the return value of the method call. If there is no such part, then the method does not return a value (and its Java return type will be void).
In the case of the getAuthor operation, only String_1 appears in the parameterOrder attribute. Since this part is listed in the input message, it must be an in argument. The output message contains a single part that is not listed in the parameterOrder attribute. This part must therefore be the return value.
The WSDL specification allows the parameterOrder attribute to be omitted. In this case, the rules just described are still used to identify which message parts represent input and output parameters. However, there is possible doubt over the way in which parts listed in the output message but not in the input message are to be treated � do they represent out arguments, or is one of them to be considered the result of the method call? When generating Java code from WSDL, it doesn't really matter, except as a matter of style, which interpretation is chosen, since the calling code will be written with knowledge of the signature of the generated method. JAX-RPC therefore resolves the issue as follows:
If there is a single part in the output message that is not also in the input message, it is mapped to the return value of the method.
If there is more than one part in the output message that is not in the input message, they are all mapped as out arguments and the return type of the method is void.
Naturally, if all of the parts appear in both the input and output messages, then they all represent in/out arguments and the return type of the method is void.
A method that does not have any arguments is described using an input message that has no parts. An example of this is the getBookCount( ) method, which is mapped to the getBookCount operation:
<operation name="getBookCount" parameterOrder=""> <input message="tns:BookQuery_getBookCount"/> <output message="tns:BookQuery_getBookCountResponse"/> </operation>
The BookQuery_getBookCount message contains no parts:
<message name="BookQuery_getBookCount"/>
A Java method that may throw an exception as a result of an error detected by the service implementation is mapped to an operation element containing one fault element for each possible exception. The getPrice( ) method, defined as follows, is an example of this:
public abstract double getPrice(String name) throws BookServiceException, RemoteException;
The operation element for this method looks like this:
<operation name="getPrice" parameterOrder="String_1"> <input message="tns:BookQuery_getPrice"/> <output message="tns:BookQuery_getPriceResponse"/> <fault name="BookServiceException" message="tns:BookServiceException"/> </operation>
Note that only the service-defined exception is listed as a fault element. The message that describes the fault contains the information to be made available through accessor methods of the Java exception class. In this case, the exception provides only a string that describes the error that was detected. The BookServiceException method therefore consists of a part that contains a simple XML schema type:
<message name="BookServiceException"> <part name="BookServiceException" type="xsd:string"/> </message>
In the case of an exception with more than one associated data element, wsdeploy creates a complexType in the types section that has a field for each data element for which the exception has a public accessor method, and it uses the type attribute of the part element to refer to it. For example, suppose we define BookServiceException so that it supplies an extra Boolean value that indicates a transient error, in order for the client to retry the failed operation later. To map this, wsdeploy generates the following complexType in the types section:
<complexType name="BookServiceException"> <sequence> <element name="message" type="string"/> <element name="retry" type="boolean"/> </sequence> </complexType>
The message element now looks like this:
<message name="BookServiceException"> <part name="BookServiceException" type="ns2:BookServiceException"/> </message>
The fault element is, of course, unaffected by this change.
The input, output, and fault elements must all have a name, unique within the enclosing portType element, that can be used to link them to their associated bindings (described in the next section). The name is declared using the name attribute, as the fault element in the definition of the getPrice operation shows:
<operation name="getPrice" parameterOrder="String_1">
<input message="tns:BookQuery_getPrice"/>
<output message="tns:BookQuery_getPriceResponse"/>
<fault name="BookServiceException" message="tns:BookServiceException"/>
</operation>
Notice that in this example, the input and output elements do not provide a value for this attribute. This is possible because the WSDL specification allows the name attribute to be defaulted, with the default value being inferred according to the following rules:
For a one-way or notification message, the name attribute has the same value as the name attribute of the operation itself.
For a request-response operation, the name attribute of the input element is defaulted to XXXRequest, and the name attribute of the output element is defaulted to XXXResponse, where XXX is the value of the name attribute of the operation.
For a solicit-response operation, the name attribute of the ouput element is defaulted to XXXSolicit, and the name attribute of the input element is defaulted to XXXResponse, where XXX is the value of the name attribute of the operation.
Given these rules, the definition of the getPrice operation just shown is equivalent to the following:
<operation name="getPrice" parameterOrder="String_1"> <input name="getPriceRequest" message="tns:BookQuery_getPrice"/> <output name="getPriceResponse" message="tns:BookQuery_getPriceResponse"/> <fault name="BookServiceException" message="tns:BookServiceException"/> </operation>
The name attribute for a fault element cannot be defaulted.
The elements that you have seen so far create an abstract definition of a web service that tells you the operations that it provides, and what information each of them requires as input and returns as output. At this point, though, you don't know which protocols can be used to access the service or how the inputs and outputs are mapped to real protocol messages. The binding elements provide this information.
Each binding element describes the protocol binding for a single portType to a single protocol. To map a web service to more than one protocol, create a separate set of bindings for each protocol. The overall structure of a binding element is shown in Example 5-6.
<binding name="bindingName" type= "portTypeName"> <!-- Binding-specific information for the portType goes here --> <operation name="operationName"> <!-- One of these per operation --> <!-- Binding-specific information for this operation goes here --> <input name="messageName"> <!-- 0 or 1 of these --> <!-- Binding-specific information for this message goes here --> </input> <output name="messageName"> <!-- 0 or 1 of these --> <!-- Binding-specific information for this message goes here --> </output> <fault name="messageName"> <!-- 0 or 1 for each fault --> <!-- Binding-specific information for this message goes here --> </fault> </operation> </binding>
A binding element contains an operation element for each operation in its associated
portType
, and each input, output, and fault element in the portType operation also has a corresponding input, output, or fault element here. The core WSDL specification defines only the binding, operation, input, output, and fault elements � the additional elements necessary to provide the actual binding information are defined by individual per-protocol bindings. These elements are inserted at the points indicated by the comments in Example 5-6. Since SOAP is the most commonly used binding for web services, the WSDL specification describes a set of elements that can be used to specify a SOAP binding, but recognizes that it may need to be extended to meet future requirements. The specification also defines elements that can be used to bind a web service onto HTTP, but in this chapter, we deal only with bindings in which the underlying protocol is SOAP 1.1.
The purpose of the SOAP binding is to define the following:
The transport protocol used to carry the SOAP messages.
The value of the SOAPAction header needed to access the service.
Whether each operation is RPC-style or document-style.
For each part of the input, output, and fault messages associated with the operation, whether the corresponding elements appear within the SOAP header or the body and how they are encoded. If there are any parts that appear in an attachment, then the MIME binding described later in this chapter is used in conjunction with the SOAP binding to describe the structure of the message.
A typical example of a SOAP binding is shown in Example 5-7, which contains part of the binding element generated for the BookQuery interface of the book web service. For the sake of clarity, only two of the operations are included here. The bindings for the other operations follow the same pattern as those shown and do not use any additional constructs. The elements that relate to the SOAP binding, which are highlighted, all have the prefix soap. This prefix is mapped to the namespace URI for the SOAP binding � http://schemas.xmlsoap.org/wsdl/soap.[6]
[6] A full description of the SOAP binding, together with the HTTP and MIME bindings, can be found in the WSDL 1.1 specification.
<binding name="BookQueryBinding" type="tns:BookQuery"> <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="rpc"/> <operation name="getAuthor"> <soap:operation soapAction=""/> <input> <soap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" use="encoded" namespace="urn:jwsnut.chapter2.bookservice/wsdl/ BookQuery"/> </input> <output> <soap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" use="encoded" namespace="urn:jwsnut.chapter2.bookservice/wsdl/ BookQuery"/> </output> </operation> <operation name="getPrice"> <soap:operation soapAction=""/> <input> <soap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" use="encoded" namespace="urn:jwsnut.chapter2.bookservice/wsdl/ BookQuery"/> </input> <output> <soap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" use="encoded" namespace="urn:jwsnut.chapter2.bookservice/wsdl/ BookQuery"/> </output> <fault name="BookServiceException"> <soap:fault encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" use="encoded" namespace="urn:jwsnut.chapter2.bookservice/wsdl/ BookQuery"/> </fault> </operation> </binding>
The WSDL binding element specifies that this is a binding for the BookQuery portType and assigns it the name BookQueryBinding. This name is used later in a port element to associate a protocol address with this binding (see Section 5.2.8). Within the binding, each operation from the portType has a corresponding operation element, linked to the operation using the name element. Here, the bindings for the getAuthor and getPrice operations (which are shown in Example 5-5) are defined.
Each abstract operation in a WSDL document is defined in terms of its input, output, and error messages. In the binding for the same operation, the concrete representation of each of these messages is specified. The linkage between the input and output elements in the binding and the corresponding elements in the portType operation element is implicit, since there cannot be more than one instance of each of these elements for any given operation. For example, the input element for the getAuthor operation describes the SOAP binding of the BookQuery_getAuthor message, since this is the message associated with the input element of the getAuthor operation in Example 5-5. By contrast, there may be more than one fault element for a given operation; therefore, the name attribute should be used to link the binding for each fault to its definition in the portType operation element, as shown in the binding for the getPrice operation in Example 5-7.
Each binding element has a corresponding soap:binding element that provides information that is applicable to all of the operations for the portType to which it relates. The soap:binding element for the BookQuery portType looks like this:
<soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="rpc"/>
The presence of this element makes it clear that the binding that it is part of uses SOAP messaging. It has two attributes:
Although HTTP is currently the protocol most commonly used to carry SOAP messages, other protocols such as SMTP or even FTP could also be used. Different conventions might be used to wrap a SOAP message in each protocol � for example, SOAP messages carried by HTTP make use of HTTP headers and, if there are attachments, MIME headers for each attachment are also added. The transport attribute indirectly specifies the conventions to be applied by supplying a URI that identifies the underlying transport protocol. Implementations that use a binding for a particular protocol are assumed to know how SOAP messages are wrapped for that protocol. For HTTP, this URI is http://schemas.xmlsoap.org/soap/http.
This attribute is a default that specifies whether the operations in this binding are RPC-style or document-style. It takes the value rpc or document, as appropriate. Each operation can override this default if necessary. If this attribute is omitted, then the style of each operation is taken to be document unless otherwise stated in the soap:operation element.
The attributes of the soap:binding element just shown tell us that it relates to a mapping of SOAP messages to the HTTP protocol and that its operations are RPC-style by default. Most web services created using JAX-RPC will use this style, whereas those built with SAAJ (or JAXM) are more likely to use document-style interactions. However, as you'll see in Chapter 6, it is also possible to use JAX-RPC to create a web service that uses document-style operations.
Each operation element within a binding normally contains a soap:operation element that specifies SOAP-related information relating to that operation. This element has two attributes.
The value of this attribute is a URI that becomes the value of the SOAPAction header for the operation. SOAP over HTTP requires that this header be present, even if the service implementation does not use it (as is the case with JAX-RPC). If the service does not make use of SOAPAction, then the value should be supplied as an empty string, as shown for both operations in Example 5-7. For other protocols, this attribute should not be supplied at all.
The style attribute allows each operation to override the default style specified by the soap:binding element. If neither the soap:operation element nor the soap:binding element provides a value for this attribute, then the operation has document style.
The remaining SOAP binding elements specify how the parts in the messages referred to from the input, output, and fault elements of the portType operation element are used to construct a SOAP message. The soap:body and soap:header elements are used to assign parts to the message body and header, respectively, whereas soap:fault and soap:headerfault create fault information either in the body or the header. The general form of soap:body looks like this:
<soap:body parts= "partslist" use= "literal | encoded" encodingStyle= "uriList" namespace="uri"/>
The parts attribute lists those parts from the list associated with the message element that will appear in the SOAP message body with these attributes. It is permissible to use more than one soap:body element if some parts need to be included with, for example, a different encoding. If the parts attribute is omitted (which is probably the most common case), then all parts of the message are included.
The required use attribute and the optional encodingStyle attribute specify how the types listed for the message parts are to be serialized into the message. If use has the value literal, then the associated data is serialized according to its schema in the types section of the WSDL document. The value encoded specifies that an encoding scheme or series of encoding schemes, whose URIs are given by the encodingStyle parameter, are used to serialize the data. Although these attributes partly determine the way in which the parts are represented within the SOAP message, the operation style also affects the final encoding. We'll see examples that demonstrate exactly how this works in Chapter 6.
The namespace attribute supplies the URI for the namespace to be applied to XML elements created from this part that do not have an explicit namespace assigned as a result of the encoding in use. It may be omitted if not required.
The input and output elements for the getAuthor operation in Example 5-7 contain a typical soap:body element:
<soap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" use="encoded" namespace="urn:jwsnut.chapter2.bookservice/wsdl/BookQuery"/>
This element specifies that all parts of the input message will appear in the body (all parts appear because the parts attribute is omitted). The namespace for any elements that do not have a namespace explicitly assigned in the serialization schema will be urn:jwsnut.chapter2.bookservice/wsdl/BookQuery. The data will be encoded using the standard SOAP section 5 encoding rules (described in Chapter 3).
The soap:fault element has the same attributes as soap:body and results in the content that it describes being added as a Detail element inside a SOAP Fault element in the message body. As an example of the use of this element, the getPrice operation has a fault element that is bound as follows:
<soap:fault encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" use="encoded" namespace="urn:jwsnut.chapter2.bookservice/wsdl/BookQuery"/>
The soap:header and soap:headerfault elements are identical to soap:body and
soap:fault
, respectively, apart from the fact that they have an extra attribute and their output appears in the SOAP message header instead of the body. The soap:header element looks like this:
<soap:header message="message" part="partslist" use= "literal | encoded" encodingStyle= "uriList" namespace="uri"/>
The soap:body and soap:fault elements refer implicitly to the message associated with the input, output, or fault element in their surrounding operation element. Both soap:header and soap:headerfault can use parts from a different message by explicitly referencing that message with the message attribute. This allows headers and message bodies to be described separately for convenience. If this attribute is not used, then the parts are obtained from the message that is normally associated with the element.
The SOAP binding on its own is sufficient for messages that do not require attachments. The MIME binding can be used when attachments are needed. The WSDL description for a message that contains one or more attachments consists of a set of mime:part elements wrapped in a mime:multipartRelated element, where the namespace prefix mime is mapped to the URI http://schemas.xmlsoap.org/wsdl/mime. For example, the parts for an output message for an operation that returns some image data might be declared like this:
<message name="imageResult"> <part name="body" type= "bodyType"/> <part name="imageData" type= "ArrayOfHexBinary"/> </message>
where bodyType and ArrayOfHexBinary are assumed to be defined in the types section. In the binding shown here, the body part is mapped to the SOAP body, while imageData appears as an attachment:
<output> <mime:multipartRelated> <mime:part> <soap:body parts="body"> </mime:part> <mime:part> <mime:content part="imageData" type="image/gif"/> <mime:content part="imageData" type="image/jpeg"/> <mime:content part="imageData" type="image/png"/> </mime:part> </mime:multipartRelated> </output
The mime:multipartRelated element signals that this binding represents a SOAP with attachments message, where the SOAP envelope and each attachment are represented by a nested soap:part element. The first such element contains a soap:body element and is therefore mapped to the body part of the SOAP envelope. It is also permissible to use soap:header, soap:fault, and soap:headerfault elements as required.
MIME content within an attachment is described using a mime:content element, where the type attribute specifies the MIME type of the data that may appear in the attachment. Where, as in this case, several such elements appear, any of the listed MIME types might be expected to appear in the attachment. Alternate types can also be specified using wildcards, such as:
<mime:content part="imageData" type="image/*"/>
which allows all types of images, and:
<mime:content part="imageData" type="*/*"/>
which permits arbitrary MIME-encoded data. In all cases where there are alternatives, the actual type of the data in an attachment must be determined at runtime by examining the MIME headers of the received message.
The MIME binding also provides a way to describe arbitrary XML within an attachment using the mime:mimeXml element:
<mime:mimeXml part="partName"/>
The schema for the XML itself can be inferred from the part based on either the type or the element within the types section (or an imported schema document) that it refers to.
A binding element describes how the operations within a portType are mapped to SOAP messages or messages in other protocols, but they don't tell you how to locate an instance of the portType. This is the job of the port element, which maps a binding of a portType to a URI that can be used to access it using the protocol associated with the binding. A service element groups together a set of related ports. A WSDL document may contain several service elements, which are distinguished from each other by their name attributes. There is no requirement for a service to contain elements for each port defined in the WSDL document or for all of the ports in a given service element to use the same binding. Example 5-8 shows the service and port elements for the book web service.
<service name="BookService"> <port name="BookQueryPort" binding="tns:BookQueryBinding"> <soap:address location="http://localhost:8000/Books/BookQuery"/> </port> </service>
A port is associated with a binding via its binding attribute. The actual address is specified using an element that is specific to the binding's protocol. Here, the soap:address element from the SOAP binding is used to provide the URL at which the service endpoint interface for the port can be accessed.
So far in this chapter, we have described a WSDL document as if it were a single file. In the real world, however, it would be more useful to be able to break down a WSDL definition into smaller pieces and place each of them in a separate file, so that a set of common definitions can be shared by several web services without having to replicate them in each WSDL document. This can be achieved by using either or both of the WSDL import and XML schema import elements. The following sections show how you might use these elements to distribute the definitions for the book web service over several files.
One obvious way to improve reusability of WSDL definitions is to extract those data type definitions that might be of general use and place them in a separate XML schema document, which could then be imported into any number of WSDL documents. As noted in Section 5.2.2 and shown in Example 5-3 earlier in this chapter, the generated WSDL file for the book service contains two sets of type definitions:
Definitions of types that are part of the book service itself, such as the BookInfo value type
Definitions that are introduced by JAX-RPC to describe data types that it provides internally, such as HashMap
These definitions belong to different namespaces and are contained in two separate schema elements within the type element of the generated WSDL file. Since an XML schema document can only contain a single schema element (and since the definitions, being in different namespaces, cannot be merged together), it is necessary to create two XML schema documents to extract them from the WSDL file, which we'll call bookTypes.xsd (the content of which is shown in Example 5-9) and baseTypes.xsd (shown in Example 5-10).
<?xml version="1.0" encoding="UTF-8"?> <schema targetNamespace="urn:jwsnut.chapter2.bookservice/types/BookQuery" xmlns:tns="urn:jwsnut.chapter2.bookservice/types/BookQuery" xmlns:soap-enc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns="http://www.w3.org/2001/XMLSchema"> <complexType name="ArrayOfBookInfo"> <complexContent> <restriction base="soap-enc:Array"> <attribute ref="soap-enc:arrayType" wsdl:arrayType="tns:BookInfo[]"/> </restriction> </complexContent> </complexType> <complexType name="BookInfo"> <sequence> <element name="editor" type="string"/> <element name="author" type="string"/> <element name="price" type="double"/> <element name="title" type="string"/> </sequence> </complexType> <complexType name="BookServiceException"> <sequence> <element name="message" type="string"/> </sequence> </complexType> </schema>
<?xml version="1.0" encoding="UTF-8"?> <schema targetNamespace="http://java.sun.com/jax-rpc-ri/internal" xmlns:tns="http://java.sun.com/jax-rpc-ri/internal" xmlns:soap-enc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns="http://www.w3.org/2001/XMLSchema"> <complexType name="hashMap"> <complexContent> <extension base="tns:map"> <sequence/> </extension> </complexContent> </complexType> <complexType name="map"> <complexContent> <restriction base="soap-enc:Array"> <attribute ref="soap-enc:arrayType" wsdl:arrayType="tns:mapEntry[]"/> </restriction> </complexContent> </complexType> <complexType name="mapEntry"> <sequence> <element name="key" type="anyType"/> <element name="value" type="anyType"/> </sequence> </complexType> </schema>
Notice that these are completely freestanding XML schema documents. Therefore, each has its own schema element that declares the target namespace for its definitions, together with any other namespaces that the enclosed elements and attributes reference. Notice also that the target namespaces are different � bookTypes.xsd defines its elements in the namespace assigned to types associated with the book service, while baseTypes.xsd uses a private namespace belonging to the JAX-RPC reference implementation. In the case of bookTypes.xsd, if the types that it declares are to be used in other web services, then it might be appropriate to assign them to another namespace whose name implies a wider scope than simply the book service itself.
Having separated out the type definitions, it is now necessary to import them into the WSDL document for the book service, using the WSDL import element. Example 5-11 shows how this is done.
<?xml version="1.0" encoding="UTF-8"?> <definitions name="BookService" targetNamespace="urn:jwsnut.chapter2.bookservice/wsdl/BookQuery" xmlns:tns="urn:jwsnut.chapter2.bookservice/wsdl/BookQuery" xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:ns2="urn:jwsnut.chapter2.bookservice/types/BookQuery" xmlns:ns3="http://java.sun.com/jax-rpc-ri/internal"> <import namespace="urn:jwsnut.chapter2.bookservice/types/BookQuery" location="bookTypes.xsd"/> <import namespace="http://java.sun.com/jax-rpc-ri/internal" location="baseTypes.xsd"/> <message name="BookQuery_getAuthor"> <part name="String_1" type="xsd:string"/> </message> <!-- Rest of the file unchanged --> </definitions>
The WSDL import element has two attributes, both of which must be present:
The namespace into which the definitions from the included file are to be imported. The value of this attribute must match the target namespace defined in the imported schema document.
A URI that indicates where the imported definitions will be found. This is usually an absolute URL. In the example shown here, a relative filename is used. While this works if the WSDL file is simply used as input to the wscompile command, it would not be acceptable if it were published in a registry. For this reason, the specification requires that published WSDL documents use absolute URIs.
Note that imported types are not wrapped within a types element like those declared within the WSDL file. It is, however, possible to mix the use of imported and inline declaration within the same WSDL document by using both the import and types elements:
<!-- Import common types --> <import namespace="urn:jwsnut.chapter2.bookservice/types/BookQuery" location="bookTypes.xsd"/> <import namespace="http://java.sun.com/jax-rpc-ri/internal" location="baseTypes.xsd"/> <types> <schema targetNamespace= ". . ."> <!-- Add local declarations here --> </schema> </types>
The import element can be used to include schema definitions from any schema, not simply those that you might create specifically to define the types for your own web services. XML schema also has its own import element that can be used to reference one schema from within another. Using this element, the bookTypes.xsd file could be changed to reference the definitions in baseTypes.xsd, as shown in Example 5-12.[7]
[7] While this illustrates how to nest schema imports, it is not particularly advantageous to actually do this for the book service, because the types defined in bookTypes.xsd do not depend on those in baseTypes.xsd.
<?xml version="1.0" encoding="UTF-8"?> <schema targetNamespace="urn:jwsnut.chapter2.bookservice/types/BookQuery" xmlns:tns="urn:jwsnut.chapter2.bookservice/types/BookQuery" xmlns:soap-enc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns="http://www.w3.org/2001/XMLSchema"> <import namespace="http://java.sun.com/jax-rpc-ri/internal" schemaLocation="baseTypes.xsd"/> <!-- Rest of the file left unchanged --> </schema>
Following this change, only a single WSDL import element is required in the WSDL file, as shown in Example 5-13.
<?xml version="1.0" encoding="UTF-8"?> <definitions name="BookService" targetNamespace="urn:jwsnut.chapter2.bookservice/wsdl/BookQuery" xmlns:tns="urn:jwsnut.chapter2.bookservice/wsdl/BookQuery" xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:ns2="urn:jwsnut.chapter2.bookservice/types/BookQuery" xmlns:ns3="http://java.sun.com/jax-rpc-ri/internal"> <import namespace="urn:jwsnut.chapter2.bookservice/types/BookQuery" location="bookTypes.xsd"/> <message name="BookQuery_getAuthor"> <part name="String_1" type="xsd:string"/> </message> <!-- Rest of the file left unchanged --> </definitions>
Notice that the XML schema import element shown in Example 5-12 imports definitions from a different namespace than the target namespace for its parent schema element. This is perfectly valid. However, the namespace attribute on the import element in the WSDL file still declares only the namespace of the schema that it directly refers to.
|
The WSDL import element can be used to include all types of definitions that may appear in a WSDL document � it is not limited to schema types. You can use this feature to separate out as much of a service definition as you like into smaller files, the primary motivation for this being reuse.
One particularly useful application of this feature is to separate the generic definition of a web service interface and its bindings from the service element that contains the addresses at which the service can be located. This allows you to use a single service definition to describe several different instances of the service that are hosted on different servers. You might, for example, decide that the demand for the book service is so great that you want to create mirror sites around the world, and allow users to make use of the mirror that gives them the fastest service by publishing the WSDL document in several registries, each with a different service element. Instead of copying and propagating the entire WSDL file, you would install only the part that contains the service element itself in the registry and import the rest of the definition by reference to its single location using an absolute URL (or other URI).
Achieving this separation for the book service is extremely simple. The first step is to remove the service elements from the BookService.wsdl file, leaving only generic definitions, as shown in Example 5-14.
<?xml version="1.0" encoding="UTF-8"?> <definitions name="BookService" targetNamespace="urn:jwsnut.chapter2.bookservice/wsdl/BookQuery" xmlns:tns="urn:jwsnut.chapter2.bookservice/wsdl/BookQuery" xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:ns2="urn:jwsnut.chapter2.bookservice/types/BookQuery" xmlns:ns3="http://java.sun.com/jax-rpc-ri/internal"> <import namespace="urn:jwsnut.chapter2.bookservice/types/BookQuery" location="bookTypes.xsd"/> <import namespace="http://java.sun.com/jax-rpc-ri/internal" location="baseTypes.xsd"/> <message name="BookQuery_getAuthor"> <part name="String_1" type="xsd:string"/> </message> <!-- OTHER FILE CONTENT NOT SHOWN --> <binding name="BookQueryBinding" type="tns:BookQuery"> <!-- Binding content not shown --> </binding> <!-- The <service> element that was here has been removed from this file --> </definitions>
Each instance of the service is realized by creating a WSDL document that imports the generic service definition and supplies the appropriate URI for its ports within the service element. Example 5-15 shows how this technique is used to declare an instance of the book service running at port 8000 of a host called targethost.
<?xml version="1.0" encoding="UTF-8"?> <definitions name="BookServiceInstance" targetNamespace="urn:jwsnut.chapter2.bookservice/wsdl/BookQuery" xmlns:tns="urn:jwsnut.chapter2.bookservice/wsdl/BookQuery" xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" > <!-- Import the common definitions for the generic service --> <import namespace="urn:jwsnut.chapter2.bookservice/wsdl/BookQuery" location="BookService.wsdl"/> <!-- Define the location of this instance of the service --> <service name="BookService"> <port name="BookQueryPort" binding="tns:BookQueryBinding"> <soap:address location="http://targethost:8000/Books/BookQuery"/> </port> </service> </definitions>
Note that since both files are WSDL documents, they both need to have definitions as their root element, and they both declare a target namespace. Although the namespaces match in this example, this is not a requirement.
It might be difficult to see why this technique is useful for a JAX-RPC service, since, so far, you have only seen how to create a JAX-RPC client using stubs supplied by wscompile based on Java interface definitions, and then connected it to the server by supplying the URL yourself. In the next chapter, however, you'll see how to use a WSDL document as the basis for your client and how to build a dynamic method call that makes use of the port address in a WSDL file.