001/* 002 * Copyright 2011 Atteo. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 005 * in compliance with the License. You may obtain a copy of the License at 006 * 007 * http://www.apache.org/licenses/LICENSE-2.0 008 * 009 * Unless required by applicable law or agreed to in writing, software distributed under the License 010 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 011 * or implied. See the License for the specific language governing permissions and limitations under 012 * the License. 013 */ 014package org.atteo.moonshine.jmx; 015 016import java.lang.management.ManagementFactory; 017import java.util.ArrayList; 018import java.util.List; 019 020import javax.inject.Inject; 021import javax.inject.Singleton; 022import javax.management.InstanceAlreadyExistsException; 023import javax.management.InstanceNotFoundException; 024import javax.management.MBeanRegistrationException; 025import javax.management.MBeanServer; 026import javax.management.MalformedObjectNameException; 027import javax.management.NotCompliantMBeanException; 028import javax.management.ObjectInstance; 029import javax.management.ObjectName; 030import javax.xml.bind.annotation.XmlRootElement; 031 032import org.atteo.classindex.ClassIndex; 033import org.atteo.moonshine.TopLevelService; 034 035import com.google.inject.AbstractModule; 036import com.google.inject.Injector; 037import com.google.inject.Module; 038 039/** 040 * Jmx helper service. 041 * 042 * <p> 043 * Starts MBean server and automatically registers any class annotated with @{@link MBean}. 044 * </p> 045 */ 046@XmlRootElement(name = "jmx") 047public class Jmx extends TopLevelService { 048 @Override 049 public Module configure() { 050 return new AbstractModule() { 051 @Override 052 protected void configure() { 053 bind(MBeanServer.class).toInstance(ManagementFactory.getPlatformMBeanServer()); 054 055 for (Class<?> klass : ClassIndex.getAnnotated(MBean.class)) { 056 bind(klass).in(Singleton.class); 057 } 058 } 059 }; 060 } 061 062 @Inject 063 private Injector injector; 064 065 @Inject 066 private MBeanServer server; 067 068 private List<ObjectName> registeredNames = new ArrayList<>(); 069 070 @Override 071 public void start() { 072 try { 073 for (Class<?> klass : ClassIndex.getAnnotated(MBean.class)) { 074 Object instance = injector.getInstance(klass); 075 ObjectName name; 076 MBean annotation = klass.getAnnotation(MBean.class); 077 if (annotation != null && !"".equals(annotation.name())) { 078 name = ObjectName.getInstance(annotation.name()); 079 } else { 080 name = ObjectName.getInstance(klass.getPackage().getName() + ":type=" 081 + klass.getSimpleName()); 082 } 083 ObjectInstance mbeanInstance = server.registerMBean(instance, name); 084 registeredNames.add(mbeanInstance.getObjectName()); 085 } 086 } catch (MalformedObjectNameException | InstanceAlreadyExistsException | MBeanRegistrationException 087 | NotCompliantMBeanException e) { 088 throw new RuntimeException(e); 089 } 090 } 091 092 @Override 093 public void close() { 094 for (ObjectName name : registeredNames) { 095 try { 096 server.unregisterMBean(name); 097 } catch (InstanceNotFoundException e) { 098 // not found? ignore 099 continue; 100 } catch (MBeanRegistrationException e) { 101 throw new RuntimeException(e); 102 } 103 } 104 } 105}