/*
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);
}
}