org.glassfish.admin.amx.util.jmx.JMXUtil Maven / Gradle / Ivy
Show all versions of payara-micro Show documentation
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 1997-2012 Oracle and/or its affiliates. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License"). You
* may not use this file except in compliance with the License. You can
* obtain a copy of the License at
* https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
* or packager/legal/LICENSE.txt. See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at packager/legal/LICENSE.txt.
*
* GPL Classpath Exception:
* Oracle designates this particular file as subject to the "Classpath"
* exception as provided by Oracle in the GPL Version 2 section of the License
* file that accompanied this code.
*
* Modifications:
* If applicable, add the following below the License Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
* "Portions Copyright [year] [name of copyright owner]"
*
* Contributor(s):
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license." If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above. However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/
//Portions Copyright [2018-2019] [Payara Foundation and/or affiliates]
package org.glassfish.admin.amx.util.jmx;
import java.io.IOException;
import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.*;
import java.util.regex.Pattern;
import javax.management.*;
import javax.management.modelmbean.DescriptorSupport;
import javax.management.openmbean.OpenMBeanAttributeInfo;
import org.glassfish.admin.amx.util.ArrayConversion;
import org.glassfish.admin.amx.util.ArrayUtil;
import org.glassfish.admin.amx.util.MapUtil;
import org.glassfish.admin.amx.util.RegexUtil;
import org.glassfish.admin.amx.util.SetUtil;
import org.glassfish.admin.amx.util.StringUtil;
import org.glassfish.admin.amx.util.TypeCast;
import org.glassfish.admin.amx.util.stringifier.SmartStringifier;
/**
*/
public final class JMXUtil
{
public static String toString(final ObjectName objectName)
{
// we can be smarter about the ordering later
return "" + objectName;
}
public static final String MBEAN_SERVER_DELEGATE = "JMImplementation:type=MBeanServerDelegate";
public static MBeanServerDelegateMBean getMBeanServerDelegateMBean(final MBeanServerConnection server)
{
return newProxyInstance(server, newObjectName(MBEAN_SERVER_DELEGATE), MBeanServerDelegateMBean.class);
}
/** Create a new proxy supporting Notifications
Type-safe; in JDK 5 generics aren't used */
public static T newProxyInstance(final MBeanServerConnection conn, final ObjectName objectName, final Class clazz)
{
return newProxyInstance(conn, objectName, clazz, true);
}
/** Type-safe; in JDK 5 generics aren't used */
public static T newProxyInstance(final MBeanServerConnection conn, final ObjectName objectName, final Class clazz, boolean notificationBroadcaster)
{
return clazz.cast(MBeanServerInvocationHandler.newProxyInstance(conn, objectName, clazz, notificationBroadcaster));
}
public static final String MBEAN_SERVER_ID_ATTRIBUTE_NAME = "MBeanServerId";
/**
The wilcard property at the end of an ObjectName which indicates
that it's an ObjectName pattern.
*/
public static final String WILD_PROP = ",*";
/**
The wilcard property at the end of an ObjectName which indicates
that all properties should be matched.
*/
public static final String WILD_ALL = "*";
public static ObjectName getMBeanServerDelegateObjectName() {
return (newObjectName("JMImplementation:type=MBeanServerDelegate"));
}
public static String getMBeanServerDelegateInfo(final MBeanServer server)
{
final MBeanServerDelegateMBean delegate = getMBeanServerDelegateMBean(server);
return "MBeanServerDelegate: {" +
"MBeanServerId = " + delegate.getMBeanServerId() +
", ImplementationMame = " + delegate.getImplementationName() +
", ImplementationVendor = " + delegate.getImplementationVendor() +
", ImplementationVersion = " + delegate.getImplementationVersion() +
", SpecificationName = " + delegate.getSpecificationName() +
", SpecificationVendor = " + delegate.getSpecificationVendor() +
", SpecificationVersion = " + delegate.getSpecificationVersion() +
" }";
}
public static void listenToMBeanServerDelegate(
final MBeanServerConnection conn,
final NotificationListener listener,
final NotificationFilter filter,
final Object handback)
throws IOException, InstanceNotFoundException
{
conn.addNotificationListener(
getMBeanServerDelegateObjectName(), listener, filter, handback);
}
public static String getMBeanServerID(final MBeanServerConnection conn)
throws IOException,
ReflectionException, InstanceNotFoundException, AttributeNotFoundException,
MBeanException
{
return ((String) conn.getAttribute(getMBeanServerDelegateObjectName(),
MBEAN_SERVER_ID_ATTRIBUTE_NAME));
}
/**
Create a new ObjectName, caller is guaranteeing that the name is
well-formed (a RuntimeException will be thrown if not). This avoids
having to catch all sorts of JMX exceptions.
Do not call this method if there is not 100% certainty of a well-formed name.
*/
public static ObjectName newObjectName(final String name)
{
try
{
return (new ObjectName(name));
}
catch (Exception e)
{
throw new RuntimeException(e.getMessage(), e);
}
}
public static ObjectName newObjectName(
final ObjectName objectName,
final String props)
{
final String domain = objectName.getDomain();
final String existingProps = objectName.getKeyPropertyListString();
final String allProps = concatenateProps(existingProps, props);
return (newObjectName(domain, allProps));
}
public static ObjectName newObjectName(
final String domain,
final String props)
{
return (newObjectName(domain + ":" + props));
}
/**
Build an ObjectName pattern.
@param domain the JMX domain
@param props properties of the ObjectName
*/
public static ObjectName newObjectNamePattern(
final String domain,
final String props)
{
String actualProps = null;
if (props.endsWith(JMXUtil.WILD_PROP) ||
props.equals(JMXUtil.WILD_ALL))
{
actualProps = props;
}
else if (props.length() == 0)
{
actualProps = "*";
}
else
{
actualProps = props + WILD_PROP;
}
return (newObjectName(domain + ":" + actualProps));
}
/**
Build an ObjectName pattern.
@param domain the JMX domain
@param props properties of the ObjectName
*/
public static ObjectName newObjectNamePattern(
final String domain,
final Map props)
{
final String propsString = mapToProps(props);
return (JMXUtil.newObjectNamePattern(domain, propsString));
}
public static String mapToProps(final Map propsMap)
{
return (MapUtil.toString(propsMap, ","));
}
public static ObjectName removeProperty(
final ObjectName objectName,
final String key)
{
ObjectName nameWithoutKey = objectName;
if (objectName.getKeyProperty(key) != null)
{
final String domain = objectName.getDomain();
final Hashtable props =
TypeCast.asHashtable(objectName.getKeyPropertyList());
props.remove(key);
if (objectName.isPropertyPattern())
{
nameWithoutKey = newObjectNamePattern(domain,
nameWithoutKey.getKeyPropertyListString());
}
else
{
try
{
nameWithoutKey = new ObjectName(domain, props);
}
catch (Exception e)
{
throw new RuntimeException(e);
}
}
}
return (nameWithoutKey);
}
private JMXUtil()
{
// disallow
}
public static final String GET = "get";
public static final String SET = "set";
public static final String IS = "is";
public static String makeProp(String name, String value)
{
return (name + "=" + value);
}
public static String concatenateProps(String props1, String props2)
{
String result;
if (props1.length() == 0)
{
result = props2;
}
else if (props2.length() == 0)
{
result = props1;
}
else
{
result = props1 + "," + props2;
}
return (result);
}
public static String concatenateProps(String props1, String props2, String props3)
{
return (concatenateProps(concatenateProps(props1, props2), props3));
}
/**
Convert a Set of ObjectName into an array
@param objectNameSet a Set of ObjectName
@return an ObjectName[]
*/
public static ObjectName[] objectNameSetToArray(final Set objectNameSet)
{
final ObjectName[] objectNames = new ObjectName[objectNameSet.size()];
objectNameSet.toArray(objectNames);
return (objectNames);
}
/**
@param key the property name, within the ObjectName
@param objectNames
@return values from each ObjectName
*/
public static String[] getKeyProperty(String key, ObjectName[] objectNames)
{
final String[] values = new String[objectNames.length];
for (int i = 0; i < objectNames.length; ++i)
{
values[i] = objectNames[i].getKeyProperty(key);
}
return (values);
}
/**
@param objectName
@param key
@return an ObjectName property with the specified key
*/
public static String getProp(
final ObjectName objectName,
final String key)
{
final String value = objectName.getKeyProperty(key);
if (value == null)
{
return (null);
}
return (makeProp(key, value));
}
public static String getProps(
final ObjectName objectName,
final Set propKeys)
{
return (getProps(objectName, propKeys, false));
}
public static String getProps(
final ObjectName objectName,
final Set propKeys,
final boolean ignoreMissing)
{
String props = "";
final Iterator iter = propKeys.iterator();
while (iter.hasNext())
{
final String key = (String) iter.next();
final String pair = getProp(objectName, key);
if (pair != null)
{
props = concatenateProps(props, pair);
}
else if (!ignoreMissing)
{
throw new IllegalArgumentException(
"key not found: " + key + " in " + objectName);
}
}
return (props);
}
/**
@param key the property name, within the ObjectName
@param objectNameSet
@return values from each ObjectName
*/
public static String[] getKeyProperty(String key, Set objectNameSet)
{
final ObjectName[] objectNames =
JMXUtil.objectNameSetToArray(objectNameSet);
return (getKeyProperty(key, objectNames));
}
/**
@param key the property name, within the ObjectName
@param objectNameSet
@return values from each ObjectName
*/
public static Set getKeyPropertySet(String key, Set objectNameSet)
{
final ObjectName[] objectNames =
JMXUtil.objectNameSetToArray(objectNameSet);
final String[] values = getKeyProperty(key, objectNames);
return (ArrayConversion.arrayToSet(values));
}
/**
Find the first key that is present in the ObjectName
@param candidateKeys
@param objectName
@return first key present in the ObjectName
*/
public static String findKey(
final Set candidateKeys,
final ObjectName objectName)
{
final Iterator iter = candidateKeys.iterator();
String match = null;
while (iter.hasNext())
{
final String key = (String) iter.next();
if (objectName.getKeyProperty(key) != null)
{
match = key;
break;
}
}
return (match);
}
/**
Find all ObjectName(s) that contains the associated key and value
@param objectNames
@param propertyKey
@param propertyValue
@return Set of all ObjectName that match
*/
public static Set findByProperty(
final Set objectNames,
final String propertyKey,
final String propertyValue)
{
final Set result = new HashSet();
final Iterator iter = objectNames.iterator();
while (iter.hasNext())
{
final ObjectName objectName = (ObjectName) iter.next();
final String value = objectName.getKeyProperty(propertyKey);
if (propertyValue.equals(value))
{
result.add(objectName);
}
}
return (result);
}
/**
Change or add a key property in an ObjectName.
*/
public static ObjectName setKeyProperty(final ObjectName objectName, final String key, final String value)
{
final String domain = objectName.getDomain();
final Hashtable props = TypeCast.asHashtable(objectName.getKeyPropertyList());
props.put(key, value);
ObjectName newObjectName = null;
try
{
newObjectName = new ObjectName(domain, props);
}
catch (MalformedObjectNameException e)
{
throw new RuntimeException(e);
}
return (newObjectName);
}
public static void unregisterAll(final MBeanServerConnection conn, final Set allNames)
throws IOException, MalformedObjectNameException, MBeanRegistrationException
{
for (final ObjectName name : allNames)
{
try
{
conn.unregisterMBean(name);
}
catch (Exception e)
{
// OK, gone, it objects, etc
}
}
}
public static void unregisterAll(final MBeanServerConnection conn)
throws IOException, MalformedObjectNameException, MBeanRegistrationException
{
unregisterAll(conn, queryNames(conn, new ObjectName("*:*"), null));
}
public static String[] getAllAttributeNames(
final MBeanServerConnection conn,
final ObjectName objectName)
throws IOException,
ReflectionException, IntrospectionException, InstanceNotFoundException
{
return (getAttributeNames(getAttributeInfos(conn, objectName)));
}
public static MBeanAttributeInfo[] filterAttributeInfos(
final MBeanAttributeInfo[] infos,
final AttributeFilter filter)
{
final ArrayList matches = new ArrayList();
for (int i = 0; i < infos.length; ++i)
{
if (filter.filterAttribute(infos[i]))
{
matches.add(infos[i]);
}
}
final MBeanAttributeInfo[] results = new MBeanAttributeInfo[matches.size()];
matches.toArray(results);
return (results);
}
/**
Get a String[] of Attribute names.
@param infos array of infos
*/
public static String[] getAttributeNames(final MBeanAttributeInfo[] infos)
{
final String[] names = new String[infos.length];
for (int i = 0; i < infos.length; ++i)
{
names[i] = infos[i].getName();
}
return (names);
}
/**
@param infos array of infos
@param attrName
*/
public static MBeanAttributeInfo getMBeanAttributeInfo(
final MBeanAttributeInfo[] infos,
final String attrName)
{
MBeanAttributeInfo info = null;
for (int i = 0; i < infos.length; ++i)
{
if (infos[i].getName().equals(attrName))
{
info = infos[i];
break;
}
}
return (info);
}
/**
@param mbeanInfo
@param attrName
*/
public static MBeanAttributeInfo getMBeanAttributeInfo(
final MBeanInfo mbeanInfo,
final String attrName)
{
return (getMBeanAttributeInfo(mbeanInfo.getAttributes(), attrName));
}
/**
@param conn
@param objectName
*/
public static MBeanAttributeInfo[] getAttributeInfos(
final MBeanServerConnection conn,
final ObjectName objectName)
throws IOException,
ReflectionException, IntrospectionException, InstanceNotFoundException
{
final MBeanAttributeInfo[] infos = conn.getMBeanInfo(objectName).getAttributes();
return (infos);
}
/**
Convert an AttributeList to a Map where the keys are the Attribute names,
and the values are Attribute.
@param attrs the AttributeList
*/
public static Map attributeListToAttributeMap(final AttributeList attrs)
{
final HashMap map = new HashMap();
for (int i = 0; i < attrs.size(); ++i)
{
final Attribute attr = (Attribute) attrs.get(i);
map.put(attr.getName(), attr);
}
return (map);
}
/**
Convert an AttributeList to a Map where the keys are the Attribute names,
and the values are the Attribute values.
@param attrs the AttributeList
*/
public static Map attributeListToValueMap(final AttributeList attrs)
{
final Map map = new HashMap();
for (int i = 0; i < attrs.size(); ++i)
{
final Attribute attr = (Attribute) attrs.get(i);
final Object value = attr.getValue();
map.put(attr.getName(), value);
}
return (map);
}
/**
Convert an AttributeList to a Map where the keys are the Attribute names,
and the values are the Attribute values.
@param attrs the AttributeList
*/
public static Map attributeListToStringMap(final AttributeList attrs)
{
final Map map = new HashMap();
for (int i = 0; i < attrs.size(); ++i)
{
final Attribute attr = (Attribute) attrs.get(i);
final Object value = attr.getValue();
final String s = (value == null ? null : "" + value);
map.put(attr.getName(), s);
}
return (map);
}
/**
Convert an MBeanAttributeInfo[] to a Map where the keys are the Attribute names,
and the values are MBeanAttributeInfo.
@param attrInfos the AttributeList
*/
public static Map attributeInfosToMap(final MBeanAttributeInfo[] attrInfos)
{
final Map map = new HashMap();
for (int i = 0; i < attrInfos.length; ++i)
{
final MBeanAttributeInfo attrInfo = attrInfos[i];
map.put(attrInfo.getName(), attrInfo);
}
return (map);
}
public static MBeanInfo removeAttributes(
final MBeanInfo origInfo,
final String[] attributeNames)
{
MBeanInfo result = origInfo;
if (attributeNames.length != 0)
{
final Map infos =
JMXUtil.attributeInfosToMap(origInfo.getAttributes());
for (int i = 0; i < attributeNames.length; ++i)
{
infos.remove(attributeNames[i]);
}
final MBeanAttributeInfo[] newInfos = new MBeanAttributeInfo[infos.keySet().size()];
infos.values().toArray(newInfos);
result = new MBeanInfo(
origInfo.getClassName(),
origInfo.getDescription(),
newInfos,
origInfo.getConstructors(),
origInfo.getOperations(),
origInfo.getNotifications(),
origInfo.getDescriptor());
}
return (result);
}
/**
Find a feature by name (attribute name, operation name, etc) and return
all matches. The feature is matched by calling MBeanFeatureInfo.getName().
@param infos infos
@param name name
@return Set of the matching items
*/
public static Set findInfoByName(
final MBeanFeatureInfo[] infos,
final String name)
{
final Set s = new HashSet();
for (int i = 0; i < infos.length; ++i)
{
final MBeanFeatureInfo info = infos[i];
if (info.getName().equals(name))
{
s.add(info);
}
}
return (s);
}
/**
Convert an Map to an Attribute list where the keys are the Attribute names,
and the values are objects.
@param m
*/
public static AttributeList mapToAttributeList(final Map m)
{
final AttributeList attrList = new AttributeList();
for (final Map.Entry me : m.entrySet())
{
final Attribute attr = new Attribute(me.getKey(), me.getValue());
attrList.add(attr);
}
return (attrList);
}
private static boolean connectionIsDead(final MBeanServerConnection conn)
{
boolean isDead = false;
// see if the connection is really dead by calling something innocuous
try
{
conn.isRegistered(new ObjectName(MBEAN_SERVER_DELEGATE));
}
catch (MalformedObjectNameException e)
{
assert (false);
}
catch (IOException e)
{
isDead = true;
}
return (isDead);
}
private static AttributeList getAttributesSingly(
MBeanServerConnection conn,
ObjectName objectName,
String[] attrNames,
Set problemNames)
throws InstanceNotFoundException
{
AttributeList attrs = new AttributeList();
for (int i = 0; i < attrNames.length; ++i)
{
final String name = attrNames[i];
try
{
final Object value = conn.getAttribute(objectName, name);
attrs.add(new Attribute(name, value));
} catch (InstanceNotFoundException e) {
// if the MBean disappeared while processing, just consider it gone
// from the start, even if we got some Attributes
throw e;
} catch (Exception e) {
if (problemNames != null)
{
problemNames.add(name);
}
}
}
return (attrs);
}
/**
Get the Attributes using getAttributes() if possible, but if exceptions
are encountered, attempt to get them one-by-one.
@param conn the conneciton
@param objectName name of the object to access
@param attrNames attribute names
@param problemNames optional Set to which problem names will be added.
@return AttributeList
*/
public static AttributeList getAttributesRobust(
MBeanServerConnection conn,
ObjectName objectName,
String[] attrNames,
Set problemNames)
throws InstanceNotFoundException, IOException
{
AttributeList attrs = null;
if (problemNames != null)
{
problemNames.clear();
}
try
{
attrs = conn.getAttributes(objectName, attrNames);
if (attrs == null)
{
attrs = new AttributeList();
}
}
catch (InstanceNotFoundException e)
{
// if it's not found, we can't do anything about it.
throw e;
}
catch (IOException e)
{
if (connectionIsDead(conn))
{
throw e;
}
// connection is still good
attrs = getAttributesSingly(conn, objectName, attrNames, problemNames);
}
catch (Exception e)
{
attrs = getAttributesSingly(conn, objectName, attrNames, problemNames);
}
return (attrs);
}
public static boolean isIs(final Method method)
{
return (method.getName().startsWith(IS) && method.getParameterTypes().length == 0);
}
/**
Return true if the method is of the form isXyz() or getXyz()
(no parameters)
*/
public static boolean isGetter(Method method)
{
return (method.getName().startsWith(GET) && method.getParameterTypes().length == 0);
}
public static boolean isGetter(final MBeanOperationInfo info)
{
return (info.getName().startsWith(GET) &&
info.getSignature().length == 0 &&
!info.getReturnType().equals("void"));
}
public static Set findOperations(
final MBeanOperationInfo[] operations,
final String operationName)
{
final Set items = new HashSet();
for (int i = 0; i < operations.length; ++i)
{
if (operations[i].getName().equals(operationName))
{
items.add(operations[i]);
}
}
return items;
}
public static MBeanOperationInfo findOperation(
final MBeanOperationInfo[] operations,
final String operationName,
final String[] types)
{
MBeanOperationInfo result = null;
for (int i = 0; i < operations.length; ++i)
{
final MBeanOperationInfo info = operations[i];
if (info.getName().equals(operationName))
{
final MBeanParameterInfo[] sig = info.getSignature();
if (sig.length == types.length)
{
result = info; // assume match...
for (int j = 0; j < sig.length; ++j)
{
if (!types[j].equals(sig[j].getType()))
{
result = null; // no match
break;
}
}
}
}
}
return (result);
}
/**
Return true if the method is of the form isXyz() or getXyz()
(no parameters)
*/
public static boolean isIsOrGetter(Method method)
{
return (isGetter(method) || isIs(method));
}
public static String getAttributeName(final Method method) {
final String methodName = method.getName();
int prefixLength;
if (methodName.startsWith(GET) || methodName.startsWith(SET)) {
prefixLength = 3;
} else {
prefixLength = 2;
}
return (methodName.substring(prefixLength, methodName.length()));
}
public static boolean isSetter(Method method)
{
return (method.getName().startsWith(SET) &&
method.getParameterTypes().length == 1 &&
method.getParameterTypes()[ 0] != Attribute.class &&
method.getReturnType().equals(Void.TYPE));
}
public static boolean isGetAttribute(Method m)
{
return (m.getName().equals("getAttribute") &&
m.getParameterTypes().length == 1 && m.getParameterTypes()[ 0] == String.class);
}
public static boolean isGetAttributes(Method m)
{
return (m.getName().equals("getAttributes") &&
m.getParameterTypes().length == 1 && m.getParameterTypes()[ 0] == String[].class);
}
public static boolean isSetAttribute(Method m)
{
return (m.getName().equals("setAttribute") &&
m.getParameterTypes().length == 1 && m.getParameterTypes()[ 0] == Attribute.class);
}
public static boolean isSetAttributes(Method m)
{
return (m.getName().equals("setAttributes") &&
m.getParameterTypes().length == 1 && m.getParameterTypes()[ 0] == AttributeList.class);
}
public static ArrayList generateAttributeInfos(
final Collection methodSet,
final boolean read,
final boolean write)
{
final ArrayList infos = new ArrayList();
assert (methodSet != null);
for (final Method m : methodSet)
{
final String methodName = m.getName();
assert (read || (write && methodName.startsWith(SET)));
final MBeanAttributeInfo info = new MBeanAttributeInfo(
getAttributeName(m),
m.getReturnType().getName(),
methodName,
read,
write,
methodName.startsWith("is"));
infos.add(info);
}
return (infos);
}
public static MBeanAttributeInfo[] generateMBeanAttributeInfos(
final Collection getterSetters,
final Collection getters,
final Collection setters)
{
final ArrayList attrsList = new ArrayList();
attrsList.addAll(generateAttributeInfos(getterSetters, true, true));
attrsList.addAll(generateAttributeInfos(getters, true, false));
attrsList.addAll(generateAttributeInfos(setters, false, true));
final MBeanAttributeInfo[] attrs = new MBeanAttributeInfo[attrsList.size()];
attrsList.toArray(attrs);
return (attrs);
}
public static String[] getSignature(final MBeanParameterInfo[] infos)
{
final String[] sig = new String[infos.length];
int i = 0;
for (final MBeanParameterInfo info : infos)
{
sig[i] = info.getType();
++i;
}
return sig;
}
public static MBeanParameterInfo[] generateSignature(final Class[] sig)
{
final MBeanParameterInfo[] infos = new MBeanParameterInfo[sig.length];
for (int i = 0; i < sig.length; ++i)
{
final Class paramClass = sig[i];
final String name = "p" + i;
final String type = paramClass.getName();
final String description = paramClass.getName();
final MBeanParameterInfo info =
new MBeanParameterInfo(name, type, description);
infos[i] = info;
}
return (infos);
}
public static MBeanOperationInfo[] generateMBeanOperationInfos(
final Collection methodSet)
{
final MBeanOperationInfo[] infos = new MBeanOperationInfo[methodSet.size()];
final Iterator iter = methodSet.iterator();
int i = 0;
while (iter.hasNext())
{
final Method m = (Method) iter.next();
final String methodName = m.getName();
final MBeanOperationInfo info = new MBeanOperationInfo(
methodName,
methodName,
generateSignature(m.getParameterTypes()),
m.getReturnType().getName(),
MBeanOperationInfo.UNKNOWN);
infos[i] = info;
++i;
}
return (infos);
}
public static MBeanInfo interfaceToMBeanInfo(final Class theInterface)
{
final Method[] methods = theInterface.getMethods();
final Map getters = new HashMap();
final Map setters = new HashMap();
final Map getterSetters = new HashMap();
final Set operations = new HashSet();
for (int i = 0; i < methods.length; ++i)
{
final Method method = methods[i];
String attrName = null;
if (isIsOrGetter(method))
{
attrName = getAttributeName(method);
getters.put(attrName, method);
}
else if (isSetter(method))
{
attrName = getAttributeName(method);
setters.put(attrName, method);
}
else
{
operations.add(method);
}
if ((attrName != null) &&
getters.containsKey(attrName) &&
setters.containsKey(attrName))
{
final Method getter = getters.get(attrName);
final Class getterType = getter.getReturnType();
final Class setterType = setters.get(attrName).getParameterTypes()[ 0];
if (getterType == setterType)
{
getters.remove(attrName);
setters.remove(attrName);
getterSetters.put(attrName, getter);
}
else
{
throw new IllegalArgumentException("Attribute " + attrName +
"has type " + getterType.getName() + " as getter but type " +
setterType.getName() + " as setter");
}
}
}
final MBeanAttributeInfo[] attrInfos =
generateMBeanAttributeInfos(getterSetters.values(),
getters.values(), setters.values());
final MBeanOperationInfo[] operationInfos =
generateMBeanOperationInfos(operations);
final MBeanInfo mbeanInfo = new MBeanInfo(
theInterface.getName(),
theInterface.getName(),
attrInfos,
null,
operationInfos,
null);
return (mbeanInfo);
}
/**
Merge two MBeanAttributeInfo[]. info1 overrides any duplication in info2.
@param infos1
@param infos2
*/
public static MBeanAttributeInfo[] mergeMBeanAttributeInfos(
final MBeanAttributeInfo[] infos1,
final MBeanAttributeInfo[] infos2)
{
// first make a Set of all names in infos1
final Set names = new HashSet();
for (final MBeanAttributeInfo info : infos1)
{
names.add(info.getName());
}
final Set merged = SetUtil.newSet(infos1);
for (final MBeanAttributeInfo info2 : infos2)
{
final String info2Name = info2.getName();
if (!names.contains(info2Name))
{
merged.add(info2);
}
}
final MBeanAttributeInfo[] infosArray = new MBeanAttributeInfo[merged.size()];
merged.toArray(infosArray);
return (infosArray);
}
/**
Merge two MBeanNotificationInfo[].
@param infos1
@param infos2
*/
public static MBeanNotificationInfo[] mergeMBeanNotificationInfos(
final MBeanNotificationInfo[] infos1,
final MBeanNotificationInfo[] infos2)
{
if (infos1 == null)
{
return infos2;
}
else if (infos2 == null)
{
return (infos1);
}
final Set all = SetUtil.newSet(infos1);
all.addAll(SetUtil.newSet(infos2));
final MBeanNotificationInfo[] merged = new MBeanNotificationInfo[all.size()];
return all.toArray(merged);
}
/**
Merge two descriptors. Values in 'src' override values in 'dest', but neither is
modified, a new one is returned.
*/
public static DescriptorSupport mergeDescriptors(
final Descriptor src,
final Descriptor dest)
{
final DescriptorSupport d = new DescriptorSupport();
// do it manually, the APIs screw up booleans making the "(true)" instead of "true".
String[] fieldNames = dest.getFieldNames();
for (final String fieldName : fieldNames)
{
d.setField(fieldName, dest.getFieldValue(fieldName));
}
// now overwrite conflicting fields with those from 'src'
fieldNames = src.getFieldNames();
for (final String fieldName : fieldNames)
{
d.setField(fieldName, src.getFieldValue(fieldName));
}
return d;
}
/**
Add MBeanNotificationInfo into the MBeanInfo.
@param origInfo
@param notifs
*/
public static MBeanInfo addNotificationInfos(
final MBeanInfo origInfo,
final MBeanNotificationInfo[] notifs)
{
MBeanInfo result = origInfo;
if (notifs != null && notifs.length != 0)
{
result = new MBeanInfo(
origInfo.getClassName(),
origInfo.getDescription(),
origInfo.getAttributes(),
origInfo.getConstructors(),
origInfo.getOperations(),
mergeMBeanNotificationInfos(origInfo.getNotifications(), notifs),
origInfo.getDescriptor());
}
return result;
}
/**
Merge two MBeanOperationInfo[].
@param infos1
@param infos2
*/
public static MBeanOperationInfo[] mergeMBeanOperationInfos(
final MBeanOperationInfo[] infos1,
final MBeanOperationInfo[] infos2)
{
if (infos1 == null)
{
return infos2;
}
else if (infos2 == null)
{
return (infos1);
}
final Set all = SetUtil.newSet(infos1);
all.addAll(SetUtil.newSet(infos2));
final MBeanOperationInfo[] merged = new MBeanOperationInfo[all.size()];
return all.toArray(merged);
}
/**
Merge two MBeanOperationInfo[].
@param infos1
@param infos2
*/
public static MBeanConstructorInfo[] mergeMBeanConstructorInfos(
final MBeanConstructorInfo[] infos1,
final MBeanConstructorInfo[] infos2)
{
if (infos1 == null)
{
return infos2;
}
else if (infos2 == null)
{
return (infos1);
}
final Set all = SetUtil.newSet(infos1);
all.addAll(SetUtil.newSet(infos2));
final MBeanConstructorInfo[] merged = new MBeanConstructorInfo[all.size()];
return all.toArray(merged);
}
/**
Make a new MBeanInfo from an existing one, substituting MBeanAttributeInfo[]
@param origMBeanInfo
@param newAttrInfos
*/
public static MBeanInfo newMBeanInfo(
final MBeanInfo origMBeanInfo,
final MBeanAttributeInfo[] newAttrInfos)
{
final MBeanInfo info = new MBeanInfo(
origMBeanInfo.getClassName(),
origMBeanInfo.getDescription(),
newAttrInfos,
origMBeanInfo.getConstructors(),
origMBeanInfo.getOperations(),
origMBeanInfo.getNotifications(),
origMBeanInfo.getDescriptor());
return (info);
}
/**
Make a new MBeanInfo from an existing one, substituting MBeanOperationInfo[]
@param origMBeanInfo
@param newOps
*/
public static MBeanInfo newMBeanInfo(
final MBeanInfo origMBeanInfo,
final MBeanOperationInfo[] newOps)
{
final MBeanInfo info = new MBeanInfo(origMBeanInfo.getClassName(),
origMBeanInfo.getDescription(),
origMBeanInfo.getAttributes(),
origMBeanInfo.getConstructors(),
newOps,
origMBeanInfo.getNotifications(),
origMBeanInfo.getDescriptor());
return (info);
}
/**
Find the index within the MBeanOperationInfo[] of the specified method with the
specified parameter types. If parameterTypes
is null, then the
first operation whose name matches is returned.
@param info
@param methodName
@param parameterTypes
@return the index of the MBeanOperationInfo, or -1 if not found
*/
public static int findMBeanOperationInfo(
final MBeanInfo info,
final String methodName,
final String[] parameterTypes)
{
int resultIdx = -1;
final MBeanOperationInfo[] ops = info.getOperations();
for (int i = 0; i < ops.length; ++i)
{
final MBeanOperationInfo op = ops[i];
if (op.getName().equals(methodName) &&
(parameterTypes == null ||
ArrayUtil.arraysEqual(parameterTypes, op.getSignature())))
{
resultIdx = i;
break;
}
}
return resultIdx;
}
public static boolean domainMatches(final String defaultDomain, final ObjectName pattern, final ObjectName candidate) {
boolean matches;
final String candidateDomain = candidate.getDomain();
if (pattern.isDomainPattern()) {
final String regex = RegexUtil.wildcardToJavaRegex(pattern.getDomain());
matches = Pattern.matches(regex, candidateDomain);
} else {
// domain is not a pattern
String patternDomain = pattern.getDomain();
if (patternDomain.length() == 0) {
patternDomain = defaultDomain;
}
matches = patternDomain.equals(candidateDomain);
}
return (matches);
}
public static boolean matchesPattern(
final String defaultDomain,
final ObjectName pattern,
final ObjectName candidate)
{
boolean matches = false;
if (domainMatches(defaultDomain, pattern, candidate))
{
final String patternProps = pattern.getCanonicalKeyPropertyListString();
final String candidateProps = candidate.getCanonicalKeyPropertyListString();
assert (patternProps.indexOf('*') < 0);
assert (candidateProps.indexOf('*') < 0);
// Since we used canonical form any match means the pattern props String
// must be a substring of candidateProps
if (candidateProps.contains(patternProps))
{
matches = true;
}
}
return (matches);
}
public static Notification cloneNotification(
final Notification in,
final Object source)
{
Notification out = null;
if (in instanceof AttributeChangeNotification &&
in.getClass() == AttributeChangeNotification.class)
{
final AttributeChangeNotification a = (AttributeChangeNotification) in;
out = new AttributeChangeNotification(
source,
a.getSequenceNumber(),
a.getTimeStamp(),
a.getMessage(),
a.getAttributeName(),
a.getAttributeType(),
a.getOldValue(),
a.getNewValue());
}
else if (in.getClass() == Notification.class)
{
out = new Notification(
in.getType(),
source,
in.getSequenceNumber(),
in.getTimeStamp(),
in.getMessage());
}
else
{
throw new IllegalArgumentException("Not supporting cloning of: " + in.getClass());
}
return out;
}
/**
The sole purpose of this method is to move compiler warnings here, thus
eliminating them from other call sites. May be removed when JMX becomes
generified.
*/
public static Set queryNames(
final MBeanServerConnection conn,
final ObjectName pattern,
final QueryExp exp)
throws java.io.IOException
{
return TypeCast.asSet(conn.queryNames(pattern, exp));
}
public static Set queryAllInDomain(
final MBeanServerConnection conn,
final String domain)
throws java.io.IOException
{
return queryNames(conn, newObjectNamePattern(domain, ""), null);
}
public static Set queryAllInDomain(
final MBeanServer conn,
final String domain)
{
return queryNames(conn, newObjectNamePattern(domain, ""), null);
}
public static Set queryLocalMBeans(
final MBeanServer conn,
final String domain,
final String server)
{
return queryNames(conn, newObjectNamePattern(domain, "instance="+server), null);
}
/**
The sole purpose of this method is to move compiler warnings here, thus
eliminating them from other call sites. May be removed when JMX becomes
generified.
*/
public static Set queryNames(
final MBeanServer server,
final ObjectName pattern,
final QueryExp exp)
{
try
{
return queryNames((MBeanServerConnection) server, pattern, exp);
}
catch (final IOException e)
{
// ignore, can't happen.
}
return Collections.emptySet();
}
/**
Get a Map from the user data field of a Notification.
This variant requires Map.
*/
public static Map getUserDataMapString_Serializable(final Notification notif)
{
final Object userData = notif.getUserData();
if (!(userData instanceof Map))
{
throw new IllegalArgumentException();
}
final Map result = TypeCast.asMap((Map) userData);
if (result != null)
{
// verify that it's a Map
for (final Map.Entry me : result.entrySet())
{
result.put(me.getKey(), me.getValue());
}
}
return result;
}
public static String interfaceName(final MBeanInfo info)
{
final Descriptor d = info.getDescriptor();
return (String) d.getFieldValue("interfaceName");
}
/** convenience function to avoid try/catch. A RuntimeException is thrown if there is a problem */
public static Object getAttribute(final MBeanServerConnection conn, final ObjectName o, final String attrName)
{
try
{
return conn.getAttribute(o, attrName);
}
catch (final Exception e)
{
throw new RuntimeException("Can't get attribute " + attrName, e);
}
}
public static T remove(final List infos, final String name)
{
T removed = null;
for (final T info : infos)
{
if (info.getName().equals(name))
{
removed = info;
infos.remove(info);
break;
}
}
return removed;
}
private static String title(final MBeanFeatureInfo info)
{
return info.getName() + ", \"" + info.getDescription() + "\"";
}
public static String toString(final Descriptor d, final int indent)
{
final String NL = StringUtil.LS;
final StringBuilder buf = new StringBuilder();
if (d != null && d.getFieldNames().length != 0)
{
buf.append(idt(indent)).append("Descriptor = ").append(NL);
for (final String fieldName : d.getFieldNames())
{
buf.append(idt(indent + 2)).append(nvp(fieldName, d.getFieldValue(fieldName))).append(NL);
}
buf.append(NL);
}
return buf.toString();
}
public static String impactStr(final int impact)
{
String s;
switch (impact) {
case MBeanOperationInfo.INFO:
s = "INFO";
break;
case MBeanOperationInfo.ACTION:
s = "ACTION";
break;
case MBeanOperationInfo.UNKNOWN:
s = "UNKNOWN";
break;
case MBeanOperationInfo.ACTION_INFO:
s = "ACTION_INFO";
break;
default:
s = "" + impact;
break;
}
return s;
}
public static String toString(final MBeanOperationInfo info, final int indent)
{
final String NL = StringUtil.LS;
final StringBuilder buf = new StringBuilder();
final String idt = idt(indent + 2);
buf.append(idt(indent)).append(title(info)).append(NL);
buf.append(idt).append(nvp("Impact", impactStr(info.getImpact()))).append(NL);
buf.append(idt).append(nvp("ReturnType", info.getReturnType())).append(NL);
buf.append(idt).append(nvp("Param count", info.getSignature().length)).append(NL);
final Descriptor d = info.getDescriptor();
if (d != null)
{
buf.append(toString(d, indent + 2));
}
return buf.toString();
}
public static String toString(final MBeanAttributeInfo info, final int indent)
{
final String NL = StringUtil.LS;
final StringBuilder buf = new StringBuilder();
final String idt = idt(indent + 2);
String rw = info.isReadable() ? "R" : "";
if (info.isWritable())
{
rw = rw + "W";
}
if (info.isIs())
{
rw = rw + ",is";
}
buf.append(idt(indent)).append(title(info)).append(NL);
buf.append(idt).append(nvp("Type", info.getType())).append(NL);
buf.append(idt).append(nvp("Access", rw)).append(NL);
final Descriptor d = info.getDescriptor();
if (d != null)
{
buf.append(toString(d, indent + 2));
}
if (info instanceof OpenMBeanAttributeInfo)
{
final OpenMBeanAttributeInfo open = (OpenMBeanAttributeInfo) info;
buf.append(idt).append(nvp("OpenType", open.getOpenType().toString())).append(NL);
buf.append(idt).append(nvp("hasLegalValues", open.hasLegalValues())).append(NL);
buf.append(idt).append(nvp("hasDefaultValue", open.hasDefaultValue())).append(NL);
buf.append(idt).append(nvp("hasMinValue", open.hasMinValue())).append(NL);
buf.append(idt).append(nvp("hasMaxValue", open.hasMaxValue())).append(NL);
if (open.hasDefaultValue())
{
buf.append(idt).append(nvp("DefaultValue", open.getDefaultValue())).append(NL);
}
}
return buf.toString();
}
/**
Produce a nice friendly text dump of the MBeanInfo; the standard toString() is unreadable.
*/
public static String toString(final MBeanInfo info)
{
final StringBuilder buf = new StringBuilder();
final String NL = StringUtil.LS;
int indent = 2;
buf.append("Classname: ").append(info.getClassName()).append(NL);
buf.append("Description: ").append(info.getDescription()).append(NL);
buf.append(toString(info.getDescriptor(), indent + 2));
buf.append(idt(indent)).append("Attributes").append(NL);
final MBeanAttributeInfo[] attrInfos = info.getAttributes();
if (attrInfos.length == 0)
{
buf.append(idt(indent + 2)).append("");
}
else
{
for (final MBeanAttributeInfo attrInfo : attrInfos)
{
buf.append(toString(attrInfo, indent + 2));
buf.append(NL);
}
}
buf.append(idt(indent)).append("Operations").append(NL);
final MBeanOperationInfo[] opInfos = info.getOperations();
if (info.getOperations().length == 0)
{
buf.append(idt(indent + 2)).append("");
}
else
{
for (final MBeanOperationInfo opInfo : opInfos)
{
buf.append(toString(opInfo, indent + 2));
}
}
return buf.toString();
}
private static String idt(final int num)
{
final StringBuilder buf = new StringBuilder();
for (int i = 0; i < num; ++i)
{
buf.append(" ");
}
return buf.toString();
}
private static String nvp(final String name, final Object value)
{
return name + " = " + SmartStringifier.DEFAULT.stringify(value);
}
}