Chapter 11. Ajax

Using Web Services

When a web application needs to get information from an external source, it typically uses a remote procedure call mechanism. In recent years, web services have emerged as a popular technology for this purpose.

Technically, a web service has two components:

  • A server that can be accessed with a transport protocol such as SOAP (Simple Object Access Protocol)

  • A description of the service in the WSDL (Web Service Description Language) format

Fortunately, you can use web services, even if you know nothing at all about SOAP and just a little about WSDL.

To make web services easy to understand, we look at a concrete example: the Amazon Web Services, described at http://www.amazon.com/gp/aws/landing.html. The Amazon Web Services allow a programmer to interact with the Amazon system for a wide variety of purposes. For example, you can get listings of all books with a given author or title, or you can fill shopping carts and place orders.

Amazon makes these services available for use by companies that want to sell items to their customers, using the Amazon system as a fulfillment backend. To run our example program, you will need to sign up with Amazon and get a free accessKey that lets you connect to the service.

A primary attraction of web services is that they are language-neutral. We will access the Amazon Web Services by using the Java programming language, but other developers can equally well use C++ or PHP. The WSDL descriptor describes the services in a language-independent manner. For example, the WSDL for the Amazon E-Commerce Service (located at http://webservices.amazon.com/AWSECommerceService/AWSECommerceService.wsdl) describes an ItemSearch operation as follows:

  <operation name="ItemSearch">      <input message="tns:ItemSearchRequestMsg"/>      <output message="tns:ItemSearchResponseMsg"/>   </operation>   ...   <message name="ItemSearchRequestMsg">      <part name="body" element="tns:ItemSearch"/>   </message>   <message name="ItemSearchResponseMsg">      <part name="body" element="tns:ItemSearchResponse"/>   </message>

Here are the definitions of the ItemSearch and ItemSearchResponse types:

  <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>   <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>     

Several technologies provide a Java programming layer over the SOAP protocol. Using the JAX-WS technology, the ItemSearch operation becomes a method call

  void itemSearch(String marketPlaceDomain, String awsAccessKeyId,      String subscriptionId, String associateTag, String xmlEscaping, String validate,      ItemSearchRequest shared, List<ItemSearchRequest> request,      Holder<OperationRequest> opHolder, Holder<List<Items>> responseHolder)     

Note

The WSDL file does not specify what the service does. It specifies only the parameter and return types.


The ItemSearchRequest parameter type is defined as

  <xs:complexType name="ItemSearchRequest">      <xs:sequence>         <xs:element name="Actor" type="xs:string" minOccurs="0"/>         <xs:element name="Artist" type="xs:string" minOccurs="0"/>          . . .         <xs:element name="Author" type="xs:string" minOccurs="0"/>          . . .         <xs:element name="ResponseGroup" type="xs:string" minOccurs="0"            maxOccurs="unbounded"/>          . . .         <xs:element name="SearchIndex" type="xs:string" minOccurs="0"/>          . . .   </xs:complexType>

This description is translated into a class:

  public class ItemSearchRequest {      public ItemSearchRequest() { ... }      public String getActor() { ... }      public void setActor(String newValue) { ... }      public String getArtist() { ... }      public void setArtist(String newValue) { ... }      ...      public String getAuthor() { ... }      public void setAuthor(String newValue) { ... }      ...      public List<String> getResponseGroup() { ... }      ...      public void setSearchIndex(String newValue) { ... }      ...   }

To invoke the search service, construct an ItemSearchRequest object and call the itemSearch method of a "port" object:

  ItemSearchRequest request = new ItemSearchRequest();   request.getResponseGroup().add("ItemAttributes");   request.setSearchIndex("Books");   Holder<List<Items>> responseHolder = new Holder<List<Items>>();   request.setAuthor(name);   port.itemSearch("", accessKey, "", "", "", "", request, null, null, responseHolder);     

The port object translates the Java object into a SOAP message, passes it to the Amazon server, translates the returned message into a ItemSearchResponse object, and places the response in the "holder" object.

Note

The Amazon documentation about the parameters and return values is extremely sketchy. However, you can fill out forms at http://awszone.com/scratchpads/index.aws to see the SOAP requests and responses. Those help you guess what parameter values you need to supply and what return values you can expect.


You obtain the port object through dependency injection. Annotate a field with the @WebServiceRef annotation:

  @WebServiceRef(wsdlLocation=      "http://webservices.amazon.com/AWSECommerceService/AWSECommerceService.wsdl")   private AWSECommerceService service;     

Then call:

  AWSECommerceServicePortType port = service.getAWSECommerceServicePort();

To generate a JAR file with the required "client-side artifact" classes, run these commands:

  glassfish/bin/wsimport -p com.corejsf.amazon        http://webservices.amazon.com/AWSECommerceService/AWSECommerceService.wsdl   jar cvf aws.jar com/corejsf/amazon/*.class     

Place the resulting JAR file into the WEB-INF/lib directory of your JSF application.

To compile the AuthorSearchBean class, include glassfish/lib/appserv-ws.jar, glassfish/ lib/appserv-ws.jar, and aws.jar in the class path.

Note

If you use Tomcat instead of GlassFish, you need to download and install the Java Web Services Developer Pack (JWSDP) from http://java.sun.com/webservices/jwsdp. Refer to the JWSDP documentation for more information.


Our sample application is straightforward. The user specifies an author name and clicks the "Search" button (see Figure 10-23).

Figure 10-23. Searching for books with a given author


We show the first page of the response in a data table (see Figure 10-24). This shows that the web service is successful. We leave it as the proverbial exercise for the reader to extend the functionality of the application.

Figure 10-24. A search result


Figure 10-25 shows the directory structure of the application. Note the JAR file in the WEB-INF/lib directory.

Figure 10-25. Directory structure of the web service test application


The bean class in Listing 10-26 contains the call to the web service. The call returns an object of type ItemSearchResponse. We stash away that object so that the result.jsp page can display its contents.

Note how the access key is set in faces-config.xml (Listing 10-27). Be sure to supply your own key in that file.

Listing 10-28 through Listing 10-30 show the JSF pages. The result.jsp page contains a data table that displays information from the response object that was returned by the search service.

Finally, Listing 10-31 is the message bundle.

Listing 10-26. amazon/src/java/com/corejsf/AuthorSearchBean.java

  1. package com.corejsf;   2.   3. import java.util.List;   4.   5. import javax.xml.ws.Holder;   6. import javax.xml.ws.WebServiceRef;   7.   8. import com.corejsf.amazon.AWSECommerceService;   9. import com.corejsf.amazon.AWSECommerceServicePortType;  10. import com.corejsf.amazon.Item;  11. import com.corejsf.amazon.ItemSearchRequest;  12. import com.corejsf.amazon.Items;  13.  14. public class AuthorSearchBean {  15.    @WebServiceRef(wsdlLocation="http://webservices.amazon.com/  16.       AWSECommerceService/AWSECommerceService.wsdl")  17.    private AWSECommerceService service;  18.  19.    private String name;  20.    private List<Item> response;  21.    private String accessKey;  22.  23.    public String getName() { return name; }  24.    public void setName(String newValue) { name = newValue; }  25.  26.    public void setAccessKey(String newValue) { accessKey = newValue; }  27.  28.    public String search() {  29.       try {  30.          AWSECommerceServicePortType port = service.getAWSECommerceServicePort();  31.  32.          ItemSearchRequest request = new ItemSearchRequest();  33.          request.getResponseGroup().add("ItemAttributes");  34.          request.setSearchIndex("Books");  35.          request.setAuthor(name);  36.  37.          Holder<List<Items>> responseHolder = new Holder<List<Items>>();  38.          port.itemSearch("", accessKey, "", "", "", "", request, null, null,  39.                responseHolder);  40.          response=responseHolder.value.get(0).getItem();  41.  42.          return "success";  43.        } catch(Exception e) {  44.          e.printStackTrace();  45.            return "failure";  46.        }  47.    }  48.  49.    public List<Item> getResponse() { return response; }  50. }     

Listing 10-27. amazon/web/WEB-INF/faces-config.xml

  1. <?xml version="1.0"?>   2. <faces-config xmlns="http://java.sun.com/xml/ns/javaee"   3.    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   4.    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee    5.       http://java.sun.com/xml/ns/javaee/web-facesconfig_1_2.xsd"   6.    version="1.2">   7.    <navigation-rule>   8.       <from-view-id>/index.jsp</from-view-id>   9.       <navigation-case>  10.          <from-outcome>success</from-outcome>  11.          <to-view-id>/result.jsp</to-view-id>  12.       </navigation-case>  13.       <navigation-case>  14.          <from-outcome>failure</from-outcome>  15.          <to-view-id>/error.jsp</to-view-id>  16.       </navigation-case>  17.    </navigation-rule>  18.    <navigation-rule>  19.       <from-view-id>/result.jsp</from-view-id>  20.       <navigation-case>  21.          <from-outcome>back</from-outcome>  22.          <to-view-id>/index.jsp</to-view-id>  23.       </navigation-case>  24.    </navigation-rule>  25.    <navigation-rule>  26.       <from-view-id>/error.jsp</from-view-id>  27.       <navigation-case>  28.          <from-outcome>continue</from-outcome>  29.          <to-view-id>/index.jsp</to-view-id>  30.       </navigation-case>  31.    </navigation-rule>  32.  33.    <managed-bean>   34.       <managed-bean-name>authorSearch</managed-bean-name>  35.       <managed-bean-class>com.corejsf.AuthorSearchBean</managed-bean-class>   36.       <managed-bean-scope>session</managed-bean-scope>   37.       <managed-property>  38.          <property-name>accessKey</property-name>  39.          <value>XXXXXXXXXXXXXXXXXXXX</value>  40.       </managed-property>  41.    </managed-bean>  42.  43.    <application>  44.       <resource-bundle>  45.          <base-name>com.corejsf.messages</base-name>  46.          <var>msgs</var>  47.       </resource-bundle>  48.    </application>  49. </faces-config>     

Listing 10-28. amazon/web/index.jsp

  1. <html>   2.    <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>   3.    <%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>   4.    <f:view>   5.       <head>   6.          <link href="styles.css" rel="stylesheet" type="text/css"/>   7.          <title><h:outputText value="#{msgs.title}"/></title>   8.       </head>   9.       <body>  10.          <h:form>  11.             <h1><h:outputText value="#{msgs.authorSearch}"/></h1>  12.             <h:outputText value="#{msgs.author}"/>  13.             <h:inputText value="#{authorSearch.name}"/>  14.             <h:commandButton value="#{msgs.search}"   15.                action="#{authorSearch.search}"/>  16.          </h:form>  17.       </body>  18.    </f:view>  19. </html>

Listing 10-29. amazon/web/result.jsp

  1. <html>   2.    <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>   3.    <%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>   4.    <f:view>   5.       <head>   6.          <title><h:outputText value="#{msgs.title}"/></title>   7.       </head>   8.       <body>   9.          <h:form>  10.             <h1><h:outputText value="#{msgs.searchResult}"/></h1>  11.             <h:dataTable value="#{authorSearch.response}" var="item"   12.                border="1">  13.                <h:column>  14.                   <f:facet name="header">  15.                      <h:outputText value="#{msgs.author1}"/>  16.                   </f:facet>  17.                   <h:outputText value="#{item.itemAttributes.author[0]}"/>  18.                </h:column>  19.                <h:column>  20.                   <f:facet name="header">  21.                      <h:outputText value="#{msgs.title}"/>  22.                   </f:facet>  23.                   <h:outputText value="#{item.itemAttributes.title}"/>  24.                </h:column>  25.                <h:column>  26.                   <f:facet name="header">  27.                      <h:outputText value="#{msgs.publisher}"/>  28.                   </f:facet>  29.                   <h:outputText value="#{item.itemAttributes.publisher}"/>  30.                </h:column>  31.                <h:column>  32.                   <f:facet name="header">  33.                      <h:outputText value="#{msgs.pubdate}"/>  34.                   </f:facet>  35.                   <h:outputText value="#{item.itemAttributes.publicationDate}"/>  36.                </h:column>  37.             </h:dataTable>  38.             <h:commandButton value="#{msgs.back}" action="back"/>  39.          </h:form>  40.       </body>  41.    </f:view>  42. </html>     

Listing 10-30. amazon/web/error.jsp

  1. <html>   2.    <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>   3.    <%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>   4.    <f:view>   5.       <head>   6.          <title><h:outputText value="#{msgs.title}"/></title>   7.       </head>   8.        <body>   9.          <h:form>  10.             <h1><h:outputText value="#{msgs.internalError}"/></h1>  11.             <p><h:outputText value="#{msgs.internalError_detail}"/></p>  12.             <p>  13.                <h:commandButton value="#{msgs.continue}" action="login"/>  14.             </p>  15.          </h:form>  16.       </body>  17.    </f:view>  18. </html>     

Listing 10-31. amazon/src/java/com/corejsf/messages.properties

  1. title=A Faces Application that Invokes a Web Service   2. authorSearch=Author Search at Amazon   3. author=Author   4. format=Format   5. search=Search   6. searchResult=Search Result   7. internalError=Internal Error   8. internalError_detail=To our chagrin, an internal error has occurred. \   9.    Please report this problem to our technical staff.  10. continue=Continue  11. author1=First Author  12. title=Title  13. publisher=Publisher  14. pubdate=Publication Date  15. back=Back

You have now seen how your web applications can connect to external services, such as databases, directories, and web services. Here are some general considerations to keep in mind.

  • JAR files are placed either in the WEB-INF/lib directory of the web application or in a library directory of the application server. You would do the latter only for libraries that are used by many applications, such as JDBC drivers.

  • Application servers typically provide common services for database connection pooling, authentication realms, and so on. Dependency injection provides a convenient and portable mechanism for locating the classes that are needed to access these services.

  • Configuration parameters can be placed into faces-config.xml or web.xml. The former is more appropriate for parameters that are intrinsic to the web application; the latter should be used for parameters that are determined at deployment time.



Core JavaServerT Faces
Core JavaServer(TM) Faces (2nd Edition)
ISBN: 0131738860
EAN: 2147483647
Year: 2004
Pages: 84

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net