apache > ws.apache
WSRF
 

Writing Callback Objects

Introduction

Callback objects provide a means to keep resource properties in synch with the corresponding state in the backend managed resource. You write callback objects and register them on any non-static resource properties. The registration of callbacks is typically done upon initialization of the Resource class, in its init method. An example of this can be seen in FileSystemResource.

There are two interfaces which can be implemented when writing a Callback object. Which one you choose depends on how you would like each ResourceProperty to behave:

  • org.apache.ws.resource.properties.ResourcePropertyCallback - Implement this interface if the resource property's value may change (not static - e.g. "name"), but is not modifiable externally. It provides the ability to refresh the front-end with the current state of your backend.
  • org.apache.ws.resource.properties.SetResourcePropertyCallback - Implement this interface if the resource property is modifiable, thus methods like insert, update and delete may be appropriate. This interface extends ResourcePropertyCallback.

Implementing a ResourcePropertyCallback

ResourcePropertyCallback is a way for you to synchronize the front-end resource properties with the backend. The interface defines one method:

ResourceProperty refreshProperty( ResourceProperty prop );

Notice the operation is passed a ResourceProperty. The ResourceProperty contains methods for pulling the individual elements out of the property. You can either get an iterator of the property elements or retrieve a specific element via an index: ResourceProperty.get(i)

The returned property will be an XmlBean type. What "type" will depend on your method description in your WSDL. If the type is a schema-defined type (string, int etc.), XmlBeans provides objects specific to those types. In BackupFrequencyCallback we see that BackupFrequency was an xsd:int and so the XmlBean type is XmlInt:

public ResourceProperty refreshProperty(ResourceProperty prop)
    {
        XmlInt xInt = (XmlInt) prop.get( 0 );
        xInt.setIntValue( m_fileSystem.getBackupFrequency() );
        return prop;
    }

In the case of complex types, XmlBeans will generate a type and that is what will be passed to the operation. An example of this in OptionsCallback:

   public ResourceProperty refreshProperty( ResourceProperty prop )
   {
      Iterator iterator = prop.iterator(  );
      while ( iterator.hasNext(  ) )
      { 
         OptionsDocument.Options o = (OptionsDocument.Options) iterator.next(  );
         clearOptionsFromProperty( o );

         //add current options...
         List options = m_fileSystem.getOptions(  );
         for ( int i = 0; i < options.size(  ); i++ )
         {
            o.addOption( options.get( i ).toString(  ) );
         }
      }

      return prop;
   }

In both cases the objects (XmlInt and Options) all extend XmlObject as a common class, however it is useful to utilize the defined class' operations directly.

Once you have a handle on the passed-in object, you will need to set the equivalent value, from the current state of your backend, on the passed-in object.

The refreshProperty method is called by Apache WSRF before servicing GetResourceProperty, GetMultipleResourceProperties and QueryResourceProperties requests to ensure that the property element(s) returned to the client are up-to-date.

Implementing a SetResourcePropertyCallback

SetResourcePropertyCallback is a way for the backend state to be updated via SetResourceProperties requests to the front-end resource. The SetResourcePropertyCallback interface defines three methods:

void deleteProperty( QName propQName );
void insertProperty( Object[] propElems );
void updateProperty( Object[] propElems );

The operations will follow the same semantics as are defined in the specification and will be restricted to the bounds defined by the resource properties document schema. If you define an element with a maxOccurs="1", and attempt to add (insertProperty) another item to it, Apache WSRF will generate a fault.

CommentCallback illustrates how these methods may be implemented:

    public void deleteProperty( QName propQName )
    {
        return; // no need to implement - Apache WSRF will never call delete for a property whose minOccurs != 0
    }

    public void insertProperty( Object[] propElems )
    {
        // Comment prop has cardinality of 1, so passed array will always have exactly one element
        XmlString xString = (XmlString) propElems[0];
        m_fileSystem.setComment( xString.getStringValue() );
    }

    public void updateProperty( Object[] propElems )
    {
        insertProperty( prop );
    }
      

Notice that the deleteProperty method does nothing since the implementor knew that the method would never be called since the schema forbids it. The updateProperty simply hands-off to the insertProperty since the implementor knew that an update on the backend is the same as an insert. The insertProperty method is the workhorse method; it takes an array of property elements and updates the corresponding backend property.

Registering a Callback

Once you've written your callback objects you will need to register them with the resource properties. This is typically done in the init method of your Resource implementation class. See the FileSystemResource for an example.