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 package org.apache.servicemix.web.jmx;
018
019 import org.apache.commons.logging.Log;
020 import org.apache.commons.logging.LogFactory;
021
022 import javax.management.AttributeNotFoundException;
023 import javax.management.InstanceNotFoundException;
024 import javax.management.JMException;
025 import javax.management.MBeanAttributeInfo;
026 import javax.management.MBeanException;
027 import javax.management.MBeanInfo;
028 import javax.management.MBeanServer;
029 import javax.management.ObjectInstance;
030 import javax.management.ObjectName;
031 import javax.management.ReflectionException;
032
033 import java.io.IOException;
034 import java.io.PrintWriter;
035 import java.util.ArrayList;
036 import java.util.Collection;
037 import java.util.HashSet;
038 import java.util.Hashtable;
039 import java.util.Iterator;
040 import java.util.List;
041 import java.util.Map;
042 import java.util.Set;
043 import java.util.TreeMap;
044 import java.util.TreeSet;
045 import java.util.Map.Entry;
046
047 /**
048 * A useful class for turning JMX statistics into XML and XHTML
049 *
050 * @version $Revision: 356269 $
051 */
052 public class JMXWriter {
053 private static final Log log = LogFactory.getLog(JMXWriter.class);
054
055 private PrintWriter writer;
056 private ManagementContext managementContext;
057 private String unknownValue = "Unknown";
058
059 public JMXWriter(PrintWriter writer, ManagementContext context) {
060 this.writer = writer;
061 managementContext = context;
062 }
063
064 public MBeanServer getMBeanServer() {
065 return managementContext.getMBeanServer();
066 }
067
068 public ManagementContext getManagementContext() {
069 return managementContext;
070 }
071
072 public void setManagementContext(ManagementContext managementContext) {
073 this.managementContext = managementContext;
074 }
075
076 public void outputHtmlNamesByDomain(Collection names) throws IOException {
077 Map map = new TreeMap();
078 for (Iterator iter = names.iterator(); iter.hasNext();) {
079 ObjectName name = (ObjectName) iter.next();
080 String domain = name.getDomain();
081 List list = (List) map.get(domain);
082 if (list == null) {
083 list = new ArrayList();
084 map.put(domain, list);
085 }
086 list.add(name);
087 }
088 for (Iterator iter = map.entrySet().iterator(); iter.hasNext();) {
089 Map.Entry entry = (Map.Entry) iter.next();
090 String domain = (String) entry.getKey();
091 names = (List) entry.getValue();
092
093 writer.print("<li>");
094 writer.print(domain);
095
096 writer.print("<ul>");
097 outputHtmlNamesByProperty(names, "Type");
098 writer.print("</ul>");
099 writer.print("</li>");
100 }
101 }
102
103 public void outputHtmlNamesByProperty(Collection names, String property) throws IOException {
104 Map map = new TreeMap();
105 for (Iterator iter = names.iterator(); iter.hasNext();) {
106 ObjectName name = (ObjectName) iter.next();
107 String propertyValue = name.getKeyProperty(property);
108 if (propertyValue == null) {
109 propertyValue = unknownValue;
110 }
111 List list = (List) map.get(propertyValue);
112 if (list == null) {
113 list = new ArrayList();
114 map.put(propertyValue, list);
115 }
116 list.add(name);
117 }
118 for (Iterator iter = map.entrySet().iterator(); iter.hasNext();) {
119 Map.Entry entry = (Map.Entry) iter.next();
120 String propertyValue = (String) entry.getKey();
121 names = (List) entry.getValue();
122
123 if (names.size() > 1) {
124 writer.print("<li><a href='");
125 printDetailURL(property, propertyValue);
126 writer.print("'>");
127 writer.print(propertyValue);
128 writer.print("</a><ul>");
129
130 // outputHtmlNames(names);
131 outputHtmlNamesSortedByShortName(names);
132 writer.print("</ul>");
133 writer.print("</li>");
134 }
135 else if (names.size() == 1) {
136 ObjectName name = (ObjectName) ((List) names).get(0);
137 outputHtmlName(name, propertyValue);
138 }
139 }
140 }
141
142 public void outputHtmlNamesSortedByShortName(Collection names) throws IOException {
143 Map map = new TreeMap();
144 for (Iterator iter = names.iterator(); iter.hasNext();) {
145 ObjectName name = (ObjectName) iter.next();
146 String propertyValue = getShortName(name);
147 map.put(propertyValue, name);
148 }
149 for (Iterator iter = map.entrySet().iterator(); iter.hasNext();) {
150 Map.Entry entry = (Map.Entry) iter.next();
151 String description = (String) entry.getKey();
152 ObjectName name = (ObjectName) entry.getValue();
153 outputHtmlName(name, description);
154 }
155 }
156
157 public void outputHtmlNames(Collection names) throws IOException {
158 for (Iterator iter = names.iterator(); iter.hasNext();) {
159 outputHtmlNames((ObjectName) iter.next());
160 }
161 }
162
163 public void outputHtmlNames(ObjectName name) throws IOException {
164 outputHtmlName(name, getShortName(name));
165 }
166
167 public void outputHtmlName(ObjectName name, String shortName) throws IOException {
168 writer.print("<li><a href='");
169 printDetailURL(name);
170
171 /*
172 * Map properties = name.getKeyPropertyList(); for (Iterator iter =
173 * properties.entrySet().iterator(); iter.hasNext();) { Map.Entry entry =
174 * (Map.Entry) iter.next(); writer.print("<property name='");
175 * writer.print(entry.getKey()); writer.print("'>");
176 * writer.print(entry.getValue()); writer.println("</property>"); }
177 */
178
179 writer.print("'>");
180 // writer.print(name.getCanonicalKeyPropertyListString());
181 writer.print(shortName);
182 writer.print("</a></li>");
183 }
184
185 /**
186 * Returns a short descriptive name of the ObjectName without the domain
187 */
188 protected String getShortName(ObjectName name) {
189 // TODO Auto-generated method stub
190 String answer = name.toString();
191 int idx = answer.indexOf(':');
192 if (idx >= 0) {
193 return answer.substring(idx + 1);
194 }
195 return answer;
196 }
197
198 public void outputNames(Collection names) throws IOException {
199 for (Iterator iter = names.iterator(); iter.hasNext();) {
200 outputNames((ObjectName) iter.next());
201 }
202 }
203
204 public void outputNames(ObjectName name) throws IOException {
205 writer.print("<mbean name='");
206 writer.print(name.getCanonicalName());
207 writer.print("' domain='");
208 writer.print(name.getDomain());
209 writer.println("'>");
210 Map properties = name.getKeyPropertyList();
211 for (Iterator iter = properties.entrySet().iterator(); iter.hasNext();) {
212 Map.Entry entry = (Map.Entry) iter.next();
213 writer.print("<property name='");
214 writer.print(entry.getKey());
215 writer.print("'>");
216 writer.print(entry.getValue());
217 writer.println("</property>");
218 }
219 writer.println("</mbean>");
220 }
221
222 public void outputDetail(Set names) throws IOException, JMException {
223
224 for (Iterator iter = names.iterator(); iter.hasNext();) {
225 outputDetail((ObjectName) iter.next());
226 }
227 }
228
229 public void outputDetail(ObjectName name) throws JMException, IOException {
230
231 MBeanServer beanServer = getMBeanServer();
232 MBeanInfo beanInfo = beanServer.getMBeanInfo(name);
233 writer.print("<mbean name='");
234 writer.print(name.getCanonicalName());
235 writer.print("' domain='");
236 writer.print(name.getDomain());
237 writer.println("'>");
238
239 MBeanAttributeInfo[] attributes = beanInfo.getAttributes();
240 for (int i = 0; i < attributes.length; i++) {
241 MBeanAttributeInfo info = attributes[i];
242 if (info.isReadable()) {
243 String attributeName = info.getName();
244 Object value = getAttributeValue(name, attributeName);
245 if (value != null) {
246 writer.print("<attribute name='");
247 writer.print(attributeName);
248 writer.print("' type='");
249 writer.print(info.getType());
250 writer.print("'>");
251 printEncodedValue(value);
252 writer.println("</attribute>");
253 }
254 }
255 }
256
257 writer.println("</mbean>");
258 }
259
260 public void outputHtmlProperties(Set names) throws JMException, IOException {
261 if (names.size() <= 1) {
262 for (Iterator iter = names.iterator(); iter.hasNext();) {
263 outputHtmlProperties((ObjectName) iter.next());
264 }
265 }else {
266 outputHtmlPropertiesGrid(names);
267 }
268 }
269
270 public void outputHtmlPropertiesGrid(Set names) throws JMException {
271 Set propertyNames = new TreeSet();
272 Map[] propertyNamesPerMBeanArray = new Map[names.size()];
273 int beanCounter = 0;
274 for (Iterator iter = names.iterator(); iter.hasNext();) {
275 ObjectName name = (ObjectName) iter.next();
276 Hashtable keyMap = name.getKeyPropertyList();
277 propertyNamesPerMBeanArray[beanCounter++] = keyMap;
278 propertyNames.addAll(keyMap.keySet());
279 }
280
281 writer.println("<table>");
282 writer.println("<tr>");
283 writer.print("<th>Domain</th>");
284 for (Iterator iter = propertyNames.iterator(); iter.hasNext();) {
285 writer.print("<th>");
286 writer.print(iter.next());
287 writer.print("</th>");
288 }
289 writer.println();
290 writer.println("</tr>");
291
292 beanCounter = 0;
293 for (Iterator iter = names.iterator(); iter.hasNext();) {
294 ObjectName name = (ObjectName) iter.next();
295
296 writer.print("<tr><td class='domainName'>");
297 writer.print(name.getDomain());
298 writer.print("</td>");
299
300 for (Iterator iter2 = propertyNames.iterator(); iter2.hasNext();) {
301 String propertyName = (String) iter2.next();
302
303 if (propertyNamesPerMBeanArray[beanCounter].containsKey(propertyName)) {
304 String value = name.getKeyProperty(propertyName);
305 writer.print("<td class='");
306 writer.print(propertyName);
307 writer.print("'>");
308 if (value != null) {
309 printEncodedValue(value);
310 }
311 writer.print("</td>");
312 }
313 }
314 writer.print("</tr>");
315 beanCounter++;
316 }
317 writer.println("</table>");
318 }
319
320
321 public void outputHtmlProperties(ObjectName name) throws JMException, IOException {
322 writer.println("<table>");
323 writer.println("<tr>");
324 writer.println("<th>Property</th><th>Value</th>");
325 writer.println("</tr>");
326
327 writer.print("<tr><td>Domain</td><td>");
328 String domain = name.getDomain();
329 if (domain != null) {
330 printEncodedValue(domain);
331 }
332 writer.print("</td></tr>");
333
334 Map map = name.getKeyPropertyList();
335 for (Iterator iter = map.entrySet().iterator(); iter.hasNext();) {
336 Map.Entry entry = (Entry) iter.next();
337 String attributeName = (String) entry.getKey();
338 String value = (String) entry.getValue();
339
340 writer.print("<tr><td>");
341 writer.print(attributeName);
342 writer.print("</td><td>");
343 if (value != null) {
344 printEncodedValue(value);
345 }
346 writer.print("</td></tr>");
347 }
348
349 writer.println("</table>");
350 }
351
352 public void outputHtmlAttributes(Set names) throws IOException, JMException {
353 if (names.size() <= 1) {
354 for (Iterator iter = names.iterator(); iter.hasNext();) {
355 outputHtmlAttributes((ObjectName) iter.next());
356 }
357 }
358 else {
359 outputHtmlAttributeGrid(names);
360 }
361 }
362
363 public void outputHtmlAttributeGrid(Set names) throws JMException {
364 MBeanServer beanServer = getMBeanServer();
365 Set attributeNames = new TreeSet();
366 Set[] attributeNamesPerMBeanArray = new Set[names.size()];
367 int beanCounter = 0;
368 for (Iterator iter = names.iterator(); iter.hasNext();) {
369 ObjectName name = (ObjectName) iter.next();
370 MBeanInfo beanInfo = beanServer.getMBeanInfo(name);
371 MBeanAttributeInfo[] attributes = beanInfo.getAttributes();
372
373 Set availableNamesPerMBean = new HashSet();
374 attributeNamesPerMBeanArray[beanCounter++] = availableNamesPerMBean;
375 for (int i = 0; i < attributes.length; i++) {
376 MBeanAttributeInfo info = attributes[i];
377 if (info.isReadable()) {
378 String attributeName = info.getName();
379 availableNamesPerMBean.add(attributeName);
380 attributeNames.add(attributeName);
381 }
382 }
383 }
384
385 writer.println("<table>");
386 writer.println("<tr>");
387 writer.print("<th>MBean</th>");
388 for (Iterator iter = attributeNames.iterator(); iter.hasNext();) {
389 writer.print("<th>");
390 writer.print(iter.next());
391 writer.print("</th>");
392 }
393 writer.println();
394 writer.println("</tr>");
395
396 beanCounter = 0;
397 for (Iterator iter = names.iterator(); iter.hasNext();) {
398 ObjectName name = (ObjectName) iter.next();
399
400 writer.print("<tr><td class='mbeanName'>");
401 writer.print(name);
402 writer.print("</td>");
403
404 for (Iterator iter2 = attributeNames.iterator(); iter2.hasNext();) {
405 String attributeName = (String) iter2.next();
406
407 if (attributeNamesPerMBeanArray[beanCounter].contains(attributeName)) {
408 Object value = getAttributeValue(name, attributeName);
409 writer.print("<td class='");
410 writer.print(attributeName);
411 writer.print("'>");
412 if (value != null) {
413 printEncodedValue(value);
414 }
415 writer.print("</td>");
416 }
417 }
418 writer.print("</tr>");
419 beanCounter++;
420 }
421 writer.println("</table>");
422 }
423
424 public void outputHtmlAttributes(ObjectName name) throws JMException, IOException {
425 MBeanServer beanServer = getMBeanServer();
426 MBeanInfo beanInfo = beanServer.getMBeanInfo(name);
427 writer.println("<table>");
428 writer.println("<tr>");
429 writer.println("<th>Attribute</th><th>Value</th><th>Type</th>");
430 writer.println("</tr>");
431
432 MBeanAttributeInfo[] attributes = beanInfo.getAttributes();
433 for (int i = 0; i < attributes.length; i++) {
434 MBeanAttributeInfo info = attributes[i];
435 if (info.isReadable()) {
436 String attributeName = info.getName();
437
438 Object value = getAttributeValue(name, attributeName);
439 writer.print("<tr><td>");
440 writer.print(attributeName);
441 writer.print("</td><td>");
442 if (value != null) {
443 printEncodedValue(value);
444 }
445 writer.print("</td><td>");
446 writer.print(info.getType());
447 writer.print("</td></tr>");
448 }
449 }
450
451 writer.println("</table>");
452 }
453
454 public void outputMBeans(Collection names) throws IOException {
455 for (Iterator iter = names.iterator(); iter.hasNext();) {
456 outputMBeans((ObjectName) iter.next());
457 }
458 }
459
460 public void outputMBeans(ObjectName name) throws IOException {
461 Map properties = name.getKeyPropertyList();
462 for (Iterator iter = properties.entrySet().iterator(); iter.hasNext();) {
463 Map.Entry entry = (Map.Entry) iter.next();
464 writer.print("<mbean name='");
465 writer.print(entry.getKey());
466 ObjectInstance objectInstance = (ObjectInstance) entry.getValue();
467 if (objectInstance != null) {
468 writer.print("' className='");
469 writer.print(objectInstance.getClassName());
470 }
471 writer.println("'/>");
472 }
473 }
474
475 public void outputHeader() throws IOException {
476 writer.println("<?xml version='1.0'?>");
477 writer.println("<mbeans>");
478 }
479
480 public void outputFooter() throws IOException {
481 writer.println("</mbeans>");
482 }
483
484 /**
485 * Encodes the value as a String and ensures that there are no bad XML
486 * characters like < or > which are encoded.
487 */
488 public void printEncodedValue(Object value) {
489 if (value != null) {
490 String text = value.toString();
491 for (int i = 0, size = text.length(); i < size; i++) {
492 char ch = text.charAt(i);
493 switch (ch) {
494 case '<':
495 writer.print("<");
496 break;
497
498 case '>':
499 writer.print(">");
500 break;
501
502 case '&':
503 writer.print("&");
504 break;
505
506 // used in ObjectName
507 case ',':
508 writer.print("%2C");
509 break;
510
511 case ':':
512 writer.print("%3A");
513 break;
514
515 case '=':
516 writer.print("%3D");
517 break;
518
519 default:
520 writer.print(ch);
521 }
522 }
523 }
524 }
525
526 /**
527 * Prints a HTTP encoded ObjectName suitable for use inside URLs
528 */
529 public void printEncodedObjectName(ObjectName name) {
530 printEncodedValue(name);
531 }
532
533 /**
534 * Outputs a URL to the detail JMX stats view
535 */
536 protected void printDetailURL(ObjectName name) {
537 writer.print("mbeanDetail.jsp?view=detail&style=html&name=");
538 printEncodedObjectName(name);
539 }
540
541 /**
542 * Outputs a URL to the detail JMX stats view
543 */
544 protected void printDetailURL(String propertyName, String propertyValue) {
545 writer.print("mbeanDetail.jsp?view=detail&style=html&query=");
546 printEncodedValue("*:" + propertyName + "=" + propertyValue + ",*");
547 }
548
549 protected Object getAttributeValue(ObjectName name, String attributeName) throws MBeanException {
550 MBeanServer beanServer = getMBeanServer();
551 Object value = null;
552 try {
553 value = beanServer.getAttribute(name, attributeName);
554 }
555 catch (AttributeNotFoundException e) {
556 log.warn("Caught: " + e, e);
557 }
558 catch (InstanceNotFoundException e) {
559 log.warn("Caught: " + e, e);
560 }
561 catch (ReflectionException e) {
562 log.warn("Caught: " + e, e);
563 }
564 return value;
565 }
566
567 }