Chapter 5. J2EE Web Services

From the start, web services have promised genuine interoperability by transmitting XML data using platform and language-independent protocols such as SOAP over HTTP. While the early days of multiple competing standards and general developer confusion may have made this more of a dream than a reality, web services have matured and standardized enough to have been incorporated into the J2EE 1.4 specification.

Keeping with the spirit of this guide, we'll assume you have some experience with web services already. If you don't, we would recommend you do some reading in advance. A good place to start would be on the JBoss wiki, which covers web services on JBoss in more depth. We also recommend J2EE Web Services by Richard Monson-Haefel for more general coverage of J2EE web services.

5.1. Web services in JBoss

JBossWS is the JBoss module responsible for providing web services in JBoss 4.0, replacing the previous JBoss.NET package. Like its predecessor, it is also based on Apache Axis ( However, JBossWS provides the complete set of J2EE 1.4 web services technologies, including SOAP, SAAJ, JAX-RPC and JAXR.

J2EE web services provides for two types of endpoints. If you think of a web service as a platform-independent invocation layer, then the endpoint is the object you are exposing the operations of and invoking operations on. Naturally, J2EE web services support exposing EJBs as web services, but only stateless session beans can be used. That makes sense given the stateless nature of web services requests. Additionally, J2EE web services provide for JAX-RPC service endpoints, (JSEs) which are nothing more than simple Java classes. We'll only be working with EJB endpoints in this example.

5.2. Duke’s Bank as a Web Service

We'll continue working with the Duke's Bank application from Chapter 4, The Duke’s Bank Application and create a simple web service for querying accounts and balances. The AccountController session bean provides this functionality to the Duke's Bank web application. Unfortunately the application uses stateful session beans as its external interface, so we can't expose the AccountController session bean directly. Instead, we'll create a new stateless session bean, the TellerBean, which will provide a more suitable web service endpoint.

Before we start, make sure that you have built and deployed Duke's Bank according to the instructions in Chapter 4, The Duke’s Bank Application. As with that example, we'll be working from the examples/bank directory. Although TellerBean will have already been compiled when you deployed Duke's Bank, you'll need to remember to invoke the compile target to compile any changes you might make.

ant -f jboss-build.xml compile

The magic of J2EE is in the deployment descriptors. We've seen how to deploy session beans already. Deploying a session bean as a web service is as simple as adding a service-endpoint element to the session bean definition in ejb-jar.xml. The service-endpoint specifies the class that provides the interface corresponding to the methods on the session bean being exposed as a web service.


You might have noticed that we didn't declare a home or remote interface for TellerBean. If your session bean is only accessed by the web services interface, you don't need one, so we've left them out here. Instead, we've declared the TellerEndpoint class as our endpoint interface. Our web service interface exposes two operations, both of which map onto the equivalent methods on TellerBean.

public interface TellerEndpoint
    extends Remote
    public AccountList getAccountsOfCustomer(String customerId)
        throws RemoteException;

    public BigDecimal getAccountBalance(String accountID)
        throws RemoteException;

The required web services deployment descriptors (WSDL file, JAX-RPC mapping file, webservices deployment descriptor) can be generated using the wstools generator that comes with JBossWS. The wstools target runs the generator.

ant -f jboss-build.xml wstools

The wstools program uses the wstools-config.xml file to guide the generation project.

<configuration xmlns="">
        <service name="TellerService" style="rpc" endpoint="com.jboss.ebank.TellerEndpoint"/>
        <namespaces target-namespace=""
        <mapping file="jaxrpc-mapping.xml"/>
        <webservices ejb-link="TellerBean"/>

The following artificats are generated by this configuration.

  • TellerService.wsdl: This is the WSDL definition that describes the web service. Some values, like the SOAP address, will be filled in at runtime by JBossWS.

  • jaxrpc-mapping.xml: This mapping file describes the mapping between the WSDL types and the underlying Java implementation. Since the client program happens to use the same Java classes, we will re-use this file for the client-side mappings.

  • webservices.xml: This file declares the webservice. It links the endpoint to a server-side component (in this case a session bean) and points to the location of the related deployment files.

This web service is a simple session bean, so deploying it only requires us to package up the bean and the associated deployment descriptors into an EJB JAR file. The package-ws task accomplishes this, and the deploy-ws target deploys the EJB JAR to JBoss.

ant -f jboss-build.xml package-ws
ant -f jboss-build.xml deploy-ws

Once the service is deployed you can view the WSDL (Web Service Description Language) for it by browsing to the URL http://localhost:8080/bankws-ejb/TellerService?wsdl. In this example we generate the WSDL, but it would also have been possible to write the WSDL for the service by hand and then generate a Java endpoint interface for it using wsdl2java, which is also provided with JBossWS.

5.3. Running the Web Service Client

We’ve also supplied a Java client which accesses the web service from a non-J2EE environment.

public class WSClient {
    public static void main(String[] args) 
        throws Exception 
        URL url = 
            new URL("http://localhost:8080/bankws-ejb/TellerBean?wsdl");

        QName qname = new QName("",

        File mapping = new File("dd/ws/jaxrpc-mapping.xml");
        ServiceFactoryImpl factory = new ServiceFactoryImpl();
        Service            service = factory.createService(url, qname, mapping.toURL());

        TellerEndpoint endpoint = (TellerEndpoint)

        String customer = "200";
        System.out.println("Customer: " + customer);
        AccountList accounts = endpoint.getAccountsOfCustomer(customer);
        String[]    ids      = accounts.getAccounts();
        for (int i=0; i<ids.length; i++) {
            System.out.println("account[" + ids[i] +  "]  " + 

The client can be run using the run-ws target.

ant -f jboss-build.xml run-ws

The client will display the balance for each account belonging to the given customer.

     [java] Customer: 200
     [java] account[5005]  3300.00
     [java] account[5006]  2458.32
     [java] account[5007]  220.03
     [java] account[5008]  59601.35

5.4. Monitoring webservices requests

When processing web services requests, it is often useful to be able and observe the actual messages being passed between the client and the server. JBossWS logs this information in the category. To enable web services logging, add the following debug category to the log4j.xml file:

<category name="">
    <priority value="DEBUG"/>

When enabled, all SOAP requests and responses will be logged to the server.log file. Here is a log of a call to the getAccountsOfCustomer method.

2005-05-16 17:50:43,479 DEBUG [org.jboss.axis.transport.http.AxisServlet] 
<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv=""
  <ns1:getAccountsOfCustomer xmlns:ns1="">
...2006-05-23 14:51:51,710 DEBUG [] Outgoing SOAPMessage
<env:Envelope xmlns:env=''>
  <ns1:getAccountsOfCustomerResponse xmlns:ns1=''>
   <result xmlns:xsi=''>