EJB Endpoints

An EJB endpoint is a stateless session bean that serves as a web service. Basically, the endpoint exposes a stateless session bean through a new component interface, called the endpoint interface; remote clients use SOAP 1.1 to access the methods defined in this interface. Because an EJB endpoint is simply a SOAP-accessible stateless session bean, it has the same advantages as other EJBs. An EJB endpoint runs in the EJB container that automatically manages transactions and security and provides access to other EJBs and resources via the JNDI ENC.

To illustrate how an EJB endpoint is developed, we’ll create a new version of the TravelAgent EJB. The revised TravelAgent will use the same logic as the TravelAgent EJB developed in Chapter 11 and the ReservationProcessor developed in Chapter 12, but it will be deployed as a stateless session bean with an endpoint interface. The TravelAgent endpoint is based on the WSDL document shown earlier in this chapter.

The WSDL Document

Every EJB endpoint must have a WSDL document that describes the web service. The <portType> declared by the WSDL document must be aligned with the endpoint interface of the web service. In other words, the mapping between the WSDL <portType> and the endpoint interface must be correct according to the JAX-RPC specification. One way to accomplish this is to create the WSDL document first, and then use it to generate the endpoint interface:

<?xml version="1.0"?>
<definitions name="TravelAgent"
   xmlns="http://schemas.xmlsoap.org/wsdl/"
   xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
   xmlns:xsd="http://www.w3.org/2001/XMLSchema"
   xmlns:titan="http://www.titan.com/TravelAgent"
   targetNamespace="http://www.titan.com/TravelAgent">

<!-- message elements describe the parameters and return values -->
<message name="RequestMessage">
   <part name="cruiseId"   type="xsd:int" />
   <part name="cabinId"    type="xsd:int" />
   <part name="customerId" type="xsd:int" />
   <part name="price"      type="xsd:double" />
</message>
<message name="ResponseMessage">
   <part name="reservationId" type="xsd:string" />
</message>

<!-- portType element describes the abstract interface of a web service -->
<portType name="TravelAgentEndpoint">
  <operation name="makeReservation">
     <input message="titan:RequestMessage"/>
     <output message="titan:ResponseMessage"/>
  </operation>
</portType>

<!-- binding element tells us which protocols and encoding styles are used  -->
<binding name="TravelAgentBinding" type="titan:TravelAgentEndpoint">
   <soap:binding style="rpc" 
                 transport="http://schemas.xmlsoap.org/soap/http"/>
   <operation name="makeReservation">
      <soap:operation soapAction="" /> 
      <input>
        <soap:body use="literal" 
              namespace="http://www.titan.com/TravelAgent"/>
      </input>
      <output>
        <soap:body use="literal" 
              namespace="http://www.titan.com/TravelAgent"/>
      </output>
   </operation>
</binding>

<!-- service element tells us the Internet address of a web service -->
<service name="TravelAgentService">
  <port name="TravelAgentPort" binding="titan:TravelAgentBinding">
     <soap:address location="http://www.titan.com/webservices/TravelAgent" /> 
  </port>
</service>

</definitions>

The Endpoint Interface

Based on this WSDL document, we can generate a JAX-RPC endpoint interface, which will be implemented by our EJB endpoint. The endpoint interface is generated from the <portType> and <message> definitions (and <types>, if present). The endpoint interface looks like this:

package com.titan.webservice;

public interface TravelAgentEndpoint extends java.rmi.Remote {
    public java.lang.String makeReservation(int cruiseId, int cabinId, 
                                            int customerId, double price) 
    throws java.rmi.RemoteException;
}

The endpoint interface defines the business methods that will be accessible as SOAP operations. The interface extends java.rmi.Remote—there is no EJBObject interface—and defines one or more business methods, each of which must throw a java.rmi.RemoteException. The types that can be used as parameters and return types are the same types that can be used with JAX-RPC generated endpoints (see Table 15-1). You can also use simple Java bean types for holding complex data.

No Home Interface

An EJB endpoint does not define a home interface; there is no EJB home object for creating or locating EJB endpoints. An EJB endpoint cannot be created or located; it’s a truly stateless service, both semantically and physically. The only time an EJB would have a home interface is if the EJB defined remote or local interfaces in addition to the endpoint interface. In other words, a single EJB can be local, remote, and an endpoint.

The Stateless Bean Class

The bean class defined for the TravelAgent endpoint must implement the methods defined by the endpoint interface. A stateless bean class can implement the endpoint interface directly—something that’s not recommended for the local or remote interfaces. That’s because the endpoint interface is a direct descendent of java.rmi.Remote, and doesn’t define any EJBObject methods. Here’s the new definition for the TravelAgent bean class:

package com.titan.webservice;
import com.titan.reservation.*;
import com.titan.cruise.*;
import com.titan.customer.*;
import com.titan.cabin.*;
import com.titan.processpayment.*;
import java.rmi.RemoteException;
import javax.rmi.PortableRemoteObject;
import javax.naming.NamingException;
import javax.ejb.EJBException;
import java.util.Date;
import java.util.Calendar;

public class TravelAgentBean 
                      implements TravelAgentEndpoint, javax.ejb.SessionBean {
    public javax.naming.Context jndiContext;

    public void ejbCreate( ) {}

    public String makeReservation(int cruiseId, int cabinId, 
                                  int customerId, double price){
                  try {
                  CruiseLocal cruise = this.getCruise(cruiseId);
                  CabinLocal cabin = this.getCabin(cabinId);           
                  CustomerRemote customer = this.getCustomer(customerId);
                  CreditCardDO card = this.getCreditCard(customerId);
   
                  ReservationHomeLocal resHome = (ReservationHomeLocal)            
                  jndiContext.lookup("java:comp/env/ejb/ReservationHomeLocal");
                  ReservationLocal reservation =
                  resHome.create(customer, cruise, cabin, price, new Date( ));
                  Object ref = jndiContext.lookup(
                         "java:comp/env/ejb/ProcessPaymentHomeRemote");
                  ProcessPaymentHomeRemote ppHome = (ProcessPaymentHomeRemote)
                  PortableRemoteObject.narrow(ref, ProcessPaymentHomeRemote.class);
            
                  ProcessPaymentRemote process = ppHome.create( );
                  process.byCredit(customer, card, price);

                  return reservation.getPrimaryKey( ).toString( );

                  } catch(Exception e) {
                  throw new EJBException(e);
                  }
                  }

    public CustomerRemote getCustomer(int customer_id) throws Exception { 
        Integer customerID = new Integer(customer_id);
        CustomerHomeRemote home = (CustomerHomeRemote)
                jndiContext.lookup("java:comp/env/ejb/CustomerHomeRemote");
            
        return home.findByPrimaryKey(customerID);
    }
    public CreditCardDO getCreditCard(int customer_id) throws Exception{
        Integer customerID = new Integer(customer_id);
        CustomerHomeLocal home = (CustomerHomeLocal)
                jndiContext.lookup("java:comp/env/ejb/CustomerHomeLocal");
            
        CustomerLocal customer = home.findByPrimaryKey(customerID);
        CreditCardLocal card = customer.getCreditCard( );
        return new CreditCardDO(card.getNumber( ),card.getExpirationDate( ),
                                card.getCreditOrganization( ));
    }
    public CabinLocal getCabin(int cabin_id) throws Exception { 
        Integer cabinID = new Integer(cabin_id);
        CabinHomeLocal home = (CabinHomeLocal)
             jndiContext.lookup("java:comp/env/ejb/CabinHomeLocal");
            
        return home.findByPrimaryKey(cabinID);
    }
    public CruiseLocal getCruise(int cruise_id) throws Exception { 
        Integer cruiseID = new Integer(cruise_id);
        CruiseHomeLocal home = (CruiseHomeLocal)
               jndiContext.lookup("java:comp/env/ejb/CruiseHomeLocal");
           
        return home.findByPrimaryKey(cruiseID);
    }
    public void ejbRemove( ) {}
    public void ejbActivate( ) {}
    public void ejbPassivate( ) {}   
    public void setSessionContext(javax.ejb.SessionContext cntx){
        try {
            jndiContext = new javax.naming.InitialContext( );
        }catch(NamingException ne) {
            throw new EJBException(ne);
        }
    }
}

The TravelAgentBean class is not that different from the TravelAgent EJB developed earlier in this chapter (the version that uses the Charge-It credit card processing web service). The primary difference is that it responds to web service calls, rather than remote or local calls.

The Deployment Files

The TravelAgent endpoint requires four deployment files: a standard ejb-jar.xml deployment descriptor, a WSDL file, a JAX-RPC mapping file, and a webservices.xml file.

ejb-jar.xml file

An EJB endpoint is deployed using the same ejb-jar.xml elements as a regular stateless session bean. The endpoint declares a single component interface element, the <service-endpoint>. This element can be used only with stateless session beans that are deployed as EJB endpoints. A single EJB can actually support remote, local, and endpoint interfaces simultaneously. Here, we’ll keep it simple and limit the TravelAgent endpoint to web services. Other than the <service-endpoint> element, the rest of the deployment descriptor is pretty much the same as a regular stateless session bean:

<?xml version='1.0' encoding='UTF-8' standalone='yes'?>
<ejb-jar 
     xmlns="http://java.sun.com/xml/ns/j2ee"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
                         http://java.sun.com/xml/ns/j2ee/ejb-jar_2_1.xsd"
     version="2.1">
    <enterprise-beans>
        <session>
            <description>
                A Web Service reservation service
            </description>
            <ejb-name>TravelAgentEjbEndpoint</ejb-name>
                     <service-endpoint>
                     com.titan.webservice.TravelAgentEndpoint
                     </service-endpoint>
                     <ejb-class>
                     com.titan.webservice.TravelAgentBean
                     </ejb-class>
                     <session-type>Stateless</session-type>
                     <transaction-type>Container</transaction-type>
            <ejb-ref>
                <ejb-ref-name>ejb/ProcessPaymentHomeRemote</ejb-ref-name>
                <ejb-ref-type>Session</ejb-ref-type>
                <home>com.titan.processpayment.ProcessPaymentHomeRemote</home>
                <remote>com.titan.processpayment.ProcessPaymentRemote</remote>
            </ejb-ref>
            ...
        </session>
        ...
    </enterprise-beans>
    <assembly-descriptor>
        ...
    </assembly-descriptor>
</ejb-jar>

The value for the <ejb-name> element can be anything you choose; in this book, we use the suffix “Endpoint” to denote an EJB endpoint component.

You cannot declare the transaction attribute of any method of an endpoint as mandatory , because doing so implies that the Enterprise Bean method must be enrolled in the calling client’s transaction. Since transaction propagation is not standardized in web services, it’s assumed that the client will not be propagating a transaction.

WSDL file

The WSDL file used to generate the endpoint interface must be packaged with the EJB endpoint. Normally, the WSDL document is placed in the META-INF directory of the JAR file, but it can go anywhere as long as it’s in the same JAR file as the EJB endpoint.

JAX-RPC mapping file

EJB endpoints, like JAX-RPC generated stubs, require you to define a JAX-RPC mapping file. The mapping file can have any name, but it should be descriptive, and the file type should be XML. It’s common to name this file mapping.xml or travelagent_mapping.xml, or something along those lines. Here’s a lightweight JAX-RPC mapping file for the TravelAgent endpoint:

<?xml version='1.0' encoding='UTF-8' ?>
<java-wsdl-mapping
  xmlns="http://java.sun.com/xml/ns/j2ee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
               http://www.ibm.com/webservices/xsd/j2ee_jaxrpc_mapping_1_1.xsd"
  version="1.1">
  <package-mapping>
    <package-type>com.titan.webservice</package-type>
                         <namespaceURI>http://www.titan.com/TravelAgent</namespaceURI>
  </package-mapping>
</java-wsdl-mapping>

The JAX-RPC mapping file was covered earlier in this chapter, in the section entitled “The JAX-RPC Mapping File.” Basically, this deployment descriptor maps a Java package to the XML Namespace of the WSDL <port> and other elements, helping the container to understand which packaged classes are associated with which WSDL definitions.

webservices.xml file

The webservices.xml file is the baling wire that ties the separate deployment files together. It defines the relationships between the ejb-jar.xml, the WSDL file, and the JAX-RPC mapping file:

<?xml version='1.0' encoding='UTF-8' ?>
<webservices 
   xmlns="http://java.sun.com/xml/ns/j2ee"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns:titan="http://www.titan.com/TravelAgent"
   xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
                 http://www.ibm.com/webservices/xsd/j2ee_web_services_1_1.xsd"
   version="1.1">

      <webservice-description>
         <webservice-description-name>TravelAgentService
         </webservice-description-name>
         <wsdl-file>/META-INF/travelagent.wsdl</wsdl-file>
         <jaxrpc-mapping-file>/META-INF/travelagent_mapping.xml
         </jaxrpc-mapping-file>
         <port-component>
            <port-component-name>TravelAgentEndpoint</port-component-name>
            <wsdl-port>titan:TravelAgentPort</wsdl-port>
            <service-endpoint-interface>
               com.titan.webservice.TravelAgentEndpoint
            </service-endpoint-interface>
            <service-impl-bean>
               <ejb-link>TravelAgentEjbEndpoint</ejb-link>
            </service-impl-bean>
         </port-component>
      </webservice-description>
</webservices>

The <webservice-description> element describes an EJB endpoint: there may be one or more of these elements in a single webservices.xml file.[46] The <webservice-description-name> is a unique name assigned to the web service description. It can be anything you like. The <wsdl-file> element points to the WSDL document of the EJB endpoint. Each EJB endpoint has exactly one WSDL document, which is usually located in the META-INF directory of the EJB-JAR file. When the EJB endpoint is deployed, your deployment tool will probably provide you with the option of copying the WSDL document to some type of public URL or registry so that others can discover the web service. The <jaxrpc-mapping-file> element indicates the location of the JAX-RPC mapping file that is associated with the EJB endpoint and the WSDL document. It, too, is usually located in the META-INF directory of the EJB JAR file.

The <port-component> element maps a stateless session bean declared in the ejb-jar.xml file to a specific <port> in the WSDL document. The <port-component-name> is the logical name you assign the EJB endpoint. It can be anything. The <wsdl-port> element maps the EJB endpoint deployment information to a specific WSDL <port> element in the WSDL document. The <service-endpoint-interface> is the fully qualified name of the endpoint interface—it must be the same interface declared by the <service-endpoint> element for the EJB in the ejb-jar.xml file. The <service-impl-bean> and its <ejb-link> element link the <port-component> to a specific EJB in the ejb-jar.xml. The value of the <ejb-link> must match the value of the <ejb-name> in the ejb-jar.xml file.



[46] The <webservice-description> element can also describe a JAX-RPC service endpoint, which is a servlet-based web service that is outside the scope of this book.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.145.174.253