001: package com.jamonapi;
002:
003: /**
004: * Main workhorse for creating monitors.
005: *
006: */
007:
008: import java.util.*;
009:
010: import com.jamonapi.utils.DetailData;
011:
012: /** Factory that creates Monitors. This can be created directly. MonitorFactory is simply
013: * a wrapper that makes calling this class simpler. MonitorFactory contains a static reference to
014: * a FactoryEnabled class.
015: *
016: * @author steve souza
017: *
018: */
019:
020: public class FactoryEnabled implements MonitorFactoryInterface {
021:
022: /** Creates a new instance of MonFactoryEnabled. Also initializes the standard
023: * JAMon time monitor range (ms.)
024: */
025: public FactoryEnabled() {
026: initialize();
027: }
028:
029: // note the default capacity for a HashMap is 16 elements with a load factor of
030: // .75. This means that after 12 elements have been loaded the HashMap doubles,
031: // and doubles again at 24 etc. By setting the HashMap to a higher value it need not
032: // grow as often. You can also have jamon use a different map type via the setMap method.
033: private Map map;
034: private Counter allActive;
035: private Counter primaryActive;
036: private RangeFactory rangeFactory;// Builds Range objects
037: private static final boolean PRIMARY = true;
038: private static final boolean NOT_PRIMARY = false;
039: private static final boolean TIME_MONITOR = true;
040: private static final boolean NOT_TIME_MONITOR = false;
041: private static final String VERSION = "2.7";
042:
043: private synchronized void initialize() {
044: map = Collections.synchronizedMap(new HashMap(500));
045: allActive = new Counter();
046: primaryActive = new Counter();
047: rangeFactory = new RangeFactory();// Builds Range objects
048:
049: setRangeDefault("ms.", RangeHolder.getMSHolder());
050: setRangeDefault("percent", RangeHolder.getPercentHolder());
051: }
052:
053: public Monitor add(MonKey key, double value) {
054: return getMonitor(key).add(value);
055: }
056:
057: public Monitor add(String label, String units, double value) {
058: return getMonitor(new MonKeyImp(label, units)).add(value);
059: }
060:
061: public Monitor start(MonKey key) {
062: return getTimeMonitor(key, NOT_PRIMARY).start();
063: }
064:
065: public Monitor start(String label) {
066: return getTimeMonitor(new MonKeyImp(label, "ms."), NOT_PRIMARY)
067: .start();
068: }
069:
070: public Monitor startPrimary(MonKey key) {
071: return getTimeMonitor(key, PRIMARY).start();
072: }
073:
074: public Monitor startPrimary(String label) {
075: return getTimeMonitor(new MonKeyImp(label, "ms."), PRIMARY)
076: .start();
077: }
078:
079: public Monitor start() {
080: return new TimeMon2().start();
081: }
082:
083: public Monitor getMonitor() {
084: return new MonitorImp(
085: new MonKeyImp("defaultMon", "defaultMon"), null,
086: new ActivityStats(), false);
087: }
088:
089: /** allows for using a faster/open source map */
090: public void setMap(Map map) {
091: this .map = map;
092: }
093:
094: public Monitor getMonitor(MonKey key) {
095: return getMonitor(key, NOT_PRIMARY, NOT_TIME_MONITOR);
096: }
097:
098: public Monitor getMonitor(String label, String units) {
099: return getMonitor(new MonKeyImp(label, units));
100: }
101:
102: public Monitor getTimeMonitor(MonKey key) {
103: return getTimeMonitor(key, NOT_PRIMARY);
104: }
105:
106: public Monitor getTimeMonitor(String label) {
107: return getTimeMonitor(new MonKeyImp(label, "ms."), NOT_PRIMARY);
108: }
109:
110: // Range methods
111:
112: // logical should be < or <= to determine how to use range values.
113: // if it is neither it defaults to <=
114: /** Note if a null is passed in it will have the same effect as an empty
115: * RangeHolder (i.e. it will perform null operations)
116: */
117: public void setRangeDefault(String key, RangeHolder rangeHolder) {
118: RangeImp range = null;
119: if (rangeHolder != null || rangeHolder.getSize() > 0)
120: range = new RangeBase(rangeHolder);
121:
122: rangeFactory.setRangeDefault(key, range);
123: }
124:
125: public String[] getRangeHeader() {
126: return rangeFactory.getHeader();
127: }
128:
129: public Object[][] getRangeNames() {
130: return rangeFactory.getData();
131: }
132:
133: public void remove(MonKey key) {
134: map.remove(key);
135: }
136:
137: public void remove(String label, String units) {
138: map.remove(new MonKeyImp(label, units));
139: }
140:
141: public boolean exists(MonKey key) {
142: return map.containsKey(key);
143: }
144:
145: public boolean exists(String label, String units) {
146: return map.containsKey(new MonKeyImp(label, units));
147: }
148:
149: public int getNumRows() {
150: return map.size();
151: }
152:
153: // MonitorComposite methods
154: /** getComposite("AllMonitors") is the same as getRootMonitor() */
155: public MonitorComposite getRootMonitor() {
156: return new MonitorComposite(getMonitors());
157: }
158:
159: /** Pass in the units (or range type) and return all monitors of that
160: * type. 'AllMonitors' is a special argument returns a composite of surprise surprise all monitors
161: *getComposite("AllMonitors") is the same as getRootMonitor() ;
162: **/
163: public MonitorComposite getComposite(String units) {
164: return new MonitorComposite(getMonitors(units));
165: }
166:
167: public String getVersion() {
168: return VERSION;
169: }
170:
171: // INTERNALS/PRIVATES FOLLOW
172: private MonitorImp getTimeMonitor(MonKey key, boolean isPrimary) {
173: return getMonitor(key, isPrimary, TIME_MONITOR);
174: }
175:
176: /***This was changed 11/24/06 to fix syncronization problems reported as bug */
177: private synchronized MonitorImp getMonitor(MonKey key,
178: boolean isPrimary, boolean isTimeMonitor) {
179: // note using MonKey over String concatenation doubled the speed
180: // of the code, and was only slightly slower than using just the label
181: // as the key
182: MonitorImp mon = getExistingMonitor(key);
183: // chance of 2 threads going into the next code simultaneously
184: if (mon == null) {
185: mon = createMon(key, isPrimary, isTimeMonitor);
186: putMon(key, mon);
187: }
188:
189: if (mon.isEnabled()) {
190: mon = (isTimeMonitor) ? new TimeMon(key, mon
191: .getMonInternals()) : new DecoMon(key, mon
192: .getMonInternals());
193: }
194:
195: return mon;
196:
197: }
198:
199: private MonitorImp createMon(MonKey key, boolean isPrimary,
200: boolean isTimeMonitor) {
201: ActivityStats activityStats = new ActivityStats(new Counter(),
202: primaryActive, allActive);
203: // get default range for this type and assign it to the monitor
204: RangeImp range = rangeFactory.getRangeDefault(
205: key.getRangeKey(), activityStats);
206: MonitorImp mon = new MonitorImp(key, range, activityStats,
207: isTimeMonitor);
208:
209: mon.setPrimary(isPrimary);
210: return mon;
211: }
212:
213: private MonitorImp[] getMonitors(String units) {
214: MonitorImp[] monitors = getMonitors();
215: if (monitors == null || units == null)
216: return null;
217: else if ("AllMonitors".equalsIgnoreCase(units))
218: return monitors;
219:
220: List rows = new ArrayList(500);
221:
222: int size = monitors.length;
223: for (int i = 0; i < size; i++) {
224: // if units of range match units of this monitor then
225: if (units.equalsIgnoreCase(monitors[i].getMonKey()
226: .getRangeKey()))
227: rows.add(monitors[i]);
228: }
229:
230: if (rows.size() == 0)
231: return null;
232: else
233: return (MonitorImp[]) rows.toArray(new MonitorImp[0]);
234:
235: }
236:
237: private Collection getAllMonitors() {
238: Collection monitors = map.values();
239: if (monitors == null || monitors.size() == 0)
240: return null;
241: else
242: return monitors;
243:
244: }
245:
246: private MonitorImp[] getMonitors() {
247: Collection monitors = getAllMonitors();
248: if (monitors == null || monitors.size() == 0)
249: return null;
250: else
251: return (MonitorImp[]) monitors.toArray(new MonitorImp[0]);
252: }
253:
254: private MonitorImp getExistingMonitor(MonKey key) {
255: return (MonitorImp) map.get(key);
256: }
257:
258: private void putMon(MonKey key, MonitorImp mon) {
259: map.put(key, mon);
260: }
261:
262: /** Builds ranges */
263: private static class RangeFactory implements DetailData {
264: private Map rangeFactoryMap = Collections
265: .synchronizedMap(new HashMap(50));
266:
267: private void setRangeDefault(String key, RangeImp range) {
268: rangeFactoryMap.put(key, range);
269: // at this point we could set primary and all active counters
270: }
271:
272: /** null or range doesn't exists returns a null range object */
273: private RangeImp getRangeDefault(String key,
274: ActivityStats activityStats) {
275: RangeImp range = (RangeImp) rangeFactoryMap.get(key);
276: if (range != null)
277: range = range.copy(activityStats);
278:
279: return range;
280:
281: }
282:
283: public String[] getHeader() {
284: return new String[] { "RangeName" };
285: }
286:
287: public Object[][] getData() {
288: return getRangeNames(getSortedRangeNames());
289: }
290:
291: // Returns a choice of ranges.
292: private Object[][] getRangeNames(Object[] rangeNames) {
293: int len = (rangeNames == null) ? 0 : rangeNames.length;
294: Object[][] data = new Object[len + 1][];
295: // always populate first entry with 'AllMonitors'
296: data[0] = new Object[] { "AllMonitors" };
297:
298: for (int i = 0; i < len; i++)
299: data[i + 1] = new Object[] { rangeNames[i] };
300:
301: return data;
302:
303: }
304:
305: // returns sorted array of all the unit types
306: private Object[] getSortedRangeNames() {
307: Object[] rangeNames = rangeFactoryMap.keySet().toArray();
308:
309: if (rangeNames == null)
310: return null;
311: else {
312: Arrays.sort(rangeNames);
313: return rangeNames;
314: }
315: }
316:
317: }
318:
319: /** Wipe out existing jamon data. Same as instantiating a new FactoryEnabled object. */
320: public synchronized void reset() {
321: initialize();
322: }
323:
324: public void enableGlobalActive(boolean enable) {
325: allActive.enable(enable);
326:
327: }
328:
329: public boolean isGlobalActiveEnabled() {
330: return allActive.isEnabled();
331: }
332:
333: public Iterator iterator() {
334: // TODO Auto-generated method stub
335: return map.values().iterator();
336: }
337:
338: }
|