Sample Application using JAX-WS, JSF, EJB 3.0, and Java Persistence APIs on Glassfish

eBay and Amazon provide Web Services APIs for developers who want to provide access to these services in their web site. This Sample Store Catalog application shows how to expose a  Service as a Web Service for remote client applications (this example was not modeled after the eBay or Amazon APIs).

This example demonstrates a Catalog Stateless Session Bean, and the Java Persistence APIs to implement Catalog Service which provides pagination of store items,  and JAX-WS to expose this Catalog Service as a Web Service. A separate example JSF JAX-WS client shows how this Catalog Web Service can then be used remotely in a sample Store web site.   I took this example  Pagination of Data Sets in a Sample Application using JSF, Catalog Facade Stateless Session, and Java Persistence APIs and modified the Catalog Session Bean to expose its public methods as Web Services, then I put the JSF Store UI in a separate Web Application and modified it to use JAX-WS to call the Catalog Web Services.

Download the Sample Application Code

Explanation of the usage of  JAX-WS,  JSF, EJB 3.0, and Java Persistence APIs in a sample Store Catalog Application

The image below shows the Catalog Listing page, which allows a user to page through a list of items in a store.

listpage.jpg


Explanation of the Catalog Web Service which uses JAX-WS, JPA, and EJB 3.0

The CatalogSession EJB  uses a JPA EntityManagerQueryobject to return a list of items. With the @PersistenceContextannotation, the CatalogBean uses dependency injection to lookup and obtain a Container Managed EntityManager.  The @Statelessannotation marks this class as a Stateless Session EJB. The@WebServiceannotation marks this class as a web service, and causes any public methods to be exposed as Web Services.  The example JSF Web Service client uses the CatalogWeb Service getItemsmethod to get the Items for displaying on the Web Store UI .   (Note: Red colors are for Java EE tags, annotations code,  and Green for my code orvariables)

        
Code Sample from: Catalog.java

  
@WebService
   @Stateless
   public class Catalogimplements CatalogService {

   @PersistenceContext(unitName="PetCatalogPu")
   private EntityManager em;
 
   @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
   public List<Item> getItems(int firstItem,int batchSize) {
        Query q = em.createQuery("select object(o) from Item as o");
        q.setMaxResults(batchSize);
        q.setFirstResult(firstItem);
        List<Item> items= q.getResultList();
        return items;
   }
   



The code below shows the Itementity class which maps to the  ITEM table that stores the item instances. This is a typical Java Persistence entity object.  For more information on this code see this previous blog.

           
Code Sample from: Item.java

@Entity

public class Item implements java.io.Serializable {

   
@Id 
      private String itemID;

    private String name;   
    private String description;   
    private String imageurl;    
    private BigDecimal price;
    @OneToOne(cascade={CascadeType.PERSIST})
    private Address address;
    @ManyToOne
    private Product product;

    
    public Item() { }
     
    public String getItemID() {
        return itemID;
    }

    public void setItemID(String itemID) {
        this.itemID = itemID;
    }

    // getters and setters for other item attributes
    ...
}   



When this application is deployed,  the JAXB,  JAX-WS, and WSDL files needed for the Service will be generated on the server. You can access the CatalogWSDL contract at this URL: http://host:8080/CatalogService/Catalog?wsdl .  Below is part of the WSDL, you can see that the Catalogclass name defaults to the portTypename and thegetItemsmethod name defaults to the operationname (defaults can be changed using annotations, see the Java EE tutorial for more information).


        
Code Sample from: CatalogService.wsdl

<portTypename="Catalog">
    <operationname="getItems">
       <input message="tns:getItems"/>
       <output message="tns:getItemsResponse"/>
    </operation>
</portType>
...
  <service name="CatalogService">
    <port name="CatalogPort" binding="tns:CatalogPortBinding">
      <soap:address location="http://host:8080/CatalogService/Catalog" />
    </port>
  </service>


Here is part of the generated xml Schema for the WSDL getItems response message:


        
Code Sample from: CatalogService.xsd

<xs:complexType name="getItemsResponse">
    <xs:sequence>
      <xs:element name="return" type="tns:item" />
    </xs:sequence>
  </xs:complexType>

  <xs:complexType name="item">
    <xs:sequence>
      <xs:element name="address" type="tns:address" minOccurs="0"/>
      <xs:element name="contactinfo" type="tns:sellercontactinfo" minOccurs="0"/>
      <xs:element name="description" type="xs:string" minOccurs="0"/>
      <xs:element name="disabled" type="xs:int"/>
      <xs:element name="imagethumburl" type="xs:string" minOccurs="0"/>
      <xs:element name="imageurl" type="xs:string" minOccurs="0"/>
      <xs:element name="itemid" type="xs:string" minOccurs="0"/>
      <xs:element name="name" type="xs:string" minOccurs="0"/>
      <xs:element name="numberofvotes" type="xs:int"/>
      <xs:element name="price" type="xs:decimal" minOccurs="0"/>
      <xs:element name="product" type="tns:product" minOccurs="0"/>
      <xs:element name="totalscore" type="xs:int"/>
    </xs:sequence>
  </xs:complexType>



and the corresponding generated JAXB class:

        
Code Sample from: GetItemResponse.java

@XmlRootElement(name = "getItemResponse")
@XmlType(name = "getItemResponse")
public class GetItemResponse {

    @XmlElement(name = "return")
    private Item _return;

    public Item getReturn() {
        return this._return;
    }

    public void setReturn(Item _return) {
        this._return = _return;
    }
   
...
}


JAX-WS delegates all data binding functionality to JAXB 2.0:
jaxb.gif.gif

After deployment on Glassfish you can access a web client tester application provided by the Glassfish Application Server at the  URL for the Web Service followed by "?Tester"  for example :  http://host:8080/CatalogService/Catalog?Tester. Below is the Web Service Tester interface for the CatalogService. It provides an easy way to call the Web Service operations from a browser.

testws.jpg

Here is an example soap request and response for the getItems WebService operation:

SOAP Request


<?xml version="1.0" encoding="UTF-8"?>
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
    <S:Header/>
    <S:Body>
        <ns2:getItems xmlns:ns2="http://model.sessionpagination/">
            <arg0>0</arg0>
            <arg1>2</arg1>
        </ns2:getItems>
    </S:Body>
</S:Envelope>

SOAP Response


<?xml version="1.0" encoding="UTF-8"?>
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
    <S:Body>
        <ns2:getItemsResponse xmlns:ns2="http://model.sessionpagination/">
            <return>
                <address>
                    <addressid>1</addressid>
                    <city>Mountain View</city>
                    <latitude>37.3857400000</latitude>
                    <longitude>-122.0839730000</longitude>
                    <state>CA</state>
                    <street1>Castro St</street1>
                    <street2/>
                    <zip>94040</zip>
                </address>
                <contactinfo>
                    <contactinfoid>1</contactinfoid>
                    <email>abc@abc.xyz</email>
                    <firstname>Sean</firstname>
                    <lastname>Brydon</lastname>
                </contactinfo>
                <description>super friendly</description>
                <itemid>1</itemid>
                <name>Friendly Cat</name>
                <numberofvotes>3</numberofvotes>
                <price>307.10</price>
                <product>
                    <category>
                        <categoryid>CATS</categoryid>
                        <description>Loving and finicky friends</description>
                        <name>Cats</name>
                    </category>
                    <description>Great for reducing mouse populations</description>
                    <name>Hairy Cat</name>
                    <productid>feline01</productid>
                </product>
                <totalscore>15</totalscore>
            </return>
            <return>
                <address>
                   ...
                </address>
                <contactinfo>
                    ...
                </contactinfo>
                <itemid>2</itemid>
                <name>Fluffy Cat</name>
                <product>
                    <category>
                        <categoryid>CATS</categoryid>
                         ...
                    </category>
                    <name>Hairy Cat</name>
                    <productid>feline01</productid>
                </product>
            </return>
        </ns2:getItemsResponse>
    </S:Body>
</S:Envelope>


Explanation of the JSF Store UI which uses JAX-WS to call the Catalog Web Service.

The JSF Store UI is a separate web application which is a JAX-WS client.

jaxws-ClientService.gif


The List.jsp page uses a JSF dataTable component to display a list of catalog items. The dataTable component is useful when you want to show a set of results in a table.

In the List.jsp web page the dataTable is defined as shown below:

        
Code Sample from:  List.jsp

<h:dataTablevalue='#{item.items}' var='dataTableItem' border="1"
      cellpadding="2" cellspacing="0">


The value attribute of a dataTable tag references the data to be included in the table. The var attribute points to a single item in that list. As the dataTable JSF component iterates through the list, each reference to dataTableItem points to the current item in the list.

The dataTable's value is bound to theitemsproperty of the ItemControllermanaged-bean class, which is defined in the faces-config.xml


        
Code Sample from: faces-context.xml

 <managed-bean>
    <managed-bean-name>item</managed-bean-name>
      <managed-bean-class>
         sessionpagination.ItemController
      </managed-bean-class>
    <managed-bean-scope>session</managed-bean-scope>
 </managed-bean>


This ItemController ManagedBean items property is defined as shown below (the blue color highlights the JAX-WS dynamic proxy classes and methods):

        
Code Sample from: ItemController.java

 public class ItemController{

  @WebServiceRef(wsdlLocation= "http://localhost:8080/CatalogService/Catalog?wsdl")
  private CatalogServiceservice;


  public DataModel getItems() {
      if (model==null  || index != firstItem){
          model=getNextItems();
      }
      return this.model;
  }
  public DataModelgetNextItems() {
      Catalog port = service.getCatalogPort();
      model = new ListDataModel(port.getItems( firstItem,batchSize));
      return model;
  }


The ItemControllerManagedBean uses dependency injection to obtain a reference to theCatalogServiceJAX-WS proxy factory class, which is generated from the Catalog WSDL file using the wsimport utility. (To see how to do this easily with Netbeans see the  Netbeans Web Services (JAX-WS) in Java EE 5 tutorial). The ItemControllerretrieves a proxy to the service by calling getCatalogPort()on the CatalogService, which returns the CatalogService Endpoint Interface.  The proxy implements theCatalogService Endpoint Interface defined by the Catalogservice. The ItemControllercan then invoke the port’s getItemsmethod.  The dynamic proxy and jaxb classes convert the WS method into a SOAP request and send it to the Web service's endpoint,  receive the SOAP response, and transform the SOAP response into the java method's return object which in this case is a List<Item>.

The getItems()method wraps a List of items, returned from the CatalogService,  in a DataModel.   The dataTable JSF component supports data binding to a collection of data objects represented by a DataModelinstance.  The data collection underlying a DataModel instance is modeled as a collection of row objects that can be accessed by a row index.  The APIs provide mechanisms to position to a specified row index, and to retrieve an object that represents the data that corresponds to the current row index.   

The Name, Photo, and Price item properties are displayed  with the JSF columncomponent:

        
Code Sample from: List.jsp

  <h:column>
      <f:facet name="header">
          <h:outputText value="Price"/>
      </f:facet>
      <h:outputTextvalue="#{dataTableItem.price}"/>
  </h:column>


The column tags represent columns of data in a dataTable. The dataTable JSF  component  iterates through the list of items (item.items) each time rendering one cell in each column and displaying  the item name, photo, and price.

For more information on the JSF part of this code see this previous blog.


Conclusion

The sample Store Catalog application demonstrates how to expose  EJB 3.0  Stateless Session EJB methods which use  the Java Persistence APIs as a Web Service operations using JAX-WS.
The sample JSF Store UI application  demonstrates how to use  the JSF dataTable andDataModel to page through a list of  Items which are retrieved from the CatalogService using JAX-WS.


Running the Sample Application on Glassfish:

  • Downloadand install GlassFish V2, following the instructions on the download page. Alternatively you can use Sun Java System Application Server PE 9, Sun's GlassFish distribution.
  • Download and install NetBeans 5.5.1
  • Download the Sample Application Code
  • install Glassfish and Netbeans 5.5.1.  Then add the glassfish application server to Netbeans.

To Open and Test Run the sessionpagination Project:

  • Open the Netbeans sessionpagination project: In Netbeans under File Open Project... go to the directory where you unzipped the sample and select the sessionpagination project.
  • If you get a message that says unresolved references, right click on the project and select Resolve Reference Problems. Use the Resolve Reference Problems dialog to map the ejb and web modules to their project, which are subdirectories beneath the sessionpagination directory.
  • After the references are resolved, right-click the sessionpagination project and select Open Required Projects.
  • If the web module says unresolved references, right-click the sessionpagination-Web module and select Resolve Reference Problems:
  • Browse to the sessionpagination-ejb directory which is a sub-directory below the sessionpagination directory and select Open Project Folder.
  • If you don't have any resolve reference problems errors then ignore those steps.
  • Starts the application server, or at least connect to the database, because the run script for this application will also create the database tables, and this will fail if the database is not started.
  • Right-click the project node and choose Run Project.
    The Netbeans IDE starts the application server, builds the application, and opens the web context page in your browser. This application also has a local JSF client in the war of the application which will be displayed.
  • To go to the web client Tester application provided by the Glassfish Application Server use the url :  http://host:8080/CatalogService/Catalog?Tester. You should see the tester page. For the getItems operation type in integer the integers 0, 5 as input and click on the getItems button. This will return a list of  items 0 through 5.

To Open and Test Run the sessionpagination-wsclient Project:

  • Open the Netbeans sessionpagination-wsclient project: In Netbeans under File Open Project... go to the directory where you unzipped the sample and select the sessionpagination-wsclient project.
  • Right-click the project node and choose Run Project.
    The Netbeans IDE  builds the application, and deploys it.
  • When you run the project, your browser should display the opening page of the application at http://localhost:8080/sessionpagination-wsclient/
index.jpg

References: