001: /*
002: * This software is released under a licence similar to the Apache Software Licence.
003: * See org.logicalcobwebs.proxool.package.html for details.
004: * The latest version is available at http://proxool.sourceforge.net
005: */
006: package org.logicalcobwebs.proxool.admin;
007:
008: import org.logicalcobwebs.concurrent.WriterPreferenceReadWriteLock;
009: import org.apache.commons.logging.Log;
010: import org.apache.commons.logging.LogFactory;
011: import org.logicalcobwebs.proxool.ProxoolException;
012:
013: import java.util.Calendar;
014:
015: /**
016: * Responsbile for a single set of statistics. It rolls over to a new set
017: * whenever it should. It provides access to the latest complete set
018: * when it is available.
019: *
020: * @version $Revision: 1.9 $, $Date: 2006/01/18 14:39:58 $
021: * @author bill
022: * @author $Author: billhorsman $ (current maintainer)
023: * @since Proxool 0.7
024: */
025: class StatsRoller {
026:
027: private static final Log LOG = LogFactory.getLog(StatsRoller.class);
028:
029: private WriterPreferenceReadWriteLock readWriteLock = new WriterPreferenceReadWriteLock();
030:
031: private Statistics completeStatistics;
032:
033: private Statistics currentStatistics;
034:
035: private Calendar nextRollDate;
036:
037: private int period;
038:
039: private int units;
040:
041: private boolean running = true;
042:
043: private CompositeStatisticsListener compositeStatisticsListener;
044:
045: private String alias;
046:
047: public StatsRoller(String alias,
048: CompositeStatisticsListener compositeStatisticsListener,
049: String token) throws ProxoolException {
050: this .alias = alias;
051: this .compositeStatisticsListener = compositeStatisticsListener;
052:
053: nextRollDate = Calendar.getInstance();
054: if (token.endsWith("s")) {
055: units = Calendar.SECOND;
056: nextRollDate.clear(Calendar.SECOND);
057: nextRollDate.clear(Calendar.MILLISECOND);
058: } else if (token.endsWith("m")) {
059: units = Calendar.MINUTE;
060: nextRollDate.clear(Calendar.MINUTE);
061: nextRollDate.clear(Calendar.SECOND);
062: nextRollDate.clear(Calendar.MILLISECOND);
063: } else if (token.endsWith("h")) {
064: nextRollDate.clear(Calendar.HOUR_OF_DAY);
065: nextRollDate.clear(Calendar.MINUTE);
066: nextRollDate.clear(Calendar.SECOND);
067: nextRollDate.clear(Calendar.MILLISECOND);
068: units = Calendar.HOUR_OF_DAY;
069: } else if (token.endsWith("d")) {
070: units = Calendar.DATE;
071: nextRollDate.clear(Calendar.HOUR_OF_DAY);
072: nextRollDate.clear(Calendar.MINUTE);
073: nextRollDate.clear(Calendar.SECOND);
074: nextRollDate.clear(Calendar.MILLISECOND);
075: } else {
076: throw new ProxoolException(
077: "Unrecognised suffix in statistics: " + token);
078: }
079:
080: period = Integer.parseInt(token
081: .substring(0, token.length() - 1));
082:
083: // Now roll forward until you get one step into the future
084: Calendar now = Calendar.getInstance();
085: while (nextRollDate.before(now)) {
086: nextRollDate.add(units, period);
087: }
088:
089: LOG.debug("Collecting first statistics for '" + token + "' at "
090: + nextRollDate.getTime());
091: currentStatistics = new Statistics(now.getTime());
092:
093: // Automatically trigger roll if no activity
094: final Thread t = new Thread() {
095:
096: public void run() {
097: while (running) {
098: try {
099: Thread.sleep(5000);
100: } catch (InterruptedException e) {
101: LOG.debug("Interruption", e);
102: }
103: roll();
104: }
105: }
106:
107: };
108: t.setDaemon(true);
109: t.start();
110: }
111:
112: /**
113: * Cancels the timer that outputs the stats
114: */
115: protected void cancel() {
116: running = false;
117: }
118:
119: private void roll() {
120: if (!isCurrent()) {
121: try {
122: readWriteLock.writeLock().acquire();
123: if (!isCurrent()) {
124: currentStatistics.setStopDate(nextRollDate
125: .getTime());
126: completeStatistics = currentStatistics;
127: currentStatistics = new Statistics(nextRollDate
128: .getTime());
129: nextRollDate.add(units, period);
130: compositeStatisticsListener.statistics(alias,
131: completeStatistics);
132: }
133: } catch (Throwable e) {
134: LOG.error("Unable to roll statistics log", e);
135: } finally {
136: readWriteLock.writeLock().release();
137: }
138: }
139: }
140:
141: private boolean isCurrent() {
142: return (System.currentTimeMillis() < nextRollDate.getTime()
143: .getTime());
144: }
145:
146: /**
147: * @see org.logicalcobwebs.proxool.admin.Admin#connectionReturned
148: */
149: public void connectionReturned(long activeTime) {
150: roll();
151: try {
152: readWriteLock.readLock().acquire();
153: currentStatistics.connectionReturned(activeTime);
154: } catch (InterruptedException e) {
155: LOG.error("Unable to log connectionReturned", e);
156: } finally {
157: readWriteLock.readLock().release();
158: }
159: }
160:
161: /**
162: * @see org.logicalcobwebs.proxool.admin.Admin#connectionRefused
163: */
164: public void connectionRefused() {
165: roll();
166: try {
167: readWriteLock.readLock().acquire();
168: currentStatistics.connectionRefused();
169: } catch (InterruptedException e) {
170: LOG.error("Unable to log connectionRefused", e);
171: } finally {
172: readWriteLock.readLock().release();
173: }
174: }
175:
176: /**
177: *
178: * @return
179: */
180: public Statistics getCompleteStatistics() {
181: try {
182: readWriteLock.readLock().acquire();
183: return completeStatistics;
184: } catch (InterruptedException e) {
185: LOG.error("Couldn't read statistics", e);
186: return null;
187: } finally {
188: readWriteLock.readLock().release();
189: }
190: }
191: }
192:
193: /*
194: Revision history:
195: $Log: StatsRoller.java,v $
196: Revision 1.9 2006/01/18 14:39:58 billhorsman
197: Unbundled Jakarta's Commons Logging.
198:
199: Revision 1.8 2003/10/27 20:24:48 billhorsman
200: roll() now makes an additional call to isCurrent() *before* it asks for a write lock. Before it
201: was getting a write lock every five seconds which effectively blocks all connections (if only briefly).
202:
203: Revision 1.7 2003/09/10 22:21:04 chr32
204: Removing > jdk 1.2 dependencies.
205:
206: Revision 1.6 2003/03/11 00:12:11 billhorsman
207: switch to concurrent package
208:
209: Revision 1.5 2003/03/06 21:56:27 billhorsman
210: remove too much debug
211:
212: Revision 1.4 2003/03/06 12:44:02 billhorsman
213: add readWriteLock
214:
215: Revision 1.3 2003/03/03 11:11:59 billhorsman
216: fixed licence
217:
218: Revision 1.2 2003/02/28 12:42:45 billhorsman
219: removed unnecessary sleep in timer
220:
221: Revision 1.1 2003/02/19 23:36:51 billhorsman
222: renamed monitor package to admin
223:
224: Revision 1.11 2003/02/08 14:27:51 chr32
225: Style fixes.
226: Also tried to fix the dublicate linebreaks in the logging classes.
227:
228: Revision 1.10 2003/02/07 14:16:46 billhorsman
229: support for StatisticsListenerIF
230:
231: Revision 1.9 2003/02/06 17:41:06 billhorsman
232: now uses imported logging
233:
234: Revision 1.8 2003/02/06 15:41:18 billhorsman
235: add statistics-log-level
236:
237: Revision 1.7 2003/02/04 17:17:03 billhorsman
238: make Timer a daemon
239:
240: Revision 1.6 2003/02/04 15:59:49 billhorsman
241: finalize now shuts down StatsRoller timer
242:
243: Revision 1.5 2003/02/02 23:32:48 billhorsman
244: fixed bug caused by last variable name change. :(
245:
246: Revision 1.4 2003/01/31 16:53:23 billhorsman
247: checkstyle
248:
249: Revision 1.3 2003/01/31 16:38:54 billhorsman
250: doc (and removing public modifier for classes where possible)
251:
252: Revision 1.2 2003/01/31 14:33:19 billhorsman
253: fix for DatabaseMetaData
254:
255: Revision 1.1 2003/01/31 11:35:57 billhorsman
256: improvements to servlet (including connection details)
257:
258: Revision 1.1 2003/01/31 00:28:57 billhorsman
259: now handles multiple statistics
260:
261: */
|