Visitor :

Apr 1, 2009

Example Source) JMX based on commons modeler.

I used the commons modeler in apache project. Simple cases for example, monitoring attribute or invoking operation of mbean are useful, but notification model is useless.
As you see in commons-modelr test source. There is written "This is problem". I knew this. But I did not notice what the statments means.
After I tested, I noticed it was wrong.

I have plan to developing commnicating jmx server and client in subscriber model like event-driven listener. Because cost of commucation between server and client is cheaper.

After I tested notification model, I realized notification model based on commons modeler. I tried to use another solution, Spring JMX. but, there are many questions about spring-jmx library in notification. So... I have to regenerate my code.

Strength of using commons modeler.
- possible to develope POJO.
- no need to know MBean in server. can be packaged. (!!)

Weakness of using commons modeler.
- problem with notification model.

Anyway. I introduce my code on commons-modeler which contain mbean-descriptors.xml. Those code are useful in invoking method or monitoring attribute of mbean.



public class MonitorAgent {

private Log log = LogFactory.getLog(MonitorAgent.class);

private JMXConnectorServer connector;

private Registry rmiRegistry;

private static MonitorAgent agent;

private String mBeanDomain = "Monitor";

private MonitorAgent() {
}

public static synchronized MonitorAgent getInstance() {
if (agent == null) {
agent = new MonitorAgent();
}
return agent;
}

/**
* MBean의 도메인 이름을 지정한다.
* @param domainName
*/
public void setMBeanDomain(String domainName) {
this.mBeanDomain = domainName;
}

/**
* JMXConnectorServer 를 초기화한다.
* @param mBeanServer
* @param port
* @throws Exception
*/
public void init(MBeanServer mBeanServer, int port) throws Exception {
Map env = new HashMap();

StringBuilder serviceURL = new StringBuilder();
serviceURL.append("service:jmx:rmi://");
serviceURL.append(NetUtil.IP);
serviceURL.append(":");
serviceURL.append(port + 1);
serviceURL.append("/jndi/rmi://");
serviceURL.append(NetUtil.IP);
serviceURL.append(":");
serviceURL.append(port);
serviceURL.append("/jmxrmi");

rmiRegistry = LocateRegistry.createRegistry(port);
JMXServiceURL serviceUrl = new JMXServiceURL(serviceURL.toString());
connector = JMXConnectorServerFactory.newJMXConnectorServer(serviceUrl, env, mBeanServer);

MBeanFactory mbeanManager = MBeanFactory.getInstance();
mbeanManager.setDomainName(mBeanDomain);
mbeanManager.addModelMBean(mBeanServer);
log.debug("serviceURL is initiated(" + serviceURL.toString() + ")");
}

public JMXConnectorServer getConnector() {
return connector;
}

public void start() throws Exception {
connector.start();
}

public void stop() throws Exception {
if (connector != null) {
connector.stop();
}
UnicastRemoteObject.unexportObject(rmiRegistry, true);
}
}




public class MBeanFactory {
private final static Log log = LogFactory.getLog(MBeanFactory.class);

private static MBeanFactory helper = null;

private static Registry registry = null;

private String domain = Constants.MONITOR_DOMAIN;

private MBeanFactory() {
}

/**
* 주어진 Domain이름으로 MBeanServer에 mbean-descriptors.xml에 정의된 Mbean들을 추가한다.
* @throws Exception
*/
public void addModelMBean(MBeanServer mbeanServer, String domainName) throws Exception {
domain = domainName;
addModelMBean(mbeanServer);
}

/**
* 주어진 MBeanServer에 mbean-descriptors.xml에 정의된 Mbean들을 추가한다.
* @throws Exception
*/
public void addModelMBean(MBeanServer mbeanServer) throws Exception {
registry = Registry.getRegistry();
String names[] = registry.findManagedBeans();
if (names.length == 0) {
InputStream stream = Constants.class.getResourceAsStream("/mbeans-descriptors.xml");
Registry.loadRegistry(stream);
stream.close();
}

if (domain == null) {
domain = mbeanServer.getDefaultDomain();
}
String[] managedBeans = registry.findManagedBeans();
for (String bean : managedBeans) {
ManagedBean managedBean = registry.findManagedBean(bean);
String mbeanClassName = managedBean.getClassName();
log.info("mbeanClassName : " + mbeanClassName);

String mbeanType = managedBean.getType();
log.info("mbeanType : " + mbeanType);

Object mbeanInstance = ReflectionUtil.createObject(mbeanClassName, null);
ModelMBeanFactory modelFactory = ModelMBeanFactory.getInstance();
ModelMBean mm = modelFactory.makeModelMBean(mbeanInstance);
mbeanServer.registerMBean(mm, new ObjectName(domain + ":type=" + mbeanType));
log.info("ModelBean added into MBeanServer in " + domain + ":type=" + mbeanType);
}
}

/**
* Factory Pattern. 가장 안전한 인스턴스 생성방법.
* @return
*/
public synchronized static MBeanFactory getInstance() {
if (helper == null) {
helper = new MBeanFactory();
}
return helper;
}

/**
* 도메인 이름을 지정한다.
* @param string
*/
public void setDomainName(String domain) {
this.domain = domain;
}
}





"-//Apache Software Foundation//DTD Model MBeans Configuration File"
"http://jakarta.apache.org/commons/dtds/mbeans-descriptors.dtd">


....



description="Java Basic Information" type="JavaMBean">
















....


public class ReflectionUtil {
private final static Log log = LogFactory.getLog(ReflectionUtil.class);

/**
* 주어진 클래스 이름과 variable Object 로 객체를 생성한다.
* @param className
* @param arg
* @return
* @throws Exception
*/
public static Object createObject(String className, Object... arg) throws Exception {
Class cl = Class.forName(className);
Constructor[] constructor = cl.getDeclaredConstructors();

ForContructor :
for (Constructor c : constructor) {
Class[] paramClass = c.getParameterTypes();

// Constructor with no parameter.
if (arg == null || arg.length == 0) {
if (paramClass.length == 0) {
c.setAccessible(true);
return c.newInstance();
}
}

// Constructor with given parameters.
if (arg != null && paramClass.length == arg.length) {
c.setAccessible(true);
boolean result = false;

ForParameter :
for (int i = 0 ; i < paramClass.length ; i++) {
if (i != 0 && result == false) {
break ForParameter;
}

if (paramClass[i].isAssignableFrom(arg[i].getClass())) {
result = true;
continue;
}
}

if (result == true) {
return c.newInstance(arg);
}
}
}
return null;
}

}


ModelBeanFactory class is Referenced in http://blogs.sun.com/jmxetc/entry/dynamicmbeans,_modelmbeans,_and_pojos...
public class ModelMBeanFactory {
private final static Log log = LogFactory.getLog(ModelMBeanFactory.class);

private static ModelMBeanFactory factory = null;

private ModelMBeanFactory() {
}

public synchronized static ModelMBeanFactory getInstance() {
if (factory == null) {
factory = new ModelMBeanFactory();
}
return factory;
}

/**
* Pojo 클래스를 ModelMBean으로 만들어줌.
* @param resource
* @return
* @throws Exception
*/
public ModelMBean makeModelMBean(Object resource) throws Exception {
final Method[] methods = resource.getClass().getMethods();
log.info("resource.getClass() : " + resource.getClass());
final List operations = new ArrayList();
final List getters = new ArrayList();
final Map setters = new LinkedHashMap();

for (Method method : methods) {
if (method.getDeclaringClass().equals(Object.class))
continue;

if (method.getName().startsWith("get")
&& !method.getName().equals("get")
&& !method.getName().equals("getClass")
&& method.getParameterTypes().length == 0
&& method.getReturnType() != void.class) {
getters.add(method);
}
if (method.getName().startsWith("set")
&& !method.getName().equals("set")
&& method.getParameterTypes().length == 1
&& method.getReturnType().equals(void.class)) {
setters.put(method.getName(), method);
}

operations.add(method);
log.info("method : " + method);
}

final List attrinfo = new ArrayList();

for (Method getter : getters) {
String attrName = getter.getName().substring(3);
String setterMethod = "set" + attrName;

Method setter = setters.remove(setterMethod);
if (setter != null) {
if (!getter.getReturnType().equals(
setter.getParameterTypes()[0])) {
log.warn("setter " + setter.getName() + " doesn't have the expected type: setter ignored.");
setter = null;
}
}
attrinfo.add(makeAttribute(getter, setter));
}

for (Method setter : setters.values()) {
log.warn("only setter, not getter");
attrinfo.add(makeAttribute(null, setter));
}

final ModelMBeanAttributeInfo[] attrs = attrinfo.toArray(new ModelMBeanAttributeInfo[attrinfo.size()]);

final int opcount = operations.size();
final ModelMBeanOperationInfo[] ops = new ModelMBeanOperationInfo[opcount];
for (int i = 0; i < opcount; i++) {
final Method m = operations.get(i);
ops[i] = new ModelMBeanOperationInfo(m.getName(), m);
}

ModelMBeanInfo mmbi = new ModelMBeanInfoSupport(resource.getClass()
.getName(), resource.getClass().getName(), attrs, null, // constructors
ops, null); // notifications
ModelMBean mmb = new RequiredModelMBean(mmbi);
mmb.setManagedResource(resource, "ObjectReference");
return mmb;
}

/**
* Make attribute.
* @param getter
* @param setter
* @return
* @throws Exception
*/
private static ModelMBeanAttributeInfo makeAttribute(Method getter, Method setter) throws Exception {
final String attrName;
if (getter != null) {
attrName = getter.getName().substring(3);
} else {
attrName = setter.getName().substring(3);
}

final List descriptors = new ArrayList();
descriptors.add("name=" + attrName);
descriptors.add("descriptorType=attribute");
if (getter != null) {
descriptors.add("getMethod=" + getter.getName());
}
if (setter != null) {
descriptors.add("setMethod=" + setter.getName());
}

final Descriptor attrD =
new DescriptorSupport(descriptors.toArray(new String[descriptors.size()]));

return new ModelMBeanAttributeInfo(attrName, attrName, getter, setter, attrD);
}
}

I start blog 3.0

First Blogging on blog 3.0. Why I write to 3.0 is what I move the bloggers 3 times.

My first blog page is http://blog.paran.com/knight76,
and second blog page is http://blog.naver.com/knight76.
Now, this site http://knight76.blogspot.com is created by me.

I'm am so happy to write in this Blogger.

I am working as a software engineer in Korea, I have experienced J2ME, J2SE, JEE architecture, also I made many applications based on Java, C, C++, perl.
In these day, I have interested in Java, Perl because of their beautiful api and architure to learn.

In my compay, I have role in development of the backend software(monitoring, caching, messaging....) and management of web system (linux, perl).