Howto: Getting Started with WebServices and JOnAS 3.X



WebServices and J2EE

    WebServices are fully integrated in J2EE 1.4 compliant Application Servers.
    Web services technologies can be seen as another communication protocol used to interoperate heterogeneous systems. Web services are based on the SOAP protocol. The SOAP messages can be transported with various transport mode (JMS, HTTP, mail, ...) but the focus of this document is the HTTP transport (because Web Services for J2EE v1.1 use only SOAP/HTTP).

Early Integration of Axis in JOnAS 3.X series

    JOnAS hosts Apache Axis starting with version 3.0. This means that the user no longer must add Axis jars in its webapp.
To use an Axis class (AdminClient, WSDL2Java, ...) from the command line, simply use the jclient script in place of the common java executable (jclient will create the appropriate classpath).

How to use WebServices


Endpoint Creation

    When it is desirable to expose some business methods as web services, a servlet container such as Tomcat or Jetty should be used to hold the Axis servlet where the SOAP messages of clients will ultimately end up.
    To configure Axis, the developer must write a .wsdd file holding Axis-specific configuration parameters. This can be in one of two different forms: a simple wsdd containing only information about the web services the developer wants to expose (see an example here), or a complete wsdd containing exposed web services information AND Axis base configuration (see an example here).
    The first form is preferred for development purposes, because the developer 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 user-defined).
    The second form is appropriate when used in a production environment where configuration changes are minor (ultimately, both forms results in the same Axis wsdd file). It MUST be named server-config.wsdd and located in the WEB-INF directory of the servlet.

Exposing Stateless Session Bean

1. Create a simple WebApp containing minimal Axis information, such as a WEB-INF/web.xml declaring the Axis servlet and servlet mapping (sample here).
2. Create a wsdd file (use the form you prefer)
3. Add mandatory parameters for EJB exposition:
The developer must set AT LEAST local OR remote interface names. If local AND remote interfaces are specified, Axis will use the REMOTE interface, even if the interfaces are different.

Refer to "Using Axis WSDD configuration files"  for more information.

Exposing Simple class (JAX-RPC class)

JAX-RPC classes are normal classes with no particular inheritance requirements, exposed as a web service.
1. Add the Axis servlet declaration in the web-app descriptor (sample here) with a servlet mapping.
2. Create a wsdd file (use whichever form you prefer).
3. Add mandatory parameters to expose JAX-RPC classes:

Client Creation

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

WSDL Knowledge

    WSDL is the easiest way to create a web service client.
    All that is necessary is to generate the files needed to access the web service, then compile them and add them into your component archive.
    This can be done from the command line using the org.apache.axis.wsdl.WSDL2Java tool.

example:
    jclient org.apache.axis.wsdl.WSDL2Java --output <destination directory> --NStoPkg
    <namespace>=<package> <wsdl url>

The --NStoPkg option is used to place generated classes in a convenient package according to the namespace of the WSDL Definition and the namespace(s) of the XML Schema(s).

Axis provides an Ant Task for automated build:
<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 :
import path.to.your.generated.classes.*;
[...]
<ServiceInterface> service = new <Service>Locator();
<PortInterface> port = service.get<PortName>();
<ObjectType> result = port.<methodName>(<arguments>);

No WSDL Knowledge

    When the client does not have the WSDL of the service to access, the developer must use Service agnostic interfaces.
    With Axis, you must instantiate an org.apache.axis.client.Service class (implementation of javax.xml.rpc.Service), create a javax.xml.rpc.Call instance from the Service, configure it manually, and invoke the Call.

Refer to the following 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 use 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, we can invoke the web service with its parameters
String result = call.invoke(new Object[] {"Hello, World!"});

Using Axis WSDD Configuration file

This section covers the basic functionality of wsdd configuration files.
For detailed information refer to the Axis User Guide and Reference Guide.

Service

<service> is the tag used to declare a web service.
Attributes:
Provider possible values: java:EJB (used to expose EJB Stateless Session Bean), java:RPC (used to expose Simple classes), java:MSG (used to ???)
Style possible values: document, rpc
    With RPC, SOAP Messages must have an element named as the operation to be invoked as their first soap:body element.
    With Document, SOAP Messages cannot have a first element with the operation name.
Use possible values: encoded, literal
    With encoded, SOAP refs can be used in the SOAP Message.
    With literal, no SOAP refs can be used in the SOAP Message.
Note: a SOAP ref is similar to 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.

Refer to the following snippet of Axis javadoc for style and use combinations:

Description of the different styles
style=rpc, use=encoded
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
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 no enclosing operation name element, but the parameters are encoded using SOAP encoding This mode is not (well?) supported by Axis.

Parameter

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

Optional

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

Mappings

    Mappings in WSDD can be set at different levels: mappings commons for all services are direct children of the deployment tag, and mappings specific for a given web service are children of the service tag.
    The developer can specify the type of mappings in the WSDD configuration file: beanMapping and typeMapping. beanMapping is a write shortcut for typeMapping when mapping bean types.
    Mapping is used to register a java type, with an XML QName and a serializer/deserializer pair.

examples:
<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"/>
Notes :
type value must be a qname in 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 deserailized the factories to be used are :
org.apache.axis.encoding.ser.ArraySerializerFactory
org.apache.axis.encoding.ser.ArrayDeserializerFactory

<beanMapping xmlns:ns="urn:my.namespace"
             languageSpecificType="java:your.java.classname"
             qname="ns:my-xml-type-name"/>
Notes :
serializer and deserializer are automatically set to BeanSerializerFactory and BeanDeserializerFactory
encodingStyle is automatically set to null (cannot be overridden)

Deployment

    A deployment Element is the root Element of any Axis WSDD file. It holds commons namespace definitions.

    A normal deployment Element looks like the following:

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

Deploy Created Web Service

    Deployment of the web service in JOnAS depends on the form of the wsdd file:
For full wsdd configuration files, simply add the wsdd file in the WEB-INF/ directory of the servlet with the name server-config.wsdd. Deployment will be performed automatically by Axis when the first client attempts to connect.
For simpler wsdd configuration files, deploy the web-app (or ear) into JOnAS (normal process). Then, use the Axis AdminClient tool:
jclient org.apache.axis.client.AdminClient -lhttp://<hostname>:<port>/<web-app-context>/<servlet-mapping-to-Axis-Servlet> <your-deploy>.wsdd