comparison 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
comparison
equal deleted inserted replaced
-1:000000000000 0:3dc0c5604566
1 package org.dancres.blitz.lease;
2
3 import java.util.ArrayList;
4
5 import java.util.logging.*;
6
7 import net.jini.config.ConfigurationException;
8 import net.jini.config.Configuration;
9
10 import org.dancres.blitz.Logging;
11 import org.dancres.blitz.ActiveObject;
12 import org.dancres.blitz.ActiveObjectRegistry;
13
14 /**
15 <p>Responsible for the co-ordination of cleanup of leased resources which
16 have expired. Any entity interested in performing such cleanup should
17 implement <code>Reapable</code> and register with a LeaseReaper.</p>
18
19 @see org.dancres.blitz.lease.Reapable
20 */
21 public class LeaseReaper implements ActiveObject, Runnable {
22 public static final long MANUAL_REAP = -1;
23
24 private static final String MODULE_NAME = "org.dancres.blitz.lease";
25 private static final String FILTER_PROPERTY = "filters";
26 private static final String NAME_PROPERTY = "name";
27
28 private static Logger theLogger =
29 Logging.newLogger("org.dancres.blitz.lease.LeaseReaper");
30
31 private String theName;
32
33 private long theReapTime;
34
35 private Thread theReapThread;
36
37 private ReapFilter theFilters;
38
39 private ArrayList theReapables = new ArrayList();
40
41 private boolean isExiting = false;
42
43 /**
44 <p>Accepts a configuration file similar to:</p>
45
46 <pre>
47 import org.dancres.blitz.lease.ReapFilter;
48
49 import org.dancres.blitz.TxnReapFilter;
50
51 org.dancres.blitz.lease {
52 // DO NOT set this to null, use an empty array
53 filters = new ReapFilter[] {new TxnReapFilter()};
54 name = "EntryReaper";
55 }
56 </pre>
57
58 <p>Which specifies the ReapFilters to install (can be a zero-length
59 array or unspecified).</p>
60
61 <p>Loads a set of ReapFilter instances from the configuration file
62 and aggregates those into a collection which implements ReapFilter.
63 Whenever reaping is triggered, each Reapable will be passed this
64 collection which it should use to ensure that it's appropriate
65 to delete a resource.</p>
66
67 @param aConfig configuration file as above
68 @param aReapPeriod how often to wake up and perform a reap
69 */
70 public LeaseReaper(Configuration aConfig, long aReapPeriod)
71 throws ConfigurationException {
72
73 theName = (String) aConfig.getEntry(MODULE_NAME,
74 NAME_PROPERTY,
75 String.class, "TheReaper");
76
77 ReapFilter[] myFilters =
78 (ReapFilter[]) aConfig.getEntry(MODULE_NAME,
79 FILTER_PROPERTY,
80 ReapFilter[].class,
81 new ReapFilter[0]);
82
83 theFilters = new ReapFilterCollection(myFilters);
84
85 theReapTime = aReapPeriod;
86
87 theLogger.log(Level.INFO, "Reaper::" + theName + ":theReapTime: " +
88 theReapTime);
89
90 for (int i = 0; i < myFilters.length; i++) {
91 theLogger.log(Level.INFO, "Reaper::" + theName + ":Filter = " +
92 myFilters[i]);
93 }
94
95 /*
96 If the reap time is greater than zero, it's not the MANUAL_REAP
97 and therefore we need to be active. If it's zero or MANUAL_REAP
98 we don't want to do this.
99 */
100 if (theReapTime > 0) {
101 theLogger.log(Level.SEVERE, "Active lease reaping enabled");
102 ActiveObjectRegistry.add(this);
103 } else if (theReapTime == MANUAL_REAP) {
104 theLogger.log(Level.SEVERE, "Manual lease reaping enabled");
105 }
106 }
107
108 /**
109 Use this constructor to create a LeaseReaper purely by programmatical
110 means with no reference to configuration files. <b>Reaping is automatic
111 or disabled, no manual option is supported</b>.
112 */
113 public LeaseReaper(String aName, ReapFilter[] aFilters,
114 long aReapPeriod)
115 throws ConfigurationException {
116
117 theName = aName;
118
119 ReapFilter[] myFilters = (aFilters != null) ? aFilters :
120 new ReapFilter[0];
121
122 theFilters = new ReapFilterCollection(myFilters);
123
124 theReapTime = aReapPeriod;
125
126 theLogger.log(Level.INFO, "Reaper::" + theName + ":theReapTime: " +
127 theReapTime);
128
129 for (int i = 0; i < myFilters.length; i++) {
130 theLogger.log(Level.INFO, "Reaper::" + theName + ":Filter = " +
131 myFilters[i]);
132 }
133
134 if (theReapTime != 0)
135 ActiveObjectRegistry.add(this);
136 }
137
138 public boolean isActive() {
139 /*
140 We want everyone to do book-keeping for both MANUAL_REAP and automatic
141 reaping modes so if reapTime is non-zero we want people to do the
142 necessary.
143 */
144 return (theReapTime != 0);
145 }
146
147 public void begin() {
148 theReapThread = new Thread(this, "LeaseReaper:" + theName);
149 theReapThread.start();
150 }
151
152 public void halt() {
153 synchronized(this) {
154 isExiting = true;
155 notify();
156 }
157
158 try {
159 theReapThread.join();
160 } catch (InterruptedException anIE) {
161 theLogger.log(Level.SEVERE, "Couldn't wait for lease reaper: " +
162 theName, anIE);
163 }
164 }
165
166 public void run() {
167 theLogger.log(Level.INFO, "Reaper started up: " + theName);
168
169 while (!isExiting) {
170 try {
171 synchronized(this) {
172 wait(theReapTime);
173 }
174
175 if (isExiting)
176 break;
177 else
178 reapImpl();
179 } catch (InterruptedException anIE) {
180 break;
181 }
182 }
183
184 theLogger.log(Level.INFO, "Reaper exited: " + theName);
185 }
186
187 public void add(Reapable aReapable) {
188 synchronized(theReapables) {
189 theReapables.add(aReapable);
190 }
191 }
192
193 public boolean filter(LeasedResource anObject) {
194 return theFilters.filter(anObject);
195 }
196
197 /**
198 Request a manual reap
199 */
200 public void reap() {
201 if (theReapTime != MANUAL_REAP) {
202 theLogger.log(Level.SEVERE, "Manual reap requested but not configured in file.");
203 return;
204 }
205
206 theLogger.log(Level.INFO, "Manual reap requested");
207 reapImpl();
208 }
209
210 private void reapImpl() {
211 Reapable[] myReapables;
212
213 synchronized(theReapables) {
214 myReapables = new Reapable[theReapables.size()];
215
216 myReapables = (Reapable[]) theReapables.toArray(myReapables);
217 }
218
219 for (int i = 0; i < myReapables.length; i++) {
220 try {
221 myReapables[i].reap(theFilters);
222 } catch (Throwable aT) {
223 theLogger.log(Level.SEVERE,
224 "Reaper encountered exception: " + theName, aT);
225 }
226 }
227 }
228
229 private static class ReapFilterCollection implements ReapFilter {
230 private ReapFilter[] theFilters;
231
232 ReapFilterCollection(ReapFilter[] aFilters) {
233 theFilters = aFilters;
234 }
235
236 public boolean filter(LeasedResource anObject) {
237 for (int i = 0; i < theFilters.length; i++) {
238 if (theFilters[i].filter(anObject))
239 return true;
240 }
241
242 return false;
243 }
244 }
245 }