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 */
017
018 package org.apache.geronimo.console.jmxmanager;
019
020 import java.net.URI;
021 import java.net.URL;
022 import java.text.DateFormat;
023 import java.util.ArrayList;
024 import java.util.Arrays;
025 import java.util.Collection;
026 import java.util.Collections;
027 import java.util.Date;
028 import java.util.HashMap;
029 import java.util.Iterator;
030 import java.util.Map;
031 import java.util.Set;
032 import java.util.TreeMap;
033
034 import javax.management.ObjectName;
035 import javax.management.j2ee.statistics.BoundaryStatistic;
036 import javax.management.j2ee.statistics.BoundedRangeStatistic;
037 import javax.management.j2ee.statistics.CountStatistic;
038 import javax.management.j2ee.statistics.RangeStatistic;
039 import javax.management.j2ee.statistics.Statistic;
040 import javax.management.j2ee.statistics.Stats;
041 import javax.management.j2ee.statistics.TimeStatistic;
042
043 import org.apache.geronimo.console.util.TimeUtils;
044 import org.apache.geronimo.gbean.AbstractName;
045 import org.apache.geronimo.gbean.AbstractNameQuery;
046 import org.apache.geronimo.gbean.GAttributeInfo;
047 import org.apache.geronimo.gbean.GBeanInfo;
048 import org.apache.geronimo.gbean.GOperationInfo;
049 import org.apache.geronimo.j2ee.j2eeobjectnames.NameFactory;
050 import org.apache.geronimo.kernel.GBeanNotFoundException;
051 import org.apache.geronimo.kernel.Kernel;
052 import org.apache.geronimo.kernel.KernelRegistry;
053 import org.directwebremoting.annotations.RemoteMethod;
054 import org.directwebremoting.annotations.RemoteProxy;
055
056 /**
057 * The JMX manager helper
058 */
059 @RemoteProxy(name="JMXHelper")
060 public class JMXManagerHelper {
061 /** Used to return all MBeans */
062 private static final String ALL_MBEANS = "AllMBeans";
063 private static final String SERVICEMODULE_KEY = "ServiceModule";
064 private static final String GBEANINFO_ATTRIB = "GBeanInfo";
065 private static final String STATSPROVIDER_ATTRIB = "statisticsProvider";
066 private static final String STATS_ATTRIB = "stats";
067
068
069 private final Kernel kernel;
070
071 /**
072 * Construct an JMX manager helper (default)
073 */
074 public JMXManagerHelper() {
075 kernel = KernelRegistry.getSingleKernel();
076 }
077
078 /**
079 * List MBeans using a domain
080 */
081 public Collection listByDomain(String domain) {
082 Collection result = new ArrayList();
083 if ((domain == null) || (domain.trim().length() == 0)) {
084 return result;
085 }
086
087 return listByPattern(domain + ":*");
088 }
089
090 /**
091 * List MBeans containing a substring in its object name
092 */
093 @RemoteMethod
094 public Collection listBySubstring(String substring) {
095 Collection result = new ArrayList();
096 if ((substring == null) || (substring.trim().length() == 0)) {
097 return result;
098 }
099
100 Collection abstractNames = getAbstractNames(substring);
101 for (Iterator it = abstractNames.iterator(); it.hasNext();) {
102 AbstractName aname = (AbstractName) it.next();
103 ObjectName oname = aname.getObjectName();
104 String[] pair = { aname.toString(), oname.toString() };
105 result.add(pair);
106 }
107
108 return result;
109 }
110
111 /**
112 * List MBeans using a pattern (ObjectName)
113 */
114 @RemoteMethod
115 public Collection listByPattern(String pattern) {
116 Collection result = new ArrayList();
117 if ((pattern == null) || (pattern.trim().length() == 0)) {
118 return result;
119 }
120
121 try {
122 // TODO: Use AbstractNameQuery
123 // Uses Object names for query pattern to support
124 // domain searches. Can't find a way to do it using
125 // AbstractNameQuery.
126 Map abstractNames = getAbstractNames();
127 ObjectName onamePattern = new ObjectName(pattern);
128 Set beans = kernel.listGBeans(onamePattern);
129 for (Iterator it = beans.iterator(); it.hasNext();) {
130 ObjectName oname = (ObjectName) it.next();
131 AbstractName aname = (AbstractName) abstractNames.get(oname);
132 String[] pair = { aname.toString(), oname.toString() };
133 result.add(pair);
134 }
135 } catch (Exception e) {
136 // Malformed object name, just return what you have
137 }
138
139 return result;
140 }
141
142 /**
143 * List MBeans using J2EE type
144 */
145 @RemoteMethod
146 public Collection listByJ2EEType(String type) {
147 Collection result = new ArrayList();
148 Map m = null;
149
150 if ((type == null) || (type.trim().length() == 0)) {
151 return result;
152 } else {
153 if (ALL_MBEANS.equalsIgnoreCase(type)) {
154 m = Collections.EMPTY_MAP;
155 } else {
156 m = Collections.singletonMap(NameFactory.J2EE_TYPE, type);
157 }
158 }
159
160 AbstractNameQuery query = new AbstractNameQuery(null, m,
161 Collections.EMPTY_SET);
162 Set beans = kernel.listGBeans(query);
163 for (Iterator it = beans.iterator(); it.hasNext();) {
164 AbstractName abstractName = (AbstractName) it.next();
165 ObjectName objectName = abstractName.getObjectName();
166 String[] pair = { abstractName.toString(), objectName.toString() };
167 result.add(pair);
168 }
169
170 return result;
171 }
172
173 /**
174 * Return all service modules
175 */
176 public Collection getServiceModules() {
177 Map svcModules = new TreeMap();
178 Collection svcModuleMBeans = getAbstractNames(SERVICEMODULE_KEY + '=');
179 for (Iterator it = svcModuleMBeans.iterator(); it.hasNext();) {
180 AbstractName aname = (AbstractName) it.next();
181 String svcModule = aname.getNameProperty(SERVICEMODULE_KEY);
182 if (!svcModules.containsKey(svcModule)) {
183 svcModules.put(svcModule, null);
184 }
185 }
186
187 return svcModules.keySet();
188 }
189
190 /**
191 * Return abstract names containing a substring
192 */
193 private Collection getAbstractNames(String substring) {
194 Collection result = new ArrayList();
195 if ((substring == null) || (substring.trim().length() == 0)) {
196 return result;
197 }
198
199 Map abstractNames = getAbstractNames();
200 for (Iterator it = abstractNames.keySet().iterator(); it.hasNext();) {
201 ObjectName oname = (ObjectName) it.next();
202 if (oname.toString().indexOf(substring) > 0) {
203 AbstractName aname = (AbstractName) abstractNames.get(oname);
204 result.add(aname);
205 }
206 }
207
208 return result;
209 }
210
211 /**
212 * Return all abstract names as a map
213 */
214 private Map getAbstractNames() {
215 Map abstractNames = new HashMap();
216 // Create Map (Key = ObjectName, Value = AbstractName)
217 AbstractNameQuery query = new AbstractNameQuery(null,
218 Collections.EMPTY_MAP, Collections.EMPTY_SET);
219 Set allBeans = kernel.listGBeans(query);
220 for (Iterator it = allBeans.iterator(); it.hasNext();) {
221 AbstractName abstractName = (AbstractName) it.next();
222 ObjectName objectName = abstractName.getObjectName();
223 abstractNames.put(objectName, abstractName);
224 }
225
226 return abstractNames;
227 }
228
229 /**
230 * Return MBean attributes
231 */
232 @RemoteMethod
233 public Collection getAttributes(String abstractName) {
234 Map attributes = new TreeMap();
235 try {
236 AbstractName aname = new AbstractName(URI.create(abstractName));
237 GBeanInfo info = kernel.getGBeanInfo(aname);
238 Set attribs = info.getAttributes();
239 for (Iterator i = attribs.iterator(); i.hasNext();) {
240 GAttributeInfo attribInfo = (GAttributeInfo) i.next();
241 // Don't include 'GBeanInfo' attributes
242 String attribName = attribInfo.getName();
243 if (!GBEANINFO_ATTRIB.equals(attribName)) {
244 Map attribInfoMap = getAttribInfoAsMap(aname, attribInfo);
245 attributes.put(attribName, attribInfoMap);
246 }
247 }
248 } catch (GBeanNotFoundException e) {
249 // GBean not found, just ignore
250 }
251
252 return attributes.values();
253 }
254
255 /**
256 * Return attribute info as map
257 */
258 private Map getAttribInfoAsMap(AbstractName abstractName,
259 GAttributeInfo attribInfo) {
260 Map map = new TreeMap();
261 String attribName = attribInfo.getName();
262 map.put("name", attribName);
263 map.put("getterName", attribInfo.getGetterName());
264 map.put("setterName", attribInfo.getSetterName());
265 map.put("type", attribInfo.getType());
266 map.put("manageable", String.valueOf(attribInfo.isManageable()));
267 map.put("persistent", String.valueOf(attribInfo.isPersistent()));
268 map.put("readable", String.valueOf(attribInfo.isReadable()));
269 map.put("writable", String.valueOf(attribInfo.isWritable()));
270 if (attribInfo.isReadable()) {
271 String attribValue = "";
272 try {
273 Object value = kernel.getAttribute(abstractName, attribName);
274 if (value != null) {
275 if (value instanceof String[]) {
276 attribValue = Arrays.asList((String[]) value)
277 .toString();
278 } else {
279 attribValue = value.toString();
280 }
281 }
282 } catch (Exception e) {
283 // GBean or attribute not found, just ignore
284 attribValue = "** EXCEPTION: " + e;
285 }
286 map.put("value", attribValue);
287 }
288 return map;
289 }
290
291 /**
292 * Return MBean operations
293 */
294 @RemoteMethod
295 public Collection getOperations(String abstractName) {
296 Map operations = new TreeMap();
297 try {
298 AbstractName aname = new AbstractName(URI.create(abstractName));
299 GBeanInfo info = kernel.getGBeanInfo(aname);
300 Set opers = info.getOperations();
301 for (Iterator i = opers.iterator(); i.hasNext();) {
302 GOperationInfo operInfo = (GOperationInfo) i.next();
303 Map operInfoMap = getOperInfoAsMap(operInfo);
304 String operName = (String) operInfoMap.get("name");
305 operations.put(operName, operInfoMap);
306 }
307 } catch (Exception e) {
308 // GBean not found, just ignore
309 }
310
311 return operations.values();
312 }
313
314 /**
315 * Return operation info as map
316 */
317 private Map getOperInfoAsMap(GOperationInfo operInfo) {
318 Map map = new TreeMap();
319 map.put("methodName", operInfo.getMethodName());
320 map.put("name", operInfo.getName());
321 map.put("parameterList", operInfo.getParameterList());
322 return map;
323 }
324
325 /**
326 * Return MBean basic info
327 */
328 @RemoteMethod
329 public Collection getMBeanInfo(String abstractName) {
330 Collection info = new ArrayList();
331 try {
332 AbstractName aname = new AbstractName(URI.create(abstractName));
333 info.add(new String[] { "abstractName", aname.toString() });
334 ObjectName oname = aname.getObjectName();
335 info.add(new String[] { "objectName", oname.toString() });
336 GBeanInfo beanInfo = kernel.getGBeanInfo(aname);
337 String className = beanInfo.getClassName();
338 info.add(new String[] { "className", className });
339 String domain = oname.getDomain();
340 info.add(new String[] { "domain", domain });
341 String j2eeType = beanInfo.getJ2eeType();
342 info.add(new String[] { "j2eeType", j2eeType });
343 // String sourceClass = beanInfo.getSourceClass();
344 // info.add(new String[] { "sourceClass", sourceClass });
345 } catch (Exception e) {
346 // GBean not found, just ignore
347 }
348
349 return info;
350 }
351
352 /**
353 * Return all MBeans that provide stats
354 */
355 @RemoteMethod
356 public Collection getStatsProvidersMBeans() {
357 Collection result = new ArrayList();
358
359 Object[] allMBeans = listByPattern("*:*").toArray();
360 for (int i = 0; i < allMBeans.length; i++) {
361 try {
362 String[] mbean = (String[]) allMBeans[i];
363 AbstractName abstractName = new AbstractName(URI
364 .create(mbean[0]));
365 Boolean statisticsProvider = (Boolean) kernel.getAttribute(
366 abstractName, "statisticsProvider");
367 if (Boolean.TRUE.equals(statisticsProvider)) {
368 result.add(mbean);
369 }
370 } catch (Exception e) {
371 // ignore
372 }
373 }
374
375 return result;
376 }
377
378 /**
379 * Return MBean stats
380 */
381 @RemoteMethod
382 public Collection getMBeanStats(String abstractName) {
383 Map mbeanStats = new TreeMap();
384 try {
385 AbstractName aname = new AbstractName(URI.create(abstractName));
386 Boolean statisticsProvider = (Boolean) kernel.getAttribute(aname,
387 STATSPROVIDER_ATTRIB);
388 Stats stats = (Stats) kernel.getAttribute(aname, STATS_ATTRIB);
389 if (statisticsProvider.booleanValue() == true && (stats != null)) {
390 String[] statisticNames = stats.getStatisticNames();
391 for (int i = 0; i < statisticNames.length; i++) {
392 Statistic statistic = stats.getStatistic(statisticNames[i]);
393
394 Collection mbeanStat = new ArrayList();
395 String name = statistic.getName();
396 mbeanStat.add(new String[] { "Name", name });
397 String className = statistic.getClass().getName();
398 // mbeanStat.add(new String[] { "Type", className });
399 mbeanStat.add(new String[] { "Description",
400 statistic.getDescription() });
401 mbeanStat.add(new String[] { "Unit", statistic.getUnit() });
402 Date startTime = new Date(statistic.getStartTime());
403 mbeanStat.add(new String[] { "Start Time",
404 startTime.toString() });
405 Date lastSampleTime = new Date(statistic
406 .getLastSampleTime());
407 mbeanStat.add(new String[] { "Last Sample Time",
408 lastSampleTime.toString() });
409
410 if (statistic instanceof CountStatistic) {
411 CountStatistic cStat = (CountStatistic) statistic;
412 long count = cStat.getCount();
413 mbeanStat.add(new String[] { "Count",
414 Long.toString(count) });
415 } else if (statistic instanceof TimeStatistic) {
416 TimeStatistic tStat = (TimeStatistic) statistic;
417 long count = tStat.getCount();
418 mbeanStat.add(new String[] { "Count",
419 Long.toString(count) });
420 String maxTime = TimeUtils.formatDuration(tStat.getMaxTime());
421 mbeanStat.add(new String[] { "Max Time",
422 maxTime });
423 String minTime = TimeUtils.formatDuration(tStat.getMinTime());
424 mbeanStat.add(new String[] { "Min Time",
425 minTime });
426 long totalTime = tStat.getTotalTime();
427 mbeanStat.add(new String[] { "Total Time",
428 Long.toString(totalTime) });
429 } else if (statistic instanceof BoundedRangeStatistic) {
430 BoundedRangeStatistic brStat = (BoundedRangeStatistic) statistic;
431 long upperBound = brStat.getUpperBound();
432 mbeanStat.add(new String[] { "Upper Bound",
433 Long.toString(upperBound) });
434 long lowerBound = brStat.getLowerBound();
435 mbeanStat.add(new String[] { "Lower Bound",
436 Long.toString(lowerBound) });
437 long highWaterMark = brStat.getHighWaterMark();
438 mbeanStat.add(new String[] { "High Water Mark",
439 Long.toString(highWaterMark) });
440 long lowWaterMark = brStat.getLowWaterMark();
441 mbeanStat.add(new String[] { "Low Water Mark",
442 Long.toString(lowWaterMark) });
443 long current = brStat.getCurrent();
444 mbeanStat.add(new String[] { "Current",
445 Long.toString(current) });
446 } else if (statistic instanceof BoundaryStatistic) {
447 BoundaryStatistic bStat = (BoundaryStatistic) statistic;
448 long upperBound = bStat.getUpperBound();
449 mbeanStat.add(new String[] { "Upper Bound",
450 Long.toString(upperBound) });
451 long lowerBound = bStat.getLowerBound();
452 mbeanStat.add(new String[] { "Lower Bound",
453 Long.toString(lowerBound) });
454 } else if (statistic instanceof RangeStatistic) {
455 RangeStatistic rStat = (RangeStatistic) statistic;
456 long highWaterMark = rStat.getHighWaterMark();
457 mbeanStat.add(new String[] { "High Water Mark",
458 Long.toString(highWaterMark) });
459 long lowWaterMark = rStat.getLowWaterMark();
460 mbeanStat.add(new String[] { "Low Water Mark",
461 Long.toString(lowWaterMark) });
462 long current = rStat.getCurrent();
463 mbeanStat.add(new String[] { "Current",
464 Long.toString(current) });
465 }
466
467 mbeanStats.put(name, mbeanStat);
468 }
469 }
470 } catch (Exception e) {
471 // GBean not found, just ignore
472 }
473
474 return mbeanStats.values();
475 }
476
477 /**
478 * Invoke MBean operation with arguments
479 */
480 @RemoteMethod
481 public String[] invokeOperWithArgs(String abstractName, String methodName,
482 String[] args, String[] types) {
483 String[] result = new String[2]; // return method name & result
484 result[0] = methodName + "(...)";
485
486 try {
487 Object[] newArgs = processOperArgs(args, types);
488 AbstractName aname = new AbstractName(URI.create(abstractName));
489 Object res = kernel.invoke(aname, methodName, newArgs, types);
490 if (res != null) {
491 result[1] = res.toString();
492 } else {
493 result[1] = "<null>";
494 }
495 } catch (Exception e) {
496 result[1] = e.toString();
497 }
498
499 return result;
500 }
501
502 /**
503 * Invoke MBean operation without arguments
504 */
505 @RemoteMethod
506 public String[] invokeOperNoArgs(String abstractName, String methodName) {
507 String[] result = new String[2]; // return method name & result
508 result[0] = methodName + "()";
509
510 try {
511 AbstractName aname = new AbstractName(URI.create(abstractName));
512 Object res = kernel.invoke(aname, methodName);
513 if (res != null) {
514 result[1] = res.toString();
515 } else {
516 result[1] = "<null>";
517 }
518 } catch (Exception e) {
519 result[1] = e.toString();
520 }
521
522 return result;
523 }
524
525 /**
526 * Process MBean operation arguments
527 */
528 private Object[] processOperArgs(String[] args, String[] types)
529 throws Exception {
530 // TODO: Modify this algorithm and add other classes
531 Object[] newArgs = new Object[args.length];
532 for (int i = 0; i < args.length; i++) {
533 String type = types[i];
534 String arg = args[i];
535 newArgs[i] = createObject(arg, type);
536 }
537
538 return newArgs;
539 }
540
541 /**
542 * Create MBean operation argument
543 */
544 private Object createObject(String arg, String type) throws Exception {
545 Object newArg = new Object();
546 if ("byte".equals(type) || "java.lang.Byte".equals(type)) {
547 newArg = new Byte(arg);
548 } else if ("short".equals(type) || "java.lang.Short".equals(type)) {
549 newArg = new Short(arg);
550 } else if ("int".equals(type) || "java.lang.Integer".equals(type)) {
551 newArg = new Integer(arg);
552 } else if ("long".equals(type) || "java.lang.Long".equals(type)) {
553 newArg = new Long(arg);
554 } else if ("float".equals(type) || "java.lang.Float".equals(type)) {
555 newArg = new Float(arg);
556 } else if ("double".equals(type) || "java.lang.Double".equals(type)) {
557 newArg = new Double(arg);
558 } else if ("char".equals(type) || "java.lang.Character".equals(type)) {
559 newArg = new Character(arg.charAt(0));
560 } else if ("boolean".equals(type) || "java.lang.Boolean".equals(type)) {
561 newArg = new Boolean(arg);
562 } else if ("java.lang.String".equals(type)) {
563 newArg = arg;
564 } else if ("java.lang.Object".equals(type)) {
565 newArg = arg;
566 } else if ("java.util.Date".equals(type)) {
567 newArg = DateFormat.getInstance().parse(arg);
568 } else if ("java.net.URL".equals(type)) {
569 newArg = new URL(arg);
570 } else if ("java.net.URI".equals(type)) {
571 newArg = new URI(arg);
572 } else if ("javax.management.ObjectName".equals(type)) {
573 newArg = new ObjectName(arg);
574 } else if ("org.apache.geronimo.gbean.AbstractName".equals(type)) {
575 newArg = new AbstractName(URI.create(arg));
576 } else {
577 // Unknown type, throw exception
578 String errorMsg = "Can't create instance of '" + type + "' using '"
579 + arg + "'.";
580 throw new IllegalArgumentException(errorMsg);
581 }
582
583 return newArg;
584 }
585
586 /**
587 * Set MBean attribute value
588 */
589 public String[] setAttribute(String abstractName, String attribName,
590 String attribValue, String attribType) {
591 String[] result = new String[2]; // return attribute name & result
592 result[0] = attribName;
593 result[1] = "<SUCCESS>";
594
595 try {
596 AbstractName aname = new AbstractName(URI.create(abstractName));
597 Object newAttribValue = createObject(attribValue, attribType);
598 kernel.setAttribute(aname, attribName, newAttribValue);
599 } catch (Exception e) {
600 result[1] = e.toString();
601 }
602
603 return result;
604 }
605
606 }