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.Properties;
024: import java.util.Set;
025: import java.util.TreeMap;
026:
027: import javax.annotation.PostConstruct;
028: import javax.annotation.Resource;
029: import javax.annotation.security.PermitAll;
030: import javax.annotation.security.RolesAllowed;
031: import javax.ejb.Local;
032: import javax.ejb.Remote;
033: import javax.ejb.Stateless;
034: import javax.ejb.Timeout;
035: import javax.ejb.Timer;
036: import javax.ejb.TimerService;
037: import javax.management.Attribute;
038: import javax.management.MBeanServer;
039: import javax.management.MBeanServerFactory;
040: import javax.management.ObjectName;
041: import javax.management.j2ee.Management;
042: import javax.management.j2ee.ManagementHome;
043: import javax.management.j2ee.statistics.CountStatistic;
044: import javax.management.j2ee.statistics.RangeStatistic;
045: import javax.management.j2ee.statistics.Statistic;
046: import javax.management.j2ee.statistics.Stats;
047: import javax.management.j2ee.statistics.TimeStatistic;
048: import javax.naming.Context;
049: import javax.naming.InitialContext;
050: import javax.sql.DataSource;
051:
052: import org.apache.commons.logging.Log;
053: import org.apache.commons.logging.LogFactory;
054: import org.apache.geronimo.monitoring.snapshot.SnapshotConfigXMLBuilder;
055: import org.apache.geronimo.monitoring.snapshot.SnapshotDBHelper;
056: import org.apache.geronimo.monitoring.snapshot.SnapshotProcessor;
057:
058: /**
059: * This is a Stateful Session Bean that will be the bottleneck for the communication
060: * between the management node and the data in the server node.
061: */
062: @Stateless(name="ejb/mgmt/MRC")
063: @Remote(MasterRemoteControlRemote.class)
064: @Local(MasterRemoteControlLocal.class)
065: @PermitAll
066: public class MasterRemoteControl {
067: private static Log log = LogFactory
068: .getLog(MasterRemoteControl.class);
069:
070: // constants
071: private static final String GERONIMO_DEFAULT_DOMAIN = "geronimo";
072: private static final Long DEFAULT_DURATION = new Long(300000);
073: private static final int DEFAULT_RETENTION = 30; // 30 days
074: private static final String DURATION = "duration";
075: private static final String RETENTION = "retention";
076:
077: // mbean server to talk to other components
078: private static MBeanServer mbServer = null;
079:
080: // mangement ejb - use this to do the monitoring
081: private static Management mejb = null;
082:
083: // credentials for snapshot processor
084: private static String username = null;
085: private static String password = null;
086: private static int port = -1;
087:
088: // inject Data Sources
089: @Resource(name="jdbc/ActiveDS")
090: private DataSource activeDS;
091: @Resource(name="jdbc/ArchiveDS")
092: private DataSource archiveDS;
093:
094: // inject a TimerService
095: @Resource
096: private TimerService timer;
097:
098: private SnapshotDBHelper snapshotDBHelper;
099:
100: public MasterRemoteControl() {
101:
102: }
103:
104: @PostConstruct
105: private void init() {
106: // set up SnaphotDBHelper with the necessary data sources
107: // Note: do not put this in the constructor...datasources are not injected by then
108: snapshotDBHelper = new SnapshotDBHelper(activeDS, archiveDS);
109: }
110:
111: /**
112: * Retrieves and instance of the MEJB and starts the snapshot process
113: */
114: @RolesAllowed("mejbuser")
115: public void setUpMEJB(String username, String password) {
116: // instantiate the MEJB, which will be our gateway to communicate to MBeans
117: try {
118: Properties p = new Properties();
119: p
120: .setProperty(Context.INITIAL_CONTEXT_FACTORY,
121: "org.apache.openejb.client.LocalInitialContextFactory");
122: InitialContext ctx = new InitialContext(p);
123:
124: ManagementHome mejbHome = (ManagementHome) ctx
125: .lookup("ejb/mgmt/MEJBRemoteHome");
126: mejb = mejbHome.create();
127:
128: // save credentials
129: this .username = username;
130: this .password = password;
131: this .port = port;
132:
133: } catch (Exception e) {
134: log.error(e.getMessage(), e);
135: }
136: }
137:
138: /**
139: * Looks up the JSR-77 statistics associated with this object name.
140: *
141: * @param objectName
142: * @return HashMap
143: * @throws Exception
144: */
145: @RolesAllowed("mejbuser")
146: public static HashMap<String, Long> getStats(String objectName)
147: throws Exception {
148: HashMap<String, Long> statsMap = new HashMap<String, Long>();
149: Stats stats = (Stats) mejb.getAttribute(new ObjectName(
150: objectName), "stats");
151: String[] sttsName = stats.getStatisticNames();
152: Statistic[] stts = stats.getStatistics();
153: for (int i = 0; i < sttsName.length; i++) {
154: Statistic aStat = stats.getStatistic(sttsName[i]);
155: if (aStat instanceof RangeStatistic) {
156: Long current = new Long(((RangeStatistic) aStat)
157: .getCurrent());
158: Long high = new Long(((RangeStatistic) aStat)
159: .getHighWaterMark());
160: Long low = new Long(((RangeStatistic) aStat)
161: .getLowWaterMark());
162: statsMap.put(stts[i].getName() + " Current", current);
163: statsMap.put(stts[i].getName() + " Max", high);
164: statsMap.put(stts[i].getName() + " Min", low);
165: } else if (aStat instanceof CountStatistic) {
166: Long current = new Long(((CountStatistic) aStat)
167: .getCount());
168: statsMap.put(stts[i].getName(), current);
169: } else if (aStat instanceof TimeStatistic) {
170: Long count = new Long(((TimeStatistic) aStat)
171: .getCount());
172: Long max = new Long(((TimeStatistic) aStat)
173: .getMaxTime());
174: Long min = new Long(((TimeStatistic) aStat)
175: .getMinTime());
176: Long total = new Long(((TimeStatistic) aStat)
177: .getTotalTime());
178: statsMap.put(stts[i].getName() + " Count", count);
179: statsMap.put(stts[i].getName() + " MaxTime", max);
180: statsMap.put(stts[i].getName() + " MinTime", min);
181: statsMap.put(stts[i].getName() + " TotalTime", total);
182: } else {
183: // for the time being, only numbers should be returned
184: }
185: }
186: return statsMap;
187: }
188:
189: /**
190: * Changes the objectName's attrName's value to attrValue
191: *
192: * @param objectName
193: * @param attrName
194: * @param attrValue
195: * @throws Exception
196: */
197: @RolesAllowed("mejbadmin")
198: public void setAttribute(String objectName, String attrName,
199: Object attrValue) throws Exception {
200: Attribute attr = new Attribute(attrName, attrValue);
201: mejb.setAttribute(new ObjectName(objectName), attr);
202: }
203:
204: // This method is called by the EJB container upon Timer expiration.
205: @Timeout
206: @PermitAll
207: public void handleTimeout(Timer theTimer) {
208: SnapshotProcessor.takeSnapshot(this .username, this .password);
209:
210: // get the duration of theTimer
211: long duration = Long.parseLong((String) theTimer.getInfo());
212: // if the duration is different than the one in the snapshot-config.xml
213: // we need to get rid of this timer and start a new one with the
214: // correct duration.
215: if (duration != getSnapshotDuration().longValue()) {
216: Collection<Timer> timers = timer.getTimers();
217: for (Iterator<Timer> it = timers.iterator(); it.hasNext();) {
218: // cancel all timers
219: it.next().cancel();
220: }
221: // start a new one
222: long newDuration = getSnapshotDuration().longValue();
223: timer.createTimer(newDuration, newDuration, ""
224: + newDuration);
225: }
226: }
227:
228: /**
229: * Begins the snapshot process given the time interval between snapshots
230: *
231: * Precondition:
232: * interval is given in milli seconds
233: *
234: * @param interval
235: */
236: @RolesAllowed("mejbuser")
237: public boolean startSnapshot(Long interval) {
238: // get the saved/default retention period
239: String retentionStr = null;
240: try {
241: retentionStr = SnapshotConfigXMLBuilder
242: .getAttributeValue("retention");
243: } catch (Exception e) {
244: // happens when there is not an instance of "retention" in the config
245: // which is okay.
246: }
247: int retention;
248: if (retentionStr == null) {
249: retention = DEFAULT_RETENTION;
250: } else {
251: retention = Integer.parseInt(retentionStr);
252: }
253: return startSnapshot(interval, retention);
254: }
255:
256: @RolesAllowed("mejbuser")
257: public boolean startSnapshot(Long interval, int retention) {
258: Collection<Timer> timers = timer.getTimers();
259: if (timers.size() == 0) {
260: saveDuration(interval.longValue());
261: saveRetention(retention);
262: timer.createTimer(0, interval.longValue(), ""
263: + interval.longValue());
264: log.info("Created timer successfully.");
265: return true;
266: } else {
267: log.warn("There is already a snapshot timer running...");
268: return false;
269: }
270: }
271:
272: /**
273: * Stops the snapshot thread
274: */
275: @RolesAllowed("mejbuser")
276: public boolean stopSnapshot() {
277: Collection<Timer> timers = timer.getTimers();
278: // stop all timers
279: boolean cancelled = false;
280: for (Iterator<Timer> it = timers.iterator(); it.hasNext();) {
281: Timer t = it.next();
282: t.cancel();
283: cancelled = true;
284: log.info("Stopped snapshot timer...");
285: }
286: return cancelled;
287: }
288:
289: /**
290: * Fetches the data stored from the snapshot thread and returns
291: * it in a ArrayList with each element being a HashMap of the attribute
292: * mapping to the statistic. All stats will be the average of
293: * 1 - n, n+1 - 2n, ..., cn+1 - c(n+1)
294: *
295: * Grabs 'numberOfSnapshots' snapshots. Grabs one snapshot per
296: * 'everyNthsnapshot'
297: *
298: * @param numberOfSnapshot
299: * @param everyNthSnapshot
300: * @return ArrayList
301: */
302: @RolesAllowed("mejbuser")
303: public ArrayList<HashMap<String, HashMap<String, Object>>> fetchSnapshotData(
304: Integer numberOfSnapshot, Integer everyNthSnapshot) {
305: return (ArrayList<HashMap<String, HashMap<String, Object>>>) snapshotDBHelper
306: .fetchData(numberOfSnapshot, everyNthSnapshot);
307: }
308:
309: /**
310: * Fetches the max amount for each statistic stored from the snapshot thread
311: * and returns it in a HashMap
312: *
313: * @param numberOfSnapshot
314: * @return HashMap
315: */
316: @RolesAllowed("mejbuser")
317: public HashMap<String, HashMap<String, Long>> fetchMaxSnapshotData(
318: Integer numberOfSnapshot) {
319: return (HashMap<String, HashMap<String, Long>>) snapshotDBHelper
320: .fetchMaxSnapshotData(numberOfSnapshot);
321: }
322:
323: /**
324: * Fetches the min amount for each statistic stored from the snapshot thread
325: * and returns it in a HashMap
326: *
327: * @param numberOfSnapshot
328: * @return HashMap
329: */
330: @RolesAllowed("mejbuser")
331: public HashMap<String, HashMap<String, Long>> fetchMinSnapshotData(
332: Integer numberOfSnapshot) {
333: return (HashMap<String, HashMap<String, Long>>) snapshotDBHelper
334: .fetchMinSnapshotData(numberOfSnapshot);
335: }
336:
337: /**
338: * Gets the elapsed time in milliseconds between each snapshot.
339: *
340: * @return Long
341: */
342: @RolesAllowed("mejbuser")
343: public Long getSnapshotDuration() {
344: // return what is stored in the snapshot-config.xml or default value
345: try {
346: String returnedDuration = SnapshotConfigXMLBuilder
347: .getAttributeValue(DURATION);
348: return Long.parseLong(returnedDuration);
349: } catch (Exception e) {
350: return DEFAULT_DURATION; // the default
351: }
352: }
353:
354: /**
355: * Sets the elapsed time in milliseconds between each snapshot.
356: * The duration will be read in each time the handleTimeout()
357: * is called. So the change will be seen when the next
358: * handleTimeout() is called.
359: *
360: * @param snapshotDuration
361: */
362: @RolesAllowed("mejbuser")
363: public void setSnapshotDuration(Long snapshotDuration) {
364: saveDuration(snapshotDuration);
365: }
366:
367: @RolesAllowed("mejbuser")
368: public void setSnapshotRetention(int retention) {
369: saveRetention(retention);
370: }
371:
372: @RolesAllowed("mejbuser")
373: public String getSnapshotRetention() {
374: try {
375: return SnapshotConfigXMLBuilder
376: .getAttributeValue(RETENTION);
377: } catch (Exception e) {
378: return "" + DEFAULT_RETENTION; // the default
379: }
380: }
381:
382: @RolesAllowed("mejbuser")
383: public Long getSnapshotCount() {
384: return snapshotDBHelper.getSnapshotCount();
385: }
386:
387: /**
388: * Fetches all mbean names that provide JSR-77 statistics
389: *
390: * @return A set containing all mbean names of mbeans that provide
391: * statistics
392: */
393: @RolesAllowed("mejbuser")
394: public Set<String> getStatisticsProviderMBeanNames() {
395: return MBeanHelper.getStatsProvidersMBeans(getAllMBeanNames());
396: }
397:
398: /**
399: * Fetches all mbean names
400: *
401: * @return A set containing all mbean names
402: */
403: @RolesAllowed("mejbuser")
404: public Set<String> getAllMBeanNames() {
405: try {
406: Set<ObjectName> names = (Set<ObjectName>) mejb.queryNames(
407: null, null);
408: Set<String> strNames = new HashSet<String>();
409: for (Iterator<ObjectName> it = names.iterator(); it
410: .hasNext();) {
411: strNames.add(it.next().getCanonicalName());
412: }
413: return strNames;
414: } catch (Exception e) {
415: log.error(e.getMessage(), e);
416: return new HashSet<String>();
417: }
418: }
419:
420: private void saveDuration(long duration) {
421: SnapshotConfigXMLBuilder.saveDuration(duration);
422: }
423:
424: private void saveRetention(int retention) {
425: SnapshotConfigXMLBuilder.saveRetention(retention);
426: }
427:
428: /**
429: * Adds a record of the mbean via its name to take snapshots of. As a result
430: * the mbeanName will be written to snapshot-config.xml
431: *
432: * @param mbeanName
433: */
434: @RolesAllowed("mejbuser")
435: public boolean addMBeanForSnapshot(String mbeanName) {
436: return SnapshotConfigXMLBuilder.addMBeanName(mbeanName);
437: }
438:
439: /**
440: * Removes a record of the mbean via its name to take snapshots of. As a result
441: * the mbeanName will be removed from snapshot-config.xml
442: *
443: * @param mbeanName
444: */
445: @RolesAllowed("mejbuser")
446: public boolean removeMBeanForSnapshot(String mbeanName) {
447: return SnapshotConfigXMLBuilder.removeMBeanName(mbeanName);
448: }
449:
450: /**
451: * @return A map: mbeanName --> ArrayList of statistic attributes for that mbean
452: */
453: @RolesAllowed("mejbuser")
454: public HashMap<String, ArrayList<String>> getAllSnapshotStatAttributes() {
455: HashMap<String, ArrayList<String>> snapshotAttributes = new HashMap<String, ArrayList<String>>();
456: Set<String> mbeans = getTrackedMBeans();
457: // for each mbean name
458: for (Iterator<String> it = mbeans.iterator(); it.hasNext();) {
459: ArrayList<String> mbeanStatsList = new ArrayList<String>();
460: String mbeanName = it.next();
461: try {
462: Stats stats = (Stats) mejb.getAttribute(new ObjectName(
463: mbeanName), "stats");
464: String[] sttsName = stats.getStatisticNames();
465: Statistic[] stts = stats.getStatistics();
466: for (int i = 0; i < sttsName.length; i++) {
467: Statistic aStat = stats.getStatistic(sttsName[i]);
468: if (aStat instanceof RangeStatistic) {
469: mbeanStatsList.add(stts[i].getName()
470: + " Current");
471: mbeanStatsList.add(stts[i].getName() + " Max");
472: mbeanStatsList.add(stts[i].getName() + " Min");
473: } else if (aStat instanceof CountStatistic) {
474: mbeanStatsList.add(stts[i].getName());
475: } else if (aStat instanceof TimeStatistic) {
476: mbeanStatsList
477: .add(stts[i].getName() + " Count");
478: mbeanStatsList.add(stts[i].getName()
479: + " MaxTime");
480: mbeanStatsList.add(stts[i].getName()
481: + " MinTime");
482: mbeanStatsList.add(stts[i].getName()
483: + " TotalTime");
484: } else {
485: // for the time being, only numbers should be returned
486: }
487: }
488: } catch (Exception e) {
489: log.error(e.getMessage(), e);
490: }
491: // save attributes to the returning list
492: snapshotAttributes.put(mbeanName, mbeanStatsList);
493: }
494: return snapshotAttributes;
495: }
496:
497: /**
498: * @return Returns true if snapshot is running.
499: */
500: @RolesAllowed("mejbuser")
501: public boolean isSnapshotRunning() {
502: Collection<Timer> timers = timer.getTimers();
503: // if there are timers there is something running to collect snapshots
504: if (timers.size() > 0) {
505: return true;
506: } else {
507: return false;
508: }
509: }
510:
511: /**
512: * @param name - object name of the mbean
513: * @param operationName - method within the class
514: * @param params - parameters for the method
515: * @param signature - types for the parameters
516: * @return Invokes the method of a class defined.
517: */
518: @RolesAllowed("mejbadmin")
519: public Object invoke(ObjectName name, String operationName,
520: Object[] params, String[] signature) throws Exception {
521: return mejb.invoke(name, operationName, params, signature);
522: }
523:
524: /**
525: * @param mbeanName
526: * @param statsName
527: * @param numberOfSnapshots
528: * @param everyNthSnapshot
529: * @return HashMap which maps from a snapshot_time --> value of the mbean.statsName at that time
530: */
531: @RolesAllowed("mejbuser")
532: public TreeMap<Long, Long> getSpecificStatistics(String mbeanName,
533: String statsName, int numberOfSnapshots,
534: int everyNthSnapshot, boolean showArchived) {
535: return snapshotDBHelper.getSpecificStatistics(mbeanName,
536: statsName, numberOfSnapshots, everyNthSnapshot,
537: showArchived);
538: }
539:
540: /**
541: * @return A set of all mbeans being tracked from the db
542: */
543: @RolesAllowed("mejbuser")
544: public Set<String> getTrackedMBeans() {
545: ArrayList<String> mbeans = (ArrayList<String>) SnapshotConfigXMLBuilder
546: .getMBeanNames();
547: Set<String> set = new HashSet<String>();
548: for (int i = 0; i < mbeans.size(); i++) {
549: set.add(mbeans.get(i));
550: }
551: return set;
552: }
553: }
|