// StaleTupleSpaceHandler.java package com.ibm.tspaces.examples.handler; /* ** 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. ** **/ import java.util.*; import com.ibm.tspaces.*; import com.ibm.tspaces.server.*; import com.ibm.tspaces.server.handler.*; /** ** ** This class is a handler for a "StaleTupleSpace" this is a space that will clean up tuples ** that are in there too long. Currenly this only means from creation time, ie reading them ** or performing some other operation will not update a tuple's timestamp. But of course, ** the handlers for those commands could be re-implemented here to update the timestamps. ** ** The handler only operates on Tuples of type StaleTuple and these tuples must always have a long in the ** first field that is a timestamp field. The handler will initialize this value on write and return ** the value to the user if they want to use it for something eg as a unique index ( assuming currentTimeMills ** returns unique values). ** ** Two commands are implemented: ** TupleSpace.WRITE -- stamps the correct time in the first field before using the basic write command. ** START -- start the daemon on the server (only call this once). This starts ** a seperate daemon thread on the server that usually sleeps, but occasionally wakes up ** to check for stale tuples which it will delete. ** ** @see TSFactory ** @see TSFExtendable ** @see TSHandler ** @author Peter Wyckoff ** @author John Thomas ** @version $Revision: 2.1.2.1 $ $Date: 2000/02/05 14:49:58 $ ************************************************************************* */ public class StaleTupleSpaceHandler extends TSHandler implements Runnable { /** ** the command to start this handler up as a daemon on the server ** that periodically deletes stale tuples */ public static final String START = "StaleTupleStart"; /** ** the following variables are used by the run method which is run as a daemon thread ** deleting tuples that have gotten stale every so often. ** */ private TS _ts = null; /** ** How log to delay between checks for stale Tuple (ms) */ private long _howOften = 0; private TSResponse _communicator = null; private String _user; private String _clientID; /** ** Until the following switch is set True, the Write ** command handler will not do anything. */ static private boolean _enabled = false; /* *************************************************************************** ** ** constructor ** ** ***************** */ /** ** empty constructor called by the factory methods to create the new handler *************************************************************************** */ public StaleTupleSpaceHandler() { Debug.out("StaleTupleSpaceHandler()"); } /* *************************************************************************** ** ** constructor ** ** ***************** */ /** ** This constructor is used to create an instance of StaleTupleSpaceHandler ** that will be used to run the thread that periodically deletes stale tuples. ** ** @param ts_ the tuple space to do ops on ** @param howOften the time (ms) to wait between checks ** @param clientID_ Transaction id ** @param communicator_ the io handle back to the client *************************************************************************** */ StaleTupleSpaceHandler(TS ts_, long howOften_, String clientID_, TSResponse communicator_ ) { Debug.out("StaleTupleSpaceHandler(ts,argtuple)"); _communicator = communicator_; _ts = ts_; _howOften = howOften_; _clientID = clientID_; } /* *************************************************************************** ** ** handles ** ** ************* */ /** ** Do I handle this command on this argument? ** For now, always say yes because the factory will only call us on ** the command strings that we handle and we operate on all types of tuples ** When each handler only handles one command, can tighten this up. ** @param commandString the command ** @param argTuple the agument to the command ** @return true if I am so inclined as to handle this command false else *************************************************************************** */ public final boolean handles(String commandString, SuperTuple argTuple) { // return argTuple instanceof StaleTuple; return true; } /* ** ************************************************************************ ** ** attributes ** ** **************** */ /** ** What type of access control attributes are required to use the handler? ** If a zero length array is returned this means no attributes are needed. ** @param commandStr the command in question ** @param argTuple The argument for the command. ** @return an array of the attributes need for this command --- at least a zero length ** array is always returned except if this is not a command for this ** handler in which case null is returned, but that should never happen. ** *************************************************************************** */ public AccessAttribute [] attributes(String cmdString, SuperTuple argTuple) throws TSHandlerException { AccessAttribute admin[] = { AccessAttribute._ADMIN_ATTRIBUTE }; AccessAttribute write[] = { AccessAttribute._WRITE_ATTRIBUTE}; if(cmdString.equals(TupleSpace.WRITE) ) return write; else return admin; } // attributes /* ** ************************************************************************ ** ** command ** ** ************* */ /** ** Implement one or more "commands" (usually one). ** ** @param ts The TupleSpace instance on which the command is executed. ** @param cmdString The cmd to be invoked ** @param argTuple The argument for the command. ** @param clientID_ The client Transaction ID ** @param communicator_ the io handle back to the client ** @param user_ the user issuing the command ** @return a "result" tuple that is the output of the command. ** @exception TSHandlerException if this handler cannot complete the command ** or there was some problem encountered while executing the ** command. ** *************************************************************************** */ public SuperTuple command( TS ts, String cmdString, SuperTuple argTuple, String clientID_, TSResponse communicator_, String user_ ) throws TSHandlerException /*, TupleSpaceClientException */ { // StaleTupleSpaceHandler this handler implements the functionality needed for // a tuple space that cleans up old tuples. // Tuple should be ( Long, other stuff) _user = user_; _communicator = communicator_; SuperTuple retValue = new Tuple(); try { if(cmdString.equals(TupleSpace.WRITE) ) { Debug.out("StaleTupleHandler: WRITE"); // until Write handler is enabled, we just do standard Write if ( _enabled ) { if (argTuple instanceof StaleTuple) { ((StaleTuple)argTuple).updateExpirationDate(); } } else { Debug.out(0,"StaleTuple: Write not enabled"); } final TSHandler simpleWrite = ts.mostBasicHandler( TupleSpace.WRITE, argTuple); retValue = simpleWrite.command( ts, TupleSpace.WRITE, argTuple, clientID_, communicator_, user_); Debug.out("simpleWrite: "+retValue); } else if(cmdString.equals(StaleTupleSpaceHandler.START)) { // Handle the START command Debug.out("StaleTupleHandler: START"); // Get the parameter that says how often we want to check Field first = argTuple.getField(0); final long howOften = ((Long)first.getValue()).longValue(); // create and start up a daemon thread to be the tuple space stale tuple deleter. StaleTupleSpaceHandler newExecuter = new StaleTupleSpaceHandler(ts,howOften,clientID_, communicator_); Thread doTheLoop = new Thread(newExecuter,"StaleKiller"); doTheLoop.setDaemon( true); // this is a daemon so set it on doTheLoop.start(); _enabled = true; // enable the Write command Debug.out(0,"StaleTuple: Write enabled"); } else { throw new TSHandlerException("Invalid command: "+cmdString); } } catch(TupleSpaceException e) { Debug.out(Debug.ALWAYS,e); throw new TSHandlerException(e.getMessage()); } return retValue; } // command /* *************************************************************************** ** ** run ** ** ********* */ /** ** actually run as a background daemon and do the deletions of stale tuples. ** *************************************************************************** */ public void run(){ try { long throwOutBeforeThis = System.currentTimeMillis(); StaleTimestamp timestamp = new StaleTimestamp(throwOutBeforeThis); StaleTuple template = new StaleTuple(timestamp); int ct =0; String myClientID; TransactionManager transMgr = TSServer.getTransMgr(); // need the basic delete not somebody elses definition of it, I think TSHandler simpleDelete = _ts.mostBasicHandler( TupleSpace.DELETE, template); Debug.out("StaleTupleHandler.run():" + _howOften ); while(true) { // generate a new Transaction Identifier and tell TransactionManager ct++; myClientID = _clientID+"START"+ct; int transID = transMgr.beginTrans(myClientID); throwOutBeforeThis = System.currentTimeMillis(); // Create a subclass of Field that contains the current date/time timestamp = new StaleTimestamp(throwOutBeforeThis); template = new StaleTuple(timestamp); Debug.out("template="+template); SuperTuple delTuple = simpleDelete.command( _ts, TupleSpace.DELETE, template, myClientID, _communicator, _user); Debug.out(0,"StaleTuples deleted " + delTuple); // commit the transaction transID = transMgr.commitTrans(myClientID); // delay until it is time to check again delay( (int)_howOften) ; } // end while loop } catch(TupleSpaceException e) { Debug.out(0,e); } } // end run /* *************************************************************************** ** ** main ** ** ********* */ /** ** This is code to test the handler by simulating what a client ** application would do to load a special handler and then invode the ** the new commands.Normally this code would be part of the application ** that is going to to make use of the handler. ** **

** The basic steps are: **

** Create a TupleSpace. Remember that this function ** must be performed by a user that has "admin" ** authority for the server **

** issue an AddFactory specifing a factory that supports ** downlable handlers. The distributed TSFExtendable ** can be used for this.. **

** Create the Handler object. **

** Issue an addHandler command for each of the commands that this handler ** will support. ** **

** The TupleSpace and its new commands are now ready for use so this ** routine will write a StaleTuple to the Space and then issue the ** START command which will actually start a thread at the server ** which will delete tuples when they expire. ** **

** This routine then writes some more StaleTuples just to verify that ** it is really working. **

** For this relatively simple test, we hardcode all of the values that ** we need. *************************************************************************** */ public static void main( String[] argv) { String Host = "localhost"; String TSName = "Stale1"; // We need to have admin authorithy. Make sure the userid and password // are correct. String MyUserid = "sysadmin"; String MyPassword = "admin"; // Check for arguments for (int i=0; i CR * - append CVS "Log" entties * * (a script that helps with #2 and #3 is in * tspaces1:~thodes/bin/update-keywords.sh) * */