axonbirch banner image

 

 


Notification - End of RPC Call

This tutorial code aims to solve a problem I have come across a lot lately on our own projects but also within the Google Web Toolkit (GWT) forums lately. The need to know when an Remote Procedure Call (RPC) has finished. Although this somewhat goes against the grain of the essence of an Asynchronous call a lot of developers still see the need to know when it has ended, sucess or failure. Below aims to solve this.

The solution takes the approach of a Transaction design implementation in that if you need 1 or more RPC calls to finish before you continue, say to add items to a drop down, then you have to ability to add items to the transaction. If you need to add more items to a transaction then the dependency is that all the items within the transaction must complete if you are able to commit. So all the RPC calls within our AsyncTransaction must be completed BEFORE we populate the drop down boxes. Make sense?

Firstly the Transaction class:

———–

import java.util.HashMap;
/**
 * This class represents the realisation that a lot of the time we need
 * to know when a AsyncCallback has finished. It works similarly to a traditional transaction in which case
 * all the actions you to be complete HAVE to be completed, if one fails then we rollback.
 * Obvious use case is when you have various different RPC calls firing, say to populate
 * a few ListBox dropdown boxes, but they are part of the whole component interface then you need
 * ALL the drop downs to be completed. This 'Transaction' idea solves this.
 *
 */
public abstract class AsyncTransaction
{
 /**
  * A bag of all the items within the transaction, must be a list
  * so that we can have duplicates.
  */
 private HashMap participants = null;

/**
  * Method adds a participant to the tranaction.
  * Basically states we need this object to be completed if we attempt
  * to commit
  *
  * @param participant Object to be added.
  */
 public void addToTransaction( TransactionalAsyncCallback participant )
 {
 	if ( participants == null )
 	{
	    participants = new HashMap();
 	}

        participants.put(new Long( participant.getSerialNumber() ), participant);
 }

/**
  * Implementers override this method with actions
  * they want to perform if we can successfully commit.
  * Typically called within an RPC onSuccess call.
  */
 public abstract void commit();

/**
  * Implementers override this method with actions
  * to be performed when failures. Typically called within
  * an RPC onFailure call.
  */
 public abstract void rollback();

/**
  * Removes a participant from the Transaction. If all removed then we call
  * @see commit() which implementing classes will call.
  * @param participant Item to be removed
  */
 public void aSyncDone( TransactionalAsyncCallback participant )
 {
 	participants.remove(new Long( participant.getSerialNumber() ));

        if (participants.isEmpty() )
 	{
	   commit();
 	}
 }

}

——

We then add a wrapper class to an AsyncCallback simply adding a getSerialId method to uniquely identify your objects.

——

import com.google.gwt.user.client.rpc.AsyncCallback;

public abstract class TransactionalAsyncCallback implements AsyncCallback
{
	public abstract void onFailure(Throwable caught);
	public abstract void onSuccess(Object result);
	public abstract long getSerialNumber();
}

—–

So far so good. The next part is the actual implementation. Here I’ll show sample code on how to implement the pattern.

—–

public class MyRPCClass
{
       /**
	 * Our RPC Transaction listening object
	 */
	private AsyncTransaction transaction = null;

        public MyRPCClass()
        {
            transaction = new AsyncTransaction()
	    {
               public void commit()
	       {
			possibleFillDropDowns();
	       }
	       public void rollback()
	       {
	                doSomethingElse();
		}
	   };

           MyCallback callback = new MyCallback();
           transaction.addToTransaction( callback );

           myRPCCall(callback);
        }

       /**
	 * Method simply populates the MetaType field in the edit panel
	 * with all our meta types
	 */
	public void myRPCCall( TransactionalAsyncCallback callback )
	{
		MyServiceAsync service =  (MyServiceAsync) GWT.create( MyService.class );
		ServiceDefTarget target = (ServiceDefTarget) service;

		String URL = GWT.getModuleBaseURL() + "url";
		target.setServiceEntryPoint( URL );

		service.remoteCall(callback);
	}

           /** Inner classes for Callback **/

	private class MyCallback extends TransactionalAsyncCallback
	{
		public void onFailure( Throwable caught )
		{
			//Your failure code
		}

		public void onSuccess(Object result)
		{
			//Your success stuff
                        //Remove from Txn ready for commit
                        transaction.aSyncDone(this);
		}

		public long getSerialNumber()
		{
                        //This can be generated to identify different callbacks
			return 1l;
		}
	}

I hope this basic example makes sense and people feel they can implement it. Any problems please contact us. Or leave a comment!

Tags: , , , ,

Leave a Reply