001: /**
002: * Treats groups of monitors the same way you treat one monitor. i.e. you can enable/disable/reset
003: * etc a group of monitors.
004: */package com.jamonapi;
005:
006: import java.util.*;
007: import com.jamonapi.utils.*;
008:
009: public class MonitorComposite extends Monitor implements DetailData {
010:
011: private final Monitor[] monitors;// the monitors in the composite
012: private final int numRows; // rows in the composite
013: private final static int TYPICAL_NUM_CHILDREN = 200;// hopefully makes it so the monitor need not grow all the time
014:
015: /** Creates a new instance of MonitorComposite */
016: public MonitorComposite(Monitor[] monitors) {
017: this .monitors = monitors;
018: numRows = (monitors == null) ? 0 : monitors.length;
019: }
020:
021: MonitorComposite() {
022: this (null);
023: }
024:
025: public Monitor[] getMonitors() {
026: return monitors;
027: }
028:
029: /** Pass in an array with col1=lables, and col2=units and then call methods */
030: public static MonitorComposite getMonitors(String[][] labels) {
031: int numRows = (labels == null) ? 0 : labels.length;
032: int numCols = (labels[0] == null) ? 0 : labels[0].length;
033:
034: Monitor[] monArray = new Monitor[numRows];
035:
036: for (int i = 0; i < numRows; i++) {
037: MonKey key = null;
038: if (numCols == 2)// i.e 2 columns - summary, units (ex: sp_proc ?, ms.)
039: key = new MonKeyImp(labels[i][0], labels[i][1]);
040: else if (numCols == 3) // 3 columns - summary, detail, units (ex: sp_proc ?, sp_proc 'steve', ms.)
041: key = new MonKeyImp(labels[i][0], labels[i][1],
042: labels[i][2]);
043:
044: monArray[i] = MonitorFactory.getMonitor(key);
045: }
046:
047: return new MonitorComposite(monArray);
048:
049: }
050:
051: public int getNumRows() {
052: return numRows;
053: }
054:
055: /** Return the header that applies to all monitors. It does not include range column headers.
056: ** It will contain label, hits, total, avg, min, max and active among other columns
057: **/
058: public String[] getBasicHeader() {
059: List header = new ArrayList();
060: if (hasData()) {
061: // being as all monitors in the composite should have the same range
062: // getting the first one should suffice to get the header
063: getFirstMon().getBasicHeader(header);
064: return (String[]) header.toArray(new String[0]);
065: } else
066: return null;
067: }
068:
069: /** Return the header with basic data and columns for each field within the range. note getHeader only works if the range of all monitors in the composite are the same.
070: **/
071: public String[] getHeader() {
072: List header = new ArrayList();
073: if (hasData()) {
074: // being as all monitors in the composite should have the same range
075: // getting the first one should suffice to get the header
076: getFirstMon().getHeader(header);
077: return (String[]) header.toArray(new String[0]);
078: } else
079: return null;
080: }
081:
082: /** Return the header with basic data and one column for each range. Note this only will work with ranges of the same type */
083: public String[] getDisplayHeader() {
084: List header = new ArrayList();
085: if (hasData()) {
086: // being as all monitors in the composite should have the same range
087: // getting the first one should suffice to get the header
088: getFirstMon().getDisplayHeader(header);
089: return (String[]) header.toArray(new String[0]);
090: } else
091: return null;
092: }
093:
094: // Various get data methods (for all data, basic data, and display data
095: // note getData will only return an array with the same number of columns in every row
096: // if the range of all monitors in the composite are the same.
097: /** Get all data including basic data as well as each element within the range */
098: public Object[][] getData() {
099: if (!hasData())
100: return null;
101:
102: Object[][] data = new Object[getNumRows()][];
103: for (int i = 0; i < numRows; i++) {
104: data[i] = getRowData((MonitorImp) monitors[i]);
105: }
106:
107: return data;
108:
109: }
110:
111: /** Get basic data (which excludes range data) */
112: public Object[][] getBasicData() {
113: if (!hasData())
114: return null;
115:
116: Object[][] data = new Object[getNumRows()][];
117: for (int i = 0; i < numRows; i++) {
118: data[i] = getBasicRowData((MonitorImp) monitors[i]);
119: }
120:
121: return data;
122:
123: }
124:
125: /** Get display data including 1 column for each range */
126: public Object[][] getDisplayData() {
127: if (!hasData())
128: return null;
129:
130: Object[][] data = new Object[getNumRows()][];
131: for (int i = 0; i < numRows; i++) {
132: data[i] = getRowDisplayData((MonitorImp) monitors[i]);
133: }
134:
135: return data;
136:
137: }
138:
139: /** A basic report in html format. It has summary info for all monitors but
140: * no range info
141: */
142: public String getReport() {
143: return getReport(0, "asc");
144: }
145:
146: /** A basic report in html format that is sorted. It has summary info for all monitors but
147: * no range info
148: */
149: public String getReport(int sortCol, String sortOrder) {
150: if (!hasData())
151: return "";
152:
153: String[] header = getBasicHeader();
154: Object[][] data = Misc.sort(getBasicData(), sortCol, sortOrder);
155: int rows = data.length;
156: int cols = header.length;
157:
158: StringBuffer html = new StringBuffer(100000);// guess on report size
159: html.append("\n<table border='1' rules='all'>\n");
160:
161: for (int i = 0; i < cols; i++)
162: html.append("<th>" + header[i] + "</th>");
163:
164: html.append("<th>" + header[0] + "</th>");//repeat first header
165: html.append("\n");
166:
167: for (int i = 0; i < rows; i++) {
168: html.append("<tr>");
169: for (int j = 0; j < cols; j++) {
170: html.append("<td>" + data[i][j] + "</td>");
171: }
172: html.append("<td>" + data[i][0] + "</td>");// repeat first column
173: html.append("</tr>\n");
174: }
175:
176: html.append("</table>");
177:
178: return html.toString();
179: }
180:
181: /** Does this have data? */
182: public boolean hasData() {
183: return (getNumRows() == 0) ? false : true;
184: }
185:
186: // Various get row data methods (for full row, basic row, and display row
187: private Object[] getRowData(MonitorImp mon) {
188: List row = new ArrayList(TYPICAL_NUM_CHILDREN);
189: mon.getRowData(row);
190: return row.toArray();
191:
192: }
193:
194: private Object[] getBasicRowData(MonitorImp mon) {
195: List row = new ArrayList();
196: mon.getBasicRowData(row);
197: return row.toArray();
198:
199: }
200:
201: private Object[] getRowDisplayData(MonitorImp mon) {
202: List row = new ArrayList(TYPICAL_NUM_CHILDREN);
203: mon.getRowDisplayData(row);
204: return row.toArray();
205:
206: }
207:
208: public void reset() {
209: for (int i = 0; i < numRows; i++)
210: monitors[i].reset();
211: }
212:
213: public void disable() {
214: for (int i = 0; i < numRows; i++)
215: monitors[i].disable();
216: }
217:
218: public void enable() {
219: for (int i = 0; i < numRows; i++)
220: monitors[i].enable();
221: }
222:
223: public double getActive() {
224: double value = 0;
225: for (int i = 0; i < numRows; i++) {
226: value += monitors[i].getActive();
227: }
228:
229: return value;
230: }
231:
232: public double getAvg() {
233: double hits = getHits();
234: double total = 0;
235:
236: for (int i = 0; i < numRows; i++) {
237: total += monitors[i].getTotal();
238: }
239:
240: if (hits == 0)
241: return 0;
242: else
243: return total / hits;
244:
245: }
246:
247: /** This returns a weighted average */
248: public double getAvgActive() {
249: double weightedActive = 0;
250: double totalHits = 0;
251:
252: for (int i = 0; i < numRows; i++) {
253: double hits = monitors[i].getHits();
254: weightedActive = hits * monitors[i].getAvgActive();
255: totalHits += hits;
256: }
257:
258: if (totalHits == 0)
259: return 0;
260: else
261: return weightedActive / totalHits;
262:
263: }
264:
265: public Date getFirstAccess() {
266: Date firstAccess = null;
267: for (int i = 0; i < numRows; i++) {
268: Date this Date = monitors[i].getFirstAccess();
269: if (firstAccess == null
270: || this Date.compareTo(firstAccess) < 0) // thisDate<firstDate
271: firstAccess = this Date;
272:
273: }
274:
275: return firstAccess;
276:
277: }
278:
279: public double getHits() {
280: double value = 0;
281: for (int i = 0; i < numRows; i++) {
282: value += monitors[i].getHits();
283: }
284:
285: return value;
286:
287: }
288:
289: public MonKey getMonKey() {
290: if (!hasData())
291: return null;
292:
293: return getFirstMon().getMonKey();
294: }
295:
296: public Date getLastAccess() {
297: Date lastAccess = null;
298: for (int i = 0; i < numRows; i++) {
299: Date this Date = monitors[i].getLastAccess();
300: if (lastAccess == null
301: || this Date.compareTo(lastAccess) > 0) // thisDate>lastAccess
302: lastAccess = this Date;
303:
304: }
305:
306: return lastAccess;
307:
308: }
309:
310: public double getLastValue() {
311: Date date = getLastAccess();
312: for (int i = 0; i < numRows; i++) {
313: if (date.compareTo(monitors[i].getLastAccess()) >= 0) // date>=getLastAccess)
314: return monitors[i].getLastValue();
315: }
316:
317: return 0;
318:
319: }
320:
321: public double getMax() {
322: double max = MonInternals.MAX_DOUBLE;
323:
324: for (int i = 0; i < numRows; i++) {
325: double this Max = monitors[i].getMax();
326:
327: if (this Max > max)
328: max = this Max;
329: }
330:
331: return max;
332: }
333:
334: public double getMaxActive() {
335: double max = MonInternals.MAX_DOUBLE;
336:
337: for (int i = 0; i < numRows; i++) {
338: double this Max = monitors[i].getMaxActive();
339:
340: if (this Max > max)
341: max = this Max;
342: }
343:
344: return max;
345: }
346:
347: public double getMin() {
348: double min = MonInternals.MIN_DOUBLE;
349:
350: for (int i = 0; i < numRows; i++) {
351: double this Min = monitors[i].getMin();
352:
353: if (this Min < min)
354: min = this Min;
355: }
356:
357: return min;
358: }
359:
360: public Range getRange() {
361: // Composite range???
362: // if they all have the same range then return the range. else return the nullrange
363: return null;
364: }
365:
366: /** This is not a true standard deviation but a average weighted std deviation. However
367: * individual monitors do have a true standard deviation
368: */
369: public double getStdDev() {
370:
371: double weightedStdDev = 0;
372: double totalHits = 0;
373:
374: for (int i = 0; i < numRows; i++) {
375: double hits = monitors[i].getHits();
376: weightedStdDev = hits * monitors[i].getStdDev();
377: totalHits += hits;
378: }
379:
380: if (totalHits == 0)
381: return 0;
382: else
383: return weightedStdDev / totalHits;
384:
385: }
386:
387: public double getTotal() {
388: double value = 0;
389: for (int i = 0; i < numRows; i++) {
390: value += monitors[i].getTotal();
391: }
392:
393: return value;
394: }
395:
396: /** It just takes one of the monitors to not be enabled for the composite to be false */
397: public boolean isEnabled() {
398: for (int i = 0; i < numRows; i++) {
399: if (!monitors[i].isEnabled())
400: return false;
401: }
402:
403: return true;
404: }
405:
406: /** It just takes one of the monitors to not be primary for the composite to be false */
407: public boolean isPrimary() {
408: for (int i = 0; i < numRows; i++) {
409: if (!monitors[i].isPrimary())
410: return false;
411: }
412:
413: return true;
414: }
415:
416: public void setActive(double value) {
417: for (int i = 0; i < numRows; i++)
418: monitors[i].setActive(0);
419: }
420:
421: public void setFirstAccess(java.util.Date date) {
422: for (int i = 0; i < numRows; i++)
423: monitors[i].setFirstAccess(date);
424:
425: }
426:
427: public void setHits(double value) {
428: for (int i = 0; i < numRows; i++)
429: monitors[i].setHits(value);
430: }
431:
432: public void setLastAccess(java.util.Date date) {
433: for (int i = 0; i < numRows; i++)
434: monitors[i].setLastAccess(date);
435: }
436:
437: public void setLastValue(double value) {
438: for (int i = 0; i < numRows; i++)
439: monitors[i].setLastValue(value);
440: }
441:
442: public void setMax(double value) {
443: for (int i = 0; i < numRows; i++)
444: monitors[i].setMax(value);
445: }
446:
447: public void setMaxActive(double value) {
448: for (int i = 0; i < numRows; i++)
449: monitors[i].setMaxActive(value);
450:
451: }
452:
453: public void setMin(double value) {
454: for (int i = 0; i < numRows; i++)
455: monitors[i].setMin(value);
456: }
457:
458: public void setPrimary(boolean isPrimary) {
459: for (int i = 0; i < numRows; i++)
460: monitors[i].setPrimary(isPrimary);
461: }
462:
463: public void setTotal(double value) {
464: for (int i = 0; i < numRows; i++)
465: monitors[i].setTotal(value);
466: }
467:
468: public void setTotalActive(double value) {
469: for (int i = 0; i < numRows; i++)
470: monitors[i].setTotalActive(value);
471: }
472:
473: public Monitor start() {
474: for (int i = 0; i < numRows; i++)
475: monitors[i].start();
476:
477: return this ;
478: }
479:
480: public Monitor stop() {
481: for (int i = 0; i < numRows; i++)
482: monitors[i].stop();
483:
484: return this ;
485: }
486:
487: private MonitorImp getFirstMon() {
488: return (MonitorImp) monitors[0];
489: }
490:
491: public Monitor add(double value) {
492: for (int i = 0; i < numRows; i++)
493: monitors[i].add(value);
494:
495: return this ;
496: }
497:
498: //
499: // public void addListener(String listenerType, JAMonListener listener) {
500: // super.addListener(listenerType, listener);
501: // for (int i=0;i<numRows;i++)
502: // monitors[i].addListener(listenerType, listener);
503: // }
504: //
505: // public JAMonListener getListener(String listenerType) {
506: // // Technically these methods of returning Listeners aren't required as tehy do default behaviours, however it makes
507: // // the behaviour more explicit now.
508: // return super.getListener(listenerType);
509: // }
510: //
511: // public void removeListener(String listenerType) {
512: // super.removeListener(listenerType);
513: // for (int i=0;i<numRows;i++)
514: // monitors[i].removeListener(listenerType);
515: // }
516: //
517:
518: // public void addMaxListener(JAMonListener maxListener) {
519: // super.addMaxListener(maxListener);
520: // for (int i=0;i<numRows;i++)
521: // monitors[i].addMaxListener(maxListener);
522: // }
523:
524: // public void addMinListener(JAMonListener minListener) {
525: // super.addMinListener(minListener);
526: // for (int i=0;i<numRows;i++)
527: // monitors[i].addMinListener(minListener);
528: //
529: // }
530:
531: // public void addValueListener(JAMonListener valueListener) {
532: // super.addValueListener(valueListener);
533: // for (int i=0;i<numRows;i++)
534: // monitors[i].addMinListener(valueListener);
535: //
536: // }
537:
538: public boolean hasListeners() {
539: if (super .hasListeners())
540: return true;
541:
542: for (int i = 0; i < numRows; i++) {
543: if (monitors[i].hasListeners())
544: return true;
545: }
546:
547: return false;
548:
549: }
550:
551: public JAMonDetailValue getJAMonDetailRow() {
552: return JAMonDetailValue.NULL_VALUE;
553: }
554:
555: public void setActivityTracking(boolean trackActivity) {
556: super .setActivityTracking(trackActivity);
557: for (int i = 0; i < numRows; i++)
558: monitors[i].setActivityTracking(trackActivity);
559:
560: }
561:
562: public boolean isActivityTracking() {
563: return super.isActivityTracking();
564: }
565:
566: }
|