/* Copyright (C) SYSTAP, LLC DBA Blazegraph 2006-2016. All rights reserved. Contact: SYSTAP, LLC DBA Blazegraph 2501 Calvert ST NW #106 Washington, DC 20008 licenses@blazegraph.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* * Created on Mar 26, 2009 */ package com.bigdata.jmx; import java.lang.management.ManagementFactory; import javax.management.InstanceAlreadyExistsException; import javax.management.MBeanRegistrationException; import javax.management.MBeanServer; import javax.management.MalformedObjectNameException; import javax.management.NotCompliantMBeanException; import javax.management.ObjectName; import javax.management.StandardMBean; import javax.management.monitor.CounterMonitor; /** * Class demonstrates the ability to declare get/set and get methods on the the * {@link IFoo} interface and expose a {@link Foo} implementation of that * interface as a {@link StandardMBean}. You can run {@link #main(String[])} * and start <code>jconsole</code> and inspect/set the "foo" attribute and see * the change on the read-only "bar" attribute. No fuss, no muss. * <p> * There are some caveats. In general, you can declare interfaces having getters * and directly expose the services implementing those interfaces as MBeans. If * the service supports a dynamic change to the value of an attribute, then you * can also put the settor on the interface to be exposed as an MBean. * <p> * The get/set methods need to be <code>synchronized</code> so that changes * made by a setter will become immediately visible to other code also * synchronized on the same reference. If the service internally uses the * getter, then consider having district objects on which you synchronize for * get() methods which are heavily used in order to minimize contention for the * object's monitor. The other option is to make the field for the attribute * <code>volatile</code>. * <p> * Since MBean methods do not declare RMI exceptions there can be a conflict in * the interface if the method is also exposed for RMI, e.g., for a jini-based * service. You need to have two interfaces for this case. * <p> * There may be some cases where an attribute needs to be broken into a current * value and a target value, much like adjusting clocks to network time. * * @author <a href="mailto:thompsonbry@users.sourceforge.net">Bryan Thompson</a> * @version $Id$ */ public class JMXTest { /** * Interface to be exposed as an MBean. * * @author <a href="mailto:thompsonbry@users.sourceforge.net">Bryan Thompson</a> * @version $Id$ */ public interface IFoo { public int getFoo(); public int setFoo(int foo); public String getBar(); } /** * Object implementing that interface. * * @author <a href="mailto:thompsonbry@users.sourceforge.net">Bryan Thompson</a> * @version $Id$ */ public static class Foo implements IFoo { private int foo = 0; synchronized public int getFoo() { return foo; } // note: synchronized for visiblility of changes. synchronized public int setFoo(int foo) { final int t = this.foo; this.foo = foo; return t; } synchronized public String getBar() { return "bar" + foo; } } public interface IClock { public long getTime(); } public static class Clock extends Thread implements IClock { private long time; public long getTime() { return time; } public void run() { while(true) { time = System.currentTimeMillis(); try { // this sets the update granularity. Thread.sleep(100); } catch (InterruptedException e) { // done; break; } } } } /** * When you run this class it registers an instance of {@link Foo} as an * MBean and then waits forever. You can run <code>jconsole</code> and * verify that you can see the MBean and its attributes and change attribute * values using the setter(s) declared on the {@link IFoo} interface. * * @param args * Not used. * * @throws InstanceAlreadyExistsException * @throws MBeanRegistrationException * @throws NotCompliantMBeanException * @throws MalformedObjectNameException * @throws NullPointerException * @throws InterruptedException */ public static void main(String[] args) throws InstanceAlreadyExistsException, MBeanRegistrationException, NotCompliantMBeanException, MalformedObjectNameException, NullPointerException, InterruptedException { // use this object to register your mbeans. final MBeanServer testMBeanServer = ManagementFactory .getPlatformMBeanServer(); // create instance of your object. final IFoo foo = new Foo(); // wrap as a standard mbean exposing the IFoo interface. final Object fooMBean = new StandardMBean(foo, IFoo.class); /* * Sets up a Clock MBean exposing the system time that updates its * internal state every 100 milliseconds. Then sets up a CounterMonitor * which observes that Clock MBean. Both are MBean and both have to be * registered before the notifications can be generated. The * CounterMBean is very picky about the data types for its arguments * (Threshold, Offset) all of which need to be Long since IClock is * returning a [long]. * * Based on http://javaboutique.internet.com/tutorials/jmx2/index2.html - * there are nearly no examples that I could find on the web for counter * monitor. */ { // create and start clock. final Clock clock = new Clock(); clock.setDaemon(true); clock.start(); // wrap as a standard mbean exposing the IClockinterface. final Object clockMBean = new StandardMBean(clock, IClock.class); /* * Setup monitor for the clock. */ final CounterMonitor cmon = new CounterMonitor(); // register the mbean. testMBeanServer.registerMBean(fooMBean, new ObjectName( "com.bigdata", "name", "Foo")); cmon.addObservedObject(new ObjectName("com.bigdata:name=Clock")); cmon.setObservedAttribute("Time"); cmon.setGranularityPeriod(1000/* ms */); cmon.setInitThreshold((Long) System.currentTimeMillis()); // offset after event trigger for retrigger. cmon.setOffset((Long) 5000L/* ms since clock is also time */); // set the difference mode ?!? cmon.setDifferenceMode(false); // make sure we get notified. cmon.setNotify(true); // register clock testMBeanServer.registerMBean(clockMBean, new ObjectName( "com.bigdata:name=Clock")); // register the monitor. testMBeanServer.registerMBean(cmon, new ObjectName( "com.bigdata:name=ClockMonitor")); // start the monitor (you can do this via jconsole as well). cmon.start(); } // verify visible using jconsole. Thread.sleep(Long.MAX_VALUE); } }