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.
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.
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
For simplicity, we will use |
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.
The WSDL file is
|
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");
}
This file is
|
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.
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; } }
This file is
|
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.
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(); mathResource.setValue(mathResource.getValue() + a); mathResource.setLastOp("ADDITION"); return new AddResponse(); }
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(); } }
This file is
|
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; } } }
This file is
|
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.