package org.safehaus.penrose.management; import org.apache.log4j.Logger; import org.safehaus.penrose.util.ClassUtil; import javax.management.*; import javax.security.auth.Subject; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.security.AccessController; import java.security.Principal; import java.util.*; /** * @author Endi Sukma Dewata */ public abstract class BaseService implements DynamicMBean { public Logger log = Logger.getLogger(getClass()); protected PenroseJMXService jmxService; protected String description; protected Collection<String> classNames = new HashSet<String>(); protected Collection<String> attributes = new TreeSet<String>(); protected Map<String,Method> getters = new TreeMap<String,Method>(); protected Map<String,Method> setters = new TreeMap<String,Method>(); protected Map<String,Method> operations = new TreeMap<String,Method>(); public BaseService() { } public void init() throws Exception { jmxService.register(getObjectName(), this); } public void destroy() throws Exception { jmxService.unregister(getObjectName()); } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } public String getBindDn() { Subject subject = Subject.getSubject(AccessController.getContext()); if (subject == null) return null; Collection<Principal> principals = subject.getPrincipals(); if (principals.isEmpty()) return null; Principal principal = principals.iterator().next(); return principal.getName(); } public PenroseJMXService getJmxService() { return jmxService; } public void setJmxService(PenroseJMXService jmxService) { this.jmxService = jmxService; } public abstract String getObjectName(); public abstract Object getObject(); public Object getAttribute(String name) throws AttributeNotFoundException, MBeanException, ReflectionException { boolean info = log.isInfoEnabled(); if (info) log.info("Getting attribute "+name+" from "+getObjectName()+"."); try { Class[] paramClass = new Class[0]; Class clazz = getClass(); try { Method method = clazz.getMethod("get"+name, paramClass); return method.invoke(this); } catch (NoSuchMethodException e) { // ignore } try { Method method = clazz.getMethod("is"+name, paramClass); return method.invoke(this); } catch (NoSuchMethodException e) { // ignore } Object object = getObject(); if (object == null) throw new Exception(getObjectName()+" is unavailable."); Class objectClass = object.getClass(); try { Method method = objectClass.getMethod("get"+name, paramClass); return method.invoke(object); } catch (NoSuchMethodException e) { // ignore } try { Method method = objectClass.getMethod("is"+name, paramClass); return method.invoke(object); } catch (NoSuchMethodException e) { // ignore } throw new AttributeNotFoundException(); } catch (IllegalAccessException e) { throw new ReflectionException(e); } catch (InvocationTargetException e) { Exception cause = (Exception)e.getCause(); log.error(cause.getMessage(), cause); throw new MBeanException(cause); } catch (Exception e) { log.error(e.getMessage(), e); throw new MBeanException(e); } finally { if (info) log.info("Get attribute completed."); } } public void setAttribute(Attribute attribute) throws AttributeNotFoundException, InvalidAttributeValueException, MBeanException, ReflectionException { boolean info = log.isInfoEnabled(); String name = attribute.getName(); Object value = attribute.getValue(); if (info) log.info("Setting attribute "+name+" in "+getObjectName()+"."); try { Class[] paramClass = new Class[] { value.getClass() }; Class clazz = getClass(); try { Method method = clazz.getMethod("set"+name, paramClass); method.invoke(this, value); return; } catch (NoSuchMethodException e) { // ignore } Object object = getObject(); Class objectClass = object.getClass(); try { Method method = objectClass.getMethod("set"+name, paramClass); method.invoke(object, value); return; } catch (NoSuchMethodException e) { // ignore } throw new AttributeNotFoundException(); } catch (IllegalAccessException e) { throw new ReflectionException(e); } catch (InvocationTargetException e) { Exception cause = (Exception)e.getCause(); log.error(cause.getMessage(), cause); throw new MBeanException(cause); } finally { if (info) log.info("Set attribute "+name+" in "+getObjectName()+" completed."); } } public AttributeList getAttributes(String[] attributes) { AttributeList list = new AttributeList(); for (String attributeName : attributes) { try { Object value = getAttribute(attributeName); list.add(new Attribute(attributeName, value)); } catch (Exception e) { log.error(e.getMessage(), e); } } return list; } public AttributeList setAttributes(AttributeList attributes) { AttributeList list = new AttributeList(); for (Object object : attributes) { try { Attribute attribute = (Attribute) object; setAttribute(attribute); list.add(attribute); } catch (Exception e) { log.error(e.getMessage(), e); } } return list; } public Object invoke(String operation, Object[] paramValues, String[] paramTypes) throws MBeanException, ReflectionException { boolean debug = log.isDebugEnabled(); boolean info = log.isInfoEnabled(); String signature = ClassUtil.getSignature(operation, paramTypes); if (info) log.info("Invoking method "+signature+" in "+getObjectName()+"."); try { Class[] paramClass = new Class[paramTypes.length]; for (int i = 0; i<paramTypes.length; i++) { String paramType = paramTypes[i]; paramClass[i] = Class.forName(paramType); } Class clazz = getClass(); try { Method method = clazz.getMethod(operation, paramClass); return method.invoke(this, paramValues); } catch (NoSuchMethodException e) { // if (debug) log.debug("No such method in "+clazz.getName()+"."); // ignore } Object object = getObject(); Class objectClass = object.getClass(); try { if (info) log.info("Invoking method in class "+objectClass.getSimpleName()); Method method = objectClass.getMethod(operation, paramClass); return method.invoke(object, paramValues); } catch (NoSuchMethodException e) { if (debug) log.debug("No such method in "+objectClass.getName()+"."); // ignore } throw new NoSuchMethodException("No such method: "+signature); } catch (ClassNotFoundException e) { throw new ReflectionException(e); } catch (NoSuchMethodException e) { throw new ReflectionException(e); } catch (IllegalAccessException e) { throw new ReflectionException(e); } catch (InvocationTargetException e) { Exception cause = (Exception)e.getCause(); //log.error(cause.getMessage(), cause); throw new MBeanException(cause); } finally { if (info) log.info("Invoke method completed."); } } public MBeanInfo getMBeanInfo() { Collection<MBeanAttributeInfo> attributeInfos = new LinkedHashSet<MBeanAttributeInfo>(); Collection<MBeanOperationInfo> operationInfos = new ArrayList<MBeanOperationInfo>(); Object object = getObject(); Class objectClass = object == null ? getClass() : object.getClass(); try { if (object != null) register(object.getClass()); } catch (Exception e) { log.error(e.getMessage(), e); } try { register(getClass()); } catch (Exception e) { log.error(e.getMessage(), e); } try { //log.debug("Attributes:"); for (String attributeName : attributes) { //log.debug(" - "+attributeName); Method getter = getters.get(attributeName); Method setter = setters.get(attributeName); attributeInfos.add(new MBeanAttributeInfo(attributeName, attributeName, getter, setter)); } //log.debug("Methods:"); for (Method method : operations.values()) { //log.debug(" - "+method.getName()); operationInfos.add(new MBeanOperationInfo(method.getName(), method)); } } catch (Exception e) { log.error(e.getMessage(), e); } return new MBeanInfo( objectClass.getName(), description, attributeInfos.toArray(new MBeanAttributeInfo[attributeInfos.size()]), null, operationInfos.toArray(new MBeanOperationInfo[operationInfos.size()]), null ); } public void register( Class clazz ) throws Exception { String className = clazz.getName(); if (classNames.contains(className)) return; Class superClass = clazz.getSuperclass(); if (superClass != null) register(superClass); //if (debug) log.debug(" - Class "+className+":"); classNames.add(className); /* for (Method method : clazz.getMethods()) { register(method); } */ for (Class interfaceClass : clazz.getInterfaces()) { String interfaceName = interfaceClass.getName(); if (interfaceName.equals("javax.management.DynamicMBean")) continue; if (!interfaceName.endsWith("MBean")) continue; //if (debug) log.debug(" - Interface "+className+":"); for (Method method : interfaceClass.getMethods()) { register(method); } } } public void register( Method method ) throws Exception { String methodName = method.getName(); //if (debug) log.debug(" - Method "+methodName+":"); if (methodName.length() > 3 && methodName.startsWith("get") && Character.isUpperCase(methodName.charAt(3)) && method.getParameterTypes().length == 0) { String attributeName = methodName.substring(3); attributes.add(attributeName); getters.put(attributeName, method); } else if (methodName.length() > 2 && methodName.startsWith("is") && Character.isUpperCase(methodName.charAt(2)) && method.getParameterTypes().length == 0) { String attributeName = methodName.substring(2); attributes.add(attributeName); getters.put(attributeName, method); } else if (methodName.length() > 3 && methodName.startsWith("set") && Character.isUpperCase(methodName.charAt(3)) && method.getParameterTypes().length == 1) { String attributeName = methodName.substring(3); attributes.add(attributeName); setters.put(attributeName, method); } else { String signature = ClassUtil.getSignature(method); operations.put(signature, method); } } }