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.xmlant file - if you are using WSDL2Java tool directly, you can alternatively specify
the
-Wcommand 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 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 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=DEBUGThis 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.