001: /*
002: * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved
003: *
004: * This file is part of Resin(R) Open Source
005: *
006: * Each copy or derived work must preserve the copyright notice and this
007: * notice unmodified.
008: *
009: * Resin Open Source is free software; you can redistribute it and/or modify
010: * it under the terms of the GNU General Public License as published by
011: * the Free Software Foundation; either version 2 of the License, or
012: * (at your option) any later version.
013: *
014: * Resin Open Source is distributed in the hope that it will be useful,
015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
017: * of NON-INFRINGEMENT. See the GNU General Public License for more
018: * details.
019: *
020: * You should have received a copy of the GNU General Public License
021: * along with Resin Open Source; if not, write to the
022: *
023: * Free Software Foundation, Inc.
024: * 59 Temple Place, Suite 330
025: * Boston, MA 02111-1307 USA
026: *
027: * @author Scott Ferguson
028: */
029:
030: package com.caucho.jmx;
031:
032: import com.caucho.log.Log;
033: import com.caucho.util.Alarm;
034: import com.caucho.util.CharBuffer;
035: import com.caucho.util.L10N;
036:
037: import javax.management.*;
038: import java.lang.reflect.Method;
039: import java.util.ArrayList;
040: import java.util.Iterator;
041: import java.util.LinkedHashMap;
042: import java.util.Map;
043: import java.util.Set;
044: import java.util.TimerTask;
045: import java.util.logging.Level;
046: import java.util.logging.Logger;
047: import java.util.regex.*;
048:
049: /**
050: * Static convenience methods.
051: */
052: public class Jmx {
053: private static final L10N L = new L10N(Jmx.class);
054: private static final Logger log = Log.open(Jmx.class);
055:
056: private static EnvironmentMBeanServer _mbeanServer;
057: private static MBeanServer _globalMBeanServer;
058:
059: /**
060: * Sets the server.
061: */
062: static void setMBeanServer(EnvironmentMBeanServer server) {
063: _mbeanServer = server;
064: }
065:
066: /**
067: * Returns the context mbean server.
068: */
069: public static MBeanServer getContextMBeanServer() {
070: if (_mbeanServer == null)
071: _mbeanServer = (EnvironmentMBeanServer) EnvironmentMBeanServerBuilder
072: .getGlobal("resin");
073:
074: return _mbeanServer;
075: }
076:
077: /**
078: * Returns the global mbean server.
079: */
080: public static MBeanServer getGlobalMBeanServer() {
081: if (_globalMBeanServer == null) {
082: getContextMBeanServer();
083:
084: ClassLoader systemLoader = ClassLoader
085: .getSystemClassLoader();
086: _globalMBeanServer = new GlobalMBeanServer(systemLoader);
087: }
088:
089: return _globalMBeanServer;
090: }
091:
092: /**
093: * Gets the static mbean server.
094: */
095: public static AbstractMBeanServer getMBeanServer() {
096: return _mbeanServer;
097: }
098:
099: /**
100: * Returns a copy of the context properties.
101: */
102: public static LinkedHashMap<String, String> copyContextProperties() {
103: AbstractMBeanServer mbeanServer = getMBeanServer();
104:
105: if (mbeanServer != null)
106: return mbeanServer.createContext().copyProperties();
107: else
108: return new LinkedHashMap<String, String>();
109: }
110:
111: /**
112: * Returns a copy of the context properties.
113: */
114: public static LinkedHashMap<String, String> copyContextProperties(
115: ClassLoader loader) {
116: AbstractMBeanServer mbeanServer = getMBeanServer();
117:
118: if (mbeanServer != null)
119: return mbeanServer.createContext(loader).copyProperties();
120: else
121: return new LinkedHashMap<String, String>();
122: }
123:
124: /**
125: * Sets the context properties.
126: */
127: public static void setContextProperties(
128: Map<String, String> properties) {
129: AbstractMBeanServer mbeanServer = getMBeanServer();
130:
131: if (mbeanServer != null)
132: mbeanServer.createContext().setProperties(properties);
133: }
134:
135: /**
136: * Sets the context properties.
137: */
138: public static void setContextProperties(
139: Map<String, String> properties, ClassLoader loader) {
140: AbstractMBeanServer mbeanServer = getMBeanServer();
141:
142: if (mbeanServer != null)
143: mbeanServer.createContext(loader).setProperties(properties);
144: }
145:
146: /**
147: * Conditionally registers an MBean with the server.
148: *
149: * @param object the object to be registered as an MBean
150: * @param name the name of the mbean.
151: *
152: * @return the instantiated object.
153: */
154: public static ObjectInstance register(Object object, String name)
155: throws InstanceAlreadyExistsException,
156: MBeanRegistrationException, MalformedObjectNameException,
157: NotCompliantMBeanException {
158: if (name.indexOf(':') < 0) {
159: Map<String, String> props = parseProperties(name);
160:
161: if (props.get("type") == null) {
162: String type = object.getClass().getName();
163: int p = type.lastIndexOf('.');
164: if (p > 0)
165: type = type.substring(p + 1);
166:
167: props.put("type", type);
168: }
169:
170: ObjectName objectName = getObjectName("resin", props);
171:
172: return register(object, objectName);
173: } else
174: return register(object, new ObjectName(name));
175:
176: }
177:
178: /**
179: * Conditionally registers an MBean with the server.
180: *
181: * @param object the object to be registered as an MBean
182: * @param name the name of the mbean.
183: *
184: * @return the instantiated object.
185: */
186: public static ObjectInstance register(Object object,
187: Map<String, String> properties)
188: throws InstanceAlreadyExistsException,
189: MBeanRegistrationException, MalformedObjectNameException,
190: NotCompliantMBeanException {
191: Map<String, String> props = copyContextProperties();
192: props.putAll(properties);
193:
194: return register(object, getObjectName("resin", props));
195: }
196:
197: /**
198: * Registers an MBean with the server.
199: *
200: * @param object the object to be registered as an MBean
201: * @param name the name of the mbean.
202: *
203: * @return the instantiated object.
204: */
205: public static ObjectInstance register(Object object, ObjectName name)
206: throws InstanceAlreadyExistsException,
207: MBeanRegistrationException, NotCompliantMBeanException {
208: return getMBeanServer().registerMBean(
209: createMBean(object, name), name);
210: }
211:
212: /**
213: * Registers an MBean with the server.
214: *
215: * @param object the object to be registered as an MBean
216: * @param name the name of the mbean.
217: *
218: * @return the instantiated object.
219: */
220: public static ObjectInstance register(Object object,
221: ObjectName name, ClassLoader loader)
222: throws InstanceAlreadyExistsException,
223: MBeanRegistrationException, NotCompliantMBeanException {
224: Thread thread = Thread.currentThread();
225: ClassLoader oldLoader = thread.getContextClassLoader();
226:
227: try {
228: thread.setContextClassLoader(loader);
229:
230: AbstractMBeanServer mbeanServer = getMBeanServer();
231:
232: if (mbeanServer != null)
233: return mbeanServer.registerMBean(createMBean(object,
234: name), name);
235: else
236: return null;
237: } finally {
238: thread.setContextClassLoader(oldLoader);
239: }
240: }
241:
242: /**
243: * Creates the dynamic mbean.
244: */
245: private static DynamicMBean createMBean(Object obj, ObjectName name)
246: throws NotCompliantMBeanException {
247: if (obj == null)
248: throw new NotCompliantMBeanException(L.l(
249: "{0} mbean is null", name));
250: else if (obj instanceof DynamicMBean)
251: return (DynamicMBean) obj;
252:
253: Class ifc = getMBeanInterface(obj.getClass());
254:
255: if (ifc == null)
256: throw new NotCompliantMBeanException(L.l(
257: "{0} mbean has no MBean interface", name));
258:
259: return new IntrospectionMBean(obj, ifc);
260: }
261:
262: /**
263: * Returns the mbean interface.
264: */
265: private static Class getMBeanInterface(Class cl) {
266: for (; cl != null; cl = cl.getSuperclass()) {
267: Class[] interfaces = cl.getInterfaces();
268:
269: for (int i = 0; i < interfaces.length; i++) {
270: Class ifc = interfaces[i];
271:
272: if (ifc.getName().endsWith("MBean")
273: || ifc.getName().endsWith("MXBean"))
274: return ifc;
275: }
276: }
277:
278: return null;
279: }
280:
281: /**
282: * Unregisters an MBean with the server.
283: *
284: * @param name the name of the mbean.
285: */
286: public static void unregister(ObjectName name)
287: throws MBeanRegistrationException,
288: InstanceNotFoundException {
289: getMBeanServer().unregisterMBean(name);
290: }
291:
292: /**
293: * Unregisters an MBean with the server.
294: *
295: * @param name the name of the mbean.
296: */
297: public static void unregister(ObjectName name, ClassLoader loader)
298: throws MBeanRegistrationException,
299: InstanceNotFoundException {
300: Thread thread = Thread.currentThread();
301: ClassLoader oldLoader = thread.getContextClassLoader();
302:
303: try {
304: thread.setContextClassLoader(loader);
305:
306: getMBeanServer().unregisterMBean(name);
307: } finally {
308: thread.setContextClassLoader(oldLoader);
309: }
310: }
311:
312: /**
313: * Registers an MBean with the server.
314: *
315: * @param object the object to be registered as an MBean
316: * @param name the name of the mbean.
317: * @param api the api for the server
318: *
319: * @return the instantiated object.
320: */
321: public static ObjectInstance register(Object object, String name,
322: Class api) throws InstanceAlreadyExistsException,
323: MBeanRegistrationException, MalformedObjectNameException,
324: NotCompliantMBeanException {
325: return register(object, new ObjectName(name), api);
326: }
327:
328: /**
329: * Registers an MBean with the server.
330: *
331: * @param object the object to be registered as an MBean
332: * @param name the name of the mbean.
333: * @param api the api for the server
334: *
335: * @return the instantiated object.
336: */
337: public static ObjectInstance register(Object object,
338: ObjectName name, Class api)
339: throws InstanceAlreadyExistsException,
340: MBeanRegistrationException, MalformedObjectNameException,
341: NotCompliantMBeanException {
342: IntrospectionMBean mbean = new IntrospectionMBean(object, api);
343:
344: return getMBeanServer().registerMBean(mbean, name);
345: }
346:
347: /**
348: * Conditionally registers an MBean with the server.
349: *
350: * @param object the object to be registered as an MBean
351: * @param name the name of the mbean.
352: *
353: * @return the instantiated object.
354: */
355: public static void unregister(String name)
356: throws InstanceNotFoundException,
357: MalformedObjectNameException, MBeanRegistrationException
358:
359: {
360: ObjectName objectName = getObjectName(name);
361:
362: getMBeanServer().unregisterMBean(objectName);
363: // return register(object, objectName);
364: }
365:
366: /**
367: * Returns an ObjectName based on a short name.
368: */
369: public static ObjectName getObjectName(String name)
370: throws MalformedObjectNameException {
371: return getMBeanServer().createContext().getObjectName(name);
372: }
373:
374: /**
375: * Parses a name.
376: */
377: public static LinkedHashMap<String, String> parseProperties(
378: String name) {
379: LinkedHashMap<String, String> map = new LinkedHashMap<String, String>();
380:
381: parseProperties(map, name);
382:
383: return map;
384: }
385:
386: /**
387: * Parses a name.
388: */
389: public static void parseProperties(Map<String, String> properties,
390: String name) {
391: parseProperties(properties, name, 0);
392: }
393:
394: /**
395: * Parses a name.
396: */
397: private static void parseProperties(Map<String, String> properties,
398: String name, int i) {
399: CharBuffer cb = CharBuffer.allocate();
400:
401: int len = name.length();
402:
403: while (i < len) {
404: for (; i < len && Character.isWhitespace(name.charAt(i)); i++) {
405: }
406:
407: cb.clear();
408:
409: int ch;
410: for (; i < len && (ch = name.charAt(i)) != '=' && ch != ','
411: && !Character.isWhitespace((char) ch); i++) {
412: cb.append((char) ch);
413: }
414:
415: String key = cb.toString();
416:
417: if (key.length() == 0) {
418: throw new IllegalArgumentException(L.l(
419: "`{0}' is an illegal name syntax.", name));
420: }
421:
422: for (; i < len && Character.isWhitespace(name.charAt(i)); i++) {
423: }
424:
425: if (len <= i || (ch = name.charAt(i)) == ',') {
426: properties.put(key, "");
427: } else if (ch == '=') {
428: for (i++; i < len
429: && Character.isWhitespace(name.charAt(i)); i++) {
430: }
431:
432: if (len <= i || (ch = name.charAt(i)) == ',') {
433: properties.put(key, "");
434: } else if (ch == '"' || ch == '\'') {
435: int end = ch;
436: cb.clear();
437:
438: for (i++; i < len && (ch = name.charAt(i)) != end; i++) {
439: if (ch == '\\') {
440: ch = name.charAt(++i);
441: cb.append((char) ch);
442: } else
443: cb.append((char) ch);
444: }
445:
446: if (ch != end)
447: throw new IllegalArgumentException(L.l(
448: "`{0}' is an illegal name syntax.",
449: name));
450:
451: i++;
452:
453: String value = cb.toString();
454:
455: properties.put(key, value);
456: } else {
457: cb.clear();
458:
459: for (; i < len && (ch = name.charAt(i)) != ','; i++)
460: cb.append((char) ch);
461:
462: properties.put(key, cb.toString());
463: }
464: } else {
465: throw new IllegalArgumentException(L.l(
466: "`{0}' is an illegal name syntax.", name));
467: }
468:
469: for (; i < len && Character.isWhitespace(name.charAt(i)); i++) {
470: }
471:
472: if (i < len && name.charAt(i) != ',')
473: throw new IllegalArgumentException(L.l(
474: "`{0}' is an illegal name syntax.", name));
475:
476: i++;
477: }
478: }
479:
480: /**
481: * Creates the clean name
482: */
483: public static ObjectName getObjectName(String domain,
484: Map<String, String> properties)
485: throws MalformedObjectNameException {
486: StringBuilder cb = new StringBuilder();
487: cb.append(domain);
488: cb.append(':');
489:
490: boolean isFirst = true;
491:
492: Pattern escapePattern = Pattern.compile("[,=:\"*?]");
493:
494: // sort type first
495:
496: String type = properties.get("type");
497: if (type != null) {
498: cb.append("type=");
499: if (escapePattern.matcher(type).find())
500: type = ObjectName.quote(type);
501: cb.append(type);
502:
503: isFirst = false;
504: }
505:
506: for (String key : properties.keySet()) {
507: if (key.equals("type"))
508: continue;
509:
510: if (!isFirst)
511: cb.append(',');
512: isFirst = false;
513:
514: cb.append(key);
515: cb.append('=');
516:
517: String value = properties.get(key);
518:
519: if (value.length() == 0
520: || (escapePattern.matcher(value).find() && !(value
521: .startsWith("\"") && value.endsWith("\"")))) {
522: value = ObjectName.quote(value);
523: }
524:
525: cb.append(value);
526: }
527:
528: return new ObjectName(cb.toString());
529: }
530:
531: /**
532: * Returns the local view.
533: */
534: /*
535: public static MBeanView getLocalView()
536: {
537: MBeanContext context = MBeanContext.getLocal();
538:
539: return context.getView();
540: }
541: */
542:
543: /**
544: * Returns the local view.
545: */
546: /*
547: public static MBeanView getLocalView(ClassLoader loader)
548: {
549: MBeanContext context = MBeanContext.getLocal(loader);
550:
551: return context.getView();
552: }
553: */
554:
555: /**
556: * Returns the local manged object.
557: */
558: public static Object find(String localName)
559: throws MalformedObjectNameException {
560: return find(getMBeanServer().createContext().getObjectName(
561: localName));
562: }
563:
564: /**
565: * Returns the local manged object.
566: */
567: public static Object find(ObjectName name) {
568: return find(name, Thread.currentThread()
569: .getContextClassLoader());
570: }
571:
572: /**
573: * Returns the local manged object.
574: */
575: public static Object findGlobal(String localName)
576: throws MalformedObjectNameException {
577: return findGlobal(getMBeanServer().createContext()
578: .getObjectName(localName));
579: }
580:
581: /**
582: * Returns the local manged object.
583: */
584: public static Object findGlobal(ObjectName name) {
585: return find(name, ClassLoader.getSystemClassLoader(),
586: getGlobalMBeanServer());
587: }
588:
589: /**
590: * Returns the local manged object.
591: */
592: public static Object find(ObjectName name, ClassLoader loader) {
593: return find(name, loader, getMBeanServer());
594: }
595:
596: /**
597: * Returns the local manged object.
598: */
599: public static Object find(ObjectName name, ClassLoader loader,
600: MBeanServer mbeanServer) {
601: try {
602: ObjectInstance obj = mbeanServer.getObjectInstance(name);
603:
604: if (obj == null)
605: return null;
606:
607: String className = obj.getClassName();
608:
609: Class cl = Class.forName(className, false, loader);
610:
611: Class ifc;
612:
613: if (cl.isInterface())
614: ifc = cl;
615: else
616: ifc = getMBeanInterface(cl);
617:
618: if (ifc == null)
619: return null;
620:
621: boolean isBroadcast = true;
622:
623: Object proxy;
624:
625: proxy = JmxInvocationHandler.newProxyInstance(mbeanServer,
626: loader, name, ifc, true);
627:
628: return proxy;
629: } catch (InstanceNotFoundException e) {
630: log.log(Level.FINE, e.toString(), e);
631: return null;
632: } catch (ClassNotFoundException e) {
633: log.log(Level.FINE, e.toString(), e);
634: return null;
635: }
636: }
637:
638: /**
639: * Returns the local manged object.
640: */
641: public static ArrayList<Object> query(ObjectName namePattern) {
642: Set<ObjectName> names = getMBeanServer().queryNames(
643: namePattern, null);
644:
645: ArrayList<Object> proxy = new ArrayList<Object>();
646: Iterator<ObjectName> iter = names.iterator();
647:
648: while (iter.hasNext()) {
649: ObjectName name = iter.next();
650:
651: proxy.add(find(name));
652: }
653:
654: return proxy;
655: }
656:
657: /**
658: * Queues a task.
659: */
660: public static void queueAbsolute(TimerTask job, long time) {
661: JobThread.queue(job, time);
662: }
663:
664: /**
665: * Queues a task.
666: */
667: public static void queueRelative(TimerTask job, long delta) {
668: queueAbsolute(job, Alarm.getCurrentTime() + delta);
669: }
670:
671: /**
672: * Dequeues a task.
673: */
674: public static void dequeue(TimerTask job) {
675: JobThread.dequeue(job);
676: }
677:
678: // static
679: public Jmx() {
680: }
681:
682: private static void initStaticMBeans() {
683: try {
684: Class cl = Class
685: .forName("java.lang.Management.ManagementFactory");
686:
687: Method method = cl.getMethod("getPlatformMBeanServer",
688: new Class[0]);
689:
690: method.invoke(null, new Object[0]);
691: } catch (Throwable e) {
692: }
693: }
694: }
|