3.3. How to use WebServices

3.3.1. Endpoint Creation

When you want to expose business methods, such as web services, you have to use a servlet container such as Tomcat to hold the Axis servlet that receives the SOAP messages from clients.

You have a choice of Axis configurations. You must write a .wsdd file that stores the Axis-specific configuration parameters. This file can be of two forms:

The first form is preferred for development purposes because you can easily change configuration values and submit them again to the Axis servlet (the Axis servlet will merge the current WEB-INF/server-config.wsdd with this new configuration file). It is usually named deploy.wsdd (its location is free).

The second form is appropriate when used in production environment where configuration changes are minor (the two forms result in the same Axis WSDD file). The file must be named server-config.wsdd and it must be located in WEB-INF directory of the servlet.

3.3.1.1. Exposing a Stateless Session Bean

To expose a Stateless Session Bean:

  1. Create a simple WebApp containing minimal Axis definitions, such as a WEB-INF/web.xml that declares the Axis servlet and a servlet mapping (see the example at ./ws/sample-web.xml).

  2. Create a WSDD file (use either of the forms described in Section 3.3.1 Endpoint Creation).

    • Add a service with a unique name (this is used to find the appropriate service to invoke from the URL String).

    • Set a provider for the service:

      java:EJB
  3. Add mandatory parameters for EJB exposition:

    • beanJndiName: A name used in Axis lookup. (If you add an ejb-ref or ejb-local-ref in the web-app descriptor, you can set a java:comp/env name here.)

    • homeInterfaceName: EJB Home interface (a fully qualified class name).

    • remoteInterfaceName: EJB Remote interface (a fully qualified class name).

    • localHomeInterfaceName: Local EJB Home interface (a fully qualified class name).

    • localInterfaceName: Local EJB interface (a fully qualified class name).

    • allowedMethods: a comma-separated list of method names that are accessible through the web service.

You must set at least local or remote interface names. If local and remote interfaces are specified, Axis chooses to use REMOTE interface, even if they are different.

See Section 3.3.3 Using an Axis WSDD Configuration file for more information.

3.3.1.2. Exposing Simple class (JAX-RPC class)

JAX-RPC classes are just normal classes, with no particular inheritance needs, that are exposed as a web service.

  1. Add the Axis servlet declaration in your web-app descriptor with a servlet mapping (see an example at ./ws/sample-web.xml).

  2. Create a WSDD file (use the form you prefer).

    • Add a service with a unique name (this is used to find an appropriate service to invoke from the URL String).

    • Set a provider for the service:

      java:RPC

  3. Add mandatory parameters for JAX-RPC classes exposition:

    • className: The fully qualified name of the class you want to expose as web service.

    • allowedMethods: A comma-separated list of method names accessible via the web service.

3.3.2. Client Creation

Creation of a web services client is heavily based on WSDL knowledge, even if it is not mandatory.

3.3.2.1. WSDL Knowledge

WSDL is the easiest way to create a web service client. You just need to generate all files needed to access the web service, compile them, and add them to your component archive. You can do this from the command line using the org.apache.axis.wsdl.WSDL2Java tool. For example:

jclient org.apache.axis.wsdl.WSDL2Java --output destination directory 
  --NStoPkg namespace=package wsdl_url

The --NStoPkg option places generated classes in a convenient package, according to the namespace of the WSDL Definition and the namespaces of the XML Schemas.

Axis provides an Ant Task (http://ws.apache.org/axis/java/ant/ant.html) for automated builds:

<taskdef name="axis-wsdl2java"
  classname="org.apache.axis.tools.ant.wsdl.Wsdl2javaAntTask">
    <!-- classpath holds jonas.jar, webservices_axis.jar, ... -->
    <classpath refid="base.classpath"/>
</taskdef>

<axis-wsdl2java url="${ws.google.wsdl}/GoogleSearch.wsdl"
      output="${src.dir}">
    <mapping namespace="urn:GoogleSearch"
      package="org.objectweb.wssample.gen.google"/>
</axis-wsdl2java>

Code sample:

import
path.to.your.generated.classes.*;
[...]
<ServiceInterface> service = new <Service>Locator();
<PortInterface> port = service.get<PortName>();
<ObjectType> result = port.<methodName>(<arguments>);

3.3.2.2. No WSDL Knowledge

When the client does not have the WSDL of the service to access, you have to use Service-agnostic interfaces.

With Axis, you have to instantiate an org.apache.axis.client.Service class (http://ws.apache.org/axis/java/apiDocs/org/apache/axis/client/Service.html) implementation of javax.xml.rpc.Service (http://java.sun.com/j2ee/1.4/docs/api/javax/xml/rpc/Service.html), create a javax.xml.rpc.Call instance (http://java.sun.com/j2ee/1.4/docs/api/javax/xml/rpc/Call.html) from the Service, configure it manually, and invoke the Call.

javax.xml.rpc.Call Example

import javax.xml.rpc.Call;
import javax.xml.rpc.Service;
import javax.xml.namespace.QName;
import javax.xml.rpc.encoding.TypeMappingRegistry;
import javax.xml.rpc.encoding.TypeMapping;
import org.apache.axis.encoding.ser.BeanSerializerFactory;
import org.apache.axis.encoding.ser.BeanDeserializerFactory;
[...]
// create a Service instance (other constructor usable, see the doc)
Service service = new org.apache.axis.client.Service();

// configure mappings if web service uses Complex types
// first get the mapping registry instance
TypeMappingRegistry tmr = service.getTypeMappingRegistry();

// create a QName representing the fully qualified name of the
// XML type to serialize/deserialize (namespace+locapart pair)
QName xmlType = new QName("namespace-of-complex-type", "complex-type-name");

// get a TypeMapping (default for axis is SOAP encoding TypeMapping)
TypeMapping tm = tmr.getDefaultTypeMapping();

// register the XML type with a Java class by specifying
// Serializer/Deserializer factories to use.
tm.register(your.java.Type.class,
            xmlType,
            new BeanSerializerFactory(your.java.Type.class, xmlType),
            new BeanDeserializerFactory(your.java.Type.class, xmlType));

// get a Call instance from the Service
// specify port to use and operation name to be invoked
// see the doc for other createCall methods usage
Call call = service.createCall(new QName("port-name", 
    new QName("operation-name")));

// where is the web service?
call.setTargetEndpointAddress("url-address-of-the-endpoint");

// now, invoke the web service with its parameters
String result = call.invoke(new Object[] {"Hello, World!"});

3.3.3. Using an Axis WSDD Configuration file

This section covers the basic functions of the wsdd configuration files. For detailed information, refer to the Axis User Guide http://ws.apache.org/axis/java/user-guide.html and Axis Reference Guide http://ws.apache.org/axis/java/reference.html.

3.3.3.1. Service

<service> is the tag used to declare a web service. attributes:

  • name: the unique name of the service

  • provider: the bridge used by Axis to invoke different objects: EJB, normal classes, CORBA objects, ...

    provider can take the following values:

    • java:EJB (used to expose EJB Stateless Session Bean)

    • java:RPC (used to expose Simple classes)

    • java:MSG

  • style: Defines the global format of the SOAP Message.

    style can take the values document or rpc.

    With rpc, SOAP Messages must have as their first soap:body element, an element named as the operation to be invoked.

    With document, SOAP Messages must not have a first element that has the operation name.

  • use: a SOAP-encoded message or a message enclosing classic XML Elements (depends on the style attributes).

    use can take the values encoded or literal.

    With encoded, SOAP references can be used in the SOAP Message.

    With literal, no SOAP references are permitted in the SOAP Message.

    NoteNote
     

    A SOAP reference is something like a pointer; in an XML SOAP Message, an Element is defined with an ID that can be referenced from somewhere else in the SOAP Message.

3.3.3.1.1. Axis javadoc for style

The following descriptions show different style and use combinations.

style=rpc, use=encoded

The first element of the SOAP body is the operation. The operation contains elements describing the parameters, which are serialized as encoded (possibly multi-ref).

<soap:body>
  <operation>
    <arg1>...</arg1>
    <arg2>...</arg2>
  </operation>
style=RPC, use=literal

The first element of the SOAP body is the operation. The operation contains elements describing the parameters, which are serialized as encoded (no multi-ref).

<soap:body>
  <operation>
    <arg1>...</arg1>
    <arg2>...</arg2>
  </operation>
style=document, use=literal

Elements of the SOAP body are the names of the parameters (there is no wrapper operation...no multi-ref).

<soap:body>
  <arg1>...</arg1>
  <arg2>...</arg2>
style=wrapped

Special case of DOCLIT where there is only one parameter and it has the same qname as the operation. In such cases, there is no actual type with the name—the elements are treated as parameters to the operation.

<soap:body>
  <one-arg-same-name-as-operation>
  <elemofarg1>...</elemofarg1>
  <elemofarg2>...</elemofarg2>
style=document, use=encoded

There is not an enclosing operation-name element, but the parameters are encoded using SOAP encoding. This mode is not (well?) supported by Axis.

3.3.3.2. Parameter

<parameter> is the tag used to configure a service. It is basically a name-value pair.

attributes

  • name: parameter name (key)

  • value: parameter value

common parameter

  • className: fully qualified class name of service class (only used for provider RPC & MSG)

  • beanJndiName: name used in Axis lookup. (If you add ejb-ref or ejb-local-ref in the web-app descriptor, you can set a java:comp/env name here.)

  • localHomeInterfaceName: Local EJB Home interface fully qualified class name.

  • localInterfaceName: Local EJB interface fully qualified class name.

  • homeInterfaceName: EJB Home interface fully qualified class name.

  • remoteInterfaceName: Remote EJB interface fully qualified class name.

  • allowedMethods: comma-separated list of method names accessible via the web service (for all providers).

  • scope: scope of the web service:

    • Request: create a new Object for each request

    • Session: keep the same Object for a given Session ID

    • Application: keep the same Object for the entire application run.

3.3.3.3. Optional

Other options can be specified to a service without parameter tags:

  • wsdlFile: specify the static wsdl file to be served when a ?WSDL request comes to the endpoint.

  • namespace: specify the web service namespace (override default namespace created from URL location of the service). With this tag you can handle the namespace value.

    By default, a namespace will look like this: http://ws.servlets.wssample.objectweb.org (for a JAX-RPC class named org.objectweb.wssample.servlets.ws)! You can write a shorter and better namespace as you wish: urn:JaxRpcWsSample for example.

  • operation: used to describe the operation exposed (avoid Axis to use reflection to discover the service interface). See the Axis documentation for details.

3.3.3.4. Mappings

Mappings in WSDD can be set at different levels: mappings commons for all services are directly children of the deployment tag, and mappings specific for a given web service are children of the service tag.

You can specify to sort mappings in the WSDD configuration file: beanMapping and typeMapping. beanMapping is a write shortcut for typeMapping that you can use when mapping bean types. It is used to register a Java type, with an XML QName and a serializer/deserializer pair.

<typeMapping xmlns:ns="urn:my.namespace"
    serializer="your.java.serializer.factory"
    deserializer="your.java.deserializer.factory"
    qname="ns:my-xml-type-name"
    type="java:your.java.classname"
    encodingStyle="encoding-namespace"/>

NoteNote
 

  • Type value must be a qname in a java-prefixed namespace (java:XXX.YYY). By default encodingStyle is set to http://schemas.xmlsoap.org/soap/encoding/ (SOAP 1.1 Encoding).

  • When Arrays of Complex Types are serialized and/or deserialized, the factories to be used are: org.apache.axis.encoding.ser.ArraySerializerFactory and org.apache.axis.encoding.ser.ArrayDeserializerFactory.

<beanMapping xmlns:ns="urn:my.namespace"
    languageSpecificType="java:your.java.classname"
    qname="ns:my-xml-type-name"/>

NoteNote
 

  • Serializer and deserializer are automatically set to BeanSerializerFactory and BeanDeserializerFactory.

  • The encodingStyle is automatically set to null (cannot be overridden).

3.3.3.5. Deployment

Deployment is the root Element of any Axis WSDD file. It holds commons namespace definition.

A normal deployment Element looks like this:

<deployment xmlns="http://xml.apache.org/axis/wsdd/"
    xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">
    <!-- ... services definitions here ... -->
</deployment>

3.3.4. Deploy Created Web Service

The deployment of the web service in JOnAS depends of the form of your wsdd file: