Globus Toolkit 4.0: Best Practices for Developing in GT4

This page provides some recommendations for developing with the Globus Toolkit 4.0 and its components.

Implementing Services

Dynamic resource creation and the factory pattern

OGSI defined a standard create method for creating new grid services. The follow on, the WS Resource Framework, no longer defines such a mechanism. This does not mean that the factory pattern is not valuable. Rather, it was removed because any non-trivial create method tends to be application specific, a observation that leads to the conclusion that there is little value in standardizing this operation. We recommend the use of the factory pattern for dynamic creation of resources. In particular we recommend writing a factory service that provides a way to create new resources and allows users to inspect state information about the aggregation of all resources created by the factory service, e.g. the number of resources managed. In addition to the factory service one would write a service that interacts with the resource instances created by the factory service.

Scalability, recovery and resource persistence

Writing scalable (in the number of resources) and recoverable, i.e. give it the ability to survive a server crash and restart, resources takes a bit of careful planning. There are several potential pitfalls:

  • Since scalability relies upon using Java soft references it is important that resource do not keep hard references to any objects that would prevent the soft reference mechanism from working.
  • When recovering resources after a container restart it is often important to re-establish the current state of the process the resource represents, e.g. if the resource is monitoring a external entity via notifications it should query for the current state of the external entity upon restart.
  • Persisted resources need to be carefully written to avoid the following problem: If a service currently holds a hard reference to the resource and the resource is destroyed, i.e. the soft reference to the resource is removed from the resource home and the resource is removed from persistent storage, then the service holding the resource reference can still cause a call to the store persistence callback. Unless the store callback was written to prevent this, calling it will restore the destroyed resource.

    For example: during a typical service operation, a service will lookup a resource using its resource home. At that point in time, the service holds a hard reference to the resource object. If another client of the service concurrently invokes a destroy operation on the same resource, thus removing the resource from the resource home and its state from persistent storage, the resource essentially becomes invalid. When this occurs it is important that the first service operation not invoke the resource's store method since doing so would inadvertently recreate (or resurrect) the resource.

    To prevent this consider writing the resource's store and remove methods in such a way as to prevent recreating resource state that has been previously destroyed by another caller.

  • Resource implementers need to be careful when storing objects created by axis as part of the web service operation invocation and containing fields resulting from a xsd:any in the corresponding schema. These complex types have references to sizable objects associated with the Axis deserialization/data-binding process. To remove these reference replace the object by calling org.globus.wsrf.encoding.ObjectSerializer.clone(originalObject) and drop the reference to the original object.

Concurrent invocations and synchronization

The container does not provide automatic synchronization of concurrent requests. This means that service implementors need to write their services to deal with potential synchronization problems. If you service itself is stateless this means that if you will need to synchronize around access to the state captured in the resource. That being said, in a lot of scenarios you can expect a single client to drive most interactions with a given resource, in which case synchronization may not be an issue.

Lease-based lifetime management

We recommend that you make use of lease based resource lifetime management to avoid orphaned resources due to network outage and other failures. Lease based lifetime management is accomplished by specifying a initial lifetime in the resource creation operation followed by periodic updates to the lifetime using the setTerminationTime operation specified in the WS Resource Lifetime specification.

Resource Types and Services

Any given WSRF service can only have a single resource properties document schema associated with it. This implies a constraint on the type of resource a service can expose, i.e. resources exposed by a service must conform to the resource properties document schema associated with the service. Note that this does not necessarily mean that services can only expose resources of a single implementation type. There may of course be multiple implementation types as long as all of these types conform to the interface dictated by the resource property document schema. Also, the resource property document schema may have extensibility elements, allowing more flexibility in the resource implementation at the expense of reducing discoverability and implicitly predictability of interactions against resources exposed by such a service. That said, the Java WS Core implementations of the Resource Home interface only allow a single resource type.

In addition, services may interact with any type of resource, unconstrained by the resource property document schema, as long as these resources are not expose by the service. This occurs frequently in the standard factory pattern, where the factory creates and manipulates a resource, but the resource itself is exposed through a different service.

Messaging granularity

Our current performance profile for the Java WS Core component currently only allows for fairly coarse grained operations at a reasonable level of performance. While this statement is in relation to Java WS Core performance it is in reality relevant to any distributed applications: Remote invocations always cost more than local invocation (give infinite CPU power/memory) and should thus be treated differently than local invocations.

Choosing an authentication mechanism

GT4 provides a implementer with a choice of 4 authentication mechanisms: HTTPS (ie SSL/TLS), WS-Security with X.509 certificates, WS-Security Username/Password authentication and a GSSAPI based WS-Trust/SecureConversation/Security based mechanism. We recommend that service implementors try to support the greatest number of mechanisms possible. Generally, services that need both authentication and message protection should always allow any mechanism other than the username/password one.

The story is somewhat different on the client end of things. Whereas server side security configuration is mostly policy driven, clients actually have to pick a specific mechanism to implement. We recommend that clients use HTTPS whenever available, i.e. whenever the service URL indicates a HTTPS transport, but are able to fall back on WS-Security with X.509 certificates should the transport be a non-https one. This recommendation is based upon performance comparisons of HTTPS vs. WS-Security based mechanisms, which have shown HTTPS to be much higher performance, especially as the message payload grows.