/*
* Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code 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 General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 4950756
* @summary Test that RequiredModelMBean.invoke will not invoke methods
* from the RequiredModelMBean class itself if they are not in the
* ModelMBeanInfo
* @author Eamonn McManus
* @run clean RequiredModelMBeanMethodTest
* @run build RequiredModelMBeanMethodTest
* @run main RequiredModelMBeanMethodTest
*/
import java.lang.reflect.*;
import javax.management.*;
import javax.management.modelmbean.*;
/*
* We do the same test with a number of different operations:
*
* - A plain operation that is directed to the managed resource in the
* usual way. We give it some parameters so we can test that the
* class loading logic for signature parameters is reasonable.
*
* - An operation (removeNotificationListener) that is directed to the
* RequiredModelMBean itself. We use this particular operation because
* it will throw an exception, which allows us to check that it did in
* fact execute.
*
* - An operation (load()) that has the same signature as a
* RequiredModelMBean operation but is directed to the resource
* because of a "class" field in the descriptor.
*
* - An operation (store()) that has the same signature as a
* RequiredModelMBean operation but is directed to the resource
* because of a "targetObject" field in the descriptor.
*
* In each case we check that the operation does not work if it is not
* in the ModelMBeanInfo, and does work if it is.
*/
public class RequiredModelMBeanMethodTest {
public static void main(String[] args) throws Exception {
boolean ok = true;
MBeanServer mbs = MBeanServerFactory.createMBeanServer();
Descriptor tralalaDescriptor =
new DescriptorSupport(new String[] {
"name=tralala",
"descriptorType=operation",
"role=operation",
"targetType=ObjectReference",
});
Method tralalaMethod =
Resource.class.getMethod("tralala",
new Class[] {int.class, Resource.class});
ModelMBeanOperationInfo tralalaInfo =
new ModelMBeanOperationInfo("tralala descr", tralalaMethod,
tralalaDescriptor);
Method remACNLMethod =
RequiredModelMBean.class.getMethod("removeAttributeChangeNotificationListener",
new Class[] {
NotificationListener.class,
String.class
});
ModelMBeanOperationInfo remACNLInfo =
new ModelMBeanOperationInfo("remACNL descr", remACNLMethod);
Descriptor loadDescriptor =
new DescriptorSupport(new String[] {
"name=load",
"descriptorType=operation",
"role=operation",
"targetType=ObjectReference",
"class=" + Resource.class.getName(),
});
ModelMBeanOperationInfo loadInfo =
new ModelMBeanOperationInfo("load", "load descr",
new MBeanParameterInfo[0],
"void", ModelMBeanOperationInfo.ACTION,
loadDescriptor);
Descriptor storeDescriptor =
new DescriptorSupport(new String[] {
"name=store",
"descriptorType=operation",
"role=operation",
"targetType=ObjectReference",
});
storeDescriptor.setField("targetObject", resource);
ModelMBeanOperationInfo storeInfo =
new ModelMBeanOperationInfo("store", "store descr",
new MBeanParameterInfo[0],
"void", ModelMBeanOperationInfo.ACTION,
storeDescriptor);
ModelMBeanInfo emptyMMBI =
new ModelMBeanInfoSupport(Resource.class.getName(),
"empty descr",
null, null, null, null);
ModelMBean emptyMMB = new RequiredModelMBean(emptyMMBI);
emptyMMB.setManagedResource(resource, "ObjectReference");
ObjectName emptyMMBName = new ObjectName("test:type=Empty");
mbs.registerMBean(emptyMMB, emptyMMBName);
System.out.println("Testing that we cannot call methods not in the " +
"ModelMBeanInfo");
try {
boolean thisok = test(mbs, emptyMMBName, false);
if (thisok)
System.out.println("...OK");
else
ok = false;
} catch (Exception e) {
System.out.println("TEST FAILED: Caught exception:");
e.printStackTrace(System.out);
ok = false;
}
ModelMBeanOperationInfo[] opInfos = {
tralalaInfo, remACNLInfo, loadInfo, storeInfo,
};
ModelMBeanInfo fullMMBI =
new ModelMBeanInfoSupport(Resource.class.getName(),
"full descr",
null, null, opInfos, null);
ModelMBean fullMMB = new RequiredModelMBean(fullMMBI);
fullMMB.setManagedResource(resource, "ObjectReference");
ObjectName fullMMBName = new ObjectName("test:type=Full");
mbs.registerMBean(fullMMB, fullMMBName);
System.out.println();
System.out.println("Testing that we can call methods in the " +
"ModelMBeanInfo");
System.out.println(" and that \"class\" or \"targetObject\" in " +
"descriptor directs methods to resource");
try {
boolean thisok = test(mbs, fullMMBName, true);
if (thisok)
System.out.println("...OK");
else
ok = false;
} catch (Exception e) {
System.out.println("TEST FAILED: Caught exception:");
e.printStackTrace(System.out);
ok = false;
}
if (ok) {
if (!resource.loadCalled || !resource.storeCalled) {
System.out.println("TEST FAILED: not called:" +
(resource.loadCalled ? "" : " load") +
(resource.storeCalled ? "" : " store"));
ok = false;
}
}
// Test the invoke("class.method") form
if (ok) {
System.out.println("Testing invoke(\"class.method\")");
resource.loadCalled = false;
mbs.invoke(fullMMBName, Resource.class.getName() + ".load",
null, null);
if (!resource.loadCalled) {
System.out.println("TEST FAILED: load not called");
ok = false;
}
try {
mbs.invoke(fullMMBName,
RequiredModelMBean.class.getName() +
".removeAttributeChangeNotificationListener",
new Object[] {boringListener, null},
new String[] {
NotificationListener.class.getName(),
String.class.getName(),
});
System.out.println("TEST FAILED: removeNotificationListener" +
" returned successfully but " +
"should not have");
ok = false;
} catch (MBeanException e) {
final Exception target = e.getTargetException();
if (target instanceof ListenerNotFoundException) {
// OK: there is no such listener
} else
throw e;
}
}
if (ok)
System.out.println("Test passed");
else {
System.out.println("TEST FAILED");
System.exit(1);
}
}
private static boolean test(MBeanServer mbs, ObjectName name,
boolean shouldWork)
throws Exception {
boolean ok = true;
final String[] names = {
"tralala",
"removeAttributeChangeNotificationListener",
"load",
"store",
};
for (int i = 0; i < 4; i++) {
boolean thisok = true;
try {
switch (i) {
case 0:
String tralala = (String)
mbs.invoke(name, names[i],
new Object[] {new Integer(5), resource},
new String[] {"int",
Resource.class.getName()});
if (!"tralala".equals(tralala)) {
System.out.println("TEST FAILED: tralala returned: " +
tralala);
thisok = false;
}
break;
case 1:
try {
mbs.invoke(name,
names[i],
new Object[] {boringListener, null},
new String[] {
NotificationListener.class.getName(),
String.class.getName(),
});
System.out.println("TEST FAILED: " + names[i] +
" returned successfully but " +
"should not have");
thisok = false;
} catch (MBeanException e) {
final Exception target = e.getTargetException();
if (target instanceof ListenerNotFoundException) {
// OK: there is no such listener
} else
throw e;
}
break;
case 2:
case 3:
mbs.invoke(name,
names[i],
new Object[0],
new String[0]);
break;
default:
throw new AssertionError();
}
thisok = shouldWork;
if (!shouldWork) {
System.out.println("TEST FAILED: " + names[i] +
" worked but should not");
}
} catch (MBeanException e) {
if (shouldWork) {
System.out.println("TEST FAILED: " + names[i] + ": " + e);
e.printStackTrace(System.out);
thisok = false;
} else {
Exception target = e.getTargetException();
if (!(target instanceof ServiceNotFoundException)) {
System.out.println("TEST FAILED: " + names[i] +
": wrong exception: " + target);
thisok = false;
}
}
} catch (Exception e) {
System.out.println("TEST FAILED: " + names[i] + ": " + e);
e.printStackTrace(System.out);
thisok = false;
}
if (thisok)
System.out.println("OK: " + names[i]);
else
ok = false;
}
return ok;
}
public static class Resource {
public String tralala(int x, Resource y) {
if (x != 5 || y != this)
return "wrong params: " + x + " " + y;
return "tralala";
}
public void load() {
loadCalled = true;
}
public void store() {
storeCalled = true;
}
boolean loadCalled, storeCalled;
}
private static Resource resource = new Resource();
private static NotificationListener boringListener =
new NotificationListener() {
public void handleNotification(Notification n, Object h) {
}
};
}