001package org.javasimon.jmx; 002 003import org.javasimon.Manager; 004import org.javasimon.SimonException; 005import org.javasimon.SimonManager; 006import org.slf4j.Logger; 007import org.slf4j.LoggerFactory; 008 009import java.lang.management.ManagementFactory; 010 011import javax.management.JMException; 012import javax.management.MBeanServer; 013import javax.management.ObjectName; 014 015/** 016 * Utility class for registering JMX beans that can be used to access Simon manager and Simons. 017 * JmxReporter is created by either {@link org.javasimon.jmx.JmxReporter#forManager(org.javasimon.Manager)} 018 * or {@link JmxReporter#forDefaultManager()}. Additional configuration methods can be called using fluent 019 * API (). 020 * Finally {@link JmxReporter#start()} will set up all expected MX beans and system is ready for monitoring 021 * through JMX. Method {@link JmxReporter#stop()} unregisters all related MX beans when monitoring is no 022 * longer required. 023 * 024 * @author <a href="mailto:ivan.mushketyk@gmail.com">Ivan Mushketyk</a> 025 * @author <a href="mailto:virgo47@gmail.com">Richard "Virgo" Richter</a> 026 */ 027public final class JmxReporter { 028 029 public static final String DEFAULT_BEAN_NAME = "org.javasimon.jmx.JmxReporter:type=Simon"; 030 public static final String DEFAULT_SIMON_DOMAIN = "org.javasimon.jmx.simons"; 031 032 private static final Logger logger = LoggerFactory.getLogger(JmxReporter.class); 033 034 /** Simon manager that will be accessed through registered JMX bean */ 035 private final Manager manager; 036 037 /** JMX bean server used by JmxReporter */ 038 private MBeanServer beanServer; 039 040 /** Name of a new JMX bean for Simon manager */ 041 private String beanName; 042 043 /** Should already registered bean with the specified name be replaced. */ 044 private boolean replaceExistingMxBeans; 045 046 /** Should JMX beans for separate Simons be registered. */ 047 private boolean registerSimons; 048 049 /** 050 * Should JMX beans for already existing Simons be registered ({@link #registerSimons} must be true 051 * for this to have effect). 052 */ 053 private boolean registerExistingSimons; 054 055 /** Domain of JMX beans for separate Simons. */ 056 private String simonDomain; 057 058 private JmxRegisterCallback jmxRegisterCallback; 059 060 private JmxReporter(Manager manager) { 061 if (manager == null) { 062 throw new IllegalArgumentException("Manager is null"); 063 } 064 065 this.manager = manager; 066 } 067 068 /** 069 * Creates new JmxReporter for the specified manager with default values. 070 * 071 * @param manager manager that will be used by JmxReporter 072 * @return new JmxReporter 073 */ 074 static public JmxReporter forManager(Manager manager) { 075 JmxReporter reporter = new JmxReporter(manager); 076 077 reporter.setBeanName(DEFAULT_BEAN_NAME); 078 reporter.simonDomain = DEFAULT_SIMON_DOMAIN; 079 reporter.beanServer = ManagementFactory.getPlatformMBeanServer(); 080 081 return reporter; 082 } 083 084 /** 085 * Creates new JmxReporter for the default manager with default values. 086 * 087 * @return new JmxReporter 088 */ 089 public static JmxReporter forDefaultManager() { 090 return forManager(SimonManager.manager()); 091 } 092 093 094 /** 095 * Specify domain for registered JMX for separate Simons. Is used only if {@link #registerSimons} set to true. 096 * 097 * @param simonDomain domain for separate JMX beans for separate Simons 098 * @return this 099 */ 100 public JmxReporter simonDomain(String simonDomain) { 101 setSimonDomain(simonDomain); 102 return this; 103 } 104 105 /** 106 * Specifies that previously registered bean with the same name should be replaced. 107 * 108 * @return this 109 */ 110 public JmxReporter replaceExisting() { 111 replaceExistingMxBeans = true; 112 return this; 113 } 114 115 /** 116 * Specifies that separate JMX beans should be registered for each Simon in current manager. 117 * 118 * @return this 119 */ 120 public JmxReporter registerSimons() { 121 registerSimons = true; 122 return this; 123 } 124 125 public JmxReporter registerExistingSimons() { 126 this.registerExistingSimons = true; 127 return this; 128 } 129 130 /** 131 * Bean name that will be used to register JMX bean for Simon manager. 132 * 133 * @param beanName bean name that will be used to register JMX bean for Simon manager 134 * @return this 135 */ 136 public JmxReporter beanName(String beanName) { 137 setBeanName(beanName); 138 return this; 139 } 140 141 JmxReporter beanServer(MBeanServer beanServer) { 142 setBeanServer(beanServer); 143 return this; 144 } 145 146 private void setBeanName(String beanName) { 147 if (beanName == null || beanName.isEmpty()) { 148 throw new IllegalArgumentException("Bean name is null or empty"); 149 } 150 151 this.beanName = beanName; 152 } 153 154 public Manager getManager() { 155 return manager; 156 } 157 158 public MBeanServer getBeanServer() { 159 return beanServer; 160 } 161 162 public void setBeanServer(MBeanServer beanServer) { 163 this.beanServer = beanServer; 164 } 165 166 public String getBeanName() { 167 return beanName; 168 } 169 170 public String getSimonDomain() { 171 return simonDomain; 172 } 173 174 public void setSimonDomain(String simonDomain) { 175 if (simonDomain == null || simonDomain.isEmpty()) { 176 throw new IllegalArgumentException("Simon domain is null or empty"); 177 } 178 this.simonDomain = simonDomain; 179 } 180 181 public boolean isReplaceExistingMxBeans() { 182 return replaceExistingMxBeans; 183 } 184 185 public void setReplaceExistingMxBeans(boolean replaceExistingMxBeans) { 186 this.replaceExistingMxBeans = replaceExistingMxBeans; 187 } 188 189 public boolean isRegisterSimons() { 190 return registerSimons; 191 } 192 193 public void setRegisterSimons(boolean registerSimons) { 194 this.registerSimons = registerSimons; 195 } 196 197 public boolean isRegisterExistingSimons() { 198 return registerExistingSimons; 199 } 200 201 public void setRegisterExistingSimons(boolean registerExistingSimons) { 202 this.registerExistingSimons = registerExistingSimons; 203 } 204 205 /** Starts JmxReporter - registers all required beans in JMX bean server. */ 206 public JmxReporter start() { 207 SimonManagerMXBean simonManagerMXBean = new SimonManagerMXBeanImpl(manager); 208 registerMXBean(simonManagerMXBean, beanName); 209 210 if (registerSimons) { 211 jmxRegisterCallback = new JmxRegisterCallback(beanServer, simonDomain); 212 if (registerExistingSimons) { 213 jmxRegisterCallback.setRegisterExisting(true); 214 } 215 manager.callback().addCallback(jmxRegisterCallback); 216 } 217 return this; 218 } 219 220 private void registerMXBean(Object bean, String newBeanName) { 221 try { 222 ObjectName beanObjectName = new ObjectName(newBeanName); 223 if (replaceExistingMxBeans && beanServer.isRegistered(beanObjectName)) { 224 logger.warn("Replacing existing SimonManager JMX bean"); 225 beanServer.unregisterMBean(beanObjectName); 226 } 227 228 logger.info("Registering new SimonManager JMX bean with name {}", newBeanName); 229 beanServer.registerMBean(bean, beanObjectName); 230 } catch (JMException e) { 231 throw new SimonException("Failed to register Jmx reporter", e); 232 } 233 } 234 235 /** Stop JMX reporter. Unregister all previously registered beans. */ 236 public void stop() { 237 unregisterManagerBean(); 238 unregisterSimonBeans(); 239 } 240 241 private void unregisterManagerBean() { 242 try { 243 ObjectName beanObjectName = new ObjectName(beanName); 244 if (beanServer.isRegistered(beanObjectName)) { 245 beanServer.unregisterMBean(beanObjectName); 246 } else { 247 logger.warn("SimonManager JMX bean with name {} was not registered", beanName); 248 } 249 } catch (JMException e) { 250 throw new SimonException("Failed to unregister SimonManager MX bean", e); 251 } 252 } 253 254 private void unregisterSimonBeans() { 255 if (jmxRegisterCallback != null) { 256 manager.callback().removeCallback(jmxRegisterCallback); 257 } 258 } 259}