/*
* Copyright (c) 1998-2011 Caucho Technology -- all rights reserved
*
* This file is part of Resin(R) Open Source
*
* Each copy or derived work must preserve the copyright notice and this
* notice unmodified.
*
* Resin Open Source 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; either version 2 of the License, or
* (at your option) any later version.
*
* Resin Open Source 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, or any warranty
* of NON-INFRINGEMENT. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License
* along with Resin Open Source; if not, write to the
*
* Free Software Foundation, Inc.
* 59 Temple Place, Suite 330
* Boston, MA 02111-1307 USA
*
* @author Sam
*/
package com.caucho.quercus.lib.resin;
import com.caucho.quercus.annotation.Name;
import com.caucho.quercus.env.ArrayValue;
import com.caucho.quercus.env.LongValue;
import com.caucho.quercus.env.Value;
import javax.management.Attribute;
import javax.management.MBeanInfo;
import javax.management.MBeanOperationInfo;
import javax.management.MBeanParameterInfo;
import javax.management.MBeanServerConnection;
import javax.management.ObjectName;
import javax.management.openmbean.*;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
public class MBean {
private static final Logger log = Logger.getLogger(MBean.class.getName());
private static final HashMap<String,Marshall> _marshallMap
= new HashMap<String,Marshall>();
private MBeanServerConnection _server;
private ObjectName _name;
private MBeanInfo _info;
MBean(MBeanServerConnection server, ObjectName name)
{
_server = server;
_name = name;
}
/**
* Returns the mbean's canonical name.
*/
public String getMbean_name()
{
return _name.getCanonicalName();
}
/**
* Returns the MBeanInfo for the mbean.
*/
@Name("mbean_info")
public MBeanInfo getMbean_info()
{
try {
if (_info == null)
_info = _server.getMBeanInfo(_name);
return _info;
} catch (Exception e) {
log.log(Level.FINE, e.toString(), e);
return null;
}
}
/**
* Returns an attribute.
*/
public Object __getField(String attrName)
{
try {
return unmarshall(_server.getAttribute(_name, attrName));
} catch (Exception e) {
log.log(Level.FINE, e.toString(), e);
return null;
}
}
/**
* Sets an attribute.
*/
public boolean __setField(String attrName, Object value)
{
try {
_server.setAttribute(_name, new Attribute(attrName, value));
return true;
} catch (Exception e) {
log.log(Level.FINE, e.toString(), e);
return false;
}
}
/**
* Calls a method.
*/
public Object __call(String name, Value values)
{
try {
int size = values.getSize();
Object []args = new Object[values.getSize()];
for (int i = 0; i < size; i++) {
args[i] = values.get(LongValue.create(i)).toJavaObject();
}
MBeanOperationInfo opInfo = findClosestOperation(name, args);
if (opInfo != null) {
String []mbeanSig = createMBeanSig(opInfo);
marshall(args, mbeanSig);
Object value = _server.invoke(_name, name, args, mbeanSig);
return unmarshall(value);
}
else {
return _server.invoke(_name, name, args, null);
}
} catch (Exception e) {
log.log(Level.FINE, e.toString(), e);
return null;
}
}
private String []createMBeanSig(MBeanOperationInfo opInfo)
{
MBeanParameterInfo []paramInfo = opInfo.getSignature();
String []sig = new String[paramInfo.length];
for (int i = 0; i < paramInfo.length; i++) {
sig[i] = paramInfo[i].getType();
}
return sig;
}
protected MBeanOperationInfo findClosestOperation(String name, Object []args)
throws Exception
{
MBeanInfo info = getMbean_info();
if (info == null)
return null;
MBeanOperationInfo []ops = info.getOperations();
MBeanOperationInfo bestOp = null;
long bestCost = Long.MAX_VALUE;
for (int i = 0; i < ops.length; i++) {
MBeanOperationInfo op = ops[i];
if (! name.equals(op.getName()))
continue;
if (op.getSignature().length == args.length) {
long cost = calculateCost(op.getSignature(), args);
if (cost < bestCost) {
bestCost = cost;
bestOp = op;
}
}
}
return bestOp;
}
private static long calculateCost(MBeanParameterInfo []paramInfo,
Object []args)
{
long cost = 0;
for (int i = 0; i < paramInfo.length; i++) {
String param = paramInfo[i].getType();
String arg;
if (args[i] != null)
arg = args[i].getClass().getName();
else
arg = "java.lang.Object";
if (param.equals(arg)) {
}
else if ((param.indexOf('[') >= 0) != (arg.indexOf('[') >= 0)) {
cost += 100;
}
else
cost += 1;
}
return cost;
}
private void marshall(Object []args, String []sig)
{
for (int i = 0; i < sig.length; i++) {
args[i] = findMarshall(sig[i]).marshall(args[i]);
}
}
private Object unmarshall(Object value)
{
if (value instanceof ObjectName) {
ObjectName name = (ObjectName) value;
return new MBean(_server, name);
}
else if (value instanceof ObjectName[]) {
ObjectName []names = (ObjectName []) value;
MBean []mbeans = new MBean[names.length];
for (int i = 0; i < names.length; i++)
mbeans[i] = new MBean(_server, names[i]);
return mbeans;
}
else if (value instanceof CompositeData) {
CompositeData compositeValue = (CompositeData) value;
CompositeType type = compositeValue.getCompositeType();
if (type != null) {
String typeName = type.getTypeName();
try {
ClassLoader loader = Thread.currentThread().getContextClassLoader();
Class<?> typeClass = Class.forName(typeName, false, loader);
Method from = typeClass.getMethod("from", new Class[] { CompositeData.class });
if (from != null)
return from.invoke(null, compositeValue);
} catch (Exception e) {
log.log(Level.FINER, e.toString(), e);
}
}
return new CompositeDataBean(compositeValue);
}
else if (value instanceof CompositeData[]) {
CompositeData []compositeValue = (CompositeData[]) value;
Object []result = new Object[compositeValue.length];
for (int i = 0; i < result.length; i++) {
result[i] = unmarshall(compositeValue[i]);
}
return result;
}
else
return value;
}
private Marshall findMarshall(String sig)
{
Marshall marshall = _marshallMap.get(sig);
if (marshall != null)
return marshall;
else
return Marshall.MARSHALL;
}
public String toString()
{
if (_name == null)
return "MBean[]";
else
return "MBean[" + _name.getCanonicalName() + "]";
}
static class Marshall {
static final Marshall MARSHALL = new Marshall();
public Object marshall(Object value)
{
return value;
}
}
static class IntMarshall extends Marshall {
static final Marshall MARSHALL = new IntMarshall();
public Object marshall(Object value)
{
if (value instanceof Integer)
return value;
else if (value instanceof Number)
return new Integer(((Number) value).intValue());
else if (value == null)
return new Integer(0);
else {
try {
return new Integer(Integer.parseInt(String.valueOf(value)));
} catch (Exception e) {
return new Integer(0);
}
}
}
}
static class LongMarshall extends Marshall {
static final Marshall MARSHALL = new LongMarshall();
public Object marshall(Object value)
{
if (value instanceof Long)
return value;
else if (value instanceof Number)
return new Long(((Number) value).longValue());
else if (value == null)
return new Long(0);
else {
try {
return new Long(Long.parseLong(String.valueOf(value)));
} catch (Exception e) {
return new Long(0);
}
}
}
}
static class LongArrayMarshall extends Marshall {
static final Marshall MARSHALL = new LongArrayMarshall();
public Object marshall(Object value)
{
if (value instanceof Long)
return new long[] { ((Long) value).longValue() };
else if (value instanceof Number)
return new long[] { ((Number) value).longValue() };
else if (value == null)
return null;
else if (value instanceof ArrayValue) {
ArrayValue array = (ArrayValue) value;
long []result = new long[array.getSize()];
for (int i = 0; i < result.length; i++)
result[i] = array.get(LongValue.create(i)).toLong();
return result;
}
else {
try {
return new long [] { Long.parseLong(String.valueOf(value)) };
} catch (Exception e) {
return new long[0];
}
}
}
}
static class StringMarshall extends Marshall {
static final Marshall MARSHALL = new StringMarshall();
public Object marshall(Object value)
{
if (value == null)
return null;
else
return value.toString();
}
}
static {
_marshallMap.put("int", IntMarshall.MARSHALL);
_marshallMap.put("java.lang.Integer", IntMarshall.MARSHALL);
_marshallMap.put("long", LongMarshall.MARSHALL);
_marshallMap.put("java.lang.Long", LongMarshall.MARSHALL);
_marshallMap.put("[J", LongArrayMarshall.MARSHALL);
_marshallMap.put("java.lang.String", StringMarshall.MARSHALL);
}
}