package org.jgroups.tests; import org.jgroups.Global; import org.jgroups.annotations.ManagedAttribute; import org.jgroups.annotations.ManagedOperation; import org.jgroups.annotations.Property; import org.jgroups.jmx.AdditionalJmxObjects; import org.jgroups.jmx.JmxConfigurator; import org.jgroups.util.Util; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeClass; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; import javax.management.*; import java.util.Date; /** * Tests exposing attributes and operations via JMX using annotations (@ManagedAttribute, @ManagedOperation) * @author Bela Ban * @since 3.3 */ @Test(groups=Global.FUNCTIONAL,singleThreaded=true) public class JmxTest { protected MBeanServer server; protected static final String NAME="jmxtest:name=obj"; protected ObjectName obj_name; protected Child obj; @BeforeClass protected void create() {server=Util.getMBeanServer();} @BeforeMethod protected void setup() throws Exception { obj_name=new ObjectName(NAME); obj=new Child(); JmxConfigurator.register(obj, server, NAME); assert server.isRegistered(obj_name); } @AfterMethod protected void destroy() throws Exception { JmxConfigurator.unregister(server, NAME); } public void testAttrWithReadOnlyAccess() throws Exception { check("age", false); setAttribute("age", 23); // cannot set assert getAttribute("age").equals((short)22); // initial_value check("ssn",false, (long)322649, 10000); } public void testAttrWithReadWriteAccess() throws Exception { check("age2", true, (short)0, (short)22); check("timer.keep_alive_time", true, (long)5000, (long)2000); } public void testGetter() throws Exception { assert !attrExists("unknown"); check("last_name", true, "Fechner", "Ban"); check("first_name", true, "Jeannette", "Bela"); check("flag", true, true, false); check("another", true, false, true); } /** Tests accessors that don't have a backing attribute (write is a no-op) */ public void testAccessorsWithoutAttribute() throws Exception { check("synthesized_value",true); Object val=getAttribute("synthesized_value"); assert val.equals(322649); setAttribute("synthesized_value", 10000); val=getAttribute("synthesized_value"); assert val.equals(322649); } public void testJavaStyleAttributes() throws Exception { check("javaStyleFlag", true, true, false); } public void testAdditionalJmxObjects() throws Exception { ProvideAdditionalObjects objs=new ProvideAdditionalObjects(); JmxConfigurator.register(objs, server, "jmxtest:name=additional_obj"); ObjectName n=new ObjectName("jmxtest:name=additional_obj"); Object val=getAttribute(n, "num_msgs_sent"); assert (int)val == 0; val=getAttribute(n, "num_msgs_received"); assert (int)val == 0; } protected void check(String attr_name, boolean writable) throws Exception { check(attr_name, writable, null, null); } protected void check(String attr_name, boolean writable, Object expected_value, Object new_value) throws Exception { assert attrExists(attr_name); MBeanAttributeInfo info=getAttributeInfo(attr_name); System.out.println(attr_name + ": " + info); assert info.isWritable() == writable; Object val=getAttribute(attr_name); if(expected_value != null) assert val.equals(expected_value) : "value of \"" + attr_name + "\" is " + val + ", but expected " + expected_value; if(new_value == null || !isWritable(attr_name)) return; setAttribute(attr_name, new_value); val=getAttribute(attr_name); assert val.equals(new_value) : "value of \"" + attr_name + "\" is " + val + ", but expected " + new_value; } protected boolean attrExists(String attr_name) { try { return server.getAttribute(obj_name, attr_name) != null; } catch(AttributeNotFoundException e) { return false; } catch(Throwable t) { throw new RuntimeException(t); } } protected boolean isWritable(String attr_name) { MBeanAttributeInfo attr_info=getAttributeInfo(attr_name); return attr_info != null && attr_info.isWritable(); } protected MBeanAttributeInfo getAttributeInfo(String attr_name) { MBeanAttributeInfo[] attrs=new MBeanAttributeInfo[0]; try { attrs=server.getMBeanInfo(obj_name).getAttributes(); for(MBeanAttributeInfo info: attrs) if(info.getName().equals(attr_name)) return info; return null; } catch(Throwable t) { return null; } } protected void setAttribute(String attr_name, Object value) throws Exception { server.setAttribute(obj_name, new Attribute(attr_name, value)); } protected Object getAttribute(String attr_name) throws Exception { return getAttribute(obj_name, attr_name); } protected Object getAttribute(ObjectName name, String attr_name) throws Exception { return server.getAttribute(name, attr_name); } protected static class Parent { @SuppressWarnings("FieldMayBeFinal") @ManagedAttribute(description="age",writable=false) private short age=22; // exposed as read-only 'age' @ManagedAttribute(description="age2",writable=true) protected short age2; @Property(name="timer.keep_alive_time", description="Timeout") protected long keep_alive=5000; protected String last_name="Fechner"; @ManagedAttribute(description="social security number",name="ssn") // read-only private static final long ssn=322649L; @ManagedAttribute(description="setter",writable=true) public String lastName() {return last_name;} public Parent lastName(String new_name) {last_name=new_name; return this;} } protected static class Child extends Parent { protected String first_name="Jeannette"; protected boolean flag=true; @Property(name="Another",writable=true) protected boolean another_flag; @Property(writable=true) protected boolean javaStyleFlag=true; public String firstName() {return first_name;} @ManagedAttribute(description="setter",writable=true) public Parent firstName(String new_name) {first_name=new_name; return this;} @ManagedAttribute(description="flag",writable=true) public boolean isFlag() {return flag;} public static int getSynthesizedValue() {return 322649;} @ManagedAttribute(description="synthesized",writable=true) public Child synthesizedValue(int v) {return this;} @ManagedAttribute(name="another",writable=true) public boolean isAnotherFlag() {return another_flag;} public Child anotherFlag(boolean flag) {another_flag=flag; return this;} public boolean javaStyleFlag() {return javaStyleFlag;} public Child javaStyleFlag(boolean flag) {javaStyleFlag=flag; return this;} } protected static class ProvideAdditionalObjects implements AdditionalJmxObjects { protected final AdditionalInfo info=new AdditionalInfo(); @ManagedAttribute(description="age",writable=true) protected int age=10; public Object[] getJmxObjects() { return new Object[]{info}; } } protected static class AdditionalInfo { @ManagedAttribute(description="number of msgs sent") protected int num_msgs_sent; @ManagedAttribute(description="number of msgs sent", writable=true) public int num_msgs_received; @ManagedAttribute(description="current date") public static String getDate() { return new Date().toString(); } @ManagedOperation(description="say name") public static void sayName() { System.out.printf("hello world\n"); } @ManagedOperation(description="foo") public static void foo() { System.out.println("foo()"); } } }