JBossWS - JAX-RPC User Guide

Since 1.2 (Native)


After JBoss Application Server 4.0 J2EE-1.4 certification we have decided to develop our own JAXRPC SOAP stack that fits better in the overall JBoss architecture and is generally more suiteable for the specific J2EE requirements for web services. JBossWS is our new implementation of web services. This document describes the JAX-RPC feature set and its usage.

In this guide we cover JAX-RPC functionality only, if you are looking for JAX-WS web services please goto the JAX-WS User Guide.

To get started you need to download jbossws and install JBossWS on your preferred target container.

This user guide applies to jbossws-1.2.0 and higher. For older versions, please consult the     JBossWS User Guide on JBoss.ORG.

 

Features

  • RPC style and Document style endpoints (wrapped and bare)
  • SOAP header values bound/unbound to endpoint parameters
  • J2EE endpoint development model for EJB and Java (JSR-109)
  • J2EE client development model (JSR-109)
  • Dynamic Invocation Interface (DII)
  • JAX-RPC client/server side handlers
  • Holders for INOUT/OUT parameters
  • Message style endpoints
  • Attachments Profile Version 1.0
  • Dynamic client/server side handler injection
  • WS-Security1.0 for XML Encryption/Signature of the SOAP message
  • WS-Addressing (W3C candidate release) and JSR-261
  • MTOM/XOP for optimized binary transport

Installation

Please refer to Installation for details.

Getting started

In order to get started we will begin with some simple endpoint implementations. This chapter will walk you through the standard J2EE 1.4 development model and explore the different style/use models to bind your endpoint implementations. A WSDL binding describes how the service is bound to a messaging protocol, particularly the SOAP messaging protocol. JBossWS conforms to the WS-I basic profile, which eliminates the encoded use. This leaves you with the following style/use models:

  • RPC/Literal
  • Document/Literal
  • Message style

Let's begin with a simple RPC web service endpoint implementation.

Simple RPC Style Endpoint

With RPC there is a wrapper element that names the endpoint operation. Child elements of the RPC parent are the individual parameters. The SOAP body is constructed based on some simple rules:

  • The port type operation name defines the endpoint method name
  • Message parts are are endpoint method parameters

This chapter describes portable J2EE-1.4 web service endpoint development model for plain java endpoints.

Let's start with a trivial service endpoint interface (SEI) that has a single operation, which takes two string parameters and returns a string.

  public interface TrivialService extends Remote
  {
     String purchase (String person, String product) throws RemoteException;
  }

There are certain rules you have to follow for a valid SEI.

  • The SEI must extend java.rmi.Remote
  • All methods must include java.rmi.RemoteException in their throws clause
  • Method parameter types are limited to the ones specified by the JAXRPC-1.1 specification

The endpoint implementation bean

The SEI defines the java contract of the web service. You will also need to provide an implementation bean. Here it is

 public class TrivialEndpointJSE implements TrivialService
 {
    public String purchase (String person, String product)
    {
       log.info("purchase: " + person + "," + product);
       return "ok" + person + product;
    }
 }

Generating required deployment artifacts

JSR-109 requires a number of deployment artifacts, which are:

  • webservices.xml, the descriptor that identifies a deployment a web service endpoint
  • wsdl, the abstract webservice contract
  • jaxrpc-mapping.xml, the mapping desriptor that bridges WSDL to java

JBossWS comes with a tool collection called WSTools. WSTools that can generate these artifacts from the given SEI. There is a command line version and an Apache Ant task available. Both take a configuration file as input. For details of the wstools configuration, see #Apendix A

  <configuration ...>
    <java-wsdl>
      <service name="SampleService" style="rpc" 
        endpoint="org.jboss.test.ws.jaxrpc.samples.rpcstyle.TrivialService"/>
    
      <namespaces target-namespace="http://org.jboss.ws/samples/rpcstyle" 
        type-namespace="http://org.jboss.ws/samples/rpcstyle/types"/>
    
      <mapping file="jaxrpc-mapping.xml"/>
      <webservices servlet-link="TrivialEndpoint"/>
    </java-wsdl>
  </configuration>      

You can run WSTools from the command line

   > jboss-inst/bin/wstools.sh -cp {path to TrivialService.class} -config wstools-config.xml

or from an ant task

    <!-- Define a taskdef for the wstools ant task -->
    <taskdef name="wstools" classname="org.jboss.ws.tools.ant.wstools">
      <classpath refid="library.classpath"/>
      <classpath refid="test.client.classpath"/>
      <classpath path="${build.test.classes.dir}"/>
    </taskdef>
    
    <!-- samples/rpcstyle -->
    <wstools dest="${build.wstools.resources.dir}/samples/rpcstyle/WEB-INF" 
      config="${test.resources.dir}/samples/rpcstyle/wstools-config.xml"/>

The endpoint as a web application

A java service endpoint is deployed as a web application.

    <web-app 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/web-app_2_4.xsd" 
      version="2.4">
    
      <servlet>
        <servlet-name>TrivialEndpoint</servlet-name>
 (1)     <servlet-class>org.jboss.test.ws.jaxrpc.samples.rpcstyle.TrivialEndpointJSE</servlet-class>
      </servlet>
    
      <servlet-mapping>
        <servlet-name>TrivialEndpoint</servlet-name>
        <url-pattern>/*</url-pattern>
      </servlet-mapping>
    
    </web-app>

Note

The content of <servlet-class> element is not at all a servlet as required by the servlet spec. It is the endpoint implementation bean that is shown above.

Packaging the endpoint

A JSR-109 java service endpoint (JSE) is packaged as a web application in a *.war file. Note, that all descriptors are located in the WEB-INF directory with the WSDL in a predefined subdirectory.

    <war warfile="${build.dir}/libs/jbossws-samples-rpcstyle.war" 
          webxml="${build.resources.dir}/samples/rpcstyle/WEB-INF/web.xml">
      <classes dir="${build.dir}/classes">
        <include name="org/jboss/test/ws/samples/rpcstyle/TrivialEndpointJSE.class"/>
        <include name="org/jboss/test/ws/samples/rpcstyle/TrivialService.class"/>
      </classes>
      <webinf dir="${build.resources.dir}/samples/rpcstyle/WEB-INF">
        <include name="jaxrpc-mapping.xml"/>
        <include name="webservices.xml"/>
        <include name="wsdl/**"/>
      </webinf>
    </war>

How a J2EE-1.4 portable web service client connects to the endpoint is described in #JSR-109 Client Proxies

SOAP message exchange

Below you see the SOAP messages that are beeing exchanged.

Incomming SOAPMessage

    <env:Envelope xmlns:env='http://schemas.xmlsoap.org/soap/envelope/'>
     <env:Header/>
     <env:Body>
      <ns1:purchase xmlns:ns1='http://org.jboss.ws/samples/rpcstyle'>
       <String_1>Kermit</String_1>
       <String_2>Ferrari</String_2>
      </ns1:purchase>
     </env:Body>
    </env:Envelope>

 

Outgoing SOAPMessage

    <env:Envelope xmlns:env='http://schemas.xmlsoap.org/soap/envelope/'>
     <env:Header/>
     <env:Body>
      <ns1:purchaseResponse xmlns:ns1='http://org.jboss.ws/samples/rpcstyle'>
       <result>okKermitFerrari</result>
      </ns1:purchaseResponse>
     </env:Body>
    </env:Envelope>

Document Style Endpoints

With document style web services two business partners agree on the exchange of complex business documents that are well defined in XML schema. For example, one party sends a document describing a purchase order, the other responds (immediately or later) with a document that describes the status of the purchase order. No need to agree on such low level details as operation names and their associated parameters.

The payload of the SOAP message is an XML document that can be validated against XML schema. No wrapping RPC element, no individual parameters.

In chapter we develop a document/literal wrapped service endpoint that uses the same service endpoint interface (SEI) as for the #Simple RPC Style Endpoint example.

   public interface TrivialService extends Remote
   {
      String purchase (String person, String product) throws RemoteException;
   }

Generating required deployment artifacts

Run wstools on a document/literal configuration

The wsdlStyle attribute is set to 'document'

  <configuration ...>
    <java-wsdl>
      <service name="SampleService" style="document" 
        endpoint="org.jboss.test.ws.jaxrpc.samples.docstyle.wrapped.TrivialService" />
    
      <namespaces target-namespace="http://org.jboss.ws/samples/docstyle/wrapped" 
         type-namespace="http://org.jboss.ws/samples/docstyle/wrapped/types"/>
    
      <mapping file="jaxrpc-mapping.xml"/>
      <webservices servlet-link="TrivialEndpoint"/>
    </java-wsdl>
  </configuration>

The generated WSDL contains complex type definitions for the request/response payloads, which are referenced from the WSDL messages

      <complexType name="purchase">
        <sequence>
          <element name="String_1" type="string" nillable="true"/>
          <element name="String_2" type="string" nillable="true"/>
        </sequence>
      </complexType>
    
      <complexType name="purchaseResponse">
        <sequence>
          <element name="result" type="string" nillable="true"/>
        </sequence>
      </complexType>

WSTools also generates request/response java objects that correspond to these schema types. These java wrapper beans are mapped in jaxrpc-mapping.xml

    <java-xml-type-mapping>
      <java-type>
        org.jboss.test.ws.jaxrpc.samples.docstyle.wrapped.TrivialService_purchase_RequestStruct
      </java-type>
      <root-type-qname xmlns:typeNS="http://org.jboss.ws/samples/docstyle/wrapped/types">
        typeNS:purchase
      </root-type-qname>
      <qname-scope>complexType</qname-scope>
      <variable-mapping>
        <java-variable-name>String_1</java-variable-name>
        <xml-element-name>String_1</xml-element-name>
      </variable-mapping>
      <variable-mapping>
        <java-variable-name>String_2</java-variable-name>
        <xml-element-name>String_2</xml-element-name>
      </variable-mapping>
    </java-xml-type-mapping>
    
    <java-xml-type-mapping>
      <java-type>
        org.jboss.test.ws.jaxrpc.samples.docstyle.wrapped.TrivialService_purchase_ResponseStruct
      </java-type>
      <root-type-qname xmlns:typeNS="http://org.jboss.ws/samples/docstyle/wrapped/types">
        typeNS:purchaseResponse
      </root-type-qname>
      <qname-scope>complexType</qname-scope>
      <variable-mapping>
        <java-variable-name>result</java-variable-name>
        <xml-element-name>result</xml-element-name>
      </variable-mapping>
    </java-xml-type-mapping>

SOAP message exchange

Below you see the SOAP messages that are beeing exchanged.

Incomming SOAPMessage

    <env:Envelope xmlns:env='http://schemas.xmlsoap.org/soap/envelope/'>
     <env:Header/>
     <env:Body>
      <ns1:purchase xmlns:ns1='http://org.jboss.ws/samples/docstyle/wrapped/types'>
       <String_1>Kermit</String_1>
       <String_2>Ferrari</String_2>
      </ns1:purchase>
     </env:Body>
    </env:Envelope>

 

Outgoing SOAPMessage

    <env:Envelope xmlns:env='http://schemas.xmlsoap.org/soap/envelope/'>
     <env:Header/>
     <env:Body>
      <ns1:purchaseResponse xmlns:ns1='http://org.jboss.ws/samples/docstyle/wrapped/types'>
       <result>okKermitFerrari</result>
      </ns1:purchaseResponse>
     </env:Body>
    </env:Envelope>

 

On the wire the message structure is no different to rpc/literal.

Document Bare Endpoints

What we have seen above is a document/literal (wrapped) endpoint. The endpoint operation paramters and return are automatically wrapped in request/response structures. The SEI methods deal with the individual properties from these request/response structures.

Whith document/literal (bare), the SEI methods deal directly with the request/response structures.

   public interface TrivialService extends Remote
   {
      TrivialOrderResponse purchase(TrivialOrder order) throws RemoteException;
   }

Run wstools with the following configuration

  <configuration ...>
    <java-wsdl>
      <service name="SampleService" style="document" parameter-style="bare" 
        endpoint="org.jboss.test.ws.samples.docstyle.bare.TrivialService" />
    
      <namespaces target-namespace="http://org.jboss.ws/samples/docstyle/bare" 
        type-namespace="http://org.jboss.ws/samples/docstyle/bare/types"/>
    
      <mapping file="jaxrpc-mapping.xml"/>
      <webservices servlet-link="TrivialEndpoint"/>
    </java-wsdl>
  </configuration>

SOAP message exchange

Below you see the SOAP messages that are beeing exchanged.

Incomming SOAPMessage

    <env:Envelope xmlns:env='http://schemas.xmlsoap.org/soap/envelope/'>
     <env:Header/>
     <env:Body>
      <ns1:purchase xmlns:ns1='http://org.jboss.ws/samples/docstyle/bare/types'>
       <person>Kermit</person>
       <product>Ferrari</product>
      </ns1:purchase>
     </env:Body>
    </env:Envelope>

 

Outgoing SOAPMessage

    <env:Envelope xmlns:env='http://schemas.xmlsoap.org/soap/envelope/'>
     <env:Header/>
     <env:Body>
      <ns1:purchaseResponse xmlns:ns1='http://org.jboss.ws/samples/docstyle/bare/types'>
       <result>okKermitFerrari</result>
      </ns1:purchaseResponse>
     </env:Body>
    </env:Envelope>

 

On the wire the message structure is no different to document/literal wrapped. That the implementation deals with the wrapper beans directly is an implementation detail.

 

Message Style Endpoints

You may come to the point where RPC/Literal or Document/Literal is not what you are looking for. This may be the case for instance, when you want to do the XML processing yourself instead of deferring it to the SOAP stack. JBossWS offers the possiblity to setup message style endpoints that do exchange raw XML documents mapped to DOM elements or SOAPElements,

This chapter describes a generic endpoint that can process arbitrary DOM elements.

Note

In the JAX-RPC specification this is not a permitted java type. JBossWS extends the standard type support by DOM Element and SOAPElement.

   public interface MessageTestService extends Remote
   {
      public Element processElement(Element msg) throws RemoteException;
   }

Generating required deployment artifacts

Run wstools with the following configuration

  <configuration ...>
    <java-wsdl>
      <service name="MessageService" style="document" parameter-style="bare" 
        endpoint="org.jboss.test.ws.jaxrpc.samples.message.MessageTestService">
        <operation name="processElement" return-xml-name="Response">
          <parameter type="javax.xml.soap.SOAPElement" xml-name="Order"/>
        </operation>
      </service>
      <namespaces target-namespace="http://org.jboss.ws/samples/message" 
        type-namespace="http://org.jboss.ws/samples/message/types"/>
      <mapping file="jaxrpc-mapping.xml"/>
      <webservices servlet-link="TestService"/>
    </java-wsdl>
  </configuration>

WSTools generates schema elements with xsd:anyType

    <schema targetNamespace="http://org.jboss.ws/samples/message" ...>
      <element name="Order" type="anyType"/>
      <element name="Response" type="anyType"/>
    </schema>
    
    <message name="Message_processElement">
      <part name="order" element="tns:Order"/>
    </message>
    
    <message name="Message_processElementResponse">
      <part name="result" element="tns:Response"/>
    </message>

Web Service Endpoints

In the previous chapter we have seen how to package and deploy simple endpoints that were all based on POJO implementations. If you really want to leverage J2EE technologies it might be more appropriate to use EJB endpoint implementations. In this chapter we will use EJB-2.1 stateless session beans as web service endpoints. To expose an EJB3 stateless session bean using JAX-WS annotations have a look at the JAX-WS User Guide.

JSR-109 promotes building portable web services in the J2EE 1.4 environment. It leverages J2EE technologies to provide a standard for developing and deploying web services on the J2EE platform.

 

JSR-109 POJO Endpoint

This chapter uses a more complex service endpoint interface (SEI) as in #Document Style Endpoints. It contains a user defined type as one of the opertion parameters.

   public interface JaxRpcTestService extends Remote
   {
      String echoString(String str1, String str2) throws RemoteException;
   
      SimpleUserType echoSimpleUserType(String str1, SimpleUserType msg) throws RemoteException;
   }

Generating required deployment artifacts

Run wstools with the following configuration

  <configuration ...>
    <java-wsdl>
      <service name="TestService" style="rpc" 
        endpoint="org.jboss.test.ws.jaxrpc.samples.jsr109pojo.JaxRpcTestService"/>

      <namespaces target-namespace="http://org.jboss.ws/samples/jsr109pojo" 
        type-namespace="http://org.jboss.ws/samples/jsr109pojo/types"/>

      <mapping file="jaxrpc-mapping.xml"/>
      <webservices servlet-link="TestService"/>
    </java-wsdl>
  </configuration>

WSTools generates request/response java objects that correspond to these schema types and that are mapped in jaxrpc-mapping.xml.

SOAP message exchange

Incomming SOAPMessage

    <env:Envelope xmlns:env='http://schemas.xmlsoap.org/soap/envelope/'>
     <env:Header/>
     <env:Body>
      <ns1:echoSimpleUserType xmlns:ns1='http://org.jboss.ws/samples/jsr109pojo'>
       <String_1>Hello</String_1>
       <SimpleUserType_2>
        <a>1</a>
        <b>2</b>
       </SimpleUserType_2>
      </ns1:echoSimpleUserType>
     </env:Body>
    </env:Envelope>

Outgoing SOAPMessage

    <env:Envelope xmlns:env='http://schemas.xmlsoap.org/soap/envelope/'>
     <env:Header/>
     <env:Body>
      <ns1:echoSimpleUserTypeResponse xmlns:ns1='http://org.jboss.ws/samples/jsr109pojo'>
       <result>
        <a>1</a>
        <b>2</b>
       </result>
      </ns1:echoSimpleUserTypeResponse>
     </env:Body>
    </env:Envelope>

JSR-109 EJB Endpoint

This chapter uses the same service endpoint interface (SEI) as in #JSR-109 POJO Endpoint.

   public interface JaxRpcTestService extends Remote
   {
      String echoString(String str1, String str2) throws RemoteException;
   
      SimpleUserType echoSimpleUserType(String str1, SimpleUserType msg) throws RemoteException;
   }

Generating required deployment artifacts

Run wstools with the following configuration

  <configuration ...>
    <java-wsdl>
      <service name="TestService" style="rpc" 
        endpoint="org.jboss.test.ws.jaxrpc.samples.jsr109ejb.JaxRpcTestService"/>
    
      <namespaces target-namespace="http://org.jboss.ws/samples/jsr109ejb" 
        type-namespace="http://org.jboss.ws/samples/jsr109ejb/types"/>
    
      <mapping file="jaxrpc-mapping.xml"/>
      <webservices ejb-link="TestService"/>
    </java-wsdl>
  </configuration>
    

The EJB deployment descriptor

The attribute value for ejbLink element corresponds to ejb-name given in ejb-jar.xml. In this example, the stateless session bean (SLSB) is only exposed as a service endpoint, it does not have a Home nor Remote interface

    <enterprise-beans>
      <session>
        <ejb-name>TestService</ejb-name>
 (1)    <service-endpoint>
            org.jboss.test.ws.jaxrpc.samples.jsr109ejb.JaxRpcTestService
         </service-endpoint>
 (2)     <ejb-class>org.jboss.test.ws.jaxrpc.samples.jsr109ejb.JaxRpcEJBEndpoint</ejb-class>
        <session-type>Stateless</session-type>
        <transaction-type>Container</transaction-type>
      </session>
    </enterprise-beans>
  1. Exposing an SEI as a webservice endpoint
  2. The SLSB endpoint implementation

ServiceLifecycle and MessageContext

Adding Service Lifecycle

Your POJO endpoint may implement javax.xml.rpc.server.ServiceLifecycle to obtain access to the javax.xml.rpc.server.ServletEndpointContext int the init() method.

The ServletEndpointContext provides an endpoint context maintained by the underlying servlet container based JAX-RPC runtime system. For service endpoints deployed on a servlet container based JAX-RPC runtime system, the context parameter in the ServiceLifecycle.init method is required to be of the Java type javax.xml.rpc.server.ServletEndpointContext.

A servlet container based JAX-RPC runtime system implements the ServletEndpointContext interface. The JAX-RPC runtime system is required to provide appropriate session, message context, servlet context and user principal information per method invocation on the endpoint class.

   public class JaxRpcJSEEndpoint implements JaxRpcTestService, ServiceLifecycle
   {
      private ServletEndpointContext context;
   
      public String echoString(String str1, String str2)
      {
         log.info("echoString: " + str1 + "," + str2);
         log.info("userPricipal: " + context.getUserPrincipal());
         return str1 + str2;
      }
   
      public void init(Object context) throws ServiceException
      {
         this.context = (ServletEndpointContext)context;
      }
   
      public void destroy()
      {
      }
   }

Currently, POJO endpoints are not pooled like their EJB counterparts. As a consequence and because WS4EE endpoints are essentially stateless, you will get a new instance of the endpoint implementation bean for every request. For stateful behaviour see #WS-Addressing.

 

Endpoint configuration

Configuration templates provide a convenient way to setup a handler configuration for JBossWS endpoints. A configuration basically includes a list of handlers that are registered with a web service endpoint upon deployment. For details see #Headers & Handlers

<jbossws-config xmlns="urn:jboss:jbossws-config:5.0"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:j2ee="http://java.sun.com/xml/ns/j2ee"
  xsi:schemaLocation="urn:jboss:jbossws-config:5.0 http://www.jboss.com/xml/jbossws-config_1_0.xsd">

  <endpoint-config>
    <config-name>Standard Endpoint</config-name>
  </endpoint-config>

  <endpoint-config>
    <config-name>Standard Secure Endpoint</config-name>
    <pre-handler-chain>
      <handler-chain-name>PreHandlerChain</handler-chain-name>
      <handler>
        <j2ee:handler-name>WSSecurityHandlerInbound</j2ee:handler-name>
        <j2ee:handler-class>org.jboss.ws.extensions.security.jaxrpc.WSSecurityHandlerInbound</j2ee:handler-class>
      </handler>
    </pre-handler-chain>
   </endpoint-config>
</jbossws-config>

These template configurations can be referenced from any jboss specific deplyoment descriptor, i.e:

   <jboss-client>
     <jndi-name>jbossws-client</jndi-name>

     <service-ref>
       <service-ref-name>service/HelloService</service-ref-name>
       <config-name>Standard Secure Client</config-name>
       <wsdl-override>http://@jbosstest.host.name@:8080/jbossws-samples-wssecurity-encrypt?wsdl</wsdl-override>
     </service-ref>
   </jboss-client>

Note

This is a proprietary configuration mechanism. In order to stay portable it's recommended to use the default JAXRPC handler configuration.

Configuration reference from web.xml

Within web.xml the same approach can be taken.

<web-app ...>

  <context-param>
 (1) <param-name>jbossws-config-name</param-name>>
 (2) <param-value>Standard Secure Endpoint</param-value>
  </context-param>

  <servlet>
    <servlet-name>HelloService</servlet-name>
    <servlet-class>org.jboss.test.ws.jaxrpc.samples.wssecurity.HelloJavaBean</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>HelloService</servlet-name>
    <url-pattern>/*</url-pattern>
  </servlet-mapping>
</web-app>
  1. predefined servlet context parameter
  2. chosen endpoint config

 

Web Services Clients

Client Proxies

A web service client connecting to an endpoint

The web service client programming model for J2EE is about accessing a remote web service from a J2EE component. Please remember that with web services the client and the server are fundamentally disconnected. There are server side issues and client side issues. In other words, if you setup a web service endpoint any client that adheres to the abstract contract in WSDL can talk to that endpoint.

If you want to implement a WS client using JBossWS (to what server impl it talks to does not matter) you use wstools to generate the required artifacts from WSDL. The artifacts are

  • Required Service Endpoint Interface (SEI)
  • Optional User Types
  • Optional User Exceptions
  • Required WSDL/Java mapping meta data (jaxrpc-mapping.xml)

Here a wstools config file that generates the client side artifacts from WSDL

    <configuration ...>
      <wsdl-java location="resources/samples/jsr181pojo/META-INF/wsdl/TestService.wsdl">
        <mapping file="jaxrpc-mapping.xml" />
      </wsdl-java>
    </configuration>

This chapter uses a J2EE-1.4 client, but for all intents and purposes, this could also be a Servlet, JSP, or EJB component. All of these J2EE components support <service-ref> elements in their respective deployment descriptor.

The J2EE client deployment model has many advantages over dynamic invocation (DII). Most Java applications (except the most trivial ones) have a need for registry lookup (JNDI) and management (JMX). A very minimal jboss configuration has a tiny footprint and provides just that. Therefore, running your client app on jboss and mangage it through JMX and have a layer of indirection for resource lookup through JNDI is recommended pratice. Additionally, you can leverage the J2EE 1.4 client programming model and obtain preconfigured web service clients from JNDI.

    <service-ref>
      <service-ref-name>service/TrivialService</service-ref-name>
      <service-interface>javax.xml.rpc.Service</service-interface>
      <wsdl-file>META-INF/wsdl/SampleService.wsdl</wsdl-file>
      <jaxrpc-mapping-file>META-INF/jaxrpc-mapping.xml</jaxrpc-mapping-file>
      <port-component-ref>
        <service-endpoint-interface>org.jboss.test.ws.jaxrpc.samples.rpcstyle.TrivialService</service-endpoint-interface>
      </port-component-ref>
    </service-ref>
      

With the configuration given above, the SampleService.wsdl must contain the correct SOAP target address. JBoss provides an override mechanism for the WSDL in jboss-client.xml.

    <jboss-client>
      <jndi-name>jbossws-client</jndi-name>
      <service-ref>
        <service-ref-name>service/TrivialService</service-ref-name>
        <wsdl-override>http://jbosstesthost:8080/jbossws-samples-rpcstyle?wsdl</wsdl-override>
      </service-ref>
    </jboss-client>

When the WSDL is obtained from the server, the server has already performed all the necessary address rewrites

Once the J2EE application client jar is deployed on a JBoss instance, it can be accessed by a separate standalone Java process.

    public void testTrivialAccess() throws Exception
    {
       InitialContext iniCtx = getInitialContext();
       Service service = (Service)iniCtx.lookup("java:comp/env/service/TrivialService");
       TrivialService port = (TrivialService)service.getPort(TrivialService.class);
       String person = "Kermit";
       String product = "Ferrari";
       String status = port.purchase(person, product);
       assertEquals("ok" + person + product, status);
    }
   
    protected InitialContext getInitialContext() throws NamingException
    {
       InitialContext iniCtx = new InitialContext();
       Hashtable env = iniCtx.getEnvironment();
       env.put(Context.URL_PKG_PREFIXES, "org.jboss.naming.client");
       env.put("j2ee.clientName", "jbossws-client");
       return new InitialContext(env);
    }

Stub properties

Standard JAXRPC Stub properties

   /** User name for authentication. */
   public static final String USERNAME_PROPERTY = "javax.xml.rpc.security.auth.username";
    
   /** Password for authentication. */
   public static final String PASSWORD_PROPERTY = "javax.xml.rpc.security.auth.password";
    
   /** Target service endpoint address.  */
   public static final String ENDPOINT_ADDRESS_PROPERTY = "javax.xml.rpc.service.endpoint.address";
    
   /** 
    This boolean property is used by a service client to indicate 
    whether or not it wants to participate in a session with a service endpoint. 
   */
   public static final String SESSION_MAINTAIN_PROPERTY = "javax.xml.rpc.session.maintain";

JBossWS propriatary Stub properties

The propriatary properties are defined in org.jboss.ws.core.StubExt

   /** ClientTimeout property: org.jboss.ws.timeout */
   static final String PROPERTY_CLIENT_TIMEOUT = "org.jboss.ws.timeout";

   /** KeyStore property: org.jboss.ws.keyStore */
   static final String PROPERTY_KEY_STORE = "org.jboss.ws.keyStore";

   /** KeyStorePassword property: org.jboss.ws.keyStorePassword */
   static final String PROPERTY_KEY_STORE_PASSWORD = "org.jboss.ws.keyStorePassword";

   /** KeyStoreType property: org.jboss.ws.keyStoreType */
   static final String PROPERTY_KEY_STORE_TYPE = "org.jboss.ws.keyStoreType";

   /** TrustStore property: org.jboss.ws.trustStore */
   static final String PROPERTY_TRUST_STORE = "org.jboss.ws.trustStore";

   /** TrustStorePassword property: org.jboss.ws.trustStorePassword */
   static final String PROPERTY_TRUST_STORE_PASSWORD = "org.jboss.ws.trustStorePassword";

   /** TrustStoreType property: org.jboss.ws.trustStoreType */
   static final String PROPERTY_TRUST_STORE_TYPE = "org.jboss.ws.trustStoreType";

   /** Authentication type, used to specify basic, etc) */
   static final String PROPERTY_AUTH_TYPE = "org.jboss.ws.authType";

   /** Authentication type, BASIC */
   static final String PROPERTY_AUTH_TYPE_BASIC = "org.jboss.ws.authType.basic";

   /** Authentication type, WSEE */
   static final String PROPERTY_AUTH_TYPE_WSSE = "org.jboss.ws.authType.wsse";

   /** Enable MTOM on the stub */
   static final String PROPERTY_MTOM_ENABLED= "org.jboss.ws.mtom.enabled";

Dynamic Invocation Interface

An unconfigured DII client

In the case of DII the client sets up the call object manually. This involves setting the operation name and in/out parameters explicitly. There is no WSDL as abstract contract for the web service communication involved. Of all the web service client technologies, this is the least favorable.

   public void testEchoString() throws Exception
   {
      ServiceFactory factory = ServiceFactory.newInstance();
      Service service = factory.createService(new QName("ANY_SERVICE_NAME"));

      Call call = service.createCall();
      call.setOperationName(new QName(TARGET_NAMESPACE, "echoString"));
      call.addParameter("String_1", Constants.TYPE_LITERAL_STRING, ParameterMode.IN);
      call.addParameter("String_2", Constants.TYPE_LITERAL_STRING, ParameterMode.IN);
      call.setReturnType(Constants.TYPE_LITERAL_STRING);

      call.setTargetEndpointAddress(TARGET_ENDPOINT_ADDRESS);

      String hello = "Hello";
      String world = "world!";
      Object retObj = call.invoke(new Object[]{hello, world});
      assertEquals(hello + world, retObj);
   }

A configured DII client

A DII client can be configured from WSDL

    public void testEchoString() throws Exception
    {
       ServiceFactory factory = ServiceFactory.newInstance();
       URL wsdlLocation = new URL(TARGET_ENDPOINT_ADDRESS + "?wsdl");
       QName serviceName = new QName(TARGET_NAMESPACE, "TestService");
       ServiceImpl service = (ServiceImpl)factory.createService(wsdlLocation, serviceName);
       call = service.createCall();
     
       QName operationName = new QName(TARGET_NAMESPACE, "echoString");
       call.setOperationName(operationName);
       assertFalse(call.isParameterAndReturnSpecRequired(operationName));
 
       String hello = "Hello";
       String world = "world!";
       Object retObj = call.invoke(new Object[]{hello, world});
       assertEquals(hello + world, retObj);
    }

Note however, that the above example does not have a notion of JAXRPC mapping. The abstract contract is given as an URL to the WSDL, but it is not expicitly said how the various types in XML schema map to Java types. It works, because above we only use strings. It would not work if complex user types were involved. Prior to standard J2EE-1.4 web services frameworks fell back to Java reflection to provide the mapping meta data.

With JSR109 we have a standard mapping metadata format usually provided through jaxrpc-mapping.xml. The name of the file is however not standardized. Unfortunately the standard JAXRPC API does not accommodate this mapping information because it predates JSR109. In JBossWS you have the option to use a propriatary API method or rely on autodiscovery of META-INF/jaxrpc-mapping.xml.

Here the propriatary API methods that we provide in org.jboss.ws.jaxrpc.ServiceFactoryImpl

   /**
    * Create a <code>Service</code> instance.
    *
    * @param wsdlURL URL for the WSDL document location
    * @param serviceName  QName for the service.
    * @param mappingURL URL for the jaxrpc-mapping.xml document location
    */
   public Service createService(URL wsdlURL, QName serviceName, URL mappingURL) throws ServiceException
   {
      ...
   }

   /**
    * Create a <code>Service</code> instance.
    *
    * @param wsdlURL URL for the WSDL document location
    * @param serviceName  QName for the service.
    * @param mappingURL URL for the jaxrpc-mapping.xml document location
    * @param securityURL URL for the jbossws-security.xml file
    */
   public Service createService(URL wsdlURL, QName serviceName, URL mappingURL, URL securityURL) throws ServiceException
   {
      ...
   }

Using SOAPConnection

It is possible to use the standard javax.xml.soap.SOAPConnection to dispatch a precreated SOAP message to a given endpoint

     public void testSAAJClientFromEnvelope() throws Exception
     {
        MessageFactory mf = MessageFactory.newInstance();
        SOAPMessage reqMsg = mf.createMessage();
    
        String request =
          "<ns1:Order xmlns:ns1='" + TARGET_NAMESPACE + 
          "' xmlns:ns2='http://somens' attrval='somevalue'>" +
          "  <ns2:Customer>Kermit</ns2:Customer>" +
          "  <Item>Ferrari</Item>" +
          "</ns1:Order>";
  
        DocumentBuilder builder = getDocumentBuilder();
        Document doc = builder.parse(new ByteArrayInputStream(request.getBytes()));
        reqMsg.getSOAPBody().addDocument(doc);
  
        SOAPConnectionFactory conFactory = SOAPConnectionFactory.newInstance();
        SOAPConnection con = conFactory.createConnection();
        SOAPMessage resMsg = con.call(reqMsg, new URL(TARGET_ENDPOINT));
  
        SOAPBody soapBody = resMsg.getSOAPBody();
        SOAPElement soapElement = (SOAPElement)soapBody.getChildElements().next();
  
        validateResponse(soapElement);
     }

Headers & Handlers

Bound SOAP Headers

Bound SOAP header elements are visible on the SEI as operation parameters, unbound SOAP headers are not. Both, bound and unbound headers are visible to JAXRPC handlers. Here is an example that uses bound headers on three SEI methods.

   public interface HeaderTestService extends Remote
   {
      void testInHeader(String bodyMsg, String headerMsg) throws RemoteException;
   
      void testInOutHeader(String bodyMsg, StringHolder headerMsg) throws RemoteException;
   
      void testOutHeader(String bodyMsg, StringHolder headerMsg) throws RemoteException;
   }

A bound header is a message part that is explicitly bound with the <soap:header> element in the WSDL binding.

    <message name="HeaderTestService_testInHeader">
      <part name="String_1" type="xsd:string"/>
      <part name="String_2" type="xsd:string"/>
    </message>
      
    <portType name="HeaderTestService">
      <operation name="testInHeader" parameterOrder="String_1 String_2">
        <input message="tns:HeaderTestService_testInHeader"/>
        <output message="tns:HeaderTestService_testInHeaderResponse"/>
      </operation>
      ...
    </portType>
      
    <binding name="HeaderTestServiceBinding" type="tns:HeaderTestService">
      <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="rpc"/>
      <operation name="testInHeader">
        <soap:operation soapAction=""/>
        <input>
          <soap:body use="literal" namespace="http://org.jboss.ws/samples/handler"/>
          <soap:header message="tns:HeaderTestService_testInHeader" 
              part="String_2" use="literal" namespace="http://somens"/>
        </input>
        <output>
          <soap:body use="literal" namespace="http://org.jboss.ws/samples/handler"/>
        </output>
      </operation>
      ...
    </binding>

SOAP message exchange

Below you see the SOAP messages that are beeing exchanged.

Incomming SOAPMessage

    <env:Envelope xmlns:env='http://schemas.xmlsoap.org/soap/envelope/'>
     <env:Header>
      <ns2:String_2 xmlns:ns2='http://somens'>IN header message</ns2:String_2>
     </env:Header>
     <env:Body>
      <ns1:testInHeader xmlns:ns1='http://org.jboss.ws/samples/handler'>
       <String_1>Hello world!</String_1>
      </ns1:testInHeader>
     </env:Body>
    </env:Envelope>

Outgoing SOAPMessage

    <env:Envelope xmlns:env='http://schemas.xmlsoap.org/soap/envelope/'>
     <env:Header/>
     <env:Body>
      <ns1:testInHeaderResponse xmlns:ns1='http://org.jboss.ws/samples/handler'/>
     </env:Body>
    </env:Envelope>

Unbound SOAP Headers

Unbound SOAP header elements are not visible on SEI methods, but in JAXRPC handlers through the SAAJ API.

    public class ServerSideHandler extends GenericHandler
    {
       public boolean handleResponse(MessageContext msgContext)
       {
          log.info("handleResponse");
    
          try
          {
               SOAPMessage soapMessage = ((SOAPMessageContext)msgContext).getMessage();
               SOAPHeader soapHeader = soapMessage.getSOAPHeader();
      
               SOAPBody soapBody = soapMessage.getSOAPBody();
               SOAPBodyElement soapBodyElement = 
                          (SOAPBodyElement)soapBody.getChildElements().next();
               String rpcName = soapBodyElement.getElementName().getLocalName();
    
               SOAPFactory soapFactory = SOAPFactory.newInstance();
               Name headerName = 
                          soapFactory.createName("HeaderValue", "ns2", "http://otherns");
               SOAPHeaderElement she = soapHeader.addHeaderElement(headerName);
               she.setValue("Unbound OUT header message");
          }
          catch (SOAPException e)
          {
             throw  new JAXRPCException(e);
          }
    
          return true;
       }
    }

Unbound SOAP Headers on the client proxy

The web service client has access to unbound headers through the proxy

   public void testUnboundInHeader() throws Exception
   {
      // Add a header to the stub
      StubExt stub = (StubExt)endpoint;
      QName xmlName = new QName("http://otherns", "HeaderValue");
      stub.addUnboundHeader(xmlName, Constants.TYPE_LITERAL_STRING, String.class, ParameterMode.IN);
      stub.setUnboundHeaderValue(xmlName, "Unbound IN header message");

      endpoint.testInHeader("Hello world!", "IN header message");
      
      String unboundRet = (String)stub.getUnboundHeaderValue(xmlName);
      assertEquals("Unbound OUT header message", unboundRet);
   }

SOAP message exchange

Below you see the SOAP messages that are beeing exchanged.

Incomming SOAPMessage

    <env:Envelope xmlns:env='http://schemas.xmlsoap.org/soap/envelope/'>
     <env:Header>
      <ns2:String_2 xmlns:ns2='http://somens'>INOUT header message</ns2:String_2>
      <ns3:HeaderValue 
          xmlns:ns3='http://otherns'>Unbound INOUT header message</ns3:HeaderValue>
     </env:Header>
     <env:Body>
      <ns1:testInOutHeader xmlns:ns1='http://org.jboss.ws/samples/handler'>
       <String_1>Hello world!</String_1>
      </ns1:testInOutHeader>
     </env:Body>
    </env:Envelope>

Outgoing SOAPMessage

    <env:Envelope xmlns:env='http://schemas.xmlsoap.org/soap/envelope/'>
     <env:Header>
      <ns2:String_2 xmlns:ns2='http://somens'>INOUT header message - response</ns2:String_2>
      <ns2:HeaderValue xmlns:ns2='http://otherns'>Unbound OUT header message</ns2:HeaderValue>
     </env:Header>
     <env:Body>
      <ns1:testInOutHeaderResponse xmlns:ns1='http://org.jboss.ws/samples/handler'/>
     </env:Body>
    </env:Envelope>

Message Handler

JAX-RPC handler provide a convinient solution to intercept SOAP message processing both inbound and outbound on the client and the server side:

    package javax.xml.rpc.handler;
    public interface Handler 
    {
       boolean handleRequest(MessageContext context);
    
       boolean handleResponse(MessageContext context);
    
       boolean handleFault(MessageContext context);
    }

A Handler implementation class is required to provide a default constructor. The methods handleRequest and handleResponse perform the actual processing work for a handler. The method handleRequest processes the request SOAP message, while the method handleResponse processes the response SOAP message. The method handleFault performs the SOAP fault processing. The MessageContext parameter provides access to the message context (for example: a SOAP message that carries an RPC request or response) that is processed by a handler.

In the following chapter we will implement a simple JAX-RPC handler and see how to configure the handler chain for JSR-109 clients and web service endpoints.

Run wstools with the following configuration

  <configuration ...>
    <java-wsdl>
      <service name="TestService" style="rpc" 
        endpoint="org.jboss.test.ws.jaxrpc.samples.handler.HeaderTestService">
        <operation name="testInHeader">
          <parameter type="java.lang.String"/>
          <parameter type="java.lang.String" xml-name="headerMsg" header="true"/>
        </operation>
        <operation name="testInOutHeader">
          <parameter type="java.lang.String"/>
          <parameter type="javax.xml.rpc.holders.StringHolder" 
            xml-name="headerMsg" header="true" mode="INOUT"/>
        </operation>
        <operation name="testOutHeader">
          <parameter type="java.lang.String"/>
          <parameter type="javax.xml.rpc.holders.StringHolder" 
            xml-name="headerMsg" header="true" mode="OUT"/>
        </operation>
      </service>
    
      <namespaces target-namespace="http://org.jboss.ws/samples/handler" 
        type-namespace="http://org.jboss.ws/samples/handler/types"/>
    
      <mapping file="jaxrpc-mapping.xml"/>
      <webservices servlet-link="TestService"/>
    </java-wsdl>
  </configuration>

The handlers must be defined manualy in webservices.xml. WSTools does not generate client/server side handler configurations.

  <webservices ...>
   <webservice-description>
    ...
    <port-component>
      ...
      <handler>
        <handler-name>HeaderTestHandler</handler-name>
        <handler-class>org.jboss.test.ws.jaxrpc.samples.handler.ServerSideHandler</handler-class>
      </handler>
    </port-component>
   </webservice-description>
  </webservices>  

Generic Handler

The javax.xml.rpc.handler.GenericHandler class is an abstract class that implements the Handler interface. Developers typically subclass the GenericHandler class unless the Handler implementation class needs another class as its superclass.

The GenericHandler class is a convenience abstract class that makes writing handlers easy. This class provides default implementations of the lifecycle methods init and destroy and also different handle methods. A handler developer should only override methods that it needs to specialize as part of the derived Handler implementation class.

  • On the client side, a request handler is invoked before an RPC request is communicated to the target service endpoint.
  • On the client side, a response or fault handler is invoked before an RPC response is returned to the service client from the target service endpoint.

On the endpoint a JAX-RPC handler may be configured and used as follows:

  • On the service endpoint side, a request handler is invoked before an RPC request is dispatched to the target service endpoint.
  • On the service endpoint side, a response or fault handler is invoked before communication back to the service client from the target service endpoint.

Configuring a client side handler

Client side JAXRPC handlers are configured as part of the <service-ref> element that is available in application-client.xml, ejb-jar.xml and web.xml.

    <service-ref>
      <service-ref-name>service/TestService</service-ref-name>
      <service-interface>javax.xml.rpc.Service</service-interface>
      <wsdl-file>META-INF/wsdl/TestService.wsdl</wsdl-file>
      <jaxrpc-mapping-file>META-INF/jaxrpc-mapping.xml</jaxrpc-mapping-file>
      <port-component-ref>
        <service-endpoint-interface>
          org.jboss.test.ws.jaxrpc.samples.handler.HeaderTestService
        </service-endpoint-interface>
      </port-component-ref>
      <handler>
        <handler-name>HeaderTestHandler</handler-name>
        <handler-class>org.jboss.test.ws.jaxrpc.samples.handler.ClientSideHandler</handler-class>
      </handler>
    </service-ref>

Dynamic Handlers

Modifying the client side handler chain dynamically

The JSR-109 specification does not allow access to the HandlerRegistry that is associated with the Service object. JBossWS extends the Service interface to provide full access to the handler chains. There can be one handler chain per service port.

   public void testRemoveServerHandlers() throws Exception
   {
      MBeanServerConnection server = getServer();
      ObjectName oname = ObjectNameFactory.create("jboss.ws:service=ServiceEndpointManager");
      ObjectName serviceID = new ObjectName("jboss.ws:di=jbossws-samples-dynamichandler.war," + 
        "service=TestService,port=HandlerTestServicePort");

      List<HandlerInfo> infos = (List<HandlerInfo>)
        server.invoke(oname, "getHandlerInfos", 
          new Object[]{serviceID}, new String[]{"javax.management.ObjectName"});
    
      Iterator<HandlerInfo> it = infos.iterator();
      while (it.hasNext())
      {
         HandlerInfo info = it.next();
         if (info.getHandlerClass() == ServerSideHandler.class)
            it.remove();
      }
    
      server.invoke(oname, "stopServiceEndpoint", new Object[]{serviceID}, 
        new String[]{"javax.management.ObjectName"});
    
      server.invoke(oname, "setHandlerInfos", new Object[]{serviceID, infos}, 
        new String[]{"javax.management.ObjectName", "java.util.List"});
    
      server.invoke(oname, "startServiceEndpoint", new Object[]{serviceID}, 
        new String[]{"javax.management.ObjectName"});
      
      String res = endpoint.testHandlers("InitalMessage");
      assertEquals("InitalMessage", res);
   }

Modifying the server side handler chain dynamically

JAXRPC-1.1 does not provide access to the service endpoint handler chain. JBossWS provides full access to the handler chains through the ServiceEndpointManager. The ServiceEndpointManager is an MBean that manages all service endpoints deployed to the server.

   public void testRemoveServerHandlers() throws Exception
   {
      MBeanServerConnection server = getServer();
      ObjectName oname = ObjectNameFactory.create("jboss.ws:service=ServiceEndpointManager");
      String serviceID = "jbossws-samples-dynamichandler.war#TestService/HandlerTestServicePort";

      List<HandlerInfo> infos = (List<HandlerInfo>)server.invoke(oname, "getHandlerInfos", 
         new Object[]{serviceID}, new String[]{"java.lang.String"});

      Iterator<HandlerInfo> it = infos.iterator();
      while (it.hasNext())
      {
         HandlerInfo info = it.next();
         if (info.getHandlerClass() == ServerSideHandler.class)
            it.remove();
      }
      server.invoke(oname, "stopServiceEndpoint", 
         new Object[]{serviceID}, new String[]{"java.lang.String"});
    
      server.invoke(oname, "setHandlerInfos", new Object[]{serviceID, infos}, 
         new String[]{"java.lang.String", "java.util.List"});
    
      server.invoke(oname, "startServiceEndpoint", 
         new Object[]{serviceID}, new String[]{"java.lang.String"});
      
      String res = endpoint.testHandlers("InitalMessage");
      assertEquals("InitalMessage", res);
   }

Holders for INOUT parameters

This chapter describes how a BigDecimalHolder can be used as an in/out parameter.

   public interface HolderTestService extends Remote
   {
      void echoBigDecimal(BigDecimalHolder val) throws RemoteException;
      ... 
   }

Generating required deployment artifacts

Run wstools with the following configuration

    <configuration xmlns="http://www.jboss.org/jbossws-tools">
      <javaToWSDL>
        <service name="TestService" wsdlStyle="rpc" 
              endpoint="org.jboss.test.ws.jaxrpc.samples.holder.HolderTestService"/>
        <namespaces targetNamespace="http://org.jboss.ws/samples/holder" 
              typeNamespace="http://org.jboss.ws/samples/holder/types"/>
        <mapping fileName="jaxrpc-mapping.xml"/>
        <wsxml servletLink="TestService"/>
      </javaToWSDL>
    </configuration>

WSTools generates WSDL messages with identical part names.

     <message name='HolderTestService_echoBigDecimal'>
      <part name='BigDecimal_1' type='xsd:decimal'/>
     </message>
        
     <message name='HolderTestService_echoBigDecimalResponse'>
      <part name='BigDecimal_1' type='xsd:decimal'/>
     </message>
    
     <portType name='HolderTestService'>
      <operation name='echoBigDecimal' parameterOrder='BigDecimal_1'>
       <input message='tns:HolderTestService_echoBigDecimal'/>
       <output message='tns:HolderTestService_echoBigDecimalResponse'/>
      </operation>
      ...
     </portType>

The <service-endpoint-method-mapping> declares the parameter mode as INOUT.

    <service-endpoint-method-mapping>
     <java-method-name>echoBigDecimal</java-method-name>
     <wsdl-operation>echoBigDecimal</wsdl-operation>
     <method-param-parts-mapping>
      <param-position>0</param-position>
      <param-type>java.math.BigDecimal</param-type>
      <wsdl-message-mapping>
       <wsdl-message xmlns:wsdlMsgNS='http://org.jboss.ws/samples/holder'>
           wsdlMsgNS:HolderTestService_echoBigDecimal
        </wsdl-message>
       <wsdl-message-part-name>BigDecimal_1</wsdl-message-part-name>
       <parameter-mode>INOUT</parameter-mode>
      </wsdl-message-mapping>
     </method-param-parts-mapping>
    </service-endpoint-method-mapping>

SOAP message exchange

Below you see the SOAP messages that are beeing exchanged.

Incomming SOAPMessage

    <env:Envelope xmlns:env='http://schemas.xmlsoap.org/soap/envelope/'>
     <env:Header/>
     <env:Body>
      <ns1:echoBigDecimal xmlns:ns1='http://org.jboss.ws/samples/holder'>
       <BigDecimal_1>1000</BigDecimal_1>
      </ns1:echoBigDecimal>
     </env:Body>
    </env:Envelope>
      

Outgoing SOAPMessage

    <env:Envelope xmlns:env='http://schemas.xmlsoap.org/soap/envelope/'>
     <env:Header/>
     <env:Body>
      <ns1:echoBigDecimalResponse xmlns:ns1='http://org.jboss.ws/samples/holder'>
       <BigDecimal_1>1001</BigDecimal_1>
      </ns1:echoBigDecimalResponse>
     </env:Body>
    </env:Envelope>

Custom Exceptions

Custom exceptions in JAXRPC are about definig SOAP faults in your abstract contract and mapping them to java exceptions. The SOAP message contains a <soap:fault> element that contains information about the cause of the fault. Java specifics like stack traces, exception class names, etc. are usually not transported because they maybe meaningless to the non-java receiver.

A good article about Exception Handling with JAX-RPC can be found at IBM's developerworks.

Lets use a service endpoint interface (SEI) that throws various user exception

public interface ExceptionServiceInterface extends Remote
{
   void throwException() throws UserException, RemoteException;

   void throwExceptionWithMessage(String message) throws UserMessageException, RemoteException;

   void throwComplexUserException(String message, int code) throws ComplexUserException, RemoteException;

   void throwComplexUserArrayException(String message, int[] code) throws ComplexUserArrayException, RemoteException;
}

Generating required deployment artifacts

Run wstools with the following configuration

<configuration ...>
  <java-wsdl>
  <service name="ExceptionService" style="rpc" 
      endpoint="org.jboss.test.ws.jaxrpc.samples.exception.ExceptionServiceInterface"/>
    
  <namespaces target-namespace="http://org.jboss.ws/samples/exception" 
      type-namespace="http://org.jboss.ws/samples/exception/types"/>
    
  <mapping file="jaxrpc-mapping.xml"/>
  <webservices ejb-link="ExceptionBean"/>
  </java-wsdl>
</configuration>


wstools produces the following abstract contract (WSDL)

  <definitions targetNamespace='http://org.jboss.ws/samples/exception' ...>
   ...
   <portType name='ExceptionServiceInterface'>
    <operation name='throwComplexUserArrayException'>
     ...
     <fault message='tns:ComplexUserArrayException'/>
    </operation>
    <operation name='throwComplexUserException'>
     ...
     <fault message='tns:ComplexUserException' name='ComplexUserException'/>
    </operation>
    <operation name='throwException'>
     ...
     <fault message='tns:UserException' name='UserException'/>
    </operation>
    <operation name='throwExceptionWithMessage'>
     ...
     <fault message='tns:UserMessageException' name='UserMessageException'/>
    </operation>
   </portType>
   ...
  </definitions>


Note the various fault elements and how they are linked to XML schema complex types. The WSDL does not contain any information about the java mapping. This is defined in jaxrpc-maping.xml, for which I will only show the exception relevant parts.

  <exception-mapping>
   <exception-type>org.jboss.test.ws.jaxrpc.samples.exception.UserException</exception-type>
   <wsdl-message>exMsgNS:UserException</wsdl-message>
  </exception-mapping>
  <exception-mapping>
   <exception-type>org.jboss.test.ws.jaxrpc.samples.exception.UserMessageException</exception-type>
   <wsdl-message>exMsgNS:UserMessageException</wsdl-message>
   <constructor-parameter-order>
    <element-name>message</element-name>
   </constructor-parameter-order>
  </exception-mapping>
  <exception-mapping>
   <exception-type>org.jboss.test.ws.jaxrpc.samples.exception.ComplexUserException</exception-type>
   <wsdl-message>exMsgNS:ComplexUserException</wsdl-message>
   <constructor-parameter-order>
    <element-name>message</element-name>
    <element-name>errorCode</element-name>
   </constructor-parameter-order>
  </exception-mapping>
  <exception-mapping>
   <exception-type>org.jboss.test.ws.jaxrpc.samples.exception.ComplexUserArrayException</exception-type>
   <wsdl-message>exMsgNS:ComplexUserArrayException</wsdl-message>
   <constructor-parameter-order>
    <element-name>message</element-name>
    <element-name>errorCodes</element-name>
   </constructor-parameter-order>
  </exception-mapping>

SOAP message exchange

Here some SOAP messages as they would appear on the wire

  <soapenv:Envelope ...>
   <soapenv:Body>
    <soapenv:Fault>
     <faultcode>soapenv:Client</faultcode>
     <faultstring>org.jboss.test.webservice.exception.UserException</faultstring>
     <detail>
    <ns1:UserException xmlns:ns1="http://org.jboss.webservice/exception/types">
     <message xsi:nil="1"/>
    </ns1:UserException>
     </detail>
    </soapenv:Fault>
   </soapenv:Body>
  </soapenv:Envelope>
  
  <soapenv:Envelope ...>
   <soapenv:Body>
    <soapenv:Fault>
     <faultcode>soapenv:Client</faultcode>
     <faultstring>Don't worry it's just a test</faultstring>
     <detail>
    <ns1:UserMessageException xmlns:ns1="http://org.jboss.webservice/exception/types">
     <message>Don't worry it's just a test</message>
    </ns1:UserMessageException>
     </detail>
    </soapenv:Fault>
   </soapenv:Body>
  </soapenv:Envelope>
  
  <soapenv:Envelope ...>
   <soapenv:Body>
    <soapenv:Fault>
     <faultcode>soapenv:Client</faultcode>
     <faultstring>Don't worry it's just a test</faultstring>
     <detail>
    <ns1:ComplexUserException xmlns:ns1="http://org.jboss.webservice/exception/types">
     <message>Don't worry it's just a test</message>
     <errorCode>200</errorCode>
    </ns1:ComplexUserException>
     </detail>
    </soapenv:Fault>
   </soapenv:Body>
  </soapenv:Envelope>
  
  <soapenv:Envelope ...>
   <soapenv:Body>
    <soapenv:Fault>
     <faultcode>soapenv:Client</faultcode>
     <faultstring>Don't worry it's just a test</faultstring>
     <detail>
    <ns1:ComplexUserArrayException xmlns:ns1="http://org.jboss.webservice/exception/types">
     <message>Don't worry it's just a test</message>
     <errorCodes>100</errorCodes>
     <errorCodes>200</errorCodes>
    </ns1:ComplexUserArrayException>
     </detail>
    </soapenv:Fault>
   </soapenv:Body>
  </soapenv:Envelope>

OneWay Invocations

This chapter describes an asynchronous one way endpoint invocation

   public interface OneWayTestService extends Remote
   {
      void oneWay(String str1) throws RemoteException;
   }

Generating required deployment artifacts

Run wstools with the following configuration

  <configuration ...>
    <java-wsdl>
      <service name="TestService" style="rpc" 
        endpoint="org.jboss.test.ws.jaxrpc.samples.oneway.OneWayTestService">
        <operation name="oneWay" one-way="true">
          <parameter type="java.lang.String"/>
        </operation>
      </service>
    
      <namespaces target-namespace="http://org.jboss.ws/samples/oneway" 
        type-namespace="http://org.jboss.ws/samples/one-way=/types"/>
    
      <mapping file="jaxrpc-mapping.xml"/>
      <webservices servlet-link="TestService"/>
    </java-wsdl>
  </configuration>

WSTools does not generate output elements in the WSDL portType nor in the binding

     <portType name='OneWayTestService'>
      <operation name='oneWay' parameterOrder='String_1'>
       <input message='tns:OneWayTestService_oneWay'/>
      </operation>
     </portType>
    
     <binding name='OneWayTestServiceBinding' type='tns:OneWayTestService'>
      <soap:binding style='rpc' transport='http://schemas.xmlsoap.org/soap/http'/>
      <operation name='oneWay'>
       <soap:operation soapAction=''/>
       <input>
        <soap:body namespace='http://org.jboss.ws/samples/oneway' use='literal'/>
       </input>
      </operation>
     </binding>
     

SOAP message exchange

Below you see the incomming SOAP message. There is no outgoing message.

    <env:Envelope xmlns:env='http://schemas.xmlsoap.org/soap/envelope/'>
     <env:Header/>
     <env:Body>
      <ns1:oneWay xmlns:ns1='http://org.jboss.ws/samples/oneway'>
       <String_1>Hello</String_1>
      </ns1:oneWay>
     </env:Body>
    </env:Envelope>

SOAP with Attachments

This chapter describes SOAP with Attachments. JBossWS conform to the WS-I AttachmentsProfile-1.0

MIME mapping required by JAXRPC-1.1

image/gifjava.awt.Image
image/jpegjava.awt.Image
text/plainjava.lang.String
multipart/*javax.mail.internet.MimeMultipart
text/xmljavax.xml.transform.Source
application/xmljavax.xml.transform.Source


The sample code uses the following service endpoint interface

    public interface Attachment extends Remote
    {
       /** Service endpoint method for image/gif */
       String sendMimeImageGIF(String message, Object mimepart) throws RemoteException;
    
       /** Service endpoint method for image/jpeg */
       String sendMimeImageJPEG(String message, Image mimepart) throws RemoteException;
    
       /** Service endpoint method for text/plain */
       String sendMimeTextPlain(String message, String mimepart) throws RemoteException;
    
       /** Service endpoint method for multipart/* */
       String sendMimeMultipart(String message, MimeMultipart mimepart) throws RemoteException;
    
       /** Service endpoint method for text/xml */
       String sendMimeTextXML(String message, Object mimepart) throws RemoteException;
    
       /** Service endpoint method for application/xml */
       String sendMimeApplicationXML(String message, Source mimepart) throws RemoteException;
    }

Generating required deployment artifacts

Run wstools with the following configuration

FIXME: JBWS-700

WSTools does generate message parts of type xsd:hexBinary and the associated mime bindings

    <message name="Attachment_sendMimeImageGIF">
      <part name="message" type="xsd:string"/>
      <part name="mimepart" type="xsd:hexBinary"/>
    </message>
      
    <binding name="AttachmentBinding" type="tns:Attachment">
      <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="rpc"/>
      <operation name="sendMimeImageGIF">
        <soap:operation soapAction=""/>
        <input>
          <mime:multipartRelated>
            <mime:part>
              <soap:body part="message" use="literal" 
                namespace="http://org.jboss.ws/samples/swa"/>
            </mime:part>
            <mime:part>
              <mime:content part="mimepart" type="image/gif"/>
            </mime:part>
          </mime:multipartRelated>
        </input>
        <output>
          <soap:body use="literal" namespace="http://org.jboss.ws/samples/swa"/>
        </output>
      </operation>
      ...
    </binding>

Access attachments on the server side

Your endpoint bean may access the attachment parts using the standard SAAJ API:

      ServletEndpointContext context = 
            (ServletEndpointContext)ctxWhichIsSetIn_ServiceLifecycle_init;

      SOAPMessageContext msgContext = (SOAPMessageContext)context.getMessageContext();
      SOAPMessage soapMessage = msgContext.getMessage();

      Iterator attachments = soapMessage.getAttachments();
      if (attachments.hasNext())
      {
         AttachmentPart ap = (AttachmentPart)attachments.next();
         String contentType = ap.getContentType();

         if (expContentType.equals("multipart/*"))
         {
            MimeMultipart mmp = (MimeMultipart)ap.getContent();
            int mmpCount = mmp.getCount();
            for (int i = 0; i < mmpCount; i++)
            {
               BodyPart bp = mmp.getBodyPart(i);
               String bpct = bp.getContentType();
               Object bpc = bp.getContent();
               ...   
            }
         }
         else if (expContentType.equals("image/gif"))
         {
            Image image = (Image)ap.getContent();
            ... 
         }
         else
         {
            ... 
         }
      }

Sending an attachment from a DII client

To send an image, we can use the standard DII API and make use of the Java activation framework. From the javadoc for DataHandler:

The DataHandler class provides a consistent interface to data available in many different sources and formats. It manages simple stream to string conversions and related operations using DataContentHandlers.

      ServiceFactory factory = ServiceFactory.newInstance();
      Service service = factory.createService(SERVICE_NAME);

      Call call = service.createCall(PORT_NAME, new QName(NS_URI, rpcMethodName));
      call.addParameter("message", Constants.XSD_STRING, ParameterMode.IN);
      call.addParameter("mimepart", Constants.MIME_IMAGE, ParameterMode.IN);
      call.setReturnType(Constants.XSD_STRING);
      call.setTargetEndpointAddress("http://" + getServerHost() + ":8080/ws4ee-attachment");

      URL url = new File("resources/webservice/attachment/attach.gif").toURL();

      String message = "Some text message";
      String value = (String)call.invoke(new Object[]{message, new DataHandler(url)});

      System.out.println(value);

Building a multipart message using SAAJ

Using the SAAJ API directly, you can also construct a MIME multipart message and send it on the wire without using an JAX-RPC client.

      MessageFactory mf = MessageFactory.newInstance();

      // Create a soap message from the message factory.
      SOAPMessage msg = mf.createMessage();

      // Message creation takes care of creating the SOAPPart
      // a required part of the message as per the SOAP 1.1 spec.
      SOAPPart sp = msg.getSOAPPart();

      // Retrieve the envelope from the soap part to start building the soap message.
      SOAPEnvelope envelope = sp.getEnvelope();

      // Create a soap body from the envelope.
      SOAPBody bdy = envelope.getBody();

      // Add a soap body element
      SOAPBodyElement sbe = bdy.addBodyElement(envelope.createName(rpcMethodName, NS_PREFIX, NS_URI));

      // Add a some child elements
      sbe.addChildElement(envelope.createName("message")).addTextNode("Some text message");
      sbe.addChildElement(envelope.createName("mimepart")).addAttribute(envelope.createName("href"), CID_MIMEPART);

      AttachmentPart ap = msg.createAttachmentPart(new DataHandler(url));
      ap.setContentType("image/gif");
      ap.setContentId(CID_MIMEPART);

      // Add the attachments to the message.
      msg.addAttachmentPart(ap);

      SOAPConnectionFactory conFactory = SOAPConnectionFactory.newInstance();
      SOAPConnection con = conFactory.createConnection();
      SOAPMessage resMessage = con.call(msg, new URL("http://localhost:8080/ws4ee-attachment"));

MTOM/XOP

This chapter describes Message Transmission Optimization Mechanism (MTOM) and XML-binary Optimized Packaging (XOP), a means of more efficiently serializing XML Infosets that have certain types of content. The related specifications are SOAP Message Transmission Optimization Mechanism (MTOM) and XML-binary Optimized Packaging (XOP)

The MTOM/XOP example uses a service endpoint interface with the same operations as in #SOAP with Attachments

MTOM schema elements

Currently neither wstools nor wscompile has support for MTOM. Fortunatly a MTOM optimizable element decalaration isn't that difficult to understand and can easily be created manually:

      <schema xmlns="http://www.w3.org/2001/XMLSchema"
              targetNamespace="http://org.jboss.ws/samples/mtom"
              xmlns:xmime="http://www.w3.org/2005/05/xmlmime">

         (1) <import schemaLocation="http://www.w3.org/2005/05/xmlmime" namespace="http://www.w3.org/2005/05/xmlmime"/>

         (2) <element name="imagejpeg" xmime:contentType="image/jpeg" type="xmime:base64Binary"/>
    </schema>
  1. Import the xmime schema declarations
  2. Derive your element declaration from xmime:base64Binary

 

Supported MTOM parameter types

 

image/jpegjava.awt.Image
text/xmljavax.xml.transform.Source
application/xmljavax.xml.transform.Source
*/*javax.activation.DataHandler

The above table shows a list of supported endpoint parameter types. The recommended approach is to use the DataHandler classes to represent binary data as service endpoint parameters.

 

Enabling MTOM

Since 1.2 (Native)

Before the 1.2 release MTOM was enabled for any JAX-RPC endpoint. This was alinged with the JAX-WS default, and thus is disabled by default now. In order to enable MTOM per endpoint you need to make sure the MTOM feature is set in the ednpoint config, i.e.

<endpoint-config>
  <config-name>Standard MTOM Endpoint</config-name>
  <feature>http://org.jboss.ws/mtom</feature>         (1)
</endpoint-config>
  1. This may added to any endpoint config you are using

 

An example MTOM request

Note

The fact that a SOAP message might be XOP encoded is actually transparent to any SOAP intermediary. This also applies to JAXRPC handlers. What does this mean? It means that JAXRPC handlers don't get to see the XOP encoded wireformat (xop:Include), instead they can access the message as if it was inlined. This is necessary in order not to break any SOAP processing modules that work on the real payload (i.e. Security). In JBossWS this results in the binary data being transformed into a base64 representation, which can easily negate the optimization efforts in the first place.

The incomming message is multipart/related. The first part is the SOAP Envelope.

POST /jbossws-samples-mtom HTTP/1.1
SOAPAction: ""
Content-Type: multipart/related; start-info="text/xml";
   type="application/xop+xml";
start="<rootpart@ws.jboss.org>";
boundary="----=_Part_2_29441291.1153833579421"
User-Agent: Java/1.5.0_07
Host: localhost:8081
Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
Connection: keep-alive
Content-Length: 915


------=_Part_2_29441291.1153833579421
Content-Type: application/xop+xml; type="text/xml"
Content-Transfer-Encoding: 8bit
Content-ID: <rootpart@ws.jboss.org>

<env:Envelope xmlns:env='http://schemas.xmlsoap.org/soap/envelope/'>
 <env:Header/>
 <env:Body>
  <ns1:sendMimeTextXML xmlns:ns1='http://org.jboss.ws/samples/mtom'>
   <message>Some text message</message>
   <ns1:textxml>
    <xop:Include
      href='cid:textxml-590c9216-9871-48a8-9239-f73831644442@ws.jboss.org'
      xmlns:xop='http://www.w3.org/2004/08/xop/include'/>
   </ns1:textxml>
  </ns1:sendMimeTextXML>
 </env:Body>
</env:Envelope>
------=_Part_2_29441291.1153833579421
Content-Type: text/xml
Content-Transfer-Encoding: binary
Content-Id: <textxml-590c9216-9871-48a8-9239-f73831644442@ws.jboss.org>

<?xml version="1.0" encoding="ISO-8859-1"?>

<mime-message>This is an xml attachment.</mime-message>

------=_Part_2_29441291.1153833579421--

JMS Transport

JBossWS supports J2EE-1.4 message driven beans (MDB) as service endpoints. A JMS message that is targeted to MDB may contain a SOAP envelope that is then dispatched to the same MDB. The MDB implements the methods on the Service Endpoint Interface (SEI), onMessage() is implemented by a base class that we provide.

 

JMS Endpoint

In this section we describe how to expose an EJB Message Driven Bean as service endpoint.

The Message Driven Bean

First you setup an ordinary message driven bean in ejb-jar.xml and jboss.xml

  <ejb-jar>
    <enterprise-beans>
      <message-driven>
        <ejb-name>OrganizationMDB</ejb-name>
        <ejb-class>org.jboss.test.ws.jaxrpc.samples.jmstransport.OrganizationJMSEndpoint</ejb-class>
        <message-selector></message-selector>
        <transaction-type>Container</transaction-type>
        <acknowledge-mode>AUTO_ACKNOWLEDGE</acknowledge-mode>
        <message-driven-destination>
          <destination-type>javax.jms.Queue</destination-type>
          <subscription-durability>NonDurable</subscription-durability>
        </message-driven-destination>
      </message-driven>
    </enterprise-beans>
  </ejb-jar>
    
  <jboss>
    <enterprise-beans>
      <message-driven>
        <ejb-name>OrganizationMDB</ejb-name>
        <destination-jndi-name>queue/RequestQueue</destination-jndi-name>
        <depends>jboss.mq.destination:service=Queue,name=RequestQueue</depends>
      </message-driven>
    </enterprise-beans>
  </jboss>

The implementation extends JMSTransportSupport, which is the actual MDB and takes care of decoding the incomming JMS message and dispatching it to the target endpoint bean.

  public class OrganizationJMSEndpoint extends JMSTransportSupport
  {
     // provide logging
     private static final Logger log = Logger.getLogger(OrganizationJMSEndpoint.class);
  
     /** Get the contact info */
     public String getContactInfo(String organization) throws RemoteException
     {
        log.info("getContactInfo: " + organization);
        return "The '" + organization + "' boss is currently out of office, please call again.";
     }
  }

Packaging the JMS Endpoint

A JMS endpoint is packaged like an #JSR-109 EJB Endpoint and uses the standard webservices.xml descriptor

  <webservices ...>
   <webservice-description>
    <webservice-description-name>OrganizationService</webservice-description-name>
    <wsdl-file>META-INF/wsdl/OrganizationService.wsdl</wsdl-file>
    <jaxrpc-mapping-file>META-INF/jaxrpc-mapping.xml</jaxrpc-mapping-file>
    <port-component>
     <port-component-name>OrganizationPort</port-component-name>
     <wsdl-port>impl:OrganizationPort</wsdl-port>
     <service-endpoint-interface>
       org.jboss.test.ws.jaxrpc.samples.jmstransport.Organization
     </service-endpoint-interface>
     <service-impl-bean>
      <ejb-link>OrganizationMDB</ejb-link>
     </service-impl-bean>
    </port-component>
   </webservice-description>
  </webservices>

JMS Client

To send a SOAP message to a JMS endpoint you use the normal JMS message producer metodology. Here is an example:

There is not yet transparent JMS transport available for web service clients. Please monitor JBWS-670 for progress on this.

      InitialContext context = new InitialContext();
      QueueConnectionFactory connectionFactory = (QueueConnectionFactory)context.lookup("ConnectionFactory");
    
      Queue reqQueue = (Queue)context.lookup("queue/RequestQueue");
      Queue resQueue = (Queue)context.lookup("queue/ResponseQueue");

      QueueConnection con = connectionFactory.createQueueConnection();
      QueueSession session = con.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
      QueueReceiver receiver = session.createReceiver(resQueue);
      ResponseListener responseListener = new ResponseListener();
      receiver.setMessageListener(responseListener);
      con.start();

      TextMessage message = session.createTextMessage(reqMessage);
      message.setJMSReplyTo(resQueue);

      QueueSender sender = session.createSender(reqQueue);
      sender.send(message);
      sender.close();

      done.acquire();
      
      assertNotNull("Expected response message", responseListener.resMessage);
      assertEquals(DOMUtils.parse(resMessage), DOMUtils.parse(responseListener.resMessage));
      
      con.stop();
      session.close();
      con.close();

Secure Endpoints

Secure the access to the SLSB

First we secure the access to the SLSB as we would do for normal (non web service) invocations.

In ejb-jar.xml, we setup the method permissions for the SLSB endpoint. Note, that it is not necessarily required for the endpoint to have home/remote interfaces.

  <enterprise-beans>
    <session>
      <ejb-name>RoleSecuredSLSB</ejb-name>
      <remote>org.jboss.test.ws.jaxrpc.samples.secureejb.OrganizationRemote</remote>
      <home>org.jboss.test.ws.jaxrpc.samples.secureejb.OrganizationHome</home>
      <service-endpoint>org.jboss.test.ws.jaxrpc.samples.secureejb.OrganizationService</service-endpoint>
      <ejb-class>org.jboss.test.ws.jaxrpc.samples.secureejb.OrganizationImpl</ejb-class>
      <session-type>Stateless</session-type>
      <transaction-type>Container</transaction-type>
      <security-role-ref>
        <role-name>friend</role-name>
      </security-role-ref>
    </session>
    <session>
      <ejb-name>BasicSecuredSLSB</ejb-name>
      <remote>org.jboss.test.ws.jaxrpc.samples.secureejb.OrganizationRemote</remote>
      <home>org.jboss.test.ws.jaxrpc.samples.secureejb.OrganizationHome</home>
      <service-endpoint>org.jboss.test.ws.jaxrpc.samples.secureejb.OrganizationService</service-endpoint>
      <ejb-class>org.jboss.test.ws.jaxrpc.samples.secureejb.OrganizationImpl</ejb-class>
      <session-type>Stateless</session-type>
      <transaction-type>Container</transaction-type>
    </session>
  </enterprise-beans>

  <assembly-descriptor>
    <security-role>
      <role-name>friend</role-name>
    </security-role>
    <method-permission>
      <role-name>friend</role-name>
      <method>
        <ejb-name>RoleSecuredSLSB</ejb-name>
        <method-name>*</method-name>
      </method>
    </method-permission>
    <method-permission>
      <unchecked/>
      <method>
        <ejb-name>BasicSecuredSLSB</ejb-name>
        <method-name>*</method-name>
      </method>
    </method-permission>
  </assembly-descriptor>

Define the security domain

Next, define the security domain for this deployment in jboss.xml. The JBossWS security context is configured in login-config.xml and uses the UsersRolesLoginModule.

  <jboss>
    <security-domain>java:/jaas/JBossWS</security-domain>
    <enterprise-beans>
      <session>
        <ejb-name>RoleSecuredSLSB</ejb-name>
        <jndi-name>ejb/RoleSecuredSLSB</jndi-name>
        <port-component>
          <port-component-name>RoleSecured</port-component-name>
          <port-component-uri>/jaxrpc-samples-ejb/RoleSecured</port-component-uri>
        </port-component>
      </session>
      <session>
        <ejb-name>BasicSecuredSLSB</ejb-name>
        <jndi-name>ejb/BasicSecuredSLSB</jndi-name>
        <port-component>
          <port-component-name>BasicSecured</port-component-name>
          <port-component-uri>/jaxrpc-samples-ejb/BasicSecured</port-component-uri>
        </port-component>
      </session>
    </enterprise-beans>
  </jboss>

In login-config.xml, that lives in the server config dir, you will find the definition of the JBossWS security domain.

  <!-- 
    A template configuration for the JBossWS security domain.
    This defaults to the UsersRolesLoginModule the same as other and should be
    changed to a stronger authentication mechanism as required.
  -->
  <application-policy name="JBossWS">
    <authentication>
      <login-module code="org.jboss.security.auth.spi.UsersRolesLoginModule"
        flag="required">
        <module-option name="usersProperties">props/jbossws-users.properties</module-option>
        <module-option name="rolesProperties">props/jbossws-roles.properties</module-option>
        <module-option name="unauthenticatedIdentity">anonymous</module-option>
      </login-module>
    </authentication>
  </application-policy>
  

Use the JAXRPC Stub to set principal/credential

A web service client may use the javax.xml.rpc.Stub object to set the username/password combination

  public void testWebServiceAccess() throws Exception
   {
      OrganizationEndpoint endpoint = service.getPort(OrganizationEndpoint.class);

      Stub stub = (Stub)endpoint;
      stub._setProperty(Stub.USERNAME_PROPERTY, "kermit");
      stub._setProperty(Stub.PASSWORD_PROPERTY, "thefrog");

      String info = endpoint.getContactInfo("mafia");
      assertEquals("The 'mafia' boss is currently out of office, please call again.", info);
   }

Using HTTP Basic Auth for security

To enable HTTP Basic authentication you need to add a port-component descriptor to your jboss.xml file, which contains an auth-method tag. We just modify the jboss.xml from above.

  <jboss>
    <security-domain>java:/jaas/JBossWS</security-domain>
    <enterprise-beans>
      <session>
        <ejb-name>RoleSecuredSLSB</ejb-name>
        <jndi-name>ejb/RoleSecuredSLSB</jndi-name>
        <port-component>
          <port-component-name>RoleSecured</port-component-name>
          <port-component-uri>/ws4ee-samples-ejb/RoleSecured</port-component-uri>
          <auth-method>BASIC</auth-method>
        </port-component>
      </session>
      <session>
        <ejb-name>BasicSecuredSLSB</ejb-name>
        <jndi-name>ejb/BasicSecuredSLSB</jndi-name>
        <port-component>
          <port-component-name>BasicSecured</port-component-name>
          <port-component-uri>/ws4ee-samples-ejb/BasicSecured</port-component-uri>
          <auth-method>BASIC</auth-method>
        </port-component>
      </session>
    </enterprise-beans>
  </jboss>

Secure HTTP transport

You can also require that all webservice requests use SSL by adding the transport-guarantee tag in your jboss.xml file. Modify jboss.xml file to also require the transport guarantee CONFIDENTIAL.

  <jboss>
    <security-domain>java:/jaas/JBossWS</security-domain>
    <enterprise-beans>
      <session>
        <ejb-name>RoleSecuredSLSB</ejb-name>
        <jndi-name>ejb/RoleSecuredSLSB</jndi-name>
        <port-component>
          <port-component-name>RoleSecured</port-component-name>
          <port-component-uri>/ws4ee-samples-ejb/RoleSecured</port-component-uri>
          <auth-method>BASIC</auth-method>
          <transport-guarantee>CONFIDENTIAL</transport-guarantee>
        </port-component>
      </session>
      <session>
        <ejb-name>BasicSecuredSLSB</ejb-name>
        <jndi-name>ejb/BasicSecuredSLSB</jndi-name>
        <port-component>
          <port-component-name>BasicSecured</port-component-name>
          <port-component-uri>/ws4ee-samples-ejb/BasicSecured</port-component-uri>
          <auth-method>BASIC</auth-method>
          <transport-guarantee>CONFIDENTIAL</transport-guarantee>
        </port-component>
      </session>
    </enterprise-beans>
  </jboss>

At last, make sure that the endpoint address in your WSDL file uses a secure protocol. The easiest way is to add "https://" to the SOAP Address entry:

   <service name="OrganizationService">
    <port name="BasicSecuredPort" binding="tns:OrganizationServiceBinding">
     <soap:address location="https://localhost:8443/ws4ee-samples-ejb/BasicSecured"/>
    </port>
    <port name="RoleSecuredPort" binding="tns:OrganizationServiceBinding">
     <soap:address location="https://localhost:8443/ws4ee-samples-ejb/RoleSecured"/>
    </port>
   </service>

For this to work the Tomcat+SSL connector must be enabled.

   <Connector port="8443" address="${jboss.bind.address}"
        maxThreads="100" minSpareThreads="5" maxSpareThreads="15"
        scheme="https" secure="true" clientAuth="want"
        keystoreFile="${jboss.server.home.dir}/conf/keystores/wsse.keystore" 
        keystorePass="jbossws"
        truststoreFile="${jboss.server.home.dir}/conf/keystores/wsse.keystore" 
        truststorePass="jbossws"
        sslProtocol = "TLS" />

For details see: Tomcat-5.5 SSL Configuration HOWTO

On the client side the truststore must be installed

     <sysproperty key="javax.net.ssl.keyStore" value="${test.resources.dir}/wsse/wsse.keystore"/>
     <sysproperty key="javax.net.ssl.trustStore" value="${test.resources.dir}/wsse/wsse.truststore"/>
     <sysproperty key="javax.net.ssl.keyStorePassword" value="jbossws"/>
     <sysproperty key="javax.net.ssl.trustStorePassword" value="jbossws"/>
     <sysproperty key="javax.net.ssl.keyStoreType" value="jks"/>
     <sysproperty key="javax.net.ssl.trustStoreType" value="jks"/>
 

In case you see the following exception, you should disable URL checking on the client side

 java.io.IOException: HTTPS hostname wrong:  should be <localhost>
   at sun.net.www.protocol.https.HttpsClient.checkURLSpoofing(HttpsClient.java:493)
   at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:418)
 

  <sysproperty key="org.jboss.security.ignoreHttpsHost" value="true"/>

WS-Addressing

The WS-Addressing sample has been migrated to JAX-WS User Guide#WS-Addressing. WS-Addressing handlers are however still available for JAX-RPC. See JAX-RPC Endpoint Configuration.

 

WS-BPEL

This chapter is dedicated to show how to use WS-BPELto specify business process behavior based on web services.

 

Specification

Originally authored by a reduced vendor charter, WS-BPEL is currently under standardization at OASIS. The latest approved document as of August 22, 2006 is:

Web Services Business Process Execution Language 2.0 Committee Draft

In the Java space, JSR-207 aims at defining metadata, interfaces and a runtime model that enable business processes to be easily and rapidly implemented using Java and deployed in J2EE containers. The request submission is:

JSR 207: Process Definition for Java

The provided foundation would support tasks commonly encountered when programming business processes such as parallel execution and asynchronous messaging.

 

Defining a business process

Business processes model the stateful behavior of a participant in a business interaction. In BPEL, a process exports and imports functionality to/from participants using web service interfaces exclusively.

At its simplest, BPEL can be used as a scripting language for web services. Consider a trivial endpoint that receives a person name, composes a greeting phrase and then replies with the greeting.

The flow diagram below represents the processing logic.

Graphical representation of the Hello World process
Graphical representation of the Hello World process

The interface our endpoint presents to the world appears in the following WSDL document. Observe no binding or service elements are present. A BPEL process is defined in terms of the interfaces (message and port type elements) of the participants, not their possible deployments.

<definitions targetNamespace="http://jbpm.org/examples/hello"
  xmlns="http://schemas.xmlsoap.org/wsdl/"
  xmlns:tns="http://jbpm.org/examples/hello" 
  xmlns:xsd="http://www.w3.org/2001/XMLSchema">

  <!-- carries the name of a person -->
  <message name="NameMessage">
    <part name="name" type="xsd:string"/>
  </message>

  <!-- carries the greeting -->
  <message name="GreetingMessage">
    <part name="greeting" type="xsd:string"/>
  </message>

  <!-- describes the interface presented to callers -->
  <portType name="Greeter">
    <operation name="sayHello">
      <input message="tns:NameMessage"/>
      <output message="tns:GreetingMessage"/>
    </operation>
  </portType>

</definitions>

The document that describes our business behavior appears below. There are three major sections in it.

  • The partnerLinks section lists the parties that interact with the process in the course of greeting the world. The sole partner link shown here corresponds to the agent sending the person name (the caller).
  • The variables section defines the data items held by the process between message exchanges. The ability to mantain data effectively makes the service provided by the process stateful. The state includes received and sent messages as well as intermediate data used in business logic.
  • The rest of the document describes the normal activities for handling a greeting request. BPEL also provides the means to perform activities in response to faults. Our trivial endpoint does not require them, tough.
<process name="HelloWorld" targetNamespace="http://jbpm.org/examples/hello"
  xmlns="http://schemas.xmlsoap.org/ws/2003/03/business-process/"
  xmlns:tns="http://jbpm.org/examples/hello"
  xmlns:bpel="http://schemas.xmlsoap.org/ws/2003/03/business-process/">

  <partnerLinks>
    <!-- establishes the relationship with the caller agent -->
    <partnerLink name="caller" partnerLinkType="tns:Greeter-Caller" myRole="Greeter" />
  </partnerLinks>

  <variables>
    <!-- holds the incoming message -->
    <variable name="request" messageType="tns:NameMessage" />
    <!-- holds the outgoing message -->
    <variable name="response" messageType="tns:GreetingMessage" />
  </variables>

  <sequence>
    
    <!-- receive the name of a person -->
    <receive operation="sayHello" partnerLink="caller" portType="tns:Greeter"
      variable="request" createInstance="yes" />
      
    <!-- compose a greeting phrase -->
    <assign>
      <copy>
        <from expression="concat('Hello, ', 
                          bpel:getVariableData('request', 'name'), 
                          '!')" />
        <to variable="response" part="greeting" />
      </copy>
    </assign>
    
    <!-- reply with the greeting -->
    <reply operation="sayHello" partnerLink="caller" portType="tns:Greeter"
      variable="response" />
  </sequence>

</process>

Notice the caller partner link references a partnerLinkType artifact not introduced so far. Partner link types are WSDL extensibility elements that represent the relationship between two services. WS-BPEL uses them as the glue between the process and its partner services.

For the process definition to be complete, we add the partner link type to the WSDL document presented earlier.

<definitions targetNamespace="http://jbpm.org/examples/hello"
  ...
  xmlns:plt="http://schemas.xmlsoap.org/ws/2003/05/partner-link/">

  <!-- characterizes the relationship between the greeter and its caller -->
  <plt:partnerLinkType name="Greeter-Caller">
    <plt:role name="Greeter">
      <plt:portType name="tns:Greeter"/>
    </plt:role>
    <!-- the Caller does not provide services to the Greeter,
         this is why we omit the "Caller" role -->    
  </plt:partnerLinkType>
  
</definitions>

Storing the process definition in the jBPM database

In the domain of business processes, traceability is important. Process engines are expected to maintain not only the current state of each process instance, but also the history of performed activities and updated variables.

To provide these features, the JBoss BPEL implementation builds on JBoss jBPM. The Graph Oriented Programming (GOP) foundation in jBPM maintains past and present graph state in a database.

Installing the jBPM service in JBoss AS is a prerrequisite. The samples suite installs a preconfigured service archive automatically. Please refer to the jBPM BPEL user guidefor details on how to customize the service to match your requirements and deployment environment. The sample code that accompanies this chapter was developed and tested with jBPM BPEL version 1.1.Beta3.

Note

The preconfigured jBPM service comes with an HSQL database, useful for development purposes. In production, you can switch to the database of your choice.

Before the process can serve requests, its definition must be stored in the jBPM database. The unit test setup code shown below performs this operation. This code comes from class org.jboss.test.ws.jaxrpc.samples.wsbpel.JbpmBpelTestSetup. The argument is a zip file containing your BPEL process and related WSDL interfaces. The submitRequest method submits the zip file to a web module deployed as part of the jBPM BPEL service. The web module connects to the database and stores the process definition.

public static void deployProcess(File processFile) throws Exception
{
   // format file component
   String file = getJbpmBpelDeployContext() + "?processfile=" + URLEncoder.encode(processFile.toURI().toString(), "UTF-8");

   // create target URL
   URL targetUrl = new URL("http", JBossWSTestHelper.getServerHost(), getServerHttpPort(), file);

   // submit process deploy request
   int responseCode = submitRequest(targetUrl);

   if (responseCode != HttpURLConnection.HTTP_OK)
      throw new IOException("could not deploy process: " + processFile);
}

The file bpel-definition.xml tells the location of the BPEL and WSDL documents inside the archive.

<bpelDefinition location="hello.bpel" xmlns="http://jbpm.org/bpel">

  <!-- makes WSDL interface elements available to the process -->
  <imports>
    <wsdl location="hello.wsdl" />
  </imports>

</bpelDefinition>

Note

The definition descriptor can also reference external WSDL documents.

 

Generating the required artifacts

Deploying a BPEL process is similar to deploying a JSR-109 endpoint starting with WSDL.

A BPEL process references the port types of the participants only, not their possible bindings or actual endpoint addresses, as mentioned in "defining a process". On the other hand, a JSR-109 deployment requires the presence of binding and service elements. JBoss BPEL supplies a tool that generates SOAP 1.1 binding and service elements required for deploying the web service provided by the process.

<!-- generate wsdl binding and service definitions for bpel processes -->
<taskdef name="servicegen" classname="org.jbpm.bpel.ant.ServiceGeneratorTask">
  <classpath refid="jbpm.bpel.classpath"/>
</taskdef>
<servicegen processfile="${tests.output.dir}/libs/jaxrpc-samples-wsbpel-hello-process.zip"
  outputdir="${tests.output.dir}/wstools/resources/jaxrpc/samples/wsbpel/hello/WEB-INF/wsdl"
  bindingfile="hello-binding-.wsdl" servicefile="hello-service.wsdl" />

The generated WSDL can be passed to wstools. Use the following configuration.

<configuration xmlns="http://www.jboss.org/jbossws-tools">
  <global>
    <package-namespace package="org.jboss.test.ws.jaxrpc.samples.wsbpel.hello"
      namespace="http://jbpm.org/examples/hello" />
  </global>
  <wsdl-java location="wstools/resources/jaxrpc/samples/wsbpel/hello/WEB-INF/wsdl/hello-service.wsdl">
    <mapping file="jaxrpc-mapping.xml" />
  </wsdl-java>
</configuration>

Note

JBoss BPEL does not use the Java mapping artifacts that wstools produces. Keep in mind that variables in a BPEL process are defined in terms of XML types and WSDL messages. JBoss BPEL extracts XML content from SOAP messages and places it in the process variables directly. Nevertheless, the Java mapping artifacts still must be present for the JSR-109 deployment to be valid. Notice the supplied service implementation bean has empty methods only. The BPEL process specifies the behavior instead.

 

Configuring the port component

Similar to the Addressing and Security components, JBoss BPEL uses a JAX-RPC message handler to extract XML content from SOAP messages.

<handler>

  <handler-name>GreeterSoapHandler</handler-name>
  <handler-class>org.jbpm.bpel.integration.server.SoapHandler</handler-class>
  
  <init-param>
    <description>name of the partner link served by this port</description>
    <param-name>partnerLinkHandle</param-name>
    <param-value>caller</param-value>
  </init-param>

</handler>

A separate descriptor, bpel-application.xml, specifies the name of the process definition.

<bpelApplication name="HelloWorld" xmlns="http://jbpm.org/bpel" />

Note

This name will be used to retrieve the process definition from the jBPM database. It must match the process name in your BPEL document.

 

Consuming the published web service

No special configuration is needed on the client side. You consume a service provided by a WS-BPEL process the same way you consume any other service.

You can reuse the Java mapping artifacts generated earlier to develop a  J2EE-1.4 Client.

InitialContext iniCtx = getInitialContext();
helloService = (HelloWorldService)iniCtx.lookup("java:comp/env/service/BpelHello");

Greeter proxy = helloService.getGreeterPort();
String greeting = proxy.sayHello("Popeye");
assertEquals("Hello, Popeye!", greeting);

WS-Eventing

WS-Eventing has been migrated to JAX-WS User Guide#WS-Eventing. It is no longer supported in JAX-RPC.

 

WS-Security

This section is specific to WS-Security for JAX-RPC endpoints/client. For general information, please refer to JAX-WS User Guide#WS-Security

Generating required deployment artifacts

Lets start with a trivial service endpoint interface (SEI) that echos a user defined type.

   public interface Hello extends Remote
   {
      public UserType echoUserType(UserType in0) throws RemoteException;
   }

Run wstools with the following configuration

  <configuration ...>
    <java-wsdl>
      <service name="HelloService" style="rpc" 
        endpoint="org.jboss.test.ws.jaxrpc.samples.wssecurity.Hello"/>
    
      <namespaces target-namespace="http://org.jboss.ws/samples/wssecurity" 
        type-namespace="http://org.jboss.ws/samples/wssecurity/types"/>
    
      <mapping file="jaxrpc-mapping.xml"/>
      <webservices servlet-link="HelloService"/>
    </java-wsdl>
  </configuration>

Configuration and setup

JBossWS uses handlers to identify ws-security encoded requests and invoke the security components to sign and encrypt messages. In order to enable security processing, the client and server side need to include a corressponding handler configuration. The preferred way is to reference a JAX-RPC Client Configuration#Standard WSSecurity Client

<jboss-client>
  <jndi-name>jbossws-client</jndi-name>
  <service-ref>
       <service-ref-name>service/HelloService</service-ref-name>
       <config-name>Standard WSSecurity Client</config-name>
       <wsdl-override>http://@jbosstest.host.name@:8080/jbossws-samples-wssecurity-encrypt?wsdl</wsdl-override>
  </service-ref>
</jboss-client>

WS-Transaction

Support for the WS-Coordination, WS-AtomicTransaction and WS-BusinessActivity specifications will be provided by technology recently acquired from Arjuna Technologies Ltd. This technology will be present within the JBoss Transactions 4.2.1 release. Further information can be obtained from the JBoss Transactions Project

XML Registries

The JAXR sample has been migrated to JAX-WS User Guide#XML Registries.

Apendix A

WSTools configuration syntax

JAX-RPC Endpoint Configuration

JAX-RPC Client Configuration