Globus Toolkit 3.9.2 Development Documentation: WS Java Core

Java Developers' Guide

Writing Web Services

A Web service in Axis is a simple Java class with a default constructor. The service class does not have to implement any specific interfaces or inherit from a certain class. The service class is specified by the 'className' parameter in the service deployment descriptor. Please see Axis User's Guide for more information.

In WSRF Core, we assume that each service operation is implemented in a stateless manner.

Document/literal

The WS-RF specifications schemas follow the document/literal mode as described in WS-I Basic Profile. The Basic Profile defines certain rules to follow for document/literal and other modes to ensure interoperability.

For example, for document/literal mode, at most one <wsdl:part> is allowed in the <wsdl:message> element and it has to define the 'element' attribute. Also, the wire signatures must be unique (cannot use the same 'element' attribute in <wsdl:part> in two different <wsdl:message> elements).

Our implementation relies on these restrictions so please keep them in mind when designing your own schema.

Note: Axis' WSDL2Java tool might sometimes incorrectly detect that schema follows the wrapped/literal mode and generate wrong stub and type classes. To ensure that document/literal mode is always used:

  • use our generateStub* tasks in <install>/share/globus_wsrf_tools/build-stubs.xml ant file
  • if you are using WSDL2Java tool directly, you can alternatively specify the -W command line option.

Also, with wrapped/literal mode, the element name had to match the operation name in wsdl. This is not necessary with document/literal mode.

WS-Addressing

The WS-RF specifications use WS-Addressing (the 2003 version of the specification) for addressing services and resources.
Our implementation uses Apache Addressing library. The API are pretty straightforward and easy to use. Most of the work is done in AddressingHandler so make sure the handler is properly deployed. See Apache Addressing documentation for details.

Call object

If you are using the javax.xml.rpc.Call object directly, you can pass the addressing information by setting a Constants.ENV_ADDRESSING_REQUEST_HEADERS property on the call object.

For example:

        Service service = new Service();
        Call call = (Call) service.createCall();

        AddressingHeaders headers = new AddressingHeaders();
        Action a = new Action(new URI("urn:action"));
        headers.setAction(a);
        EndpointReference epr = new EndpointReference("http://www.apache.org");
        headers.setFaultTo(epr);

        call.setProperty(Constants.ENV_ADDRESSING_REQUEST_HEADERS, headers);
        call.setTargetEndpointAddress(new URL(url));
        call.setOperationName(new QName(
                "http://localhost:8080/axis/services/Version", "getVersion"));
        String ret = (String) call.invoke(new Object[]

AddressingLocator class

The Apache Addressing library also contains a version of Axis' WSDL2Java tool. It extends the Axis' WSDL2Java tool functionality by generating, in addition to all the regular classes, the <service>Addressing interface and <service>AddressingLocator class.

The AddressingLocator class can be used to get a stub for a service by passing Apache Addressing EndpointReferenceType parameter.

For example:

        EndpointReferenceType epr = new EndpointReferenceType();
        epr.setAddress(
            new Address("http://localhost:8080/axis/services/Version")
        );

        VersionServiceAddressingLocator locator =
            new VersionServiceAddressingLocator();

        VerionServicePortType port = locator.getVersionPort(epr);

        port.getVersion();

ReferenceProperties

In WS-RF specifications, the WS-Addressing ReferenceProperties are used to carry resource identity information. The resource identity can be anything as long as it serializes as a XML element.

Apache Addressing library only allows a DOM Element or a SOAPElement to be a reference property.

For example:

        // this will be a reference property
        SimpleResourceKey key = new SimpleResourceKey(Counter.KEY, "123");

        ReferencePropertiesType props = new ReferencePropertiesType();

        // convert to SOAPElement and add to the list
        props.add(key.toSOAPElement()); 

        EndpointReferenceType epr = new EndpointReferenceType();
        epr.setAddress(
            new Address("http://localhost:8080/axis/services/Version")
        );
        epr.setProperties(props);

        VersionServiceAddressingLocator locator =
            new VersionServiceAddressingLocator();

        VerionServicePortType port = locator.getVersionPort(epr);

        port.getVersion();

Operation providers

GT3 introduced a concept of operation providers where a service could be composed of different parts/classes. WSRF Core also supports this functionality. In GT3 operation providers had to implement a specific interface. In WSRF Core no such interface is required. As matter of fact an operation provider is not in any way different from a standard web service. That means that any web service can automatically be used as an operation provider (as long as it uses common or standard interfaces to operate on resources.)

Configuring operation providers

To enable operation provider support for your service, make the following changes to the service deployment descriptor:

1 Change the value of the provider attribute to Handler.
2 Add a handleClass parameter with a value of org.globus.axis.providers.RPCProvider.
3

Specify providers in the providers parameter.

The value of the parameter is a space-separated list of either provider names or class names. If provider names are used, they must first be defined as parameters in the <globalConfiguration> element of the main deployment descriptor.

For example:

  <globalConfiguration>
  ...
   <parameter name="GetRPProvider" 
              value="org.globus.wsrf.impl.properties.GetResourcePropertyProvider"/>
  ...
  </globalConfiguration>
4 Add or change the value of the scope parameter to Application

The following is an example of a modified service deployment descriptor:

    <service name="SubscriptionManagerService" provider="Handler"
        use="literal" style="document">
        <parameter name="allowedMethods" value="*"/>
        <parameter name="scope" value="Application"/>
        <parameter 
            name="providers"
            value="GetRPProvider 
                   org.globus.wsrf.impl.lifetime.SetTerminationTimeProvider
                   PauseSubscriptionProvider"/>
        <parameter 
            name="handlerClass" 
            value="org.globus.axis.providers.RPCProvider"/>
        <parameter name="className" 
            value="org.globus.wsrf.impl.notification.ResumeSubscriptionProvider"/>
        <wsdlFile>share/schema/core/notification/subscription_manager_service.wsdl</wsdlFile>
    </service>
Note: The operations defined in the className service always overwrite the providers' operations. That is, if one provider defines the same method as the service specified in the className parameter, the operation will be invoked on the service. Also, if two providers define the same method, the first one specified in the providers parameter will be invoked.

Configuring allowed methods

All public methods of a service can potentially be invoked remotely unless the service is configured with the correct allowedMethods parameter. The control over allowed methods becomes more problematic if the service is configured with a number of operation providers.

To solve the problem, WSRF code adds a new allowedMethodsClass parameter which can be used to set the allowed methods from a class. The methods defined in that class are the only methods that can be invoked on the service. We recommend that the allowedMethodClass be set to the service interface class generated by WSDL2Java tool (if wsdl is used.)

Note: The allowedMethods and allowedMethodsClass parameters are exclusive of one another. In other words, you can't have both specified at the same time in the same service deployment descriptor.

JNDI

Standalone container only.

WSRF Core provides Tomcat's JNDI implementation. The file format of our jndi-config.xml is slightly different from the Tomcat's server.xml file. One main difference is that the <resourceParams> are specified as children of <resource> objects. Also, our jndi-config.xml parser is case sensitive and all elements names are lowercase.

All elements defined in the <global> section of the JNDI configuration file are deployed into the java:comp/env context under the name specified in the 'name' attribute. All <service> elements are deployed into java:comp/env/<service name> context. New objects and contexts can be added or modified dynamically at runtime but they will not be persisted. The only way to always have some object around is to deploy it in the jndi-config.xml file. All services share the same java:comp/env context. This is different from EJBs where each EJB has a separate java:comp/env context.

When deploying <resource> in jndi-config.xml make sure to use the org.globus.wsrf.tools.jndi.BeanFactory as a BeanFactory (value of a 'factory' parameter) instead of org.apache.naming.factory.BeanFactory. Your bean must have a default constructor. If your bean implements the org.globus.wsrf.tools.jndi.Initializable interface, the initialize() function will be automatically called after all parameters are set on the bean.

Please see The JNDI Tutorial for more information on JNDI programming.

Logging and Debugging

Logging in the WSRF Core is based on the Jakarta Commons Logging architecture. Commons Logging provides a consistent interface for instrumenting source code while at the same time allowing the user to plug-in a different logging implementation. Currently we use Log4j as a logging implementation.

Tracing SOAP messages

There are three methods for tracing SOAP messages: using TcpMon, using MessageLoggingHandler and enabling logging for Axis classes.

Using TcpMon

To trace SOAP messages on the wire you can use TcpMon from Apache Axis. After setting the environment using $GLOBUS_LOCATION/etc/globus-dev-env.[sh|csh|bat] you can run:

java org.apache.axis.utils.tcpmon [listenPort targetHost targetPort]

If no arguments are used, you have to fill out these values in the GUI.

Using MessageLoggingHandler

Another method for logging SOAP messages is to add the org.globus.wsrf.handlers.MessageLoggingHandler to the request or response chain in the server-config.wsdd or client-config.wsdd files.

For example:

<requestFlow>
...
<handler type="java:org.globus.wsrf.handlers.MessageLoggingHandler"/>
...
<requestFlow>

Then you must enable logging for this class in log4j.properties file and change the logging level to DEBUG:

log4j.category.org.globus.wsrf.handlers.MessageLoggingHandler=DEBUG

Enabling logging for Axis classes

Another method for tracing SOAP messages is to enable logging for selected Axis classes. Add the following lines to the log4j.properties file:

 log4j.category.org.apache.client.Call=DEBUG
 log4j.category.org.apache.axis.transport.http.HTTPSender=DEBUG
This will log Axis client side calls and Axis HTTP messages.

Debugging Log4j

If you are having problems with configuring Log4j, you can enable internal Log4j debugging by adding -Dlog4j.debug option on the java command line.