1/**
2 * Copyright (C) 2006 Google Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.google.inject.tools.jmx;
18
19import com.google.inject.Binding;
20import com.google.inject.Guice;
21import com.google.inject.Injector;
22import com.google.inject.Key;
23import com.google.inject.Module;
24
25import java.lang.annotation.Annotation;
26import java.lang.management.ManagementFactory;
27
28import javax.management.MBeanServer;
29import javax.management.MalformedObjectNameException;
30import javax.management.ObjectName;
31
32/**
33 * Provides a JMX interface to Guice.
34 *
35 * @author crazybob@google.com (Bob Lee)
36 */
37public class Manager {
38
39  /**
40   * Registers all the bindings of an Injector with the platform MBean server.
41   * Consider using the name of your root {@link Module} class as the domain.
42   */
43  public static void manage(
44      String domain,
45      Injector injector) {
46    manage(ManagementFactory.getPlatformMBeanServer(), domain, injector);
47  }
48
49  /**
50   * Registers all the bindings of an Injector with the given MBean server.
51   * Consider using the name of your root {@link Module} class as the domain.
52   */
53  public static void manage(MBeanServer server, String domain,
54      Injector injector) {
55    // Register each binding independently.
56    for (Binding<?> binding : injector.getBindings().values()) {
57      // Construct the name manually so we can ensure proper ordering of the
58      // key/value pairs.
59      StringBuilder name = new StringBuilder();
60      name.append(domain).append(":");
61      Key<?> key = binding.getKey();
62      name.append("type=").append(quote(key.getTypeLiteral().toString()));
63      Annotation annotation = key.getAnnotation();
64      if (annotation != null) {
65        name.append(",annotation=").append(quote(annotation.toString()));
66      }
67      else {
68        Class<? extends Annotation> annotationType = key.getAnnotationType();
69        if (annotationType != null) {
70          name.append(",annotation=")
71              .append(quote("@" + annotationType.getName()));
72        }
73      }
74
75      try {
76        server.registerMBean(new ManagedBinding(binding),
77            new ObjectName(name.toString()));
78      }
79      catch (MalformedObjectNameException e) {
80        throw new RuntimeException("Bad object name: " + name, e);
81      }
82      catch (Exception e) {
83        throw new RuntimeException(e);
84      }
85    }
86  }
87
88  static String quote(String value) {
89    // JMX seems to have a comma bug.
90    return ObjectName.quote(value).replace(',', ';');
91  }
92
93  /**
94   * Run with no arguments for usage instructions.
95   */
96  public static void main(String[] args) throws Exception {
97    if (args.length != 1) {
98      System.err.println("Usage: java -Dcom.sun.management.jmxremote "
99          + Manager.class.getName() + " [module class name]");
100      System.err.println("Then run 'jconsole' to connect.");
101      System.exit(1);
102    }
103
104    Module module = (Module) Class.forName(args[0]).newInstance();
105    Injector injector = Guice.createInjector(module);
106
107    manage(args[0], injector);
108
109    System.out.println("Press Ctrl+C to exit...");
110
111    // Sleep forever.
112    Thread.sleep(Long.MAX_VALUE);
113  }
114}
115