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 }