Mercurial > hg > blitz_condensed
diff src/org/dancres/blitz/lease/LeaseReaper.java @ 0:3dc0c5604566
Initial checkin of blitz 2.0 fcs - no installer yet.
author | Dan Creswell <dan.creswell@gmail.com> |
---|---|
date | Sat, 21 Mar 2009 11:00:06 +0000 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org/dancres/blitz/lease/LeaseReaper.java Sat Mar 21 11:00:06 2009 +0000 @@ -0,0 +1,245 @@ +package org.dancres.blitz.lease; + +import java.util.ArrayList; + +import java.util.logging.*; + +import net.jini.config.ConfigurationException; +import net.jini.config.Configuration; + +import org.dancres.blitz.Logging; +import org.dancres.blitz.ActiveObject; +import org.dancres.blitz.ActiveObjectRegistry; + +/** + <p>Responsible for the co-ordination of cleanup of leased resources which + have expired. Any entity interested in performing such cleanup should + implement <code>Reapable</code> and register with a LeaseReaper.</p> + + @see org.dancres.blitz.lease.Reapable + */ +public class LeaseReaper implements ActiveObject, Runnable { + public static final long MANUAL_REAP = -1; + + private static final String MODULE_NAME = "org.dancres.blitz.lease"; + private static final String FILTER_PROPERTY = "filters"; + private static final String NAME_PROPERTY = "name"; + + private static Logger theLogger = + Logging.newLogger("org.dancres.blitz.lease.LeaseReaper"); + + private String theName; + + private long theReapTime; + + private Thread theReapThread; + + private ReapFilter theFilters; + + private ArrayList theReapables = new ArrayList(); + + private boolean isExiting = false; + + /** + <p>Accepts a configuration file similar to:</p> + + <pre> + import org.dancres.blitz.lease.ReapFilter; + + import org.dancres.blitz.TxnReapFilter; + + org.dancres.blitz.lease { + // DO NOT set this to null, use an empty array + filters = new ReapFilter[] {new TxnReapFilter()}; + name = "EntryReaper"; + } + </pre> + + <p>Which specifies the ReapFilters to install (can be a zero-length + array or unspecified).</p> + + <p>Loads a set of ReapFilter instances from the configuration file + and aggregates those into a collection which implements ReapFilter. + Whenever reaping is triggered, each Reapable will be passed this + collection which it should use to ensure that it's appropriate + to delete a resource.</p> + + @param aConfig configuration file as above + @param aReapPeriod how often to wake up and perform a reap + */ + public LeaseReaper(Configuration aConfig, long aReapPeriod) + throws ConfigurationException { + + theName = (String) aConfig.getEntry(MODULE_NAME, + NAME_PROPERTY, + String.class, "TheReaper"); + + ReapFilter[] myFilters = + (ReapFilter[]) aConfig.getEntry(MODULE_NAME, + FILTER_PROPERTY, + ReapFilter[].class, + new ReapFilter[0]); + + theFilters = new ReapFilterCollection(myFilters); + + theReapTime = aReapPeriod; + + theLogger.log(Level.INFO, "Reaper::" + theName + ":theReapTime: " + + theReapTime); + + for (int i = 0; i < myFilters.length; i++) { + theLogger.log(Level.INFO, "Reaper::" + theName + ":Filter = " + + myFilters[i]); + } + + /* + If the reap time is greater than zero, it's not the MANUAL_REAP + and therefore we need to be active. If it's zero or MANUAL_REAP + we don't want to do this. + */ + if (theReapTime > 0) { + theLogger.log(Level.SEVERE, "Active lease reaping enabled"); + ActiveObjectRegistry.add(this); + } else if (theReapTime == MANUAL_REAP) { + theLogger.log(Level.SEVERE, "Manual lease reaping enabled"); + } + } + + /** + Use this constructor to create a LeaseReaper purely by programmatical + means with no reference to configuration files. <b>Reaping is automatic + or disabled, no manual option is supported</b>. + */ + public LeaseReaper(String aName, ReapFilter[] aFilters, + long aReapPeriod) + throws ConfigurationException { + + theName = aName; + + ReapFilter[] myFilters = (aFilters != null) ? aFilters : + new ReapFilter[0]; + + theFilters = new ReapFilterCollection(myFilters); + + theReapTime = aReapPeriod; + + theLogger.log(Level.INFO, "Reaper::" + theName + ":theReapTime: " + + theReapTime); + + for (int i = 0; i < myFilters.length; i++) { + theLogger.log(Level.INFO, "Reaper::" + theName + ":Filter = " + + myFilters[i]); + } + + if (theReapTime != 0) + ActiveObjectRegistry.add(this); + } + + public boolean isActive() { + /* + We want everyone to do book-keeping for both MANUAL_REAP and automatic + reaping modes so if reapTime is non-zero we want people to do the + necessary. + */ + return (theReapTime != 0); + } + + public void begin() { + theReapThread = new Thread(this, "LeaseReaper:" + theName); + theReapThread.start(); + } + + public void halt() { + synchronized(this) { + isExiting = true; + notify(); + } + + try { + theReapThread.join(); + } catch (InterruptedException anIE) { + theLogger.log(Level.SEVERE, "Couldn't wait for lease reaper: " + + theName, anIE); + } + } + + public void run() { + theLogger.log(Level.INFO, "Reaper started up: " + theName); + + while (!isExiting) { + try { + synchronized(this) { + wait(theReapTime); + } + + if (isExiting) + break; + else + reapImpl(); + } catch (InterruptedException anIE) { + break; + } + } + + theLogger.log(Level.INFO, "Reaper exited: " + theName); + } + + public void add(Reapable aReapable) { + synchronized(theReapables) { + theReapables.add(aReapable); + } + } + + public boolean filter(LeasedResource anObject) { + return theFilters.filter(anObject); + } + + /** + Request a manual reap + */ + public void reap() { + if (theReapTime != MANUAL_REAP) { + theLogger.log(Level.SEVERE, "Manual reap requested but not configured in file."); + return; + } + + theLogger.log(Level.INFO, "Manual reap requested"); + reapImpl(); + } + + private void reapImpl() { + Reapable[] myReapables; + + synchronized(theReapables) { + myReapables = new Reapable[theReapables.size()]; + + myReapables = (Reapable[]) theReapables.toArray(myReapables); + } + + for (int i = 0; i < myReapables.length; i++) { + try { + myReapables[i].reap(theFilters); + } catch (Throwable aT) { + theLogger.log(Level.SEVERE, + "Reaper encountered exception: " + theName, aT); + } + } + } + + private static class ReapFilterCollection implements ReapFilter { + private ReapFilter[] theFilters; + + ReapFilterCollection(ReapFilter[] aFilters) { + theFilters = aFilters; + } + + public boolean filter(LeasedResource anObject) { + for (int i = 0; i < theFilters.length; i++) { + if (theFilters[i].filter(anObject)) + return true; + } + + return false; + } + } +}