// Example3.java package com.ibm.tspaces.examples.simple; import com.ibm.tspaces.*; import java.util.Vector; //import com.ibm.Tspaces.server.*; /* ** Licensed Materials - Property of IBM ** ** (C) COPYRIGHT IBM Corp. 1996, 1997 All rights reserved ** ** US Government Users Restricted Rights - Use, duplication or ** disclosure restricted by GSA ADP Schedule Contract with IBM Corp. ** **/ /** ** Show how a client can register for events that are happening to a tuple space. ** ** This class will implement the Callback interface which requires that ** it have a "call" method. An instance of this class will be specified as ** a parameter to "eventRegister". Then when the event that we are waiting for ** occurs, the call method for the object will be given control. **
** This example has 3 important Threads 
**   - main    Thread that is started for the main method and also has control
**             when the test() method is called.
**             It will delete the Tuples that are written to the space.
**
**   - run     This is the Thread that is started by the main() method and uses 
**             the run() method to implement the thread.  
**             This thread will write tuples to the space.  Normally this would 
**             done by another application.
**   
**   - callback This is the callback thread.  This thread is started when the 
**             TupleSpace is initially created and it handles the information 
**             that is returned from TupleSpace commands.  It also is used 
**             to implement Event Callbacks by invoking the call() method.
**             Note that the user does not create this thread.  
** 
** This example how to register for TupleSpace events and how to correctly ** pass the tuples from the callback to other threads that will process them. ** ** @see Callback ** @see Waiter ** @see TupleSpace ** ** @author John Thomas ** @version $Revision: 2.1.2.1 $ $Date: 2000/02/10 14:19:48 $ ************************************************************************* */ public class Example3 implements Callback, Runnable { private TupleSpace ts = null; private static String host = "localhost"; private int port = TupleSpace.DEFAULTPORT; private boolean _event = false; private boolean _quit = false; /** ** Vector of Tuples used for queue */ private Vector _queue = new Vector(); /* *************************************************************************** ** ** constructor ** ** ******************** */ /** ** The constructor for this class will setup everything so that the ** call method will be given control when interesting things happen ** to the related TupleSpace */ public Example3() { int seqNum; try { // Verify that the Server is active Tuple active = TupleSpace.status(host,port); // status() returns a simple Tuple that contains "Running" or "NotRunning" Debug.out("Status="+active); if ( active == null || active.getField(0).getValue().equals("NotRunning")) { Debug.out("TSpaces server not running on " + host+":"+port ); System.exit(1); } // access the TupleSpace ts = new TupleSpace("Example3",host,port); //ts.setDebug(true); // Setup a template to describe the Tuples we are interested in. Tuple template = new Tuple( "Key2", new Field(String.class) ); // set flag for whether a new Thread will process the callback boolean newThread = false; // default is false // register for the write event // Indicate that we ourselves are implementing the Callback interface seqNum = ts.eventRegister( TupleSpace.WRITE, template, this, newThread); Debug.out("Event Registration. seqnum="+seqNum); } catch (TupleSpaceException tse) { Debug.out(tse); } } // Example3() constructor /** ** This run method will write some Tuples to the space ** This could represent the actions of another client. ** */ public void run() { try { Debug.out("Write Key1"); // no event for this one! ts.write( "Key1","data1" ); Debug.out("Write Key2"); // an event for this one! ts.write( "Key2", "data2" ); Debug.out("Write Key3"); ts.write( "Key3", "data3" ); Debug.out("Write Key2"); // an event for this one! ts.write( "Key2", "data2again" ); // an event to cause it to quit Debug.out("Write Quit"); ts.write( "Key2","Quit"); } catch (Exception e) { Debug.out(e); } } /** ** This represents the main application processing. ** ** It waits for a Tuple to appear in a Vector ** that represents a queue of ** work to be done. If there is a Tuple in the queue ** it will remove it from the queue and process it. ** In this case, it just deletes the tuples. ** When we get a tuple that has "quit" as the 2nd field ** then we clean up and leave. ** ** We could write a better queueing facility but this is ** supposed to be a simple example. ** ** */ public void test() { try { Tuple myTuple = null; while (true) { String data = ""; while (myTuple == null) { // when a tuple arrives that we are interested in // the call rtn will put it in the _queue vector synchronized (_queue) { if (_queue.size() > 0) { myTuple = (Tuple)_queue.elementAt(0); _queue.removeElementAt(0); Debug.out("Got an event "+myTuple); } // if if (myTuple == null) { Debug.out("Waiting for next event"); _queue.wait(); } } // synchronized } // Let's delete the Tuple after getting it in the callback. // Note tht we can not do this in the callback method // code. It would result in a never ending wait. TupleID id = myTuple.getTupleID(); Debug.out("Delete tuple "+id); ts.deleteTupleById(id); Debug.out("deleted="+id); data = (String)myTuple.getField(1).getValue(); myTuple = null; // we need to get a new one if (data.equals("Quit") ) { _quit = true; ts.cleanup(); break; } } // while(true) } catch (TupleSpaceException tse) { Debug.out("Exception: " + tse); tse.printStackTrace(); } catch (Exception e) { Debug.out("Exception: " + e); e.printStackTrace(); } } /* *************************************************************************** ** ** call ** ** ************* */ /** ** Implementation for the Callback interface. ** ** call an application back with a tuple it requested. In the case of an exceptional condition ** occurring on the server, isException will be true and the exception will be inside the tuple_, ** i.e., the tuple will contain one field that is a TupleSpaceServerException. **

** EventRegister has an otional parameter that controls whether the ** callback is processed in the same thread that reads the response ** from server or whether a new Thread is started to process the callback. **

** The default is to use the same thread and simply callthe callback thread. ** Thus in this case the callback should be really quick and ** return, that is it should not take up lots of time. ** Typically, it might just check that an exception was not thrown and if not ** then queue up the tuple and wake up some other thread that will do the real processing, ** Likewise in default case, Because this method is running in a thread that ** reports all callbacks from the server, ** it is important that the call() method (or any method that it invokes directly) ** do not invoke another TupleSpace command. This would cause the communication ** to the TSpaces Server to hang. **

** However if eventRegister(cmd,template,callback,true) is specified then ** the callback will be in a new thread and there are no restrictions. ** ** Also, normally the call() method will return false. It would return true ** only if this is the last call this callback class is expecting. ** For a one time read or in etc this is the case, but for EventHandlers, this is not ** the case, they will keep on servicing more and more events. ** ** @param eventName_ String that indicates what type of TupleSpace action ** "Write" or "Delete" caused this call. ** Note that only events that a cause a Write or Delete to be done are ** reported. A READ operation at the server is not reported. ** @param tsName_ the name of the tuple space this command was executed on. ** @param sequenceNumber_ the sequenceNumber for this event/command ** @param tuple_ the returned tuple or a Tuple with an exception inside ** @param isException_ was the command processed normaly or was there an exception ** ** @return return false normally, true if this is the last call ** this method should be getting. ** @see TupleSpace ** @see CallbackThread */ public boolean call( String eventName,String tsName,int seqNum,SuperTuple tuple,boolean isException) { try { // do what you want here, probably wake up some other // thread and queue up the info for it. // Remember, this code is being run in the thread // that handles callbacks from the server so don't issue TupleSpace commands. Debug.out("in call for " + eventName + ", TupleSpace = " + tsName + ",Seq #=" + seqNum + ",Tuple=" + tuple + ", isException=" + isException); // If no exception at the server, then set a switch and // place the tuple in a queue. if (! isException) { synchronized (_queue) { _queue.addElement(tuple); // add Tuple to queue Debug.out("Notify"); _queue.notifyAll(); // Wake up anyone waiting for the queue } } else { // here if server exception Exception e = (Exception)tuple.getField(0).getValue(); if (e.getMessage().equals("Normal Close")) { Debug.out(0,"Normal close event from server"); } else { Debug.out(0,e); } _event = true; _quit = true; } } catch (Exception e) { Debug.out(e); } return false; } // call() /** ** The main method for this class ** */ public static void main(String[] argv) { //Debug.setDebugOn(true); //TupleSpace.setDebug(true); try { if (argv.length > 0) host = argv[0]; // if user specified server host if ((argv.length > 1) && (argv[1].equals("-D")) ) { Debug.setDebugOn(true); //TupleSpace.setDebug(true); } // create an instance of the class // This will create the space // it will register for any write events on the space. // The resulting callback will queue the tuples. Example3 instance = new Example3(); // startup the run() method to write some tuples Thread t = new Thread(instance,"run"); t.start(); // run the test() method which read the tuples // from the queue and delete them. instance.test(); Debug.out(0,"Example3 was successful."); //Thread.sleep(5000); System.exit(0); } catch(Exception e) { Debug.out(0,"Caught an exception: ",e); } } // end main } // Example3.java /* $Log: Example3.java,v $ /* Revision 2.1.2.1 2000/02/10 14:19:48 jthomas /* Fix testcase so it doesn't hang. /* */