The callback methods

One of the ways to manage an instance's lifecycle in GT3 is through callback methods. These methods are called at specific points during an instance lifetime (such as instance creation and destruction).

Using callback methods is very simple. Our class must implement the GridServiceCallback interface, which includes all the callback methods. The following class implements all the callback methods:

// ...

import org.globus.ogsa.GridServiceCallback;

// ...

public class MathImpl extends GridServiceImpl 
                      implements MathPortType, GridServiceCallback
{

  // ...

  
  // Callback methods
  public void preCreate(GridServiceBase base) throws GridServiceException
  {
    super.preCreate(base);
    logger.info("Instance is going to be created (preCreate)");
  }

  public void postCreate(GridContext context) throws GridServiceException
  {
    super.postCreate(context);
    logger.info("Instance has been created (postCreate)");
  }

  public void activate(GridContext context) throws GridServiceException
  {
    super.activate(context);
    logger.info("Instance has been activated (activate)");
  }

  public void deactivate(GridContext context) throws GridServiceException
  {
    super.deactivate(context);
    logger.info("Instance has been deactivated (deactivate)");
  }

  public void preDestroy(GridContext context) throws GridServiceException
  {
    super.preDestroy(context);
    logger.info("Instance is going to be destroyed (preDestroy)");
  }
}
[Note]

Add these modifications to $TUTORIAL_DIR/org/globus/progtutorial/services/core/logging/impl/MathImpl.java and save it as $TUTORIAL_DIR/org/globus/progtutorial/services/core/lifecycle/impl/MathImpl.java

First of all, notice how we need to call the base class callback methods from our own callback methods. For example, in postCreate:

public void postCreate(GridContext context) throws GridServiceException
{
  super.postCreate(context);
  logger.info("Instance has been created (postCreate)");
}

It is important to do this so that the callback methods in GridServiceImpl (the base class) also get called. The GridServiceImpl callback methods take care of initializing a lot of internal values (including service data), so failing to call them will probably produce unexpected results.

[Note]

However, we don't need to call the base class callback methods when using operation providers. Remember that operation providers don't extend from GridServiceImpl, but that the GridServiceImpl is still present 'in the background' (we specified this in the WSDD file). The grid services container makes sure that both the GridServiceImpl and operation provider's callback methods are called when necessary.

Now, let's take a closer look at when each callback method is called:

Writing the deployment descriptor

The deployment descriptor will be very similar to the transient service's descriptor. The only important change is the GSH of the service and the baseClassName of the service (which is the class we've just programmed: the logging example's class plus the callback methods)

<?xml version="1.0"?>
<deployment name="defaultServerConfig" xmlns="http://xml.apache.org/axis/wsdd/"
  xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">

  <service name="progtutorial/core/lifecycle/MathFactoryService" provider="Handler" style="wrapped">
    <parameter name="name" value="MathService Factory"/>
    <parameter name="instance-name" value="MathService Instance"/>
    <parameter name="instance-schemaPath" value="schema/progtutorial/MathService/Math_service.wsdl"/>
    <parameter name="instance-baseClassName" value="org.globus.progtutorial.services.core.lifecycle.impl.MathImpl"/>
    <parameter name="instance-className" value="org.globus.progtutorial.stubs.MathService.MathPortType"/>

    <!-- Start common parameters -->
    <parameter name="allowedMethods" value="*"/>
    <parameter name="persistent" value="true"/>
    <parameter name="handlerClass" value="org.globus.ogsa.handlers.RPCURIProvider"/>
    <parameter name="className" value="org.gridforum.ogsi.Factory"/>
    <parameter name="baseClassName" value="org.globus.ogsa.impl.ogsi.GridServiceImpl"/>
    <parameter name="schemaPath" value="schema/ogsi/ogsi_factory_service.wsdl"/>
    <parameter name="operationProviders" value="org.globus.ogsa.impl.ogsi.FactoryProvider"/>
    <parameter name="factoryCallback" value="org.globus.ogsa.impl.ogsi.DynamicFactoryCallbackImpl"/>
  </service>

</deployment>
[Note]

This file is $TUTORIAL_DIR/org/globus/progtutorial/services/core/lifecycle/server-deploy.wsdd

Compiling, deploying, and trying it out

Before compiling this service, since we have a new class that produces logging information, we need to enable logging for that class:

org.globus.progtutorial.services.core.lifecycle.impl.MathImpl=console,info
[Note]

Add this line at the end of $GLOBUS_LOCATION/ogsilogging.properties

Now, let's build the service:

./tutorial_build.sh \
org/globus/progtutorial/services/core/lifecycle \
schema/progtutorial/MathService/Math.gwsdl

And deploy it:

ant deploy \
-Dgar.name=$TUTORIAL_DIR/build/lib/org_globus_progtutorial_services_core_lifecycle.gar

Testing the service

Since our service uses a factory/instance model, the first thing we need to do is create an instance:

ogsi-create-service \
 http://127.0.0.1:8080/ogsa/services/progtutorial/core/lifecycle/MathFactoryService

If you look at the server-side logs, you'll see the following: (verbosity removed for comfort)

INFO: Instance is going to be created (preCreate)
INFO: Instance has been created (postCreate)

Now, let's access the service instance using the MathService client:

java \
-classpath ./build/classes/:$CLASSPATH \
org.globus.progtutorial.clients.MathService.Client \
http://127.0.0.1:8080/ogsa/services/progtutorial/core/lifecycle/MathFactoryService/HASH \
5

Remember to use the instance GSH returned by ogsi-create-service You should now see the following in the server-side logs:

INFO: Addition invoked with parameter a=5
INFO: getValue() invoked

These are the log messages produced by the add and getValue methods, which means no callback methods have been invoked while calling add and getValue.

Now, let's destroy the instance:

ogsi-destroy-service \
http://127.0.0.1:8080/ogsa/services/progtutorial/core/lifecycle/MathFactoryService/HASH

Remember to use the instance GSH returned by ogsi-create-service You should now see the following in the server-side logs:

INFO: Instance is going to be destroyed (preDestroy)