Mercurial > hg > blitz_condensed
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 } |