Software Links
Getting Started
- Doc Structure
- A Globus Primer
- Globus Is Modular!
- Quickstart
- Installing GT
- Platform Notes
- GT Developer's Guide
- GT User's Guide (coming soon)
- Migrating from GT2
- Migrating from GT3
Reference
- Best Practices
- Coding Guidelines
- API docs
- Public Interfaces (coming soon)
- Resource Properties
- Samples
- Glossary
- Performance Studies (coming soon)
Manuals
Common Runtime
Security
- Non-WS (General) Security
- WS Java Security
- Message-level
- Authz Framework
- CAS
- Delegation Service
- MyProxy
- GSI-OpenSSH
- SimpleCA
- SGAS
Data Mgt
MDS4
Execution Mgt
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
providerattribute toHandler. - Add a
handleClassparameter with a value oforg.globus.axis.providers.RPCProvider. Specify providers in the
providersparameter.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
scopeparameter toApplicationorRequest.
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 uses a simple in-memory JNDI implementation provided by the Naming subproject of the Apache Directory Project.
The jndi-config.xml files are used to configure the
JNDI registry in Java WS Core. The file format of
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.
Please see The JNDI Tutorial for more information on JNDI programming.
When deploying a Java Bean using the
<resource> entry in
jndi-config.xml please note the following:
The Java Bean must have a default constructor.
If the Java Bean implements the
org.globus.wsrf.jndi.Initializableinterface theinitialize()method will be automatically called after all parameters are set on the bean.If the Java Bean implements the
org.globus.wsrf.jndi.Destroyableinterface thedestroy()method will be automatically called on container shutdown.Each Java Bean is configured with a factory class specified by a factory resource parameter. The factory is an optional parameter and therefore can be omitted. If this parameter is not specified, the default
org.globus.wsrf.tools.jndi.BeanFactoryfactory class will be used. Otherwise, the class specified by the parameter will be used. Do not useorg.apache.naming.factory.BeanFactoryas a factory class.
To obtain JNDI InitialContext do:
import org.globus.wsrf.jndi.JNDIUtils; ... InitialContext ctx =
JNDIUtils.getInitialContext(); Foo foo = (Foo)ctx.lookup(...);![]() | Note |
|---|---|
It is important to use this API to obtain the
|
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 1.0 for
addressing services and resources. Java WS Core uses a modified version of 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.
Since the Apache Addressing project is being archived, the source code has been imported to Globus CVS and package name has been changed to avoid conflicts. Refer to FIXME: LINK TO TECH DEPENDENCY.
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
ReferenceParameters are used to carry resource
identity information. In previous versions of the WSRF/WSN specification, ReferenceProperties was used for the same purpose. The resource identity can be anything as long as it serializes
as a XML element. The ReferenceParameters 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 parameters.
For example, create ReferenceParametersType 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); ReferenceParametersType props = new
ReferenceParametersType(); // 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.setReferenceParameters(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.setParameters(props); VersionServiceAddressingLocator
locator = new VersionServiceAddressingLocator(); VerionServicePortType port =
locator.getVersionPort(epr); port.getVersion(); Java Beans generated by Apache Axis that represent a XML type with the
xsd:any content implement the
org.apache.axis.encoding.AnyContentType interface and
have get_any() and
set_any() methods. There are several API to help you
deal with the AnyContentType content.
To convert AnyContentType content to a Java object
use the ObjectDeserializer API. For example:
AnyContentType bean = ...; Integer value =
(Integer)ObjectDeserializer.getFirstAsObject( bean), Integer.class); To convert a Java object into a type that can be used with
AnyContentType content use the ObjectSerializer API. For example:
// convert Java object into SOAPElement EndpointReferenceType object = ...; QName
elementName = new QName("http://example.com", "EPR"); SOAPElement element =
ObjectSerializer.toSOAPElement(object, elementName); // set the SOAPlement as Any
content AnyContentType bean = ...; AnyHelper.setAny(bean, element); To examine the raw AnyContentType content use the
AnyHelper API to serialize it as XML. For example:
AnyContentType bean = ...; String contents = AnyHelper.toSingleString(bean);
System.out.println("Contents: " + contents);You can use the ObjectSerializer API to serialize the Java object into a file (in XML format):
// object to serialize EndpointReferenceType epr = ...; // root element name
QName elementName = new QName("http://example.com", "EPR"); FileWriter out = null; try {
out = new FileWriter("epr.xml"); ObjectSerializer.serialize(out, epr, elementName);
out.write('\n'); } catch (IOException e) { System.err.println("Error: " +
e.getMessage()); } finally { if (out != null) { try { out.close(); } catch (Exception
ee) {} } } Similarly, use can use the ObjectDeserializer API to deserialize a file containing XML data into a Java object:
// deserialized object EndpointReferenceType epr = ...; FileInputStream in =
null; try { in = new FileInputStream("epr.xml"); epr =
(EndpointReferenceType)ObjectDeserializer.deserialize( new InputSource(in),
EndpointReferenceType.class); } catch (IOException e) { System.err.println("Error: " +
e.getMessage()); } finally { if (in != null) { try { in.close(); } catch (Exception ee)
{} } } There are a few steps involved in setting up and receiving notifications:
The notification consumer application must provide an implementation of the NotifyCallback
interface. The deliver function of the interface will
be invoked whenever a notification for that consumer arrives.
![]() | Note |
|---|---|
The |
For resource property notifications the message
parameter will usually be of
ResourcePropertyValueChangeNotificationElementType
type. From that type you can retrieve the real notification message which contains
the new and optionally the old value of the resource property. Example:
import org.globus.wsrf.encoding.DeserializationException;
import org.globus.wsrf.utils.NotificationUtil;
import org.oasis.wsrf.properties.ResourcePropertyValueChangeNotificationType;
...
// Notification callback
public void deliver(List topicPath, EndpointReferenceType producer,
Object message) {
ResourcePropertyValueChangeNotificationType changeMessage
= null;
try {
changeMessage = NotificationUtil.getRPValueChangeNotification(message);
} catch (DeserializationException e) {
// handle exception
}
Integer newValue =
(Integer)ObjectDeserializer.getFirstAsObject( changeMessage.getNewValue(),
Integer.class); System.out.println("New value: " + newValue); if
(changeMessage.getOldValue() != null) { Integer oldValue =
(Integer)ObjectDeserializer.getFirstAsObject( changeMessage.getNewValue(),
Integer.class); System.out.println("Old value: " + oldValue); } } The resource property values are of
AnyContentType type. Please see the Working with
AnyContentType content section for more information on how to deal with
such types.
For other non-resource property notifications the
message parameter will either be of the type into
which the message type maps into (if there is an appropriate type mapping defined)
or of org.w3c.dom.Element type if there is no
appropriate type mapping defined. Example:
public void deliver(List topicPath, EndpointReferenceType producer, Object
message) { EndpointReferenceType epr = null; if (message instanceof Element) { //
type mapping not defined, try to deserialize into right Java // type using
ObjectDeserializer API. epr = (EndpointReferenceType)ObjectDeserializer.toObject(
(Element)message, EndpointReferenceType.class); } else if (message instanceof
EndpointReferenceType) { // type mapping defined epr =
(EndpointReferenceType)message; } else { // some other type } } The custom notification message type mappings can be defined in a
client-server-config.wsdd file. This file can be deployed
with your service (it must be placed directly under the etc/
directory in the GAR file). Please see the
$GLOBUS_LOCATION/etc/globus_wsrf_core/client-server-config.wsdd
file for an example. If your callback implementation will be used on the
server-side, you might also need to define the type mappings in your
server-config.wsdd.
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; ...
Subscribe request = new Subscribe();
request.setConsumerReference(consumerEPR);
TopicExpressionType topicExpression = new TopicExpressionType();
topicExpression.setDialect(WSNConstants.SIMPLE_TOPIC_DIALECT);
topicExpression.setValue(Counter.VALUE);
MessageElement element =
(MessageElement)ObjectSerializer
.toSOAPElement(topicExpression, WSNConstants.TOPIC_EXPRESSION);
FilterType filter = new FilterType();
filter.set_any(new MessageElement[] { element });
request.setFilter(filter);
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) {} } }
The Version API can be used to obtain Java WS Core version information programmatically. For example to display major, minor and patch version information do:
import org.globus.wsrf.utils.Version; ... System.out.println("Major: " +
Version.getMajor()); System.out.println("Minor: " + Version.getMinor());
System.out.println("Micro: " + Version.getMicro());
Java WS Core supports SOAP with Attachments. DIME, MIME, and MTOM formats are supported. This section provides brief sample code. Detailed code can be found in the automated tests for this feature at http://viewcvs.globus.org/viewcvs.cgi/wsrf/java/core/test/unit/src/org/globus/wsrf/impl/security/, AttachmentTestService.java and AttachmentsTests.java.
To add an attachment to a request do:
import javax.activation.DataHandler; import javax.activation.FileDataSource;
import javax.xml.rpc.Stub; import org.apache.axis.client.Call; .... File file = new
File(..); DataHandler dataHandler = new DataHandler(new FileDataSource(file));
((Stub)port)._setProperty( Call.ATTACHMENT_ENCAPSULATION_FORMAT,
Call.ATTACHMENT_ENCAPSULATION_FORMAT_MTOM);
((org.apache.axis.client.Stub)port).addAttachment(dataHandler); To retrieve attachments associated with a request do:
import javax.activation.DataHandler; import javax.xml.soap.AttachmentPart; import
org.apache.axis.Message; import org.apache.axis.MessageContext; .... MessageContext
msgContext = MessageContext.getCurrentContext(); Message reqMsg =
msgContext.getRequestMessage(); if (reqMsg.getAttachmentsImpl() == null) { throw new
Exception("Attachments are not supported"); } Iterator it = reqMsg.getAttachments();
while (it.hasNext()) { AttachmentPart part = (AttachmentPart) it.next(); DataHandler
dataHandler = part.getDataHandler(); } The SwA support adds a small overhead to overall SOAP processing. To disable SwA
support for improved performance delete
$GLOBUS_LOCATION/lib/common/geronimo-activation_1.0.2_spec-1.1-SNAPSHOT.jar
and
$GLOBUS_LOCATION/lib/common/geronimo-javamail_1.3.1_spec-1.1-SNAPSHOT.jar
files.
Please note that SOAP attachments can be used with message security but they will not be signed or encrypted.
Java WS Core currently provides two ways of querying the resource properties using
XPath: the standard method and a proprietary method. The standard method is defined by
the WS-ResourceProperties specification and all
implementations of this specification support it. The proprietary method is a custom
solution and therefore only supported by Globus Toolkit. The proprietary method is a new
query dialect called TargetedXPath. The
TargetedXPath query dialect offers three key
advantages over the standard XPath query method:
Namespace mappings - a set of explicit namespace mappings to be passed along with the query. With these mappings the query expression can be dramatically simplified as namespace prefixes can be used freely within the query.
Single resource property querying - a specific resource property can be queried instead of the entire resource property document.
WS-Enumeration support - the query results can be returned as an enumeration.
The globus-xpath-query command line
tool can be used to query resource properties with the
TargetedXPath query dialect. If the query results were
returned as an enumeration they can be retrieved using the ws-enumerate command line tool.
Example querying resource properties using the
TargetedXPath query dialect:
import org.globus.wsrf.core.query.targetedXPath.TargetedXPathQueryType; import
org.globus.wsrf.core.query.targetedXPath.NamespaceMappingType; import
org.globus.wsrf.query.targetedXPath.TargetedXPathConstants; ... TargetedXPathQueryType
targetedQuery = new TargetedXPathQueryType(); NamespaceMappingType nsMap[] = new
NamespaceMappingType[1]; nsMap[0] = new NamespaceMappingType();
nsMap[0].setMappedName("fooPrefix"); nsMap[0].setNamespace(new
URI("http://fooNamespace")); targetedQuery.setNamespaceMappings(nsMap);
targetedQuery.setQueryString("boolean(//fooPrefix:fooElement)"); QueryExpressionType
query = new QueryExpressionType();
query.setDialect(TargetedXPathConstants.TARGETED_XPATH_DIALECT);
query.setValue(targetedQuery); QueryResourceProperties_Element queryRequest = new
QueryResourceProperties_Element(); queryRequest.setQueryExpression(query);
QueryResourcePropertiesResponse queryResponse =
port.queryResourceProperties(queryRequest); To query a specific resource property do:
... targetedQuery.setNamespaceMappings(nsMap);
targetedQuery.setQueryString("boolean(//fooPrefix:fooElement)"); QName rp = new
QName("http://foo", "bar"); targetedQuery.setResourcePropertyName(rp); ... To return query results as an enumeration do:
import org.xmlsoap.schemas.ws._2004._09.enumeration.EnumerationContextType; ...
targetedQuery.setNamespaceMappings(nsMap);
targetedQuery.setQueryString("boolean(//fooPrefix:fooElement)");
targetedQuery.setEnumerateResults(Boolean.TRUE); ... QueryResourcePropertiesResponse
queryResponse = port.queryResourceProperties(queryRequest); EnumerationContextType
context = (EnumerationContextType)ObjectDeserializer.getFirstAsObject( queryResponse,
EnumerationContextType.class); 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 the 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 the 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 the 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. URLs with "local" protocol name are used for local invocations.
To invoke a service locally, do the following:
Create a service URL with "local" protocol:
URL url = new URL("local:///wsrf/services/MyService");And as normal make the call:
MyServiceAddressingLocator locator = new MyServiceAddressingLocator(); MyService port = locator.getMyServicePort(url); port.hello();
That's all. By default the local invocations are made using the default instance of
the AxisServer engine. It is possible to make local
invocations using a different AxisServer engine
instance if there is a MessageContext associated with
the current thread (the MessageContext should have a
reference to the desired AxisServer engine instance).
To make a local invocation using non-default AxisServer
engine add the following (using above example):
import org.globus.axis.transport.local.LocalTransportUtils; ... MyService port =
... LocalTransportUtils.enableLocalTransport((Stub)port);
port.hello(); The "local" protocol URL handler is automatically registered by Java WS Core. However, sometimes it might be necessary to install the handler explicitly. To register the "local" URL protocol hander do the following:
import org.globus.axis.transport.local.LocalTransportUtils; ...
LocalTransportUtils.init(); ... This step must be done before creating URLs with
"local" protocol. Also, make sure that
axis-local.jar is accessible from the system
classloader.
Axis associates a MessageContext object with the
current thread of execution only during a remote service invocation (when a service
method is actually called remotely). Sometimes, it might be necessary to execute a piece
of code with some specific MessageContext object
associated with the current thread. For example, a background server-side task might
want to call some service method directly.
The MessageContextHelper API can be used to temporarily associate a specific
MessageContext object with the current thread in
order to call some code that needs that context to be associated with the thread.
Example:
import org.globus.axis.utils.MessageContextHelper; ... MessageContext newCtx =
...; MessageContextHelper helper = new MessageContextHelper(newCtx); helper.set(); try {
// call code that needs MessageContext associated with the thread } finnally {
helper.restore(); } ... By default Java WS Core clients will use HTTP 1.1 protocol with chunked encoding. Java WS Core clients will also attempt to reuse HTTP/S connections between the calls. The default timeout for clients is 10 minutes. All of these connection properties can be controlled programmatically using the HTTPUtils API as shown below.
![]() | Note |
|---|---|
Please note that once a connection property is set on a given Stub, it is applied to ALL calls made using that Stub. |
To set connection timeout do (the timeout value is in milliseconds):
import org.globus.axis.transport.HTTPUtils; ... MyServiceAddressingLocator
locator = new MyServiceAddressingLocator(); MyService port =
locator.getMyServicePort(url); // set timeout to 2 minutes
HTTPUtils.setTimeout((Stub)port, 1000 * 60 * 2); port.hello();
To control connection reuse do:
import org.globus.axis.transport.HTTPUtils; ... MyServiceAddressingLocator
locator = new MyServiceAddressingLocator(); MyService port =
locator.getMyServicePort(url); // close connection after the call
HTTPUtils.setCloseConnection((Stub)port, true); port.hello();
// do not close connection - let it be reused
HTTPUtils.setCloseConnection((Stub)port, false); port.hello();
To control whether HTTP chunked encoding should be used do:
import org.globus.axis.transport.HTTPUtils; ... MyServiceAddressingLocator
locator = new MyServiceAddressingLocator(); MyService port =
locator.getMyServicePort(url); // disable chunked encoding
HTTPUtils.setChunkedEncoding((Stub)port, false); port.hello();
// re-enable chunked encoding HTTPUtils.setChunkedEncoding((Stub)port,
true); port.hello(); To control what HTTP protocol version should be used do:
import org.globus.axis.transport.HTTPUtils; ... MyServiceAddressingLocator
locator = new MyServiceAddressingLocator(); MyService port =
locator.getMyServicePort(url); // force HTTP 1.0
HTTPUtils.setHTTP10Version((Stub)port, true); port.hello(); //
force HTTP 1.1 HTTPUtils.setHTTP10Version((Stub)port, false);
port.hello(); To check if a container is running remotely (given the service URL) add
?wsdl to the end of the service URL. If only the
host and the port number information of the container are known, create an appropriate
service URL using a standard service such as the
Version service. For example:
http://[host]:[port]/wsrf/services/Version?wsdl
(assuming the services are deployed under
/wsrf/services/ context).
Use DeploymentState API to check if a container is running locally (given the
GLOBUS_LOCATION of the container is known). For
example:
import org.globus.tools.gar.DeploymentState; ... String globusLocation = ...;
DeploymentState state = new DeploymentState(globusLocation); boolean running =
state.isRunning(); ![]() | Note |
|---|---|
This method will work only with a standalone container only. |
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) and undeployed using globus-undeploy-gar (globus-undeploy-gar) 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
.jarfiles 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.wsddin the GAR is copied to$GLOBUS_LOCATION/etc/<gar.id>/server-config.wsdd. If a profile name was specified during deployment, theserver-deploy.wsddwill be copied to$GLOBUS_LOCATION/etc/<gar.id>/<profile.name>-server-config.wsdd. Theserver-config.wsddfile will be set with user-only access permissions. - The
jndi-config-deploy.xmlin the GAR is copied to$GLOBUS_LOCATION/etc/<gar.id>/jndi-config.xml. If a profile name was specified during deployment thejndi-config-deploy.xmlwill be copied to$GLOBUS_LOCATION/etc/<gar.id>/<profile.name>-jndi-config.xml. Thejndi-config.xmlfile will be set with user only-access permissions. - The
client-deploy.wsddin the GAR is merged into a common$GLOBUS_LOCATION/client-config.wsddfile. - An undeploy script
(
$GLOBUS_LOCATION/etc/globus_packages/<gar.id>/undeploy.xml) is created. - A
etc/post-deploy.xmlAnt script is called if the GAR contains one. The setup target is called automatically.
Notes:
- If the
post-deploy.xmlscript creates some files, they will not be removed byundeploy. - During deployment, filtering is done for contents of the
server-deploy.wsddandjndi-config-deploy.xmlfiles 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).
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 all tests contained in a given jar file with an internal container run the following:
$ cd $GLOBUS_LOCATION $ ant -f share/globus_wsrf_test/runtests.xml run
-Dtests.jar=<test.jar>Where <test.jar> is an
absolute path to the jar file that contains the tests.
To execute all tests contained in a given jar file with an external container run the following:
$ cd $GLOBUS_LOCATION $ ant -f share/globus_wsrf_test/runtests.xml runServer
-Dtests.jar=<test.jar>By default, the external container is assumed to be running at
http://localhost:8080/wsrf/services/. To specify a
different container, use the
-Dtest.server.url=<url> property.
By default, all PackageTests and
SecurityTests tests will be executed. To execute
PackageTests only, specify
-DbasicTestsOnly=true option. To execute
SecurityTests only, specify
-DsecurityTestsOnly=true option.
By default, the test results will be generated in the XML format.
To execute a single test suite with an internal container run the following:
$ cd $GLOBUS_LOCATION $ ant -f share/globus_wsrf_test/runtests.xml runOne
-Dtest.class=<test.class>Where <test.class> is a Java class
that contains a test suite.
To execute a single test suite with an external container run the following:
$ cd $GLOBUS_LOCATION $ ant -f share/globus_wsrf_test/runtests.xml runOneServer
-Dtest.class=<test.class>By default, the external container is assumed to be running at
http://localhost:8080/wsrf/services/. To specify a
different container, use the
-Dtest.server.url=<url> property.
By default, the test results will be generated in the plain text format.
It is also possible to execute a single test case (or a set of test cases) within a
test suite by specifying a
-Dtests=<testCase1[,testCaseN]> property.
However, this will only work with test suites that inherit from
org.globus.wsrf.test.FilteredTestSuite or
org.globus.wsrf.test.GridTestSuite classes. Example:
$ cd $GLOBUS_LOCATION $ ant -f share/globus_wsrf_test/runtests.xml runOne \
-Dtest.class=org.globus.interop.widget.test.PackageTests \
-Dtests="testScenario1,testScenario2"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.test.format property to generate the
test results in a specified format (xml or
plain). Example:
$ ant -f share/... -Djunit.test.format=plain
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. |
![[Note]](/docbook-images/note.gif)
![[Important]](/docbook-images/important.gif)