4.1. Splitting up the implementation

4.1.1. The resource, the home, and the service

In this chapter, we will split our implementation into three files. We will see that, for the most part, we will simply take code from the previous chapter and divide it among the three files.

  • The resource: $EXAMPLES_DIR/org/globus/examples/services/core/singleton/impl/MathResource.java

  • The resource home: $EXAMPLES_DIR/org/globus/examples/services/core/singleton/impl/MathResourceHome.java

  • The service itself: $EXAMPLES_DIR/org/globus/examples/services/core/singleton/impl/MathService.java

Before looking at the actual Java code, let's make sure we understand how these three implementation files are related.

Figure 4.1. Relationships between the Service, the Resource Home, and the Resource

Relationships between the Service, the Resource Home, and the Resource
  • The service is the stateless frontend (the client only interacts with this class, even if there are more classes lurking around in the background). Remember from Section 1.3, “WSRF: The Web Services Resource Framework” section that, since we're following a 'resource approach' to statefulness, the web service will always be stateless. However, we can give the impression of being stateful by retrieving a stateful resource whenever we want to access state information.

  • The resource is the stateful class were we keep all our information.

  • The resource home is in charge of managing the resources. For example, the (stateless) service will use the resource home to retrieve the (stateful) resource. In this chapter, the resource home will be very simple since it will only deal with a single (or singleton) resource. In the next chapter, we will see how to set up a resource home that can manage several resources.

[Tip]ServiceResourceHome

You might be wondering how this related to the example we saw in the previous chapter. Even though we did not implement a resource home, there was a resource home lurking around in the background. Remember the following line from the JNDI config file?

<resource name="home" type="org.globus.wsrf.impl.ServiceResourceHome">

We used a Globus-supplied resource home called ServiceResourceHome. As the following figure shows, the ServiceResourceHome is a special type of resource home that always returns the service object when asked for a resource. This allows us to implement our resource and service in the same class.

For simplicity, we will use ServiceResourceHome in other examples in the tutorial, as it will spare us a lot of code. However, remember that the preferred way of implementing services is by splitting up the implementation, as we will do in this chapter. When you start writing your own services, you should only use ServiceResourceHome for very simple services.

4.1.2. The WSDL file

In this chapter, we are only changing the implementation of our service. The interface is still the same, so there's no need to modify the WSDL file. We can reuse the one from the previous chapter.

[Note]

The WSDL file is $EXAMPLES_DIR/schema/examples/MathService_instance/Math.wsdl

4.1.3. The QNames interface

Once again, the first bit of code we are going to write is the namespaces interface. Again, since we are reusing the WSDL file from the previous chapter, there's no big changes to the MathQNames interface, except for the fact that we are now placing our Java classes in a new package.

package org.globus.examples.services.core.singleton.impl;

import javax.xml.namespace.QName;

public interface MathQNames {
	public static final String NS = "http://www.globus.org/namespaces/examples/core/MathService_instance";

	public static final QName RP_VALUE = new QName(NS, "Value");

	public static final QName RP_LASTOP = new QName(NS, "LastOp");

	public static final QName RESOURCE_PROPERTIES = new QName(NS,
			"MathResourceProperties");
}
[Note]

This file is $EXAMPLES_DIR/org/globus/examples/services/core/singleton/impl/MathQNames.java.

In the following chapters, we won't see the complete code of each new MathQNames interface. As you see, it is pretty straightforward to write it from the WSDL file. From now on, we will simply point you to the location of the file in the examples bundle.

4.1.4. The resource resource

The first big class we will see in the resource implementation. You will be (pleasantly) surprised to see that it is practically identical to the MathService class from the previous chapter. The only thing missing is the add, subtract, and getValueRP methods, which we will now place in the service implementation.

Also, notice how all the RP initialization code is no longer in the constructor, but in an initialize method.

package org.globus.examples.services.core.singleton.impl;

import org.globus.wsrf.Resource;
import org.globus.wsrf.ResourceProperties;
import org.globus.wsrf.ResourceProperty;
import org.globus.wsrf.ResourcePropertySet;
import org.globus.wsrf.impl.SimpleResourcePropertySet;
import org.globus.wsrf.impl.ReflectionResourceProperty;

public class MathResource implements Resource, ResourceProperties {

	/* Resource Property set */
	private ResourcePropertySet propSet;

	/* Resource properties */
	private int value;

	private String lastOp;

	/* Initializes RPs */
	public void initialize() throws Exception {
		this.propSet = new SimpleResourcePropertySet(
				MathQNames.RESOURCE_PROPERTIES);

		try {
			ResourceProperty valueRP = new ReflectionResourceProperty(
					MathQNames.RP_VALUE, "Value", this);
			this.propSet.add(valueRP);
			setValue(0);

			ResourceProperty lastOpRP = new ReflectionResourceProperty(
					MathQNames.RP_LASTOP, "LastOp", this);
			this.propSet.add(lastOpRP);
			setLastOp("NONE");
		} catch (Exception e) {
			throw new RuntimeException(e.getMessage());
		}
	}

	/* Get/Setters for the RPs */
	public int getValue() {
		return value;
	}

	public void setValue(int value) {
		this.value = value;
	}

	public String getLastOp() {
		return lastOp;
	}

	public void setLastOp(String lastOp) {
		this.lastOp = lastOp;
	}

	/* Required by interface ResourceProperties */
	public ResourcePropertySet getResourcePropertySet() {
		return this.propSet;
	}
}
[Note]

This file is $EXAMPLES_DIR/org/globus/examples/services/core/singleton/impl/MathResource.java.

As you can see, this class contains all the code required to implement the resource and its resource properties (Value and LastOp). Remember that this is the stateful component.

4.1.5. The service implementation

This class, on the other hand, will contain the add, subtract, and getValueRP methods the client will interact with. However, we can't reuse the code from the previous chapter. Remember, for example, how we implemented the add operation:

public AddResponse add(int a) throws RemoteException {
	value += a;
	lastOp = "ADDITION";

	return new AddResponse();
}

Now that we're splitting up the implementation, the stateful information is no longer in the service class itself, so we don't have a value or lastOp variable we can interact with. Any operation that requires working with stateful information will have to work with a MathResource object. So, our add method will look something like this:

public AddResponse add(int a) throws RemoteException {
	MathResource mathResource = getResource(); 1
	mathResource.setValue(mathResource.getValue() + a); 2
	mathResource.setLastOp("ADDITION"); 3

	return new AddResponse();
}
1

First of all, we have to get a reference to the resource. The getResource method is described shortly.

2

Now that we have a hold of the resource, we can work with its stateful information. In this step, we simply retrieve the value (using the getValue method in the MathResource object), add parameter a, and set the new value with setValue.

3

Finally, we set the last operation to be "ADDITION".

The getResource method used above is a private method that retrieves this service's singleton resource. As you can see, this method simply uses ResourceContext (a Globus class) to obtain the resource.

private MathResource getResource() throws RemoteException {
	Object resource = null;
	try {
		resource = ResourceContext.getResourceContext().getResource();
	} catch (Exception e) {
		throw new RemoteException("", e);
	}
	
	MathResource mathResource = (MathResource) resource;
	return mathResource;
}

The complete source code for the service implementation is:

package org.globus.examples.services.core.singleton.impl;

import java.rmi.RemoteException;

import org.globus.examples.services.core.singleton.impl.MathResource;
import org.globus.wsrf.ResourceContext;
import org.globus.examples.stubs.MathService_instance.AddResponse;
import org.globus.examples.stubs.MathService_instance.SubtractResponse;
import org.globus.examples.stubs.MathService_instance.GetValueRP;

public class MathService {

	/*
	 * Private method that gets a reference to the resource specified in the
	 * endpoint reference.
	 */
	private MathResource getResource() throws RemoteException {
		Object resource = null;
		try {
			resource = ResourceContext.getResourceContext().getResource();
		} catch (Exception e) {
			throw new RemoteException("Unable to access resource.", e);
		}

		MathResource mathResource = (MathResource) resource;
		return mathResource;
	}

	/* Implementation of add, subtract, and getValue operations */

	public AddResponse add(int a) throws RemoteException {
		MathResource mathResource = getResource();
		mathResource.setValue(mathResource.getValue() + a);
		mathResource.setLastOp("ADDITION");

		return new AddResponse();
	}

	public SubtractResponse subtract(int a) throws RemoteException {
		MathResource mathResource = getResource();
		mathResource.setValue(mathResource.getValue() - a);
		mathResource.setLastOp("SUBTRACTION");

		return new SubtractResponse();
	}

	public int getValueRP(GetValueRP params) throws RemoteException {
		MathResource mathResource = getResource();

		return mathResource.getValue();
	}

}
[Note]

This file is $EXAMPLES_DIR/org/globus/examples/services/core/singleton/impl/MathService.java.

4.1.6. The resource home

The implementation of the resource home is extremely simple since we're extending from an existing class included in the toolkit, SingletonResourceHome. That base class provides practically all the functionality our resource home needs to manage a single resource. The only thing we have to do is implement the findSingleton method, which is called internally by the ResourceContext class when we first request the resource. The findSingleton method creates a new MathResource object, initializes it, and returns it. The base class SingletonResourceHome keeps a copy of that resource, which is returned each time the resource is requested.

The complete source code would be:

package org.globus.examples.services.core.singleton.impl;

import org.globus.wsrf.Resource;
import org.globus.wsrf.impl.SingletonResourceHome;

public class MathResourceHome extends SingletonResourceHome {

	public Resource findSingleton() {
		try {
			// Create a resource and initialize it.
			MathResource mathResource = new MathResource();
			mathResource.initialize();
			return mathResource;
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}

	}
}
[Note]

This file is $EXAMPLES_DIR/org/globus/examples/services/core/singleton/impl/MathResourceHome.java.

The usefulness of having a resource home might not be apparent in this simple case (when we have a singleton resource). However, a resource home adds a lot of versatility to our implementation, specially when we have to deal with multiple resources. For example, a resource home can be used to perform special actions when a resource is created and later destroyed (adding an entry in a database, writing out a log message, etc.). In the next chapter, we will see how we modify the implementation of the resource home to accomodate multiple resources.