/**
* Copyright (c) 2000-present Liferay, Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 2.1 of the License, or (at your option)
* any later version.
*
* This library 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 Lesser General Public License for more
* details.
*/
package com.liferay.portal.fabric.status;
import com.liferay.portal.fabric.status.JMXProxyUtil.GetAttributeProcessCallable;
import com.liferay.portal.fabric.status.JMXProxyUtil.JMXProxyInvocationHandler;
import com.liferay.portal.fabric.status.JMXProxyUtil.OperationProcessCallable;
import com.liferay.portal.fabric.status.JMXProxyUtil.Optional;
import com.liferay.portal.fabric.status.JMXProxyUtil.ProcessCallableExecutor;
import com.liferay.portal.fabric.status.JMXProxyUtil.SetAttributeProcessCallable;
import com.liferay.portal.kernel.concurrent.DefaultNoticeableFuture;
import com.liferay.portal.kernel.concurrent.NoticeableFuture;
import com.liferay.portal.kernel.process.ProcessCallable;
import com.liferay.portal.kernel.process.ProcessException;
import com.liferay.portal.kernel.test.rule.CodeCoverageAssertor;
import com.liferay.portal.kernel.test.util.RandomTestUtil;
import com.liferay.portal.kernel.util.ProxyUtil;
import com.liferay.portal.kernel.util.ReflectionUtil;
import java.io.Serializable;
import java.lang.management.CompilationMXBean;
import java.lang.management.LockInfo;
import java.lang.management.ManagementFactory;
import java.lang.management.MemoryUsage;
import java.lang.management.MonitorInfo;
import java.lang.management.PlatformManagedObject;
import java.lang.management.ThreadInfo;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import javax.management.AttributeNotFoundException;
import javax.management.InstanceNotFoundException;
import javax.management.MBeanServer;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import javax.management.openmbean.CompositeData;
import javax.management.openmbean.CompositeDataSupport;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.ClassRule;
import org.junit.Test;
/**
* @author Shuyang Zhou
*/
public class JMXProxyUtilTest {
@ClassRule
public static final CodeCoverageAssertor codeCoverageAssertor =
CodeCoverageAssertor.INSTANCE;
@Before
public void setUp() throws Exception {
MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
mBeanServer.registerMBean(_testClass, _testClassObjectName);
}
@After
public void tearDown() throws Exception {
MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
mBeanServer.unregisterMBean(_testClassObjectName);
}
@Test
public void testConstructor() {
new JMXProxyUtil();
}
@Test
public void testDecodeArrayToList() {
String[] stringArray = RandomTestUtil.randomStrings(10);
Object stringList = JMXProxyUtil.decode(List.class, stringArray);
Assert.assertEquals(Arrays.asList(stringArray), stringList);
String string = RandomTestUtil.randomString();
Assert.assertSame(string, JMXProxyUtil.decode(List.class, string));
}
@Test
public void testDecodeCompositeData() throws Exception {
MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
CompositeDataSupport compositeDataSupport =
(CompositeDataSupport)mBeanServer.getAttribute(
createObjectName(ManagementFactory.MEMORY_MXBEAN_NAME),
"HeapMemoryUsage");
MemoryUsage memoryUsage = (MemoryUsage)JMXProxyUtil.decode(
MemoryUsage.class, compositeDataSupport);
Assert.assertEquals(
compositeDataSupport.get("init"), memoryUsage.getInit());
Assert.assertEquals(
compositeDataSupport.get("used"), memoryUsage.getUsed());
Assert.assertEquals(
compositeDataSupport.get("committed"), memoryUsage.getCommitted());
Assert.assertEquals(
compositeDataSupport.get("max"), memoryUsage.getMax());
Thread currentThread = Thread.currentThread();
CompositeData[] compositeDatas = (CompositeData[])mBeanServer.invoke(
createObjectName(ManagementFactory.THREAD_MXBEAN_NAME),
"getThreadInfo",
new Object[] {new long[] {currentThread.getId()}, true, true},
new String[] {
long[].class.getName(), boolean.class.getName(),
boolean.class.getName()
});
Assert.assertEquals(
Arrays.toString(compositeDatas), 1, compositeDatas.length);
compositeDataSupport = (CompositeDataSupport)compositeDatas[0];
ThreadInfo threadInfo = (ThreadInfo)JMXProxyUtil.decode(
ThreadInfo.class, compositeDataSupport);
Assert.assertEquals(
compositeDataSupport.get("threadId"), threadInfo.getThreadId());
Assert.assertEquals(
compositeDataSupport.get("threadName"), threadInfo.getThreadName());
Assert.assertEquals(
compositeDataSupport.get("suspended"), threadInfo.isSuspended());
Assert.assertEquals(
compositeDataSupport.get("inNative"), threadInfo.isInNative());
Assert.assertEquals(
compositeDataSupport.get("blockedCount"),
threadInfo.getBlockedCount());
Assert.assertEquals(
compositeDataSupport.get("blockedTime"),
threadInfo.getBlockedTime());
Assert.assertEquals(
compositeDataSupport.get("waitedCount"),
threadInfo.getWaitedCount());
Assert.assertEquals(
compositeDataSupport.get("waitedTime"), threadInfo.getWaitedTime());
assertEquals(
createLockInfo((CompositeData)compositeDataSupport.get("lockInfo")),
threadInfo.getLockInfo());
Assert.assertEquals(
compositeDataSupport.get("lockName"), threadInfo.getLockName());
Assert.assertEquals(
compositeDataSupport.get("lockOwnerId"),
threadInfo.getLockOwnerId());
Assert.assertEquals(
compositeDataSupport.get("lockOwnerName"),
threadInfo.getLockOwnerName());
Assert.assertArrayEquals(
createStackTraceElements(
(CompositeData[])compositeDataSupport.get("stackTrace")),
threadInfo.getStackTrace());
assertEquals(
createMonitorInfos(
(CompositeData[])compositeDataSupport.get("lockedMonitors")),
threadInfo.getLockedMonitors());
assertEquals(
createLockInfos(
(CompositeData[])compositeDataSupport.get(
"lockedSynchronizers")),
threadInfo.getLockedSynchronizers());
Assert.assertSame(
compositeDataSupport,
JMXProxyUtil.decode(Object.class, compositeDataSupport));
}
@Test
public void testDecodeCompositeDataArray() throws Exception {
MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
CompositeData[] compositeDatas = (CompositeData[])mBeanServer.invoke(
createObjectName(ManagementFactory.THREAD_MXBEAN_NAME),
"dumpAllThreads", new Object[] {true, true},
new String[] {boolean.class.getName(), boolean.class.getName()});
ThreadInfo[] threadInfos = (ThreadInfo[])JMXProxyUtil.decode(
ThreadInfo[].class, compositeDatas);
assertEquals(createThreadInfos(compositeDatas), threadInfos);
Assert.assertSame(
compositeDatas,
JMXProxyUtil.decode(ThreadInfo.class, compositeDatas));
}
@Test
public void testEquals() {
final ObjectName objectName = ObjectName.WILDCARD;
Assert.assertTrue(
JMXProxyUtil.equals(
objectName,
new PlatformManagedObject() {
@Override
public ObjectName getObjectName() {
return objectName;
}
}));
Assert.assertTrue(
JMXProxyUtil.equals(
objectName,
ProxyUtil.newProxyInstance(
JMXProxyUtil.class.getClassLoader(),
new Class<?>[] {Runnable.class},
new JMXProxyInvocationHandler(objectName, null))));
Assert.assertFalse(
JMXProxyUtil.equals(
objectName,
ProxyUtil.newProxyInstance(
JMXProxyUtil.class.getClassLoader(),
new Class<?>[] {Runnable.class},
new InvocationHandler() {
@Override
public Object invoke(
Object proxy, Method method, Object[] args) {
return null;
}
})));
Assert.assertFalse(JMXProxyUtil.equals(objectName, new Object()));
}
@Test
public void testGetAttributeProcessCallableFailureInstanceNotFound() {
GetAttributeProcessCallable getAttributeProcessCallable =
new GetAttributeProcessCallable(_unknowObjectName, "Name", true);
try {
getAttributeProcessCallable.call();
Assert.fail();
}
catch (ProcessException pe) {
Throwable throwable = pe.getCause();
Assert.assertSame(
InstanceNotFoundException.class, throwable.getClass());
}
}
@Test
public void testGetAttributeProcessCallableFailureInstanceOptional()
throws ProcessException {
GetAttributeProcessCallable getAttributeProcessCallable =
new GetAttributeProcessCallable(
_testClassObjectName, "NameX", true);
Assert.assertNull(getAttributeProcessCallable.call());
}
@Test
public void testGetAttributeProcessCallableFailureInstanceRequired() {
GetAttributeProcessCallable getAttributeProcessCallable =
new GetAttributeProcessCallable(
_testClassObjectName, "NameX", false);
try {
getAttributeProcessCallable.call();
Assert.fail();
}
catch (ProcessException pe) {
Throwable throwable = pe.getCause();
Assert.assertSame(
AttributeNotFoundException.class, throwable.getClass());
}
}
@Test
public void testIsGetGetter() {
Assert.assertTrue(JMXProxyUtil.isGetGetter("getXYZ"));
Assert.assertFalse(JMXProxyUtil.isGetGetter("getXYZ", Object.class));
Assert.assertFalse(JMXProxyUtil.isGetGetter("GetXYZ"));
}
@Test
public void testIsIsGetter() {
Assert.assertTrue(JMXProxyUtil.isIsGetter("isXYZ"));
Assert.assertFalse(JMXProxyUtil.isIsGetter("isXYZ", Object.class));
Assert.assertFalse(JMXProxyUtil.isIsGetter("IsXYZ"));
}
@Test
public void testIsObjectEquals() throws NoSuchMethodException {
Assert.assertTrue(
JMXProxyUtil.isObjectEquals(
Object.class.getMethod("equals", Object.class)));
Assert.assertFalse(
JMXProxyUtil.isObjectEquals(Object.class.getMethod("wait")));
class OverrideClass {
@Override
public boolean equals(Object object) {
return super.equals(object);
}
@Override
public int hashCode() {
return super.hashCode();
}
}
Assert.assertFalse(
JMXProxyUtil.isObjectEquals(
OverrideClass.class.getMethod("equals", Object.class)));
}
@Test
public void testIsObjectHashCode() throws NoSuchMethodException {
Assert.assertTrue(
JMXProxyUtil.isObjectHashCode(Object.class.getMethod("hashCode")));
Assert.assertFalse(
JMXProxyUtil.isObjectHashCode(Object.class.getMethod("wait")));
class OverrideClass {
@Override
public boolean equals(Object object) {
return super.equals(object);
}
@Override
public int hashCode() {
return super.hashCode();
}
}
Assert.assertFalse(
JMXProxyUtil.isObjectHashCode(
OverrideClass.class.getMethod("hashCode")));
}
@Test
public void testIsObjectToString() throws NoSuchMethodException {
Assert.assertTrue(
JMXProxyUtil.isObjectToString(Object.class.getMethod("toString")));
Assert.assertFalse(
JMXProxyUtil.isObjectToString(Object.class.getMethod("wait")));
class OverrideClass {
@Override
public String toString() {
return super.toString();
}
}
Assert.assertFalse(
JMXProxyUtil.isObjectToString(
OverrideClass.class.getMethod("toString")));
}
@Test
public void testIsOptional() throws NoSuchMethodException {
class TestOptional {
@Optional
public void method1() {
}
@SuppressWarnings("unused")
public void method2() {
}
}
Assert.assertTrue(
JMXProxyUtil.isOptional(TestOptional.class.getMethod("method1")));
Assert.assertFalse(
JMXProxyUtil.isOptional(TestOptional.class.getMethod("method2")));
}
@Test
public void testIsSetter() {
Assert.assertTrue(JMXProxyUtil.isSetter("setXYZ", Object.class));
Assert.assertFalse(JMXProxyUtil.isSetter("setXYZ"));
Assert.assertFalse(JMXProxyUtil.isSetter("SetXYZ", Object.class));
}
@Test
public void testJMXProxyInvocationHandlerEquals() throws Throwable {
JMXProxyInvocationHandler jmxProxyInvocationHandler =
new JMXProxyInvocationHandler(
_testClassObjectName, _processCallableExecutor);
Assert.assertTrue(
(boolean)jmxProxyInvocationHandler.invoke(
null, Object.class.getMethod("equals", Object.class),
new Object[] {
new PlatformManagedObject() {
@Override
public ObjectName getObjectName() {
return _testClassObjectName;
}
}
}));
}
@Test
public void testJMXProxyInvocationHandlerHashCode() throws Throwable {
JMXProxyInvocationHandler jmxProxyInvocationHandler =
new JMXProxyInvocationHandler(
_testClassObjectName, _processCallableExecutor);
Assert.assertEquals(
_testClassObjectName.hashCode(),
(int)jmxProxyInvocationHandler.invoke(
null, Object.class.getMethod("hashCode"), new Object[0]));
}
@Test
public void testJMXProxyInvocationHandlerToString() throws Throwable {
JMXProxyInvocationHandler jmxProxyInvocationHandler =
new JMXProxyInvocationHandler(
_testClassObjectName, _processCallableExecutor);
Assert.assertEquals(
_testClassObjectName.toString(),
jmxProxyInvocationHandler.invoke(
null, Object.class.getMethod("toString"), new Object[0]));
}
@Test
public void testNewProxySystemClass() {
CompilationMXBean compilationMXBean =
ManagementFactory.getCompilationMXBean();
CompilationMXBean compilationMXBeanProxy = JMXProxyUtil.newProxy(
compilationMXBean.getObjectName(), CompilationMXBean.class,
_processCallableExecutor);
Assert.assertEquals(
compilationMXBean.getName(), compilationMXBeanProxy.getName());
Assert.assertEquals(
compilationMXBean.getObjectName(),
compilationMXBeanProxy.getObjectName());
Assert.assertEquals(
compilationMXBean.isCompilationTimeMonitoringSupported(),
compilationMXBeanProxy.isCompilationTimeMonitoringSupported());
}
@Test
public void testNewProxyUserClass() {
TestClassMXBean testClassMXBean = JMXProxyUtil.newProxy(
_testClassObjectName, TestClassMXBean.class,
_processCallableExecutor);
Assert.assertEquals(_testClass.getName(), testClassMXBean.getName());
String newName = "newName";
testClassMXBean.setName(newName);
Assert.assertEquals(newName, testClassMXBean.getName());
Assert.assertEquals(
"doSomething", testClassMXBean.doSomething("doSomething"));
}
@Test
public void testOperationProcessCallableFail() {
OperationProcessCallable operationProcessCallable =
new OperationProcessCallable(
_unknowObjectName, "doSomething", new Object[] {"doSomething"},
new String[] {String.class.getName()});
try {
operationProcessCallable.call();
Assert.fail();
}
catch (ProcessException pe) {
Throwable throwable = pe.getCause();
Assert.assertSame(
InstanceNotFoundException.class, throwable.getClass());
}
}
@Test
public void testOperationProcessCallableSuccess() throws ProcessException {
OperationProcessCallable operationProcessCallable =
new OperationProcessCallable(
_testClassObjectName, "doSomething",
new Object[] {"doSomething"},
new String[] {String.class.getName()});
Assert.assertEquals("doSomething", operationProcessCallable.call());
}
@Test
public void testSetAttributeProcessCallableFailureInstanceNotFound() {
SetAttributeProcessCallable setAttributeProcessCallable =
new SetAttributeProcessCallable(
_unknowObjectName, "Name", "newName", true);
try {
setAttributeProcessCallable.call();
Assert.fail();
}
catch (ProcessException pe) {
Throwable throwable = pe.getCause();
Assert.assertSame(
InstanceNotFoundException.class, throwable.getClass());
}
}
@Test
public void testSetAttributeProcessCallableFailureOptional()
throws ProcessException {
String oldName = _testClass.getName();
SetAttributeProcessCallable setAttributeProcessCallable =
new SetAttributeProcessCallable(
_testClassObjectName, "NameX", "newName", true);
Assert.assertNull(setAttributeProcessCallable.call());
Assert.assertEquals(oldName, _testClass.getName());
}
@Test
public void testSetAttributeProcessCallableFailureRequired() {
SetAttributeProcessCallable setAttributeProcessCallable =
new SetAttributeProcessCallable(
_testClassObjectName, "NameX", "newName", false);
try {
setAttributeProcessCallable.call();
Assert.fail();
}
catch (ProcessException pe) {
Throwable throwable = pe.getCause();
Assert.assertSame(
AttributeNotFoundException.class, throwable.getClass());
}
}
@Test
public void testSetAttributeProcessCallableSuccess()
throws ProcessException {
String newName = "newName";
SetAttributeProcessCallable setAttributeProcessCallable =
new SetAttributeProcessCallable(
_testClassObjectName, "Name", newName, true);
Assert.assertNull(setAttributeProcessCallable.call());
Assert.assertEquals(newName, _testClass.getName());
}
public interface TestClassMXBean {
public String doSomething(String s);
public String getName();
public boolean isValid();
public void setName(String name);
}
protected static void assertEquals(LockInfo lockInfo1, LockInfo lockInfo2) {
if (lockInfo1 == lockInfo2) {
return;
}
Assert.assertEquals(lockInfo1.getClassName(), lockInfo2.getClassName());
Assert.assertEquals(
lockInfo1.getIdentityHashCode(), lockInfo2.getIdentityHashCode());
}
protected static void assertEquals(
LockInfo[] lockInfos1, LockInfo[] lockInfos2) {
Assert.assertEquals(
Arrays.toString(lockInfos2), lockInfos1.length, lockInfos2.length);
for (int i = 0; i < lockInfos1.length; i++) {
assertEquals(lockInfos1[i], lockInfos2[i]);
}
}
protected static void assertEquals(
MonitorInfo[] monitorInfos1, MonitorInfo[] monitorInfos2) {
Assert.assertEquals(
Arrays.toString(monitorInfos2), monitorInfos1.length,
monitorInfos2.length);
for (int i = 0; i < monitorInfos1.length; i++) {
Assert.assertEquals(
monitorInfos1[i].getClassName(),
monitorInfos2[i].getClassName());
Assert.assertEquals(
monitorInfos1[i].getIdentityHashCode(),
monitorInfos2[i].getIdentityHashCode());
Assert.assertEquals(
monitorInfos1[i].getLockedStackDepth(),
monitorInfos2[i].getLockedStackDepth());
Assert.assertEquals(
monitorInfos1[i].getLockedStackFrame(),
monitorInfos2[i].getLockedStackFrame());
}
}
protected static void assertEquals(
ThreadInfo[] threadInfos1, ThreadInfo[] threadInfos2) {
Assert.assertEquals(
Arrays.toString(threadInfos2), threadInfos1.length,
threadInfos2.length);
for (int i = 0; i < threadInfos1.length; i++) {
Assert.assertEquals(
threadInfos1[i].toString(), threadInfos2[i].toString());
}
}
protected static LockInfo createLockInfo(CompositeData compositeData) {
if (compositeData == null) {
return null;
}
return new LockInfo(
(String)compositeData.get("className"),
(int)compositeData.get("identityHashCode"));
}
protected static LockInfo[] createLockInfos(
CompositeData[] compositeDatas) {
LockInfo[] lockInfos = new LockInfo[compositeDatas.length];
for (int i = 0; i < compositeDatas.length; i++) {
lockInfos[i] = createLockInfo(compositeDatas[i]);
}
return lockInfos;
}
protected static MonitorInfo[] createMonitorInfos(
CompositeData[] compositeDatas) {
MonitorInfo[] monitorInfos = new MonitorInfo[compositeDatas.length];
for (int i = 0; i < compositeDatas.length; i++) {
monitorInfos[i] = MonitorInfo.from(compositeDatas[i]);
}
return monitorInfos;
}
protected static ObjectName createObjectName(String name) {
try {
return new ObjectName(name);
}
catch (MalformedObjectNameException mone) {
return ReflectionUtil.throwException(mone);
}
}
protected static StackTraceElement[] createStackTraceElements(
CompositeData[] compositeDatas) {
StackTraceElement[] stackTraceElements =
new StackTraceElement[compositeDatas.length];
for (int i = 0; i < compositeDatas.length; i++) {
stackTraceElements[i] = new StackTraceElement(
(String)compositeDatas[i].get("className"),
(String)compositeDatas[i].get("methodName"),
(String)compositeDatas[i].get("fileName"),
(int)compositeDatas[i].get("lineNumber"));
}
return stackTraceElements;
}
protected static ThreadInfo[] createThreadInfos(
CompositeData[] compositeDatas) {
ThreadInfo[] threadInfos = new ThreadInfo[compositeDatas.length];
for (int i = 0; i < compositeDatas.length; i++) {
threadInfos[i] = ThreadInfo.from(compositeDatas[i]);
}
return threadInfos;
}
private final ProcessCallableExecutor _processCallableExecutor =
new ProcessCallableExecutor() {
@Override
public <V extends Serializable> NoticeableFuture<V> execute(
ProcessCallable<V> processCallable) {
DefaultNoticeableFuture<V> defaultNoticeableFuture =
new DefaultNoticeableFuture<>();
try {
defaultNoticeableFuture.set(processCallable.call());
}
catch (ProcessException pe) {
defaultNoticeableFuture.setException(pe);
}
return defaultNoticeableFuture;
}
};
private final TestClass _testClass = new TestClass(
TestClass.class.getName());
private final ObjectName _testClassObjectName = createObjectName(
"com.liferay:type=TestClass");
private final ObjectName _unknowObjectName = createObjectName(
"com.liferay:type=Unknown");
private static class TestClass implements TestClassMXBean {
public TestClass(String name) {
_name = name;
}
@Override
public String doSomething(String s) {
return s;
}
@Override
public String getName() {
return _name;
}
@Override
public boolean isValid() {
return true;
}
@Override
public void setName(String name) {
_name = name;
}
private String _name;
}
}