package org.oddjob.jmx; import java.io.IOException; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import javax.management.MBeanServerConnection; import org.oddjob.Structural; import org.oddjob.arooa.registry.BeanDirectory; import org.oddjob.arooa.registry.BeanDirectoryOwner; import org.oddjob.jmx.general.DomainNode; import org.oddjob.jmx.general.MBeanDirectory; import org.oddjob.jmx.general.SimpleDomainNode; import org.oddjob.jmx.general.SimpleMBeanSession; import org.oddjob.script.InvokeJob; import org.oddjob.structural.ChildHelper; import org.oddjob.structural.StructuralListener; /** * @oddjob.description Expose a JMX Server so that Oddjob jobs * can interact with it. * <p> * Features of this service include: * <ul> * <li>Attributes of MBeans can be read and changed.</li> * <li>Operations on MBeans can be invoked.</li> * <li>MBeans are displayed as part of Oddjob's job hierarchy within * Oddjob Explorer.</li> * </ul> * * MBeans are identified as part of Oddjob's property expansion * syntax using their full Object Names. If this service is given * the id 'my-jmx-world' an MBean in the domain 'mydomain' and name * 'type=greeting,name=hello' would be identified from another Oddjob * job with the expression: * * <pre> * ${my-jmx-world/mydomain:type=greeting,name=hello} * </pre> * * Note that what is being referenced here is an Oddjob wrapper around * the MBean that allows operations and attributes of the MBean to accessed * elsewhere. What is referenced is not an MBean instance. * <p> * The example below shows an MBean (wrapper) being passed as the source * property to an {@link InvokeJob}. * <p> * Attributes of the MBean can be accessed as if they were properties of * the MBean. If the MBean above has an attribute 'FullText' its value * can be accessed using the expression: * * <pre> * ${my-jmx-world/mydomain:type=greeting,name=hello.FullText} * </pre> * * If an MBean Object Name contains dots (.) it must be quoted using double * quotes. If the domain in the above example was my.super.domain the * MBean can be identified with the expression: * * <pre> * ${my-jmx-world/"my.super.domain:type=greeting,name=hello"} * </pre> * * and the attribute with: * * <pre> * ${my-jmx-world/"my.super.domain:type=greeting,name=hello".FullText} * </pre> * * Note that this support for quoting does not apply to Oddjob property * expansion expressions in general - only too these MBean identifiers. * * @oddjob.example * * This example demonstrates reading an attribute, setting an attribute * and invoking an operation. * * {@oddjob.xml.resource org/oddjob/jmx/JMXServiceExample.xml} * * * @author Rob Gordon */ public class JMXServiceJob extends ClientBase implements Structural, BeanDirectoryOwner { /** Child helper */ private ChildHelper<DomainNode> childHelper = new ChildHelper<DomainNode>(this); private BeanDirectory beanDirectory; @Override protected void doStart(final MBeanServerConnection mbsc, ScheduledExecutorService notificationProcessor) throws IOException { SimpleMBeanSession session = new SimpleMBeanSession( getArooaSession(), mbsc); beanDirectory = new MBeanDirectory(session); String[] domains = mbsc.getDomains(); for (String domain: domains) { DomainNode node = new SimpleDomainNode(domain, session); childHelper.addChild(node); // done after add to allow logger archiver to be added. node.initialise(); } notificationProcessor.scheduleAtFixedRate(new Runnable() { public void run() { try { int count = mbsc.getMBeanCount(); logger().debug("Heartbeat with bean count " + count); } catch (Exception e) { try { doStop(WhyStop.HEARTBEAT_FAILURE, e); } catch (Exception e1) { logger().error("Failed to stop.", e1); } } } @Override public String toString() { return "Heartbeat"; } }, getHeartbeat(), getHeartbeat(), TimeUnit.MILLISECONDS); } @Override protected void onStop(WhyStop why) { while (childHelper.size() > 0) { DomainNode node = childHelper.removeChildAt(0); node.destroy(); } this.beanDirectory = null; } @Override public BeanDirectory provideBeanDirectory() { return beanDirectory; } /* (non-Javadoc) * @see org.oddjob.Structural#addStructuralListener(org.oddjob.structural.StructuralListener) */ @Override public void addStructuralListener(StructuralListener listener) { childHelper.addStructuralListener(listener); } /* (non-Javadoc) * @see org.oddjob.Structural#removeStructuralListener(org.oddjob.structural.StructuralListener) */ @Override public void removeStructuralListener(StructuralListener listener) { childHelper.removeStructuralListener(listener); } }