blob: 8b685741b793b72239c1b88c36ae798caa07a4c1 [file] [log] [blame]
/*
* Copyright 2007-2008 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
/*
* @test QueryNotifFilterTest
* @bug 6610917
* @summary Test the QueryNotificationFilter class
* @author Eamonn McManus
*/
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.management.Attribute;
import javax.management.AttributeChangeNotification;
import javax.management.MBeanAttributeInfo;
import javax.management.MBeanInfo;
import javax.management.MBeanServer;
import javax.management.MalformedObjectNameException;
import javax.management.Notification;
import javax.management.NotificationFilter;
import javax.management.ObjectInstance;
import javax.management.ObjectName;
import javax.management.Query;
import javax.management.QueryEval;
import javax.management.QueryExp;
import javax.management.QueryNotificationFilter;
public class QueryNotifFilterTest {
private static class Case {
final Notification notif;
final QueryExp query;
final boolean expect;
final Class<? extends Notification> notifClass;
Case(Notification notif, String query, boolean expect) {
this(notif, query, notif.getClass(), expect);
}
Case(Notification notif, String query,
Class<? extends Notification> notifClass, boolean expect) {
this(notif, Query.fromString(query), notifClass, expect);
}
Case(Notification notif, QueryExp query, boolean expect) {
this(notif, query, notif.getClass(), expect);
}
Case(Notification notif, QueryExp query,
Class<? extends Notification> notifClass, boolean expect) {
this.notif = notif;
this.query = query;
this.expect = expect;
this.notifClass = notifClass;
}
}
/* In principle users can create their own implementations of QueryExp
* and use them with QueryNotificationFilter. If they do so, then
* they can call any MBeanServer method. Not all of those methods
* will work with the special MBeanServer we concoct to analyze a
* Notification, but some will, including some that are not called
* by the standard queries. So we check each of those cases too.
*/
private static class ExoticCase {
final Notification trueNotif;
final Notification falseNotif;
final QueryExp query;
ExoticCase(Notification trueNotif, Notification falseNotif, QueryExp query) {
this.trueNotif = trueNotif;
this.falseNotif = falseNotif;
this.query = query;
}
}
private static abstract class ExoticQuery
extends QueryEval implements QueryExp {
private final String queryString;
ExoticQuery(String queryString) {
this.queryString = queryString;
}
abstract boolean apply(MBeanServer mbs, ObjectName name) throws Exception;
//@Override - doesn't override in JDK5
public boolean apply(ObjectName name) {
try {
return apply(getMBeanServer(), name);
} catch (Exception e) {
e.printStackTrace(System.out);
return false;
}
}
@Override
public String toString() {
return queryString;
}
}
private static ObjectName makeObjectName(String s) {
try {
return new ObjectName(s);
} catch (MalformedObjectNameException e) {
throw new RuntimeException(e);
}
}
public static class CustomNotification extends Notification {
public CustomNotification(String type, Object source, long seqNo) {
super(type, source, seqNo);
}
public String getName() {
return "claude";
}
public boolean isInteresting() {
return true;
}
}
private static final Notification simpleNotif =
new Notification("mytype", "source", 0L);
private static final Notification attrChangeNotif =
new AttributeChangeNotification(
"x", 0L, 0L, "msg", "AttrName", "int", 2, 3);
private static final ObjectName testObjectName = makeObjectName("a:b=c");
private static final Notification sourcedNotif =
new Notification("mytype", testObjectName, 0L);
private static final Notification customNotif =
new CustomNotification("mytype", testObjectName, 0L);
private static final Case[] testCases = {
new Case(simpleNotif, "Type = 'mytype'", true),
new Case(simpleNotif, "Type = 'mytype'",
Notification.class, true),
new Case(simpleNotif, "Type = 'mytype'",
AttributeChangeNotification.class, false),
new Case(simpleNotif, "Type != 'mytype'", false),
new Case(simpleNotif, "Type = 'somethingelse'", false),
new Case(attrChangeNotif, "AttributeName = 'AttrName'", true),
new Case(attrChangeNotif,
"instanceof 'javax.management.AttributeChangeNotification'",
true),
new Case(attrChangeNotif,
"instanceof 'javax.management.Notification'",
true),
new Case(attrChangeNotif,
"instanceof 'javax.management.relation.MBeanServerNotification'",
false),
new Case(attrChangeNotif,
"class = 'javax.management.AttributeChangeNotification'",
true),
new Case(attrChangeNotif,
"javax.management.AttributeChangeNotification#AttributeName = 'AttrName'",
true),
new Case(sourcedNotif,
testObjectName,
true),
new Case(sourcedNotif,
makeObjectName("a*:b=*"),
true),
new Case(sourcedNotif,
makeObjectName("a*:c=*"),
false),
new Case(customNotif, "Name = 'claude'", true),
new Case(customNotif, "Name = 'tiddly'", false),
new Case(customNotif, "Interesting = true", true),
new Case(customNotif, "Interesting = false", false),
};
private static final ExoticCase[] exoticTestCases = {
new ExoticCase(
simpleNotif, new Notification("notmytype", "source", 0L),
new ExoticQuery("getAttributes") {
boolean apply(MBeanServer mbs, ObjectName name)
throws Exception {
List<Attribute> attrs = mbs.getAttributes(
name, new String[] {"Type", "Source"}).asList();
return (attrs.get(0).equals(new Attribute("Type", "mytype")) &&
attrs.get(1).equals(new Attribute("Source", "source")));
}
}),
new ExoticCase(
new Notification("mytype", "source", 0L) {},
simpleNotif,
new ExoticQuery("getClassLoaderFor") {
boolean apply(MBeanServer mbs, ObjectName name)
throws Exception {
return (mbs.getClassLoaderFor(name) ==
this.getClass().getClassLoader());
}
}),
new ExoticCase(
sourcedNotif, simpleNotif,
new ExoticQuery("getDomains") {
boolean apply(MBeanServer mbs, ObjectName name)
throws Exception {
return Arrays.equals(mbs.getDomains(),
new String[] {testObjectName.getDomain()});
}
}),
new ExoticCase(
simpleNotif, attrChangeNotif,
new ExoticQuery("getMBeanInfo") {
boolean apply(MBeanServer mbs, ObjectName name)
throws Exception {
MBeanInfo mbi = mbs.getMBeanInfo(name);
// If we ever add a constructor to Notification then
// we will have to change the 4 below.
if (mbi.getOperations().length > 0 ||
mbi.getConstructors().length != 4 ||
mbi.getNotifications().length > 0)
return false;
Set<String> expect = new HashSet<String>(
Arrays.asList(
"Class", "Message", "SequenceNumber", "Source",
"TimeStamp", "Type", "UserData"));
Set<String> actual = new HashSet<String>();
for (MBeanAttributeInfo mbai : mbi.getAttributes())
actual.add(mbai.getName());
return actual.equals(expect);
}
}),
new ExoticCase(
simpleNotif, attrChangeNotif,
new ExoticQuery("getObjectInstance") {
boolean apply(MBeanServer mbs, ObjectName name)
throws Exception {
ObjectInstance oi = mbs.getObjectInstance(name);
return oi.getClassName().equals(Notification.class.getName());
}
}),
new ExoticCase(
sourcedNotif, simpleNotif,
new ExoticQuery("queryNames") {
boolean apply(MBeanServer mbs, ObjectName name)
throws Exception {
Set<ObjectName> names = mbs.queryNames(null,
Query.eq(Query.attr("Type"), Query.value("mytype")));
return names.equals(Collections.singleton(testObjectName));
}
}),
new ExoticCase(
sourcedNotif, simpleNotif,
new ExoticQuery("queryMBeans") {
boolean apply(MBeanServer mbs, ObjectName name)
throws Exception {
Set<ObjectInstance> insts = mbs.queryMBeans(null,
Query.eq(Query.attr("Type"), Query.value("mytype")));
if (insts.size() != 1)
return false;
ObjectInstance inst = insts.iterator().next();
return (inst.getObjectName().equals(testObjectName) &&
inst.getClassName().equals(Notification.class.getName()));
}
}),
};
private static enum Test {
QUERY_EXP("query"), STRING("string"), STRING_PLUS_CLASS("string with class");
private final String name;
Test(String name) {
this.name = name;
}
@Override
public String toString() {
return name;
}
}
public static void main(String[] args) throws Exception {
boolean allok = true;
for (Case testCase : testCases) {
for (Test test : Test.values()) {
QueryNotificationFilter nf;
String queryString;
switch (test) {
case QUERY_EXP: {
QueryExp inst = Query.isInstanceOf(
Query.value(testCase.notifClass.getName()));
QueryExp and = Query.and(inst, testCase.query);
queryString = Query.toString(and);
nf = new QueryNotificationFilter(and);
break;
}
case STRING: {
String s = "instanceof '" + testCase.notifClass.getName() + "'";
queryString = s + " and " + Query.toString(testCase.query);
nf = new QueryNotificationFilter(queryString);
break;
}
case STRING_PLUS_CLASS:
queryString = null;
nf = new QueryNotificationFilter(
testCase.notifClass, Query.toString(testCase.query));
break;
default:
throw new AssertionError();
}
boolean accept = nf.isNotificationEnabled(testCase.notif);
if (queryString != null) {
queryString = Query.toString(Query.fromString(queryString));
if (!queryString.equals(Query.toString(nf.getQuery()))) {
System.out.println("FAIL: query string mismatch: expected " +
"\"" + queryString + "\", got \"" +
Query.toString(nf.getQuery()));
allok = false;
}
}
boolean ok = (accept == testCase.expect);
System.out.println((ok ? "pass" : "FAIL") + ": " +
testCase.query + " (" + test + ")");
allok &= ok;
}
}
for (ExoticCase testCase : exoticTestCases) {
NotificationFilter nf = new QueryNotificationFilter(testCase.query);
for (boolean expect : new boolean[] {true, false}) {
Notification n = expect ? testCase.trueNotif : testCase.falseNotif;
boolean accept = nf.isNotificationEnabled(n);
boolean ok = (accept == expect);
System.out.println((ok ? "pass" : "FAIL") + ": " +
testCase.query + ": " + n);
allok &= ok;
}
}
if (!allok)
throw new Exception("TEST FAILED");
}
}