001: /**
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */package org.apache.geronimo.monitoring;
017:
018: import java.util.ArrayList;
019: import java.util.Collection;
020: import java.util.HashMap;
021: import java.util.HashSet;
022: import java.util.Iterator;
023: import java.util.Set;
024: import java.util.TreeMap;
025:
026: import javax.management.Attribute;
027: import javax.management.MBeanServer;
028: import javax.management.MBeanServerFactory;
029: import javax.management.ObjectName;
030: import javax.management.j2ee.Management;
031: import javax.management.j2ee.ManagementHome;
032: import javax.management.j2ee.statistics.BoundedRangeStatistic;
033: import javax.management.j2ee.statistics.RangeStatistic;
034: import javax.management.j2ee.statistics.Stats;
035: import javax.management.j2ee.statistics.CountStatistic;
036: import javax.management.j2ee.statistics.Statistic;
037: import javax.management.j2ee.statistics.TimeStatistic;
038: import javax.naming.Context;
039: import javax.naming.InitialContext;
040: import javax.naming.NamingException;
041: import javax.sql.DataSource;
042:
043: import org.apache.commons.logging.Log;
044: import org.apache.commons.logging.LogFactory;
045:
046: import org.apache.geronimo.connector.outbound.ManagedConnectionFactoryWrapper;
047: import org.apache.geronimo.gbean.AbstractName;
048: import org.apache.geronimo.gbean.GBeanInfo;
049: import org.apache.geronimo.gbean.GBeanInfoBuilder;
050: import org.apache.geronimo.gbean.GBeanLifecycle;
051:
052: import org.apache.geronimo.monitoring.MBeanHelper;
053:
054: import org.apache.xbean.naming.context.WritableContext.NestedWritableContext;
055:
056: import org.apache.geronimo.monitoring.snapshot.SnapshotThread;
057: import org.apache.geronimo.monitoring.snapshot.SnapshotConfigXMLBuilder;
058: import org.apache.geronimo.monitoring.snapshot.SnapshotDBHelper;
059:
060: /**
061: * This is the GBean that will be the bottleneck for the communication
062: * between the management node and the data in the server node.
063: */
064: public class MasterRemoteControlJMX implements GBeanLifecycle {
065: private static Log log = LogFactory
066: .getLog(MasterRemoteControlJMX.class);
067: // constants
068: private static final String GERONIMO_DEFAULT_DOMAIN = "geronimo";
069: private static final Long DEFAULT_DURATION = new Long(300000);
070: private static final int DEFAULT_RETENTION = 30;
071: private static final String RETENTION = "retention";
072: private static final String DURATION = "duration";
073:
074: // mbean server to talk to other components
075: private static MBeanServer mbServer = null;
076:
077: // threads
078: private static SnapshotThread snapshotThread = null;
079:
080: // datasources
081: private DataSource activeDS;
082: private DataSource archiveDS;
083:
084: private SnapshotDBHelper snapshotDBHelper;
085:
086: public MasterRemoteControlJMX() {
087: // retrieve the mbean server
088: ArrayList mbServerList = MBeanServerFactory
089: .findMBeanServer(null);
090: if (mbServerList.size() >= 1) {
091: mbServer = (MBeanServer) mbServerList.get(0);
092: for (int i = 0; i < mbServerList.size(); i++) {
093: String domain = ((MBeanServer) mbServerList.get(i))
094: .getDefaultDomain();
095: if (domain.equals(GERONIMO_DEFAULT_DOMAIN)) {
096: mbServer = (MBeanServer) mbServerList.get(i);
097: break;
098: }
099: }
100: }
101: // ensure that the mbServer has something in it
102: if (mbServer == null) {
103: mbServer = MBeanServerFactory
104: .createMBeanServer(GERONIMO_DEFAULT_DOMAIN);
105: }
106:
107: // set up SnaphotDBHelper with the necessary data sources
108: // Note: do not put this in the constructor...datasources are not injected by then
109: try {
110: InitialContext ic = new InitialContext();
111: activeDS = (DataSource) ((ManagedConnectionFactoryWrapper) ic
112: .lookup("jca:/org.apache.geronimo.plugins/agent-ds/JCAManagedConnectionFactory/jdbc/ActiveDS"))
113: .$getResource();
114: archiveDS = (DataSource) ((ManagedConnectionFactoryWrapper) ic
115: .lookup("jca:/org.apache.geronimo.plugins/agent-ds/JCAManagedConnectionFactory/jdbc/ArchiveDS"))
116: .$getResource();
117: // activeDS = (DataSource)((NestedWritableContext)ic.lookup("jms:conn")).lookup("jdbc/ActiveDS");
118: // archiveDS = (DataSource)((NestedWritableContext)ic.lookup("jms:conn")).lookup("jdbc/ArchiveDS");
119: } catch (Exception e) {
120: log.error(e.getMessage());
121: e.printStackTrace();
122: }
123: snapshotDBHelper = new SnapshotDBHelper(activeDS, archiveDS);
124: }
125:
126: /**
127: * Looks up the JSR-77 statistics associated with this object name.
128: *
129: * @param objectName
130: * @return HashMap
131: * @throws Exception
132: */
133: public static HashMap getStats(String objectName) throws Exception {
134: HashMap statsMap = new HashMap();
135: Stats stats = (Stats) mbServer.getAttribute(new ObjectName(
136: objectName), "stats");
137: String[] sttsName = stats.getStatisticNames();
138: Statistic[] stts = stats.getStatistics();
139: for (int i = 0; i < sttsName.length; i++) {
140: Statistic aStat = stats.getStatistic(sttsName[i]);
141: if (aStat instanceof RangeStatistic) {
142: Long current = new Long(((RangeStatistic) aStat)
143: .getCurrent());
144: Long high = new Long(((RangeStatistic) aStat)
145: .getHighWaterMark());
146: Long low = new Long(((RangeStatistic) aStat)
147: .getLowWaterMark());
148: statsMap.put(stts[i].getName() + " Current", current);
149: statsMap.put(stts[i].getName() + " Max", high);
150: statsMap.put(stts[i].getName() + " Min", low);
151: } else if (aStat instanceof CountStatistic) {
152: Long current = new Long(((CountStatistic) aStat)
153: .getCount());
154: statsMap.put(stts[i].getName(), current);
155: } else if (aStat instanceof TimeStatistic) {
156: Long current = new Long(((TimeStatistic) aStat)
157: .getCount());
158: Long max = new Long(((TimeStatistic) aStat)
159: .getMaxTime());
160: Long min = new Long(((TimeStatistic) aStat)
161: .getMinTime());
162: Long total = new Long(((TimeStatistic) aStat)
163: .getTotalTime());
164: statsMap.put(stts[i].getName() + " CurrentTime",
165: current);
166: statsMap.put(stts[i].getName() + " MaxTime", max);
167: statsMap.put(stts[i].getName() + " MinTime", min);
168: statsMap.put(stts[i].getName() + " TotalTime", total);
169: } else {
170: // this should never happen
171: throw new Exception();
172: }
173: }
174: return statsMap;
175: }
176:
177: /**
178: * Changes the objectName's attrName's value to attrValue
179: *
180: * @param objectName
181: * @param attrName
182: * @param attrValue
183: * @throws Exception
184: */
185: public void setAttribute(String objectName, String attrName,
186: Object attrValue) throws Exception {
187: Attribute attr = new Attribute(attrName, attrValue);
188: mbServer.setAttribute(new ObjectName(objectName), attr);
189: }
190:
191: /**
192: * Stops the snapshot thread
193: */
194: public boolean stopSnapshot() {
195: if (snapshotThread != null) {
196: if (snapshotThread.getSnapshotDuration() != Long.MAX_VALUE) {
197: saveDuration(snapshotThread.getSnapshotDuration());
198: snapshotThread.setSnapshotDuration(Long.MAX_VALUE);
199: log.info("Snapshot thread stopped.");
200: return true;
201: } else {
202: return false;
203: }
204: } else {
205: log
206: .error("There is not a snapshot thread running. Stopping aborted.");
207: return false;
208: }
209: }
210:
211: /**
212: * Fetches the data stored from the snapshot thread and returns
213: * it in a ArrayList with each element being a HashMap of the attribute
214: * mapping to the statistic. All stats will be the average of
215: * 1 - n, n+1 - 2n, ..., cn+1 - c(n+1)
216: *
217: * Grabs 'numberOfSnapshots' snapshots. Grabs one snapshot per
218: * 'everyNthsnapshot'
219: *
220: * @param numberOfSnapshot
221: * @param everyNthSnapshot
222: * @return ArrayList
223: */
224: public ArrayList<HashMap<String, HashMap<String, Object>>> fetchSnapshotData(
225: Integer numberOfSnapshot, Integer everyNthSnapshot) {
226: return (ArrayList<HashMap<String, HashMap<String, Object>>>) snapshotDBHelper
227: .fetchData(numberOfSnapshot, everyNthSnapshot);
228: }
229:
230: /**
231: * Fetches the max amount for each statistic stored from the snapshot thread
232: * and returns it in a HashMap
233: *
234: * @param numberOfSnapshot
235: * @return HashMap
236: */
237: public HashMap<String, HashMap<String, Long>> fetchMaxSnapshotData(
238: Integer numberOfSnapshot) {
239: return (HashMap<String, HashMap<String, Long>>) snapshotDBHelper
240: .fetchMaxSnapshotData(numberOfSnapshot);
241: }
242:
243: /**
244: * Fetches the min amount for each statistic stored from the snapshot thread
245: * and returns it in a HashMap
246: *
247: * @param numberOfSnapshot
248: * @return HashMap
249: */
250: public HashMap<String, HashMap<String, Long>> fetchMinSnapshotData(
251: Integer numberOfSnapshot) {
252: return (HashMap<String, HashMap<String, Long>>) snapshotDBHelper
253: .fetchMinSnapshotData(numberOfSnapshot);
254: }
255:
256: /**
257: * Gets the elapsed time in milliseconds between each snapshot.
258: *
259: * @return Long
260: */
261: public Long getSnapshotDuration() {
262: try {
263: return Long.parseLong(SnapshotConfigXMLBuilder
264: .getAttributeValue(DURATION));
265: } catch (Exception e) {
266: return new Long(DEFAULT_DURATION);
267: }
268: }
269:
270: /**
271: * Sets the elapsed time in milliseconds between each snapshot.
272: *
273: * @param snapshotDuration
274: */
275: public void setSnapshotDuration(Long snapshotDuration) {
276: if (snapshotThread != null) {
277: snapshotThread.setSnapshotDuration(snapshotDuration
278: .longValue());
279: saveDuration(snapshotThread.getSnapshotDuration());
280: } else {
281: log.warn("There is not a snapshot thread instantiated.");
282: }
283: }
284:
285: public void setSnapshotRetention(Integer retention) {
286: saveRetention(retention.intValue());
287: }
288:
289: /**
290: * Begins the snapshot process given the time interval between snapshots
291: *
292: * Precondition:
293: * interval is given in milli seconds
294: *
295: * @param interval
296: */
297: public boolean startSnapshot(Long interval) {
298: // get the saved/default retention period
299: String retentionStr = null;
300: try {
301: retentionStr = SnapshotConfigXMLBuilder
302: .getAttributeValue(RETENTION);
303: } catch (Exception e) {
304: // happens when there is not an instance of "retention" in the config
305: // which is okay.
306: }
307: int retention;
308: if (retentionStr == null) {
309: retention = DEFAULT_RETENTION;
310: } else {
311: retention = Integer.parseInt(retentionStr);
312: }
313: return startSnapshot(interval, new Integer(retention));
314: }
315:
316: /**
317: * Begins the snapshot process given the time interval between snapshots
318: *
319: * Precondition:
320: * interval is given in milli seconds
321: *
322: * @param interval
323: */
324: public boolean startSnapshot(Long interval, Integer retention) {
325: if ((snapshotThread == null || (snapshotThread != null && (snapshotThread
326: .SnapshotStatus() == 0)))
327: && interval.longValue() > 0) {
328: saveDuration(interval.longValue());
329: saveRetention(retention.intValue());
330: snapshotThread = new SnapshotThread(interval.longValue(),
331: mbServer);
332: snapshotThread.start();
333: log.info("Snapshot thread successfully created.");
334: return true;
335: } else {
336: log.warn("There is already a snapshot thread running.");
337: return false;
338: }
339: }
340:
341: public Long getSnapshotCount() {
342: return snapshotDBHelper.getSnapshotCount();
343: }
344:
345: /**
346: * Fetches all mbean names that provide JSR-77 statistics
347: *
348: * @return A set containing all mbean names of mbeans that provide
349: * statistics
350: */
351: public Set<String> getStatisticsProviderMBeanNames() {
352: return (Set<String>) MBeanHelper
353: .getStatsProvidersMBeans(getAllMBeanNames());
354: }
355:
356: /**
357: * Fetches all mbean names
358: *
359: * @return A set containing all mbean names
360: */
361: public Set<String> getAllMBeanNames() {
362: try {
363: Set<ObjectName> names = (Set<ObjectName>) mbServer
364: .queryNames(null, null);
365: Set<String> strNames = new HashSet<String>();
366: for (Iterator<ObjectName> it = names.iterator(); it
367: .hasNext();) {
368: strNames.add(it.next().getCanonicalName());
369: }
370: return strNames;
371: } catch (Exception e) {
372: log.error(e.getMessage(), e);
373: return new HashSet<String>();
374: }
375: }
376:
377: public void doFail() {
378: doStop();
379: }
380:
381: /**
382: * Executes when the GBean starts up. Also starts the snapshot thread.
383: */
384: public void doStart() {
385:
386: }
387:
388: /**
389: * Executes when the GBean stops. Also stops the snapshot thread.
390: */
391: public void doStop() {
392: if (SnapshotStatus() == 1) {
393: stopSnapshot();
394: }
395: }
396:
397: private void saveDuration(long duration) {
398: SnapshotConfigXMLBuilder.saveDuration(duration);
399: }
400:
401: private void saveRetention(int retention) {
402: SnapshotConfigXMLBuilder.saveRetention(retention);
403: }
404:
405: /**
406: * Adds a record of the mbean via its name to take snapshots of. As a result
407: * the mbeanName will be written to snapshot-config.xml
408: *
409: * @param mbeanName
410: */
411: public boolean addMBeanForSnapshot(String mbeanName) {
412: return SnapshotConfigXMLBuilder.addMBeanName(mbeanName);
413: }
414:
415: /**
416: * Removes a record of the mbean via its name to take snapshots of. As a result
417: * the mbeanName will be removed from snapshot-config.xml
418: *
419: * @param mbeanName
420: */
421: public boolean removeMBeanForSnapshot(String mbeanName) {
422: return SnapshotConfigXMLBuilder.removeMBeanName(mbeanName);
423: }
424:
425: /**
426: * @return A map: mbeanName --> ArrayList of statistic attributes for that mbean
427: */
428: public HashMap<String, ArrayList<String>> getAllSnapshotStatAttributes() {
429: HashMap<String, ArrayList<String>> snapshotAttributes = new HashMap<String, ArrayList<String>>();
430: Set<String> mbeans = getTrackedMBeans();
431: // for each mbean name
432: for (Iterator<String> it = mbeans.iterator(); it.hasNext();) {
433: ArrayList<String> mbeanStatsList = new ArrayList<String>();
434: String mbeanName = it.next();
435: try {
436: Stats stats = (Stats) mbServer.getAttribute(
437: new ObjectName(mbeanName), "stats");
438: String[] sttsName = stats.getStatisticNames();
439: Statistic[] stts = stats.getStatistics();
440: for (int i = 0; i < sttsName.length; i++) {
441: Statistic aStat = stats.getStatistic(sttsName[i]);
442: if (aStat instanceof RangeStatistic) {
443: mbeanStatsList.add(stts[i].getName()
444: + " Current");
445: mbeanStatsList.add(stts[i].getName() + " Max");
446: mbeanStatsList.add(stts[i].getName() + " Min");
447: } else if (aStat instanceof CountStatistic) {
448: mbeanStatsList.add(stts[i].getName());
449: } else if (aStat instanceof TimeStatistic) {
450: mbeanStatsList
451: .add(stts[i].getName() + " Count");
452: mbeanStatsList.add(stts[i].getName()
453: + " MaxTime");
454: mbeanStatsList.add(stts[i].getName()
455: + " MinTime");
456: mbeanStatsList.add(stts[i].getName()
457: + " TotalTime");
458: } else {
459: // for the time being, only numbers should be returned
460: }
461: }
462: } catch (Exception e) {
463: log.error(e.getMessage(), e);
464: }
465: // save attributes to the returning list
466: snapshotAttributes.put(mbeanName, mbeanStatsList);
467: }
468: return snapshotAttributes;
469: }
470:
471: public Set<String> getTrackedMBeans() {
472: ArrayList<String> mbeans = (ArrayList<String>) SnapshotConfigXMLBuilder
473: .getMBeanNames();
474: Set<String> set = new HashSet<String>();
475: for (int i = 0; i < mbeans.size(); i++) {
476: set.add(mbeans.get(i));
477: }
478: return set;
479: }
480:
481: public Integer getSnapshotRetention() {
482: try {
483: return new Integer(SnapshotConfigXMLBuilder
484: .getAttributeValue(RETENTION));
485: } catch (Exception e) {
486: return new Integer(DEFAULT_RETENTION); // the default
487: }
488: }
489:
490: /**
491: * @param name - object name of the mbean
492: * @param operationName - method within the class
493: * @param params - parameters for the method
494: * @param signature - types for the parameters
495: * @return Invokes the method of a class defined.
496: */
497: public Object invoke(ObjectName name, String operationName,
498: Object[] params, String[] signature) throws Exception {
499: return mbServer.invoke(name, operationName, params, signature);
500: }
501:
502: /**
503: * @param mbeanName
504: * @param statsName
505: * @param numberOfSnapshots
506: * @param everyNthSnapshot
507: * @return HashMap which maps from a snapshot_time --> value of the mbean.statsName at that time
508: */
509: public TreeMap<Long, Long> getSpecificStatistics(String mbeanName,
510: String statsName, Integer numberOfSnapshots,
511: Integer everyNthSnapshot, Boolean showArchived) {
512: return snapshotDBHelper.getSpecificStatistics(mbeanName,
513: statsName, numberOfSnapshots.intValue(),
514: everyNthSnapshot.intValue(), showArchived);
515: }
516:
517: /**
518: * @return Returns true if snapshot is running.
519: */
520: public Integer SnapshotStatus() {
521: // TODO: check if the snapshot thread is running
522: if (snapshotThread == null) {
523: return 0;
524: } else {
525: return snapshotThread.SnapshotStatus();
526: }
527: }
528:
529: public static final GBeanInfo GBEAN_INFO;
530:
531: static {
532: GBeanInfoBuilder infoFactory = GBeanInfoBuilder.createStatic(
533: "MasterRemoteControlJMX", MasterRemoteControlJMX.class);
534: infoFactory.addOperation("getStats",
535: new Class[] { String.class }, "HashMap");
536: infoFactory.addOperation("setAttribute", new Class[] {
537: String.class, String.class, Object.class }, "void");
538: infoFactory.addOperation("startSnapshot",
539: new Class[] { Long.class }, "Boolean");
540: infoFactory.addOperation("startSnapshot", new Class[] {
541: Long.class, Integer.class }, "Boolean");
542: infoFactory.addOperation("stopSnapshot", new Class[] {},
543: "Boolean");
544: infoFactory.addOperation("fetchSnapshotData", new Class[] {
545: Integer.class, Integer.class }, "ArrayList");
546: infoFactory.addOperation("fetchMaxSnapshotData",
547: new Class[] { Integer.class }, "HashMap");
548: infoFactory.addOperation("fetchMinSnapshotData",
549: new Class[] { Integer.class }, "HashMap");
550: infoFactory.addOperation("getSnapshotDuration", new Class[] {},
551: "Long");
552: infoFactory.addOperation("getSnapshotCount", new Class[] {},
553: "Long");
554: infoFactory.addOperation("setSnapshotDuration",
555: new Class[] { Long.class }, "void");
556: infoFactory.addOperation("getStatisticsProviderMBeanNames",
557: new Class[] {}, "Set");
558: infoFactory.addOperation("getAllMBeanNames", new Class[] {},
559: "Set");
560: infoFactory.addOperation("getAllSnapshotStatAttributes",
561: new Class[] {}, "HashMap");
562: infoFactory.addOperation("addMBeanForSnapshot",
563: new Class[] { String.class }, "void");
564: infoFactory.addOperation("removeMBeanForSnapshot",
565: new Class[] { String.class }, "void");
566: infoFactory.addOperation("getSnapshotRetention",
567: new Class[] {}, "Integer");
568: infoFactory.addOperation("setSnapshotRetention",
569: new Class[] { Integer.class }, "void");
570: infoFactory.addOperation("SnapshotStatus", new Class[] {},
571: "Integer");
572: infoFactory.addOperation("getSpecificStatistics", new Class[] {
573: String.class, String.class, Integer.class,
574: Integer.class, Boolean.class }, "TreeMap");
575: infoFactory.addOperation("getTrackedMBeans", new Class[] {},
576: "Set");
577: infoFactory.setConstructor(new String[] {});
578: GBEAN_INFO = infoFactory.getBeanInfo();
579: }
580:
581: public static GBeanInfo getGBeanInfo() {
582: return GBEAN_INFO;
583: }
584: }
|