2.3. Amazon's E-Commerce Web Service
The section title has the popular and formerly official
name for one of the web services that Amazon hosts. The official name is now
Amazon Associates Web Service. The service in question is accessible as SOAP-based or
REST-style. The service
is free of charge, but it does require registration at http://affiliate-program.amazon.com/gp/associates/join. For the examples in this section, an Amazon access key (as opposed to the secret access key used
to generate an authentication token) is required.
Amazon's E-Commerce service replicates the interactive
experience at the Amazon website. For example, the
service supports searching for items, bidding on items and putting items up for
bid, creating a shopping cart and filling it with items, and so on. The two
sample clients illustrate item search.
This section examines two Java clients
against the Amazon E-Commerce service. Each client is generated with Java
support code from the wsimport utility introduced earlier. The difference between the
two clients refines the distinction between the wrapped and unwrapped
conventions.
2.3.1. An E-Commerce Client in
Wrapped Style
The Java support code for
the client can be generated with the command:
% wsimport -keep -p awsClient \
http://ecs.amazonaws.com/AWSECommerceService/AWSECommerceService.wsdl
Recall that the -p awsClient
part of the command
generates a package (and, therefore, a subdirectory) named awsClient.
The source code for the first Amazon
client, AmazonClientW, resides in the working
directory; that is, the parent directory of awsClient. Example 2-10 is the application code, which searches for
books about quantum gravity.
Example 2-10. An E-Commerce Java
client in wrapped style
import awsClient.AWSECommerceService; import awsClient.AWSECommerceServicePortType; import awsClient.ItemSearchRequest; import awsClient.ItemSearch; import awsClient.Items; import awsClient.Item; import awsClient.OperationRequest; import awsClient.SearchResultsMap; import javax.xml.ws.Holder; import java.util.List; import java.util.ArrayList;
class AmazonClientW { // W is for Wrapped style public static void main(String[ ] args) { if (args.length < 1) { System.err.println("Usage: java AmazonClientW <access key>"); return; } final String access_key = args[0];
// Construct a service object to get the port object. AWSECommerceService service = new AWSECommerceService(); AWSECommerceServicePortType port = service.getAWSECommerceServicePort();
// Construct an empty request object and then add details. ItemSearchRequest request = new ItemSearchRequest(); request.setSearchIndex("Books"); request.setKeywords("quantum gravity");
ItemSearch search = new ItemSearch(); search.getRequest().add(request); search.setAWSAccessKeyId(access_key);
Holder<OperationRequest> operation_request = null; Holder<List<Items>> items = new Holder<List<Items>>();
port.itemSearch(search.getMarketplaceDomain(), search.getAWSAccessKeyId(), search.getSubscriptionId(), search.getAssociateTag(), search.getXMLEscaping(), search.getValidate(), search.getShared(), search.getRequest(), operation_request, items);
// Unpack the response to print the book titles. Items retval = items.value.get(0); // first and only Items element List<Item> item_list = retval.getItem(); // list of Item subelements for (Item item : item_list) // each Item in the list System.out.println(item.getItemAttributes().getTitle()); } }
|
The code is compiled and executed in
the usual way but requires your access key (a string such as
1A67QRNF7AGRQ1XXMJ07) as a command-line argument. On a sample run, the output
for an item search among books on the string quantum gravity was:
The Trouble With Physics
The Final Theory: Rethinking Our Scientific Legacy
Three Roads to Quantum Gravity
Keeping It Real (Quantum Gravity, Book 1)
Selling Out (Quantum Gravity, Book 2)
Mr Tompkins in Paperback
Head First Physics
Introduction to Quantum Effects in Gravity
The Large, the Small and the Human Mind
Feynman Lectures on Gravitation
The AmazonClientW client
is not intuitive. Indeed, the code uses relatively obscure types such as
Holder. The itemSearch method, which does
the actual search, takes 10 arguments, the last of which, named items in this example, holds the service response. This
response needs to be unpacked in order to get a list of the book titles returned
from the search. The next client is far simpler. Before looking at the simpler
client, however, it will be instructive to consider what makes the first client
so tricky.
In the binding section of the WSDL for the E-Commerce service, the
style is set to the default,
document, and the encoding is likewise set to
the default, literal. Further, the
wrapped convention is in play, as this segment from the XSD illustrates:
<xs:element name="ItemSearch">
<xs:complexType>
<xs:sequence>
<xs:element name="MarketplaceDomain"
type="xs:string" minOccurs="0"/>
<xs:element name="AWSAccessKeyId"
type="xs:string" minOccurs="0"/>
<xs:element name="SubscriptionId"
type="xs:string" minOccurs="0"/>
<xs:element name="AssociateTag"
type="xs:string" minOccurs="0"/>
<xs:element name="XMLEscaping"
type="xs:string" minOccurs="0"/>
<xs:element name="Validate"
type="xs:string" minOccurs="0"/>
<xs:element name="Shared"
type="tns:ItemSearchRequest" minOccurs="0"/>
<xs:element name="Request"
type="tns:ItemSearchRequest" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:element>
This XSD segment defines the ItemSearch element, which is the wrapper type in the body of a
SOAP request. Here is a segment from the XSD's message section, which shows that the request message is the type
defined above:
<message name="ItemSearchRequestMsg">
<part name="body" element="tns:ItemSearch"/>
</message>
For the service response to an
ItemSearch, the wrapper type defined in the XSD is:
<xs:element name="ItemSearchResponse">
<xs:complexType>
<xs:sequence>
<xs:element ref="tns:OperationRequest" minOccurs="0"/>
<xs:element ref="tns:Items" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:element>
The impact of these WSDL
definitions is evident in the SOAP request message from a client and the SOAP
response message from the server. Example 2-11
shows a SOAP request from a sample run.
Example 2-11. A SOAP request against
Amazon's E-Commerce service
<?xml version="1.0" ?> <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:ns1="http://webservices.amazon.com/AWSECommerceService/2008-03-03"> <soapenv:Body> <ns1:ItemSearch> <ns1:AWSAccessKeyId>...</ns1:AWSAccessKeyId> <ns1:Request> <ns1:Keywords>quantum gravity</ns1:Keywords> <ns1:SearchIndex>Books</ns1:SearchIndex> </ns1:Request> </ns1:ItemSearch> </soapenv:Body> </soapenv:Envelope>
|
The ItemSearch wrapper is the single XML
element in the SOAP body and this element has two subelements, one with the name
ns1:AWSAccessKeyId and the other with the name
ns1:Request, whose subelements specify the
search string (in this case, quantum gravity) and the search category (in this
case, Books).
Here is part of the SOAP response for the
request above:
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<SOAP-ENV:Body>
<ItemSearchResponse
xmlns="http://webservices.amazon.com/AWSECommerceService/2008-03-03">
<OperationRequest>
<HTTPHeaders>
<Header Name="UserAgent" Value="Java/1.6.0"></Header>
</HTTPHeaders>
<RequestId>0040N1YEKV0CRCT2B5PR</RequestId>
<Arguments>
<Argument Name="Service" Value="AWSECommerceService"></Argument>
</Arguments>
<RequestProcessingTime>0.0566580295562744</RequestProcessingTime>
</OperationRequest>
<Items>
<Request>
<IsValid>True</IsValid>
<ItemSearchRequest>
<Keywords>quantum gravity</Keywords>
<SearchIndex>Books</SearchIndex>
</ItemSearchRequest>
</Request>
<TotalResults>207</TotalResults>
<TotalPages>21</TotalPages>
<Item>
<ASIN>061891868X</ASIN>
<DetailPageURL>http://www.amazon.com/gp/redirect.html...
</DetailPageURL>
<ItemAttributes>
<Author>Lee Smolin</Author>
<Manufacturer>Mariner Books</Manufacturer>
<ProductGroup>Book</ProductGroup>
<Title>The Trouble With Physics</Title>
</ItemAttributes>
</Item>
...
</Items>
</ItemSearchResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
The SOAP body now consists of a single element named
ItemSearchResponse, which is defined as
a type in the service's WSDL. This element contains various subelements, the
most interesting of which is named Items. The Items subelement
contains multiple Item subelements, one apiece
for a book on quantum gravity. Only one Item is shown, but this is enough to see the
structure of the response document. The code near the end of the
AmazonClientW reflects the structure of the SOAP response: first the
Items element is extracted, then a list of Item subelements,
each of which contains a book's title as an XML attribute.
Now we can look at a wsimport-generated artifact for the E-Commerce service,
in particular at the annotations on the itemSearch method with its 10
arguments. The method is declared in the AWSECommerceServicePortType
interface, which declares a single @WebMethod for each of the
E-Commerce service's operations. Example 2-12 shows the declaration
of interest.
Example 2-12. Java code generated
from Amazon's E-Commerce WSDL
@WebMethod(operationName = "ItemSearch", action = "http://soap.amazon.com") @RequestWrapper(localName = "ItemSearch", targetNamespace = "http://webservices.amazon.com/AWSECommerceService/2008-03-03", className = "awsClient.ItemSearch") @ResponseWrapper(localName = "ItemSearchResponse", targetNamespace = "http://webservices.amazon.com/AWSECommerceService/2008-03-03", className = "awsClient.ItemSearchResponse") public void itemSearch( @WebParam(name = "MarketplaceDomain", targetNamespace = "http://webservices.amazon.com/AWSECommerceService/2008-03-03") String marketplaceDomain, @WebParam(name = "AWSAccessKeyId", targetNamespace = "http://webservices.amazon.com/AWSECommerceService/2008-03-03") String awsAccessKeyId, ... ItemSearchRequest shared, @WebParam(name = "Request", targetNamespace = "http://webservices.amazon.com/AWSECommerceService/2008-03-03") List<ItemSearchRequest> request, @WebParam(name = "OperationRequest", targetNamespace = "http://webservices.amazon.com/AWSECommerceService/2008-03-03", mode = WebParam.Mode.OUT) Holder<OperationRequest> operationRequest, @WebParam(name = "Items", targetNamespace = "http://webservices.amazon.com/AWSECommerceService/2008-03-03", mode = WebParam.Mode.OUT) Holder<List<Items>> items);
|
The last two parameters, named operationRequest and
items, are described as WebParam.Mode.OUT to signal that they
represent return values from the E-Commerce service to the requester. An
OUT parameter is returned in a
Java Holder object. The method itemSearch thus reflects the XSD request and response types from
the WSDL. The XSD type ItemSearch, which
is the request wrapper, has eight subelements such as
MarketplaceDomain, AWSAccessKeyId, and
ItemSearchRequest. Each of these subelements occurs as a
parameter in the itemSearch method. The XSD type
ItemSearchResponse has two subelements, named OperationRequest
and Items, which are the last two parameters (the OUT
parameters) in the itemSearch method. The tricky part for the
programmer, of course, is that itemSearch
becomes hard to invoke precisely because of the 10 arguments, especially because
the last 2 arguments hold the return values.
Why does the wrapped style result in such
a complicated client? Recall that the wrapped style is meant to give a
document-style service the look and feel of an
rpc-style service without giving up the advantages of document
style. The wrapped document style requires a wrapper XML
element, typically with the name of a web service
operation such as ItemSearch, that has a typed
XML subelement per operation parameter. In the
case of the itemSearch operation in the
E-Commerce service, there are eight in or
request parameters and two out or response
parameters, including the critical Items response
parameter. The XML subelements that represent the parameters occur in an
xs:sequence, which means that each parameter
is positional. For example, the response parameter Items must come last in the list of 10 parameters because the
part @ResponseWrapper comes after the @RequestWrapper and the
Items parameter comes last in the @ResponseWrapper. The upshot is that the wrapped style makes for a very
tricky invocation of the itemSearch method.
The wrapped style, without a workaround, may well produce an irritated
programmer. The next section presents a workaround.
2.3.2. An E-Commerce Client in
Unwrapped Style
The client built from
artifacts in the unwrapped style is simpler than the client built from artifacts
in the wrapped style. However, artifacts for the simplified E-Commerce client
are generated from the very same WSDL as the artifacts for the more complicated,
wrapped-style client. The underlying SOAP messages have the same structure with
either the complicated or the simplified client. Yet the clients differ
significantly鈥攖he simplified client is far easier to code and to understand.
Here is the call to invokeSearch in the simplified client:
ItemSearchResponse response = port.itemSearch(item_search);
The itemSearch method now
takes one argument and returns a value, which is assigned to the object
reference response. Unlike the
complicated client, the simplified client has no Holder of a return value, which is an exotic and difficult
construct. The invocation of itemSearch
is familiar, identical in style to method calls in standalone applications. The
full simplified client is in Example 2-13.
Example 2-13. An E-Commerce Java
client in unwrapped style
import awsClient2.AWSECommerceService; import awsClient2.AWSECommerceServicePortType; import awsClient2.ItemSearchRequest; import awsClient2.ItemSearchResponse; import awsClient2.ItemSearch; import awsClient2.Items; import awsClient2.Item; import java.util.List;
class AmazonClientU { // U is for Unwrapped style public static void main(String[ ] args) { // Usage if (args.length != 1) { System.err.println("Usage: java AmazonClientW <access key<"); return; } final String access_key = args[0];
// Create service and get portType reference. AWSECommerceService service = new AWSECommerceService(); AWSECommerceServicePortType port = service.getAWSECommerceServicePort();
// Create request. ItemSearchRequest request = new ItemSearchRequest();
// Add details to request. request.setSearchIndex("Books"); request.setKeywords("quantum gravity"); ItemSearch item_search= new ItemSearch(); item_search.setAWSAccessKeyId(access_key); item_search.getRequest().add(request);
// Invoke service operation and get response. ItemSearchResponse response = port.itemSearch(item_search);
List<Items> item_list = response.getItems(); for (Items next : item_list) for (Item item : next.getItem()) System.out.println(item.getItemAttributes().getTitle()); } }
|
Generating the simplified client with the wsimport is ironically more complicated than
generating the complicated client. Here is the command, on three lines to
enhance readability:
% wsimport -keep -p awsClient2 \
http://ecs.amazonaws.com/AWSECommerceService/AWSECommerceService.wsdl \
-b custom.xml .
The -b flag at the
end specifies a customized jaxws:bindings
document, in this case in the file custom.xml, that overrides wsimport defaults, in this case a WrapperStyle
setting of true. Example 2-14 shows the document
with the customized binding information.
Example 2-14. A customized bindings
document for wsimport
<jaxws:bindings wsdlLocation = "http://ecs.amazonaws.com/AWSECommerceService/AWSECommerceService.wsdl" xmlns:jaxws="http://java.sun.com/xml/ns/jaxws"> <jaxws:enableWrapperStyle>false</jaxws:enableWrapperStyle> </jaxws:bindings>
|
The impact of the
customized binding document is evident in the generated artifacts. For example,
the segment of the AWSECommerceServicePortType artifact becomes:
@SOAPBinding(parameterStyle = SOAPBinding.ParameterStyle.BARE)
public interface AWSECommerceServicePortType {
...
@WebMethod(operationName = "ItemSearch",
action = "http://soap.amazon.com")
@WebResult(name = "ItemSearchResponse",
targetNamespace =
"http://webservices.amazon.com/AWSECommerceService/2008-04-07",
partName = "body")
public ItemSearchResponse itemSearch(
@WebParam(name = "ItemSearch",
targetNamespace =
"http://webservices.amazon.com/AWSECommerceService/2008-04-07",
partName = "body")
ItemSearch body);
The wsimport-generated interface
AWSECommerceServicePortType now has the
annotation @SOAPBinding.ParameterStyle.BARE, where BARE is the alternative
to WRAPPED. JWS names the attribute
parameterStyle because the contrast
between wrapped and unwrapped in document-style
web services comes down to how parameters are represented in the SOAP body. In
the unwrapped style, the parameters occur bare; that is, as a sequence of unwrapped XML subelements
in the SOAP body. In the wrapped style, the parameters occur as wrapped XML subelements of an
XML element with the name of the service operation; and the wrapper XML element
is the only direct subelement of the SOAP body.
What may be surprising
is that the structure of the underlying SOAP messages, both the request and the
response, remain unchanged. For instance, the request message from the
simplified client AmazonClientU is identical
in structure to the request message from the complicated client
AmazonClientW. Here is the body of the SOAP
envelope from a request that the simplified client generates:
<soapenv:Body>
<ns1:ItemSearch>
<ns1:AWSAccessKeyId>...</ns1:AWSAccessKeyId>
<ns1:Request>
<ns1:Keywords>quantum gravity</ns1:Keywords>
<ns1:SearchIndex>Books</ns1:SearchIndex>
</ns1:Request>
</ns1:ItemSearch>
</soapenv:Body>
The SOAP body contains a single
wrapper element, ns1:ItemSearch, with subelements
for the access key identifier and the request details. The complicated,
wrapped-style client generates requests with the identical structure.
The key difference is in the Java client
code, of course. The simplified client, with the unwrapped
parameterStyle, calls invokeSearch with one argument of type
ItemSearch and expects a single response of type
ItemSearchResponse. So the parameterStyle with a value of
BARE eliminates the complicated call to invokeSearch with 10 arguments, 8 of which are arguments bound to the
subelements in the @RequestWrapper, and 2
of which are arguments bound to subelements in the
@ResponseWrapper.
The E-Commerce example shows that the
wrapped document-style, despite its
advantages, can complicate the programming of a client. In that example, the
simplified client with the BARE or unwrapped
parameterStyle is a workaround.
The underlying WSDL for the E-Commerce
example could be simplified, which would make clients against the service easier
to code. Among SOAP-based web services available commercially, it is not unusual
to find complicated WSDLs that in turn complicate the clients written against
the service.
2.3.3. Tradeoffs Between the RPC
and Document Styles
JWS still supports
both rpc and document styles, with document as the default; for both styles, only literal
encoding is
supported in compliance with the WS-I Basic Profile. The issue of rpc
versus document often is touted as a freedom of choice issue. Nonetheless, it is clear that
document style, especially in the wrapped
flavor, is rapidly gaining mind share. This subsection briefly reviews some
tradeoffs between the two styles.
As in any tradeoff scenario, the pros
and cons need to be read with a critical eye, especially because a particular
point may be cited as both a pro and a con. One familiar complaint against the
rpc style is that it imposes the
request/response pattern on the service. However, this pattern remains the
dominant one in real-world, SOAP-based web services, and there are obviously
situations (for instance, validating a credit card to be used in a purchase) in
which the request/response pattern is needed.
Here are some upsides of the rpc style:
The automatically generated WSDL is
relatively short and simple because there is no
types section.
Messages in the WSDL carry the names
of the underlying web service operations, which
are @WebMethods in a Java-based service. The
WSDL thus has a what you see is
what you get style with respect to the service's
operations.
Message throughput may improve
because the messages do not carry any type-encoding information.
Here are some downsides to the rpc style:
The WSDL, with its empty types
section, does not provide an XSD against which the body of a SOAP message can be
validated.
The service cannot use arbitrarily
rich data types because there is no XSD to define such types. The service is
thus restricted to relatively simple types such as integers, strings, dates, and
arrays of such.
This style, with its obvious link to the
request/response pattern, encourages tight
coupling between the service and the
client. For example, the Java client ch01.ts.TimeClient blocks on the call:
port.getTimeAsString()
until either the service responds or
an exception is thrown. This same point is sometimes made by noting that the
rpc style has an inherently synchronous as opposed to asynchronous
invocation idiom. The next section offers a workaround, which shows how JWS
supports nonblocking clients under the request/response pattern.
Java services written in this style may
not be consumable in other frameworks, thus undermining interoperability.
Further, long-term support within the web services community and from the WS-I
group is doubtful.
Here are some upsides of the
document style:
The body of a SOAP message can be validated against the XSD in the
types section of the WSDL.
A service in this style can use
arbitrarily rich data types, as the XML Schema language supports not only simple
types such as integers, strings, and dates, but also arbitrarily rich complex
types.
There is great flexibility in how the
body of a SOAP message is structured so long as the structure is clearly defined
in an XSD.
The wrapped convention provides a way to enjoy a
key upside of the rpc style鈥攏aming the body
of a SOAP message after the corresponding service operation鈥攚ithout enduring the
downsides of the rpc style.
Here are some downsides of the
document style:
In the unwrapped variant, the SOAP
message does not carry the name of the service operation, which can complicate
the dispatching of messages to the appropriate program code.
The wrapped variant adds a level of
complexity, in particular at the API level. Writing a client against a
wrapped-document service can be
challenging, as the AmazonClientW example shows.
The wrapped variant does not support
overloaded service operations because the XML wrapper element in the body of a SOAP message must
have the name of the service operation. In effect, then, there can be only one operation for a given
element name.
2.3.4. An Asynchronous E-Commerce
Client
As noted earlier, the original
TimeClient blocks on calls against the
TimeServer service operations. For example, the call:
port.getTimeAsString()
blocks until either a response from the web
service occurs or an exception is thrown. The call to getTimeAsString is, therefore, known as a blocking or synchronous
call. JWS also
supports nonblocking or asynchronous clients against web services.
Example 2-15 shows a client that makes an asynchronous call against
the E-Commerce service.
Example 2-15. An asynchronous client
against the E-Commerce service
import javax.xml.ws.AsyncHandler; import javax.xml.ws.Response;
import awsClient3.AWSECommerceService; import awsClient3.AWSECommerceServicePortType; import awsClient3.ItemSearchRequest; import awsClient3.ItemSearchResponse; import awsClient3.ItemSearch; import awsClient3.Items; import awsClient3.Item;
import java.util.List; import java.util.concurrent.ExecutionException;
class AmazonAsyncClient { public static void main(String[ ] args) { // Usage if (args.length != 1) { System.err.println("Usage: java AmazonAsyncClient <access key>"); return; } final String access_key = args[0];
// Create service and get portType reference. AWSECommerceService service = new AWSECommerceService(); AWSECommerceServicePortType port = service.getAWSECommerceServicePort();
// Create request. ItemSearchRequest request = new ItemSearchRequest();
// Add details to request. request.setSearchIndex("Books"); request.setKeywords("quantum gravity"); ItemSearch item_search= new ItemSearch(); item_search.setAWSAccessKeyId(access_key); item_search.getRequest().add(request);
port.itemSearchAsync(item_search, new MyHandler());
// In this case, just sleep to give the search process time. // In a production application, other useful tasks could be // performed and the application could run indefinitely. try { Thread.sleep(400); } catch(InterruptedException e) { System.err.println(e); } }
// The handler class implements handleResponse, which executes // if and when there's a response. static class MyHandler implements AsyncHandler<ItemSearchResponse> { public void handleResponse(Response<ItemSearchResponse> future) { try { ItemSearchResponse response = future.get(); List<Items> item_list = response.getItems(); for (Items next : item_list) for (Item item : next.getItem()) System.out.println(item.getItemAttributes().getTitle()); } catch(InterruptedException e) { System.err.println(e); } catch(ExecutionException e) { System.err.println(e); } } } }
|
The nonblocking E-Commerce client
uses artifacts generated by wsimport, again with a customized bindings file. Here is the
file:
<jaxws:bindings
wsdlLocation=
"http://ecs.amazonaws.com/AWSECommerceService/AWSECommerceService.wsdl"
xmlns:jaxws="http://java.sun.com/xml/ns/jaxws">
<jaxws:enableWrapperStyle>false</jaxws:enableWrapperStyle>
<jaxws:enableAsyncMapping>true</jaxws:enableAsyncMapping>
</jaxws:bindings>
with the enableAsyncMapping attribute set to
true.
The nonblocking call can follow
different styles. In the style shown here, the call to itemSearchAsync
takes two arguments: the first is an ItemSearchRequest, and the second
is a class that implements the AsyncHandler interface, which declares a
single method named handleResponse. The call is:
port.itemSearchAsync(item_search, new MyHandler());
If and when an ItemSearchResponse comes from the
E-Commerce service, the method handleResponse in the MyHandler
class executes as a separate thread and prints out the books' titles.
There is a version of itemSearchAsync that takes one
argument, an ItemSearchRequest. In this version the
call also returns if and when the E-Commerce service sends a response, which
then can be processed as in the other E-Commerce clients. In this style, the
application might start a separate thread to execute this code segment:
Response<ItemSearchResponse> res = port.itemSearchAsync(item_search);
try {
ItemSearchResponse response = res.get();
List<Items> item_list = response.getItems();
for (Items next : item_list)
for (Item item : next.getItem())
System.out.println(item.getItemAttributes().getTitle());
}
catch(InterruptedException e) { System.err.println(e); }
catch(ExecutionException e) { System.err.println(e); }
JWS is flexible in supporting nonblocking
as well as the default blocking clients. In the end, it is application logic
that determines which type of client is suitable.
No comments:
Post a Comment