Table of Contents
This guide contains information of interest to developers working with Java WS Core. It provides reference information for application developers, including APIs, architecture, procedures for using the APIs and code samples.
New Features in the GT 4.0 release
- Implementation of the 2004/06 OASIS WSRF and WSN working draft specifications (with minor fixes to the 1.2-draft-01 published schemas and with the March 2004 version of the WS-Addressing specification)
- Basic HTTP/1.1 client & server support
- JNDI-based registry based on the JNDI service in Apache Tomcat
- An implementation of the Work Manager and Timer specifications
Other Supported Features
- A standalone and embeddable container
- Tomcat 4.1 and 5.0 support
- Basic API for resource persistence and recovery
- Persistent subscriptions support
- Automatic service and ResourceHome activation on startup
- Operation providers
Deprecated Features
- None
Java WS Core should work on any platform that supports J2SE 1.3.1 or higher.
Tested platforms for Java WS Core:
- Linux (Red Hat 7.3)
- Windows 2000 and XP
- Solaris 9
Tested JVMs for Java WS Core:
- Sun JVM 1.3.1, 1.4.2 and 1.5.0
- IBM JVM 1.3.1, 1.4.1, and 1.4.2
- BEA JRockit JVM 1.5.0
JVM notes:
Tested containers for Java WS Core:
- Java WS Core container
- Tomcat 4.1.31
- Tomcat 5.0.30
Protocol changes since GT version 3.2
- HTTP/1.1 with 'chunked' transfer encoding is now used by default.
- Wire messages follow the new schemas and therefore are completely different (see below).
API changes since GT version 3.2
- The majority of the APIs are new. Some APIs resemble GT 3.2 APIs, for example
ServiceData
is replaced byResourceProperty
andServiceDataSet
is replaced byResourcePropertySet
.
Schema changes since GT version 3.2
- Schemas are completely new. The WS Java Core implements the OASIS WSRF and WSN working drafts specifications (with minor fixes to the 1.2-draft-01 published schemas and with the March 2004 version of the WS-Addressing specification.)
Java WS Core depends on the following GT components:
Java WS Core depends on the following 3rd party software:
Please see the Technology Dependencies Details page for details.
The service configuration files such as jndi-config.xml or server-config.wsdd (located under $GLOBUS_LOCATION/etc/<gar>/
directory) may contain private information such as database passwords, etc. Ensure that these configuration files are only readable by the user that is running the container.
The deployment process automatically sets the permissions of the jndi-config.xml
and server-config.wsdd
files as user readable only. However, this might not work correctly on all platforms and this does not apply to any other configuration files.
The services using subscription persistence API or other basic persistence helper API will store all or part of its persistent data under the ~/.globus/persisted
directory. Ensure that the entire ~/.globus/persisted
directory is only readable by the user running the container.
A client can potentially invoke a service function that is not formally defined in the WSDL but it is defined in the service implementation class. There are two ways to prevent this from happening:
- Define all service methods in your service class as either
private
orprotected
. - Configure appropriate
allowedMethods
orallowedMethodsClass
parameter in the service deployment descriptor (please see Java WS Core Configuration for details).
- Java WS Core Design Document [doc | pdf]
- Java WS Core UML [vsd | Resource (.gif), Resource Property (gif), Notification (gif)]
- Java WS Core Notification UML Sequence Diagrams [vsd | Subscription (jpg), Notification (jpg)]
The semantics and syntax of the APIs and WSDL for the component, along with descriptions of domain-specific structured interface data, can be found in the Java WS Core Public Interfaces Chapter.
The WSRF and WSN 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.
Java WS Core relies on these restrictions so please keep them in mind when designing your own schema.
In the document/literal mode as defined in the WS-I Basic Profile at most one <wsdl:part> is allowed in the <wsdl:message> element and it must use 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).
![]() | 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:
Also, with wrapped/literal mode, the element name had to match the operation name in wsdl. This is not necessary with document/literal mode. |
Do not use or mix the literal mode with the SOAP encoding mode (R2706). For example, do not use the soapenc:Array
type. Please see the 5.2.3 section in the WS-I Basic Profile for details.
GT3 introduced the concept of operation providers where a service could be composed of different parts/classes. Java WS Core also supports this functionality. In GT3 operation providers had to implement a specific interface. In Java WS Core no such interface is required. In fact, an operation provider is not in any way different from a standard web service. That means that any web service implementation can automatically be used as an operation provider (as long as it uses common or standard interfaces to operate on resources).
To enable operation provider support for your service, make the following changes to the service deployment descriptor:
- Change the value of the
provider
attribute toHandler
. - Add a
handleClass
parameter with a value oforg.globus.axis.providers.RPCProvider
. 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 (etc\globus_wsrf_core\server-config.wsdd
).For example:
<globalConfiguration> ... <parameter name="GetRPProvider" value="org.globus.wsrf.impl.properties.GetResourcePropertyProvider"/> ... </globalConfiguration>
- Add or change the value of the
scope
parameter toApplication
orRequest
.
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 |
Java WS Core provides Tomcat's JNDI implementation. The file format of Java WS Core's 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, Java WS Core's jndi-config.xml
parser is case sensitive and all element 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 the java:comp/env/services/<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 an 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.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.
To activate a service, an RPCProvider is available from both Axis and Globus.
The scope
setting of the service dictates when and how service instances
are created:
Table 1. Scope settings
Application | One instance of the service is used for all invocations. |
Request | One instance is created per invocation. This is the default (if scope parameter is not set in the deployment descriptor). |
Session | One instance is created per session. |
If the service
implements the javax.xml.rpc.server.ServiceLifecycle interface,
the lifecycle methods will be called according to the scope
setting
as a service instance is created and destroyed.
For example, in Application scope, destroy() will be called on container shutdown, and in Request scope it will be called after the service method is called.
With Axis RPCProvider, JAAS credentials are never associated with the invocation thread.
The scope
setting of the service dictates when and how service instances
are created (only Application and Request scopes are supported
with Globus RPCProvider):
Table 2. Scope settings and activation
Application |
Service/provider instances are created either on first invocation or on container startup. The behavior is determined by the value of the "loadOnStartup" parameter. This will work in the same way in both the stand-alone container and in Tomcat. If the service or the container is configured with a security
descriptor, the appropriate credentials will be associated with the thread
during activation (using JAAS). Also, during activation a basic Axis
MessageContext will be associated with the thread with only |
Request |
One instance is created per invocation. This is the default (if scope parameter is not set in the deployment descriptor). Behaves more or less just like the Axis RPCProvider (service/providers instances are created per invocation, ServiceLifecycle methods called right before and after service method invocation, no JAAS credentials during ServiceLifecycle methods). |
A ResourceHome will be activated either on the first service invocation or, if "loadOnStartup" parameter is set to "true", during container startup. Both mechanisms trigger actual activation by looking up the ResourceHome in the JNDI directory. This initial lookup causes a proper MessageContext and/or JAAS subject to be associated with the current thread, instantiation of the object implementing the ResourceHome and, if the ResourceHome implements the org.globus.wsrf.jndi.Initializable interface, the invocation of the initialize() function.
In fact, the same steps are performed upon initial lookup of any JNDI resource entry that uses the org.globus.wsrf.jndi.BeanFactory class for its factory and is defined directly under a service entry in a jndi-config.xml file.
The WS-RF and WS-N specifications distributed with Java WS Core use WS-Addressing (the
March 2004 version of the specification) for addressing services and resources.
Java WS Core uses the Apache Addressing library for WS-Addressing support. The API is pretty straightforward
and easy to use. Most of the work is done in AddressingHandler
deployed
in the client and server configuration files. See Apache Addressing documentation for details.
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(); String url = "http://localhost:8080/axis/services/Version"; AddressingHeaders headers = new AddressingHeaders(); headers.setTo(new To(url)); // pass the addressing info to the addressing handler call.setProperty(Constants.ENV_ADDRESSING_REQUEST_HEADERS, headers); call.setTargetEndpointAddress(new URL(url)); call.setOperationName(new QName(url, "getVersion")); // url here is just a namespace String ret = (String) call.invoke(new Object[]);
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 the Apache Addressing EndpointReferenceType
parameter.
For example:
String url = "http://localhost:8080/axis/services/Version"; EndpointReferenceType epr = new EndpointReferenceType(); epr.setAddress(new Address(url)); VersionServiceAddressingLocator locator = new VersionServiceAddressingLocator(); VerionServicePortType port = locator.getVersionPort(epr); port.getVersion();
In the WS-RF and WS-N 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. The ReferenceProperties
are serialized as separate SOAP headers in the SOAP envelope.
The Apache Addressing library only allows a DOM Element
or a SOAPElement
to
be a reference property.
For example, create ReferencePropertiesType
and fill it with resource key info:
// create a reference property QName keyName = new QName("http://axis.org", "VersionKey"); String keyValue = "123"; SimpleResourceKey key = new SimpleResourceKey(keyName, keyValue); ReferencePropertiesType props = new ReferencePropertiesType(); // convert to SOAPElement and add to the list props.add(key.toSOAPElement()); ...
Then pass it to AddressingHeaders
:
...
Service service = new Service();
Call call = (Call) service.createCall();
String url = "http://localhost:8080/axis/services/Version";
AddressingHeaders headers = new AddressingHeaders();
headers.setTo(new To(url));
headers.setReferenceProperties(props);
// pass the addressing info to the addressing handler
call.setProperty(Constants.ENV_ADDRESSING_REQUEST_HEADERS, headers);
call.setTargetEndpointAddress(new URL(url));
call.setOperationName(new QName(url, "getVersion")); // url here is just a namespace
String ret = (String) call.invoke(new Object[]);
Or set it on EndpointReferenceType
:
...
String url = "http://localhost:8080/axis/services/Version";
EndpointReferenceType epr = new EndpointReferenceType();
epr.setAddress(new Address(url));
epr.setProperties(props);
VersionServiceAddressingLocator locator =
new VersionServiceAddressingLocator();
VerionServicePortType port = locator.getVersionPort(epr);
port.getVersion();
There are a few steps involved in setting up and receiving notifications:
The notification consumer application must provide an implementation of the org.globus.wsrf.NotifyCallback
interface. The deliver
function of the interface will be invoked whenever a notification for that consumer arrives. The message
parameter will either be of org.w3c.dom.Element
type if the message type was unknown or some object mapped to the type of the message.
![]() | Note |
---|---|
The |
In order to facilitate the receipt of notifications, start a NotificationConsumerManager
by
doing the following:
import org.globus.wsrf.NotificationConsumerManager; ... NotificationConsumerManager consumer = null; try { consumer = NotificationConsumerManager.getInstance(); consumer.startListening(); ... } catch (...) { ... }
![]() | Important |
---|---|
On the client when the
On the server when the
|
Register the callback implementation with the NotificationConsumerManager
(once
it is started) using the createNotificationConsumer
function.
The createNotificationConsumer
function
returns an endpoint for this notification consumer.
Example:
import org.globus.wsrf.NotifyCallback; import org.apache.axis.message.addressing.EndpointReferenceType; ... MyCallback callback = new MyCallback(); EndpointReferenceType consumerEPR = consumer.createNotificationConsumer(callback); ... class MyCallback implements NotifyCallback { .... }
Pass the endpoint returned by the createNotificationConsumer
function
to the subscribe call.
Example:
import org.oasis.wsn.TopicExpressionType; import org.oasis.wsn.Subscribe; import org.oasis.wsn.SubscribeResponse; import org.globus.wsrf.WSNConstants; import org.globus.wsrf.WSRFConstants; ... TopicExpressionType topicExpression = new TopicExpressionType(); topicExpression.setDialect(WSNConstants.SIMPLE_TOPIC_DIALECT); topicExpression.setValue(WSRFConstants.TERMINATION_TIME); Subscribe request = new Subscribe(); request.setUseNotify(Boolean.TRUE); request.setConsumerReference(consumerEPR); request.setTopicExpression(topicExpression); SubscribeResponse subResponse = port.subscribe(request); ...
Once done with the notifications, do the following clean up tasks.
Step 5a: Destroy subscriptions resource. Make sure to explicitly destroy the subscription resource or set its termination time. Example:
import org.globus.wsrf.core.notification.SubscriptionManager; import org.globus.wsrf.core.notification.service.SubscriptionManagerServiceAddressingLocator; import org.oasis.wsrf.lifetime.Destroy; ... SubscriptionManagerServiceAddressingLocator sLocator = new SubscriptionManagerServiceAddressingLocator(); SubscriptionManager manager = sLocator.getSubscriptionManagerPort( subResponse.getSubscriptionReference()); manager.destroy(new Destroy()); ...
Step 5b: Un-register the callback.
Make sure to call (especially in error cases) the
NotificationConsumerManager.removeNotificationConsumer()
function
to unregister the callback from the NotificationConsumerManager
.
Step 5c: Release resources. In addition, make sure to always call the
NotificationConsumerManager.stopListening()
function
when finished using the NotificationConsumerManager
. Otherwise,
some resources might not be released.
Example:
... } catch(Exception e) { ... } finally { if (consumer != null) { try { consumer.stopListening(); } catch (Exception ee) {} } }
In most cases, a service will need to return the endpoint information of the container to a client. Unfortunately, getting that information might not be easy. The only reliable way of getting the container endpoint information is to extract it from the MessageContext.TRANS_URL
property of the MessageContext/ResourceContext
associated with the current thread.
To obtain base container endpoint information use ServiceHost
API. For example:
import org.globus.wsrf.container.ServiceHost; ... URL containerBaseUrl = ServiceHost.getBaseURL(); ...
The above will return the base container URL such as http://localhost:8080/wsrf/services/
.
To obtain service endpoint information use ResourceContext
API. For example:
import org.globus.wsrf.ResourceContext; ... URL serviceUrl = ResourceContext.getResourceContext().getServiceURL(); ...
The above will return the service URL such as http://localhost:8080/wsrf/services/MyService
.
To obtain WS-Addressing endpoint for the service use AddressingUtils
API. For example:
import org.apache.axis.message.addressing.EndpointReferenceType; import org.globus.wsrf.utils.AddressingUtils; ... EndpointReferenceType containerEndpoint = AddressingUtils.createEndpointReference(null); ...
The above will create a EndpointReferenceType
object initialized with the Address
field set to the service URL (as before) and empty reference properties. Also, you can pass a non-null ResourceKey
instance to the createEndpointReference()
function to create an endpoint for a specific resource. The reference properties field of the created EndpointReferenceType
object will be set to the given ResourceKey
.
![]() | Note |
---|---|
The |
While we strongly recommend that you use the JNDI mechanism to provide your service with configuration information, it is sometimes necessary to obtain the value of parameters set in the WSDD file. Java WS Core provides some helper functions to ease this process:
import org.globus.wsrf.utils.ContextUtils; import org.apache.axis.MessageContext; ... MessageContext context = MessageContext.getCurrentContext(); String sampleProperty = (String) ContextUtils.getServiceProperty(context, "myProperty"); ...
Note that this function requires that a MessageContext
is associated with the current thread, which in general means that the call needs to happen within the context of a web service invocation.
![]() | Note |
---|---|
Specifying parameters using WSDD files depends on Axis and will likely not be supported in future versions of the toolkit. |
The following properties can be obtained from the SOAPContext/MessageContext associated with the current thread:
-
org.apache.axis.Constants.MC_HOME_DIR
- the base directory from which the wsdl files are loaded. -
org.apache.axis.Constants.MC_CONFIGPATH
- the base directory from which different configuration files are loaded. -
org.apache.axis.Constants.MC_REMOTE_ADDR
- the IP address of the client. -
org.apache.axis.MessageContext.TRANS_URL
- the URL of the request.
The Constants.MC_CONFIGPATH
property should be used to load any type of configuration file. Only Constants.MC_CONFIGPATH
and Constants.MC_HOME_DIR
are associated with the thread during activation.
In the standalone container the Constants.MC_HOME_DIR
and Constants.MC_CONFIGPATH
properties will usually point to the same directory. However, in Tomcat they will point to two different directories. Since GT 4.0.1, the Constants.MC_HOME_DIR
value can be accessed using the org.globus.wsrf.ContainerConfig.getSchemaDirectory()
static call, and Constants.MC_CONFIGPATH
value via the org.globus.wsrf.ContainerConfig.getBaseDirectory()
static call.
Services in the container can be invoked locally. Local invocations work just like remote invocations (all handlers are called, messages get serialized/deserialized) but messages do not travel over the network - everything happens in memory.
Local invocations can only be made on the server side and only when a Axis MessageContext is associated with a current thread. URLs with "local" protocol name are used for local invocations.
To invoke a service locally, do the following:
Register "local" protocol handler:
import org.globus.axis.transport.local.LocalTransportUtils; ... LocalTransportUtils.init(); ...
Create a service URL with "local" protocol:
URL url = new URL("local:///wsrf/services/MyService");
Configure the service stub for local invocation and make the call:
MyServiceAddressingLocator locator = new MyServiceAddressingLocator(); MyService port = locator.getMyServicePort(url); LocalTransportUtils.enableLocalTransport((Stub)port); port.hello();
Any program that is based on Java WS Core should contain as a first entry in its classpath the directory of the Java WS Core installation. This is to ensure that the right client-config.wsdd is used by the client. That configuration file contains important client-side information such as handlers, type mappings, etc.
Also, any program that is a notification consumer should be initialized with
the appropriate GLOBUS_LOCATION
system property (set to the installation
directory of Java WS Core). If the system property is not set, the notification
consumer might not initialize or work properly.
The GAR (Grid Archive) file is a single file which contains all the files and information that the container needs to deploy a service. The GAR files are deployed using globus-deploy-gar (globus-deploy-gar(1)) and undeployed using globus-undeploy-gar (globus-undeploy-gar(1)) tools.
Table 3. GAR file structure
docs/
| This directory contains service documentation files. |
share/
| This directory contains files that can be accessed or used by all services. |
schema/
| This directory contains service WSDL and schema files. |
etc/
| This directory contains service configuration files and a post-deploy.xml Ant script. |
bin/
| This directory contains service executables such as command line tools, GUI, etc. |
lib/
| This directory contains service and third party library files and any LICENSE files. |
server-deploy.wsdd
| This file is the server side deployment descriptor. |
client-deploy.wsdd
| This file is the client side deployment descriptor. |
jndi-config-deploy.xml
| This file is the JNDI configuration file. |
The contents of the GAR file are processed in the following way (all steps are performed only if necessary):
- Any files in the
docs/
directory in the GAR are copied into the$GLOBUS_LOCATION/docs/<gar.id>/
directory. - Any files in the
share/
directory in the GAR are copied into the$GLOBUS_LOCATION/share/<gar.id>/
directory. - Any files in the
schema/
directory in the GAR are copied into the$GLOBUS_LOCATION/share/schema/
directory. - Any files in the
etc/
directory in the GAR are copied into the$GLOBUS_LOCATION/etc/<gar.id>/
directory. - Any files in the
bin/
directory in the GAR are copied into the$GLOBUS_LOCATION/bin/
directory. - Any
.jar
files in thelib/
directory of the GAR are copied into the$GLOBUS_LOCATION/lib/
directory. - Any file that contains the word "LICENSE" in the name in the
lib/
directory of the GAR is copied into the$GLOBUS_LOCATION/share/licenses/
directory. - The
server-deploy.wsdd
in the GAR is copied to$GLOBUS_LOCATION/etc/<gar.id>/server-config.wsdd
. If a profile name was specified during deployment, theserver-deploy.wsdd
will be copied to$GLOBUS_LOCATION/etc/<gar.id>/<profile.name>-server-config.wsdd
. Theserver-config.wsdd
file will be set with user-only access permissions. - The
jndi-config-deploy.xml
in the GAR is copied to$GLOBUS_LOCATION/etc/<gar.id>/jndi-config.xml
. If a profile name was specified during deployment thejndi-config-deploy.xml
will be copied to$GLOBUS_LOCATION/etc/<gar.id>/<profile.name>-jndi-config.xml
. Thejndi-config.xml
file will be set with user only-access permissions. - The
client-deploy.wsdd
in the GAR is merged into a common$GLOBUS_LOCATION/client-config.wsdd
file. - An undeploy script (
$GLOBUS_LOCATION/etc/globus_packages/<gar.id>/undeploy.xml
) is created. - A
etc/post-deploy.xml
Ant script is called if the GAR contains one. The setup target is called automatically.
Notes:
- If the
post-deploy.xml
script creates some files, they will not be removed byundeploy
. - During deployment, filtering is done for contents of the
server-deploy.wsdd
andjndi-config-deploy.xml
files to replace the@config.dir@
token with the "etc/<gar.id>
" value, and the@gar.id@
token with the "<gar.id>
" value.
To create a GAR file use the following example:
<property name="build.packages" location= "${deploy.dir}/share/globus_wsrf_common/build-packages.xml"/> ... <property name="garjars.id" value="garjars"/> <fileset dir="lib" id="garjars"/> <property name="garetc.id" value="garetc"/> <fileset dir="etc" id="garetc"/> ... <target name="dist" depends="..."> <ant antfile="${build.packages}" target="makeGar"> <property name="gar.name" value="mygar.gar"/> <reference refid="${garjars.id}"/> <reference refid="${garetc.id}"/> </ant> </target>
The gar.name
property must be passed. That property specifies the gar file to create. The makeGar
task will look for deploy-client.wsdd
, deploy-server.wsdd
, and deploy-jndi-config.xml
files in the base directory of the calling Ant process. All of these files are optional and do not have exist. The list of files to be included in the GAR file is passed via Ant references. The makeGar
accepts the following references: garjars.id
, garschema.id
, garetc.id
, garshare.id
, gardocs.id
, and garbin.id
. All of these references are optional and do not have to be defined.
In the above example, all files in the etc
and lib
directories, and the deploy-client.wsdd
, deploy-server.wsdd
, and deploy-jndi-config.xml
files (if they exist) will be included into the GAR file.
To deploy a GAR file use the following example:
<property name="build.packages" location= "${deploy.dir}/share/globus_wsrf_common/build-packages.xml"/> ... <target name="deploy" depends="..."> <ant antfile="${build.packages}" target="deployGar"> <property name="gar.name" value="mygar.gar"/> </ant> </target>
The gar.name
property must be passed. That property specifies the gar file to deploy. Optionally, the profile
property can be passed to indicate which configuration profile the gar should be deployed under.
To undeploy a GAR file use the following example:
<property name="build.packages" location= "${deploy.dir}/share/globus_wsrf_common/build-packages.xml"/> ... <target name="undeploy"> <ant antfile="${build.packages}" target="undeployGar"> <property name="gar.id" value="mygar"/> </ant> </target>
The gar.id
property must be passed. This property specifies the base name of the gar to undeploy.
Bourne Shell and Windows batch scripts can be automatically generated to hide the details of launching a Java program from the command line.
To generate such a command line script, write a Ant task that calls the generateLauncher
target
in $GLOBUS_LOCATION/share/globus_wsrf_common/build-launcher.xml
.
The following properties/parameters must be specified:
-
${launcher-name}
- the base name of script to generate. -
${class.name}
- the name of Java class the script must call.
For example:
... <property name="env.GLOBUS_LOCATION" value="."/> <property name="deploy.dir" location="${env.GLOBUS_LOCATION}"/> <property name="abs.deploy.dir" location="${deploy.dir}"/> <property name="build.launcher" location="${abs.deploy.dir}/share/globus_wsrf_common/build-launcher.xml"> ... <ant antfile="${build.launcher}" target="generateLauncher"> <property name="launcher-name" value="myClient"/> <property name="class.name" value="org.mypackage.MyClient"/> </ant>
It is also possible to specify default JVM options and command line options via the default.jvm.options
and default.cmd.line
parameters. When passing multiple parameters using default.jvm.options
for Unix/Linux scripts the parameters must be separated by ${DELIM}
delimiter. For example:
<target name="generateUnixScripts" if="generate.unix" depends="testUnix"> <ant antfile="${build.launcher}" target="generateLauncher"> ... <property name="default.jvm.options" value="-DFOO="$FOO"${DELIM}-DBAR="$BAR"/> </ant> </target>
In general the generation of the command line scripts is done in the post-deploy.xml
script
during GAR deployment (globus-deploy-gar(1)).
Tests in the Java WS Core are based on the JUnit API. JUnit must first be installed with Ant. To install JUnit with Ant copy the junit.jar
found in JUnit distribution to the $ANT_HOME/lib
directory. Alternatively, you can add the junit.jar
to your
CLASSPATH, or source $GLOBUS_LOCATION/etc/globus-devel-env.sh
.
Always make sure to group your tests under the PackageTests.java
and/or SecurityTests.java
test
suites. Put all tests that require any type of credentials in the SecurityTests.java
test
suite.
If you are writing basic unit tests that do not require a container to run, just use the regular JUnit classes to write such tests.
If you are writing
tests that require a container to execute, use the org.globus.wsrf.test.GridTestCase
class
instead of junit.framework.TestCase
as your base class for your
tests. Also ensure your PackageTests.java
or SecurityTests.java
extends
the org.globus.wsrf.test.GridTestSuite
instead of junit.framework.TestSuite
.
The org.globus.wsrf.test.GridTestSuite
and org.globus.wsrf.test.GridTestCase
must be
used together. The org.globus.wsrf.test.GridTestCase
class exposes
a TEST_CONTAINER
variable that can be used to obtain the URL of
the container (TEST_CONTAINER.getBaseURL()
). By default an embedded
container will be started for all tests in the test suite. To specify an external
container, pass the -Dweb.server.url=<base.url>
system property
on the java
command line.
To execute the tests on the Java WS Core install, run the following (assuming the tests have been deployed into that install):
$ cd $GLOBUS_LOCATION $ ant -f share/globus_wsrf_test/runtests.xml runServer -Dtests.jar=<test.jar>
Where <test.jar>
is an absolute path to the jar file that contains the tests.
By default, the tests that use a container will try to access a container
running at http://localhost:8080/wsrf/services/
.
To specify a
different container, use the -Dtest.server.url=<url>
property.
To execute PackageTests only, specify -DbasicTestsOnly=true
.
To execute SecurityTests only, specify -DsecurityTestsOnly=true
.
The test reports will be put in the $GLOBUS_LOCATION/share/globus_wsrf_test/tests/test-reports
directory
by default. A different test reports directory can be specified
by passing -Djunit.reports.dir=<directory>
.
Use -Djunit.jvmarg
to pass arbitrary properties to the testing JVM. Example:
$ ant -f share/... -Djunit.jvmarg="-Dorg.globus.wsrf.container.server.id=myServerID"
Java WS Core allows for custom query/topic expression evaluators to be plugged in. The process of adding a new query/topic expression evaluator is composed of three steps:
The evaluators must be registered in order for Java WS Core to recognize them. The registration is done through the JNDI configuration file. The expression evaluators must be deployed as global resources under a specific subcontext.
The query expression evaluators must be deployed as global resources
under the
query/eval/
subcontext in the JNDI configuration
file.
Example:
<global> <resource name="query/eval/MyQueryExpressionEval" type="foo.bar.MyQueryExpressionEvaluator"> <resourceParams> <parameter> <name>factory</name> <value>org.globus.wsrf.jndi.BeanFactory</value> </parameter> </resourceParams> </resource> </global>
Where the <resource>
attribute:
name
| Specifies the name of the evaluator in JNDI space. The name can be arbitrary as long as it is unique and is in the right subcontext as explained above. |
type
| Specifies the class that implements the expression evaluator. |
Topic expression evaluators must be deployed as global resources under
the
topic/eval/
subcontext in the JNDI configuration file.
Example:
<global> <resource name="topic/eval/MyTopicExpressionEval" type="foo.bar.MyTopicExpressionEvaluator"> <resourceParams> <parameter> <name>factory</name> <value>org.globus.wsrf.jndi.BeanFactory</value> </parameter> </resourceParams> </resource> </global>
Where the <resource>
attribute:
name
| Specifies the name of the evaluator in JNDI space. The name can be arbitrary as long as it is unique and is in the right subcontext as explained above. |
type
| Specifies the class that implements the expression evaluator. |
A serializer/deserializer must be registered for the dialect of the evaluator in order for the expression to be properly serialized and deserialized. The serializers/deserializers for the dialect are deployed as almost any other type mapping. In general, each type mapping specifies a type QName. For dialect serializers/deserializers, that type QName takes a slightly different name.
For query expression evaluators, that QName must have the local name part
set to
QueryExpressionDialect
and
namespace part set to the dialect of the query expression evaluator.
Example:
<typeMapping encodingStyle="" deserializer="org.apache.axis.encoding.ser.SimpleDeserializerFactory" serializer="org.apache.axis.encoding.ser.SimpleSerializerFactory" type="java:java.lang.String" qname="ns12:QueryExpressionDialect" xmlns:ns12="http://foo.bar/MyQueryDialect"/>
![]() | Note |
---|---|
These type mappings must be deployed both on the client and the server. |
For topic expression evaluators, that QName must have the local name part
set to
TopicExpressionDialect
and
namespace part set to the dialect of the topic expression evaluator.
Example:
<typeMapping encodingStyle="" deserializer="org.apache.axis.encoding.ser.SimpleDeserializerFactory" serializer="org.apache.axis.encoding.ser.SimpleSerializerFactory" type="java:java.lang.String" qname="ns12:TopicExpressionDialect" xmlns:ns12="http://foo.bar/MyTopicDialect"/>
![]() | Note |
---|---|
These type mappings must be deployed both on the client and the server. |
The standard GetCurrentMessageProvider
might not know how to properly
serialize the notification message currently associated with the specified topic.
The GetCurrentMessageProvider
can be configured to use a helper
serializer for a given notification message type.
To configure such a helper serializer,
define the following global resource in your deploy-jndi.xml
configuration
file:
<global> <resource name="providers/GetCurrentMessageProvider/foo.bar.MyNotificationMessage" type="foo.bar.MyMessageSerializer"> <resourceParams> <parameter> <name>factory</name> <value>org.globus.wsrf.jndi.BeanFactory</value> </parameter> </resourceParams> </resource> </global>
Where the <resource>
attribute:
name
| Must start with
providers/GetCurrentMessageProvider/
and must end with the full class name of the notification message. |
type
| Specifies the class that implements the org.globus.wsrf.encoding.ObjectConverter interface and is responsible for serializing the notification message. The GetCurrentMessageProvider will use the type of the notification message to find the helper serializer. |
Logging in the Java WS Core is based on the Jakarta Commons Logging API. 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. Log4j uses a separate configuration file to configure itself. Please see Log4j documentation for details on the configuration file format.
Java WS Core is deployed with two Log4j configuration files:
$GLOBUS_LOCATION/container-log4j.properties
(configures logging for the standalone container)$GLOBUS_LOCATION/log4j.properties
(configures logging for everything else besides the standalone container)
The simplest 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 handler class in the appropriate log4j.properties
files and change the logging level to DEBUG:
log4j.category.org.globus.wsrf.handlers.MessageLoggingHandler=DEBUG
Another method for tracing SOAP messages is to enable logging for selected
Axis classes. Add the following lines to the appropriate log4j.properties
files:
log4j.category.org.apache.client.Call=DEBUG log4j.category.org.apache.axis.transport.http.HTTPSender=DEBUG # enable the following logger for HTTPS/HTTPG transport handlers log4j.category.org.globus.axis.axis.transport=DEBUG
This will log Axis client side calls and Axis HTTP messages.
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]
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. Make
sure to also start the standalone container with the proxy
server port option set to the listenPort
value.
JVM vendors provide useful tools and troubleshooting guides for debugging Java processes. Please use those guides for debugging your programs, for example:
If a Java process appears to hang, for example in case of the standalone container, the list of deployed services is not shown after a while or all requests to the container time out, requesting the JVM thread dump might help diagnose the problem.
To request JVM thread dump run:
kill -QUIT <JVM process id>
If this command is successful, the thread dump information should be printed to the standard output or error of the Java process. Therefore, the thread dump information might appear on the console of that process or in a file to which the standard output/error of process is redirected to. Please also note that on certain JVMs the thread dump information might be put in a separate file.
When filing bugs of such nature please always include the JVM thread dump information.
When a client fails with the following exception:
java.io.IOException: No socket factory for 'https' protocol at org.apache.axis.transport.http.HTTPSender.getSocket(HTTPSender.java:179) at org.apache.axis.transport.http.HTTPSender.writeToSocket(HTTPSender.java:397) at org.apache.axis.transport.http.HTTPSender.invoke(HTTPSender.java:135)
add the following to the client:
import org.globus.axis.util.Util; ... static { Util.registerTransport(); } ...
When a client fails with the following exception:
No client transport named 'https' found at org.apache.axis.client.AxisClient.invoke(AxisClient.java:170) at org.apache.axis.client.Call.invokeEngine(Call.java:2726)
The client is most likely loading an incorrect client-config.wsdd
configuration file. Ensure that the GT4 installation directory is listed as a first entry in the CLASSPATH
of the client. For example:
CLASSPATH=/usr/local/globus-4.0.0:/foo/bar/others.jar:...
If you are seeing this problem in Tomcat, copy the client-config.wsdd
from the GT4 installation directory to the Web application's WEB-INF/classes
directory.
The above error indicates that the wrong version of Xalan is being used. This happens with Some JDK versions and can be fixed by placing the correct version in the endorsed directory.
$GLOBUS_LOCATION/endorsed has the correct jars. You can either put the jar in the endorsed directory of the JVM or specify -Djava.endorsed.dir property to point to the endorsed directory. Clients that are shipped as a part of the toolkit should have the property specified by default.
In general, if you want to investigate a problem on your own please see the
Debugging and Logging
section for details on how to turn on debugging. Also, please note that most of the command line clients have a -debug
option that will display more detailed error messages, including the error stack traces.
Also, searching the mailing lists such as
[email protected] or
[email protected] (before posting a message) can also be very fruitful.
Finally, if you think you have found a bug please report it in our Bugzilla system. Please include
as much as detail about the problem as possible.
Overview material about WSRF and WSN and more information on the implemented WSDL and schema can be found here.
Information about ongoing standards work can be found here:
A basic proxy support is provided. The
org.globus.wsrf.proxy.port
system
property can be set to the port of the proxy server (the proxy server must run
on the same machine as the container). This will make any code that uses the ServiceHost
or AddressingUtils
API
return the address of the proxy server instead of the container. This could be
useful, for example, for debugging purposes.
The
org.globus.wsrf.proxy.port
system property can be passed to globus-start-container
script via the GLOBUS_OPTIONS
environment property. For example:
$ setenv GLOBUS_OPTIONS="-Dorg.globus.wsrf.proxy.port=5555" $ globus-start-container
Please note that not all of the code will obey the proxy port setting.