Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openanolis
dragonwell8_jdk
提交
f799712d
D
dragonwell8_jdk
项目概览
openanolis
/
dragonwell8_jdk
通知
4
Star
2
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
D
dragonwell8_jdk
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
提交
f799712d
编写于
4月 01, 2008
作者:
E
emcmanus
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
6610917: Define a generic NotificationFilter
Summary: Adds javax.management.QueryNotificationFilter Reviewed-by: dfuchs
上级
1cb28fec
变更
10
隐藏空白更改
内联
并排
Showing
10 changed file
with
885 addition
and
53 deletion
+885
-53
src/share/classes/com/sun/jmx/interceptor/DefaultMBeanServerInterceptor.java
...om/sun/jmx/interceptor/DefaultMBeanServerInterceptor.java
+2
-15
src/share/classes/com/sun/jmx/mbeanserver/MBeanAnalyzer.java
src/share/classes/com/sun/jmx/mbeanserver/MBeanAnalyzer.java
+8
-12
src/share/classes/com/sun/jmx/mbeanserver/MBeanIntrospector.java
...re/classes/com/sun/jmx/mbeanserver/MBeanIntrospector.java
+14
-0
src/share/classes/com/sun/jmx/mbeanserver/NotificationMBeanSupport.java
...ses/com/sun/jmx/mbeanserver/NotificationMBeanSupport.java
+81
-0
src/share/classes/com/sun/jmx/mbeanserver/OpenConverter.java
src/share/classes/com/sun/jmx/mbeanserver/OpenConverter.java
+1
-1
src/share/classes/com/sun/jmx/mbeanserver/Repository.java
src/share/classes/com/sun/jmx/mbeanserver/Repository.java
+2
-11
src/share/classes/com/sun/jmx/mbeanserver/Util.java
src/share/classes/com/sun/jmx/mbeanserver/Util.java
+10
-0
src/share/classes/javax/management/ObjectName.java
src/share/classes/javax/management/ObjectName.java
+3
-14
src/share/classes/javax/management/QueryNotificationFilter.java
...are/classes/javax/management/QueryNotificationFilter.java
+417
-0
test/javax/management/query/QueryNotifFilterTest.java
test/javax/management/query/QueryNotifFilterTest.java
+347
-0
未找到文件。
src/share/classes/com/sun/jmx/interceptor/DefaultMBeanServerInterceptor.java
浏览文件 @
f799712d
...
@@ -34,8 +34,6 @@ import java.util.Set;
...
@@ -34,8 +34,6 @@ import java.util.Set;
import
java.util.HashSet
;
import
java.util.HashSet
;
import
java.util.WeakHashMap
;
import
java.util.WeakHashMap
;
import
java.lang.ref.WeakReference
;
import
java.lang.ref.WeakReference
;
import
java.io.PrintWriter
;
import
java.io.StringWriter
;
import
java.security.AccessControlContext
;
import
java.security.AccessControlContext
;
import
java.security.Permission
;
import
java.security.Permission
;
import
java.security.ProtectionDomain
;
import
java.security.ProtectionDomain
;
...
@@ -51,7 +49,6 @@ import javax.management.InstanceAlreadyExistsException;
...
@@ -51,7 +49,6 @@ import javax.management.InstanceAlreadyExistsException;
import
javax.management.InstanceNotFoundException
;
import
javax.management.InstanceNotFoundException
;
import
javax.management.IntrospectionException
;
import
javax.management.IntrospectionException
;
import
javax.management.InvalidAttributeValueException
;
import
javax.management.InvalidAttributeValueException
;
import
javax.management.JMException
;
import
javax.management.JMRuntimeException
;
import
javax.management.JMRuntimeException
;
import
javax.management.ListenerNotFoundException
;
import
javax.management.ListenerNotFoundException
;
import
javax.management.MalformedObjectNameException
;
import
javax.management.MalformedObjectNameException
;
...
@@ -84,11 +81,10 @@ import static com.sun.jmx.defaults.JmxProperties.MBEANSERVER_LOGGER;
...
@@ -84,11 +81,10 @@ import static com.sun.jmx.defaults.JmxProperties.MBEANSERVER_LOGGER;
import
com.sun.jmx.mbeanserver.DynamicMBean2
;
import
com.sun.jmx.mbeanserver.DynamicMBean2
;
import
com.sun.jmx.mbeanserver.ModifiableClassLoaderRepository
;
import
com.sun.jmx.mbeanserver.ModifiableClassLoaderRepository
;
import
com.sun.jmx.mbeanserver.MBeanInstantiator
;
import
com.sun.jmx.mbeanserver.MBeanInstantiator
;
import
com.sun.jmx.mbeanserver.MXBeanSupport
;
import
com.sun.jmx.mbeanserver.Repository
;
import
com.sun.jmx.mbeanserver.Repository
;
import
com.sun.jmx.mbeanserver.NamedObject
;
import
com.sun.jmx.mbeanserver.NamedObject
;
import
com.sun.jmx.defaults.ServiceName
;
import
com.sun.jmx.mbeanserver.Introspector
;
import
com.sun.jmx.mbeanserver.Introspector
;
import
com.sun.jmx.mbeanserver.Util
;
import
com.sun.jmx.remote.util.EnvHelp
;
import
com.sun.jmx.remote.util.EnvHelp
;
/**
/**
...
@@ -623,18 +619,9 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor {
...
@@ -623,18 +619,9 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor {
List
<
String
>
result
=
new
ArrayList
<
String
>(
domains
.
length
);
List
<
String
>
result
=
new
ArrayList
<
String
>(
domains
.
length
);
for
(
int
i
=
0
;
i
<
domains
.
length
;
i
++)
{
for
(
int
i
=
0
;
i
<
domains
.
length
;
i
++)
{
try
{
try
{
ObjectName
domain
=
new
ObjectName
(
domains
[
i
]
+
":x=x"
);
ObjectName
domain
=
Util
.
new
ObjectName
(
domains
[
i
]
+
":x=x"
);
checkMBeanPermission
((
String
)
null
,
null
,
domain
,
"getDomains"
);
checkMBeanPermission
((
String
)
null
,
null
,
domain
,
"getDomains"
);
result
.
add
(
domains
[
i
]);
result
.
add
(
domains
[
i
]);
}
catch
(
MalformedObjectNameException
e
)
{
// Should never occur... But let's log it just in case.
if
(
MBEANSERVER_LOGGER
.
isLoggable
(
Level
.
SEVERE
))
{
MBEANSERVER_LOGGER
.
logp
(
Level
.
SEVERE
,
DefaultMBeanServerInterceptor
.
class
.
getName
(),
"getDomains"
,
"Failed to check permission for domain = "
+
domains
[
i
],
e
);
}
}
catch
(
SecurityException
e
)
{
}
catch
(
SecurityException
e
)
{
// OK: Do not add this domain to the list
// OK: Do not add this domain to the list
}
}
...
...
src/share/classes/com/sun/jmx/mbeanserver/MBeanAnalyzer.java
浏览文件 @
f799712d
...
@@ -107,10 +107,7 @@ class MBeanAnalyzer<M> {
...
@@ -107,10 +107,7 @@ class MBeanAnalyzer<M> {
private
MBeanAnalyzer
(
Class
<?>
mbeanInterface
,
private
MBeanAnalyzer
(
Class
<?>
mbeanInterface
,
MBeanIntrospector
<
M
>
introspector
)
MBeanIntrospector
<
M
>
introspector
)
throws
NotCompliantMBeanException
{
throws
NotCompliantMBeanException
{
if
(!
mbeanInterface
.
isInterface
())
{
introspector
.
checkCompliance
(
mbeanInterface
);
throw
new
NotCompliantMBeanException
(
"Not an interface: "
+
mbeanInterface
.
getName
());
}
try
{
try
{
initMaps
(
mbeanInterface
,
introspector
);
initMaps
(
mbeanInterface
,
introspector
);
...
@@ -121,11 +118,10 @@ class MBeanAnalyzer<M> {
...
@@ -121,11 +118,10 @@ class MBeanAnalyzer<M> {
// Introspect the mbeanInterface and initialize this object's maps.
// Introspect the mbeanInterface and initialize this object's maps.
//
//
private
void
initMaps
(
Class
<?>
mbean
Interfac
e
,
private
void
initMaps
(
Class
<?>
mbean
Typ
e
,
MBeanIntrospector
<
M
>
introspector
)
throws
Exception
{
MBeanIntrospector
<
M
>
introspector
)
throws
Exception
{
final
Method
[]
methodArray
=
mbeanInterface
.
getMethods
();
final
List
<
Method
>
methods1
=
introspector
.
getMethods
(
mbeanType
);
final
List
<
Method
>
methods
=
eliminateCovariantMethods
(
methods1
);
final
List
<
Method
>
methods
=
eliminateCovariantMethods
(
methodArray
);
/* Run through the methods to detect inconsistencies and to enable
/* Run through the methods to detect inconsistencies and to enable
us to give getter and setter together to visitAttribute. */
us to give getter and setter together to visitAttribute. */
...
@@ -234,13 +230,13 @@ class MBeanAnalyzer<M> {
...
@@ -234,13 +230,13 @@ class MBeanAnalyzer<M> {
but existing code may depend on it and users may be used to seeing
but existing code may depend on it and users may be used to seeing
operations or attributes appear in a particular order. */
operations or attributes appear in a particular order. */
static
List
<
Method
>
static
List
<
Method
>
eliminateCovariantMethods
(
Method
[]
methodArray
)
{
eliminateCovariantMethods
(
List
<
Method
>
startMethods
)
{
// We are assuming that you never have very many methods with the
// We are assuming that you never have very many methods with the
// same name, so it is OK to use algorithms that are quadratic
// same name, so it is OK to use algorithms that are quadratic
// in the number of methods with the same name.
// in the number of methods with the same name.
final
int
len
=
methodArray
.
length
;
final
int
len
=
startMethods
.
size
()
;
final
Method
[]
sorted
=
methodArray
.
clone
(
);
final
Method
[]
sorted
=
startMethods
.
toArray
(
new
Method
[
len
]
);
Arrays
.
sort
(
sorted
,
MethodOrder
.
instance
);
Arrays
.
sort
(
sorted
,
MethodOrder
.
instance
);
final
Set
<
Method
>
overridden
=
newSet
();
final
Set
<
Method
>
overridden
=
newSet
();
for
(
int
i
=
1
;
i
<
len
;
i
++)
{
for
(
int
i
=
1
;
i
<
len
;
i
++)
{
...
@@ -259,7 +255,7 @@ class MBeanAnalyzer<M> {
...
@@ -259,7 +255,7 @@ class MBeanAnalyzer<M> {
}
}
}
}
final
List
<
Method
>
methods
=
newList
(
Arrays
.
asList
(
methodArray
)
);
final
List
<
Method
>
methods
=
newList
(
startMethods
);
methods
.
removeAll
(
overridden
);
methods
.
removeAll
(
overridden
);
return
methods
;
return
methods
;
}
}
...
...
src/share/classes/com/sun/jmx/mbeanserver/MBeanIntrospector.java
浏览文件 @
f799712d
...
@@ -34,6 +34,7 @@ import java.lang.reflect.Constructor;
...
@@ -34,6 +34,7 @@ import java.lang.reflect.Constructor;
import
java.lang.reflect.InvocationTargetException
;
import
java.lang.reflect.InvocationTargetException
;
import
java.lang.reflect.Method
;
import
java.lang.reflect.Method
;
import
java.lang.reflect.Type
;
import
java.lang.reflect.Type
;
import
java.util.Arrays
;
import
java.util.List
;
import
java.util.List
;
import
java.util.WeakHashMap
;
import
java.util.WeakHashMap
;
...
@@ -169,6 +170,19 @@ abstract class MBeanIntrospector<M> {
...
@@ -169,6 +170,19 @@ abstract class MBeanIntrospector<M> {
*/
*/
abstract
Descriptor
getMBeanDescriptor
(
Class
<?>
resourceClass
);
abstract
Descriptor
getMBeanDescriptor
(
Class
<?>
resourceClass
);
void
checkCompliance
(
Class
<?>
mbeanType
)
throws
NotCompliantMBeanException
{
if
(!
mbeanType
.
isInterface
())
{
throw
new
NotCompliantMBeanException
(
"Not an interface: "
+
mbeanType
.
getName
());
}
}
/**
* Get the methods to be analyzed to build the MBean interface.
*/
List
<
Method
>
getMethods
(
final
Class
<?>
mbeanType
)
throws
Exception
{
return
Arrays
.
asList
(
mbeanType
.
getMethods
());
}
final
PerInterface
<
M
>
getPerInterface
(
Class
<?>
mbeanInterface
)
final
PerInterface
<
M
>
getPerInterface
(
Class
<?>
mbeanInterface
)
throws
NotCompliantMBeanException
{
throws
NotCompliantMBeanException
{
...
...
src/share/classes/com/sun/jmx/mbeanserver/NotificationMBeanSupport.java
0 → 100644
浏览文件 @
f799712d
/*
* Copyright 2007 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. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun in the LICENSE file that accompanied this code.
*
* 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.
*/
package
com.sun.jmx.mbeanserver
;
import
java.lang.reflect.Method
;
import
java.util.ArrayList
;
import
java.util.List
;
import
javax.management.NotCompliantMBeanException
;
import
javax.management.Notification
;
/**
* <p>A variant of {@code StandardMBeanSupport} where the only
* methods included are public getters. This is used by
* {@code QueryNotificationFilter} to pretend that a Notification is
* an MBean so it can have a query evaluated on it. Standard queries
* never set attributes or invoke methods but custom queries could and
* we don't want to allow that. Also we don't want to fail if a
* Notification happens to have inconsistent types in a pair of getX and
* setX methods, and we want to include the Object.getClass() method.
*/
public
class
NotificationMBeanSupport
extends
StandardMBeanSupport
{
public
<
T
extends
Notification
>
NotificationMBeanSupport
(
T
n
)
throws
NotCompliantMBeanException
{
super
(
n
,
Util
.<
Class
<
T
>>
cast
(
n
.
getClass
()));
}
@Override
MBeanIntrospector
<
Method
>
getMBeanIntrospector
()
{
return
introspector
;
}
private
static
class
Introspector
extends
StandardMBeanIntrospector
{
@Override
void
checkCompliance
(
Class
<?>
mbeanType
)
{}
@Override
List
<
Method
>
getMethods
(
final
Class
<?>
mbeanType
)
throws
Exception
{
List
<
Method
>
methods
=
new
ArrayList
<
Method
>();
for
(
Method
m
:
mbeanType
.
getMethods
())
{
String
name
=
m
.
getName
();
Class
<?>
ret
=
m
.
getReturnType
();
if
(
m
.
getParameterTypes
().
length
==
0
)
{
if
((
name
.
startsWith
(
"is"
)
&&
name
.
length
()
>
2
&&
ret
==
boolean
.
class
)
||
(
name
.
startsWith
(
"get"
)
&&
name
.
length
()
>
3
&&
ret
!=
void
.
class
))
{
methods
.
add
(
m
);
}
}
}
return
methods
;
}
}
private
static
final
MBeanIntrospector
<
Method
>
introspector
=
new
Introspector
();
}
src/share/classes/com/sun/jmx/mbeanserver/OpenConverter.java
浏览文件 @
f799712d
...
@@ -438,7 +438,7 @@ public abstract class OpenConverter {
...
@@ -438,7 +438,7 @@ public abstract class OpenConverter {
c
.
getClassLoader
()
==
null
);
c
.
getClassLoader
()
==
null
);
final
List
<
Method
>
methods
=
final
List
<
Method
>
methods
=
MBeanAnalyzer
.
eliminateCovariantMethods
(
c
.
getMethods
(
));
MBeanAnalyzer
.
eliminateCovariantMethods
(
Arrays
.
asList
(
c
.
getMethods
()
));
final
SortedMap
<
String
,
Method
>
getterMap
=
newSortedMap
();
final
SortedMap
<
String
,
Method
>
getterMap
=
newSortedMap
();
/* Select public methods that look like "T getX()" or "boolean
/* Select public methods that look like "T getX()" or "boolean
...
...
src/share/classes/com/sun/jmx/mbeanserver/Repository.java
浏览文件 @
f799712d
...
@@ -415,17 +415,8 @@ public class Repository {
...
@@ -415,17 +415,8 @@ public class Repository {
boolean
to_default_domain
=
false
;
boolean
to_default_domain
=
false
;
// Set domain to default if domain is empty and not already set
// Set domain to default if domain is empty and not already set
if
(
dom
.
length
()
==
0
)
{
if
(
dom
.
length
()
==
0
)
try
{
name
=
Util
.
newObjectName
(
domain
+
name
.
toString
());
name
=
new
ObjectName
(
domain
+
name
.
toString
());
}
catch
(
MalformedObjectNameException
e
)
{
if
(
MBEANSERVER_LOGGER
.
isLoggable
(
Level
.
FINEST
))
{
MBEANSERVER_LOGGER
.
logp
(
Level
.
FINEST
,
Repository
.
class
.
getName
(),
"addMBean"
,
"Unexpected MalformedObjectNameException"
,
e
);
}
}
}
// Do we have default domain ?
// Do we have default domain ?
if
(
dom
==
domain
)
{
if
(
dom
==
domain
)
{
...
...
src/share/classes/com/sun/jmx/mbeanserver/Util.java
浏览文件 @
f799712d
...
@@ -38,6 +38,8 @@ import java.util.Map;
...
@@ -38,6 +38,8 @@ import java.util.Map;
import
java.util.Set
;
import
java.util.Set
;
import
java.util.SortedMap
;
import
java.util.SortedMap
;
import
java.util.TreeMap
;
import
java.util.TreeMap
;
import
javax.management.MalformedObjectNameException
;
import
javax.management.ObjectName
;
public
class
Util
{
public
class
Util
{
static
<
K
,
V
>
Map
<
K
,
V
>
newMap
()
{
static
<
K
,
V
>
Map
<
K
,
V
>
newMap
()
{
...
@@ -85,6 +87,14 @@ public class Util {
...
@@ -85,6 +87,14 @@ public class Util {
return
new
ArrayList
<
E
>(
c
);
return
new
ArrayList
<
E
>(
c
);
}
}
public
static
ObjectName
newObjectName
(
String
s
)
{
try
{
return
new
ObjectName
(
s
);
}
catch
(
MalformedObjectNameException
e
)
{
throw
new
IllegalArgumentException
(
e
);
}
}
/* This method can be used by code that is deliberately violating the
/* This method can be used by code that is deliberately violating the
* allowed checked casts. Rather than marking the whole method containing
* allowed checked casts. Rather than marking the whole method containing
* the code with @SuppressWarnings, you can use a call to this method for
* the code with @SuppressWarnings, you can use a call to this method for
...
...
src/share/classes/javax/management/ObjectName.java
浏览文件 @
f799712d
...
@@ -26,6 +26,7 @@
...
@@ -26,6 +26,7 @@
package
javax.management
;
package
javax.management
;
import
com.sun.jmx.mbeanserver.GetPropertyAction
;
import
com.sun.jmx.mbeanserver.GetPropertyAction
;
import
com.sun.jmx.mbeanserver.Util
;
import
java.io.IOException
;
import
java.io.IOException
;
import
java.io.InvalidObjectException
;
import
java.io.InvalidObjectException
;
import
java.io.ObjectInputStream
;
import
java.io.ObjectInputStream
;
...
@@ -1386,12 +1387,7 @@ public class ObjectName extends ToQueryString
...
@@ -1386,12 +1387,7 @@ public class ObjectName extends ToQueryString
throws
NullPointerException
{
throws
NullPointerException
{
if
(
name
.
getClass
().
equals
(
ObjectName
.
class
))
if
(
name
.
getClass
().
equals
(
ObjectName
.
class
))
return
name
;
return
name
;
try
{
return
Util
.
newObjectName
(
name
.
getSerializedNameString
());
return
new
ObjectName
(
name
.
getSerializedNameString
());
}
catch
(
MalformedObjectNameException
e
)
{
throw
new
IllegalArgumentException
(
"Unexpected: "
+
e
);
// can't happen
}
}
}
/**
/**
...
@@ -1950,14 +1946,7 @@ public class ObjectName extends ToQueryString
...
@@ -1950,14 +1946,7 @@ public class ObjectName extends ToQueryString
*
*
* @since 1.6
* @since 1.6
*/
*/
public
static
final
ObjectName
WILDCARD
;
public
static
final
ObjectName
WILDCARD
=
Util
.
newObjectName
(
"*:*"
);
static
{
try
{
WILDCARD
=
new
ObjectName
(
"*:*"
);
}
catch
(
MalformedObjectNameException
e
)
{
throw
new
Error
(
"Can't initialize wildcard name"
,
e
);
}
}
// Category : Utilities <===================================
// Category : Utilities <===================================
...
...
src/share/classes/javax/management/QueryNotificationFilter.java
0 → 100644
浏览文件 @
f799712d
/*
* Copyright 2007 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. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun in the LICENSE file that accompanied this code.
*
* 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.
*/
package
javax.management
;
import
com.sun.jmx.mbeanserver.NotificationMBeanSupport
;
import
com.sun.jmx.mbeanserver.Util
;
import
java.lang.reflect.InvocationHandler
;
import
java.lang.reflect.InvocationTargetException
;
import
java.lang.reflect.Method
;
import
java.lang.reflect.Proxy
;
import
java.util.Collections
;
import
java.util.Set
;
/**
* <p>General-purpose notification filter. This filter can be used to
* filter notifications from a possibly-remote MBean. Most filtering
* decisions can be coded using this filter, which avoids having to
* write a custom implementation of the {@link NotificationFilter}
* class. Writing a custom implementation requires you to deploy it
* on both the client and the server in the remote case, so using this class
* instead is recommended where possible.</p>
*
* <!-- <p>Because this class was introduced in version 2.0 of the JMX API,
* it may not be present on a remote JMX agent that is running an earlier
* version. The method {@link JMX#addListenerWithFilter JMX.addListenerWithFilter}
* can be used when you cannot be sure whether this class is present in the
* agent you are connecting to.</p> -->
*
* <p>This class uses the {@linkplain Query Query API} to specify the
* filtering logic. For example, to select only notifications where the
* {@linkplain Notification#getType() type} is {@code "com.example.mytype"},
* you could use</p>
*
* <pre>
* NotificationFilter filter =
* new QueryNotificationFilter("Type = 'com.example.mytype'");
* </pre>
*
* <p>or equivalently</p>
*
* <pre>
* NotificationFilter filter =
* new QueryNotificationFilter(
* Query.eq(Query.attr("Type"), Query.value("com.example.mytype")));
* </pre>
*
* <p>(This particular example could also use
* {@link NotificationFilterSupport}.)</p>
*
* <p>Here are some other examples of filters you can specify with this class.</p>
*
* <dl>
*
* <dt>{@code QueryNotificationFilter("Type = 'com.example.type1' or
* Type = 'com.example.type2'")}
* <dd>Notifications where the type is either of the given strings.
*
* <dt>{@code QueryNotificationFilter("Type in ('com.example.type1',
* 'com.example.type2')")}
* <dd>Another way to write the previous example.
*
* <dt>{@code QueryNotificationFilter("SequenceNumber > 1000")}
* <dd>Notifications where the {@linkplain Notification#getSequenceNumber()
* sequence number} is greater than 1000.
*
* <dt>{@code QueryNotificationFilter(AttributeChangeNotification.class, null)}
* <dd>Notifications where the notification class is
* {@link AttributeChangeNotification} or a subclass of it.
*
* <dt>{@code QueryNotificationFilter(AttributeChangeNotification.class,
* "AttributeName = 'Size'")}
* <dd>Notifications where the notification class is
* {@link AttributeChangeNotification} or a subclass, and where the
* {@linkplain AttributeChangeNotification#getAttributeName() name of the
* changed attribute} is {@code Size}.
*
* <dt>{@code QueryNotificationFilter(AttributeChangeNotification.class,
* "AttributeName = 'Size' and NewValue - OldValue > 100")}
* <dd>As above, but the difference between the
* {@linkplain AttributeChangeNotification#getNewValue() new value} and the
* {@linkplain AttributeChangeNotification#getOldValue() old value} must be
* greater than 100.
*
* <dt>{@code QueryNotificationFilter("like 'com.example.mydomain:*'")}
* <dd>Notifications where the {@linkplain Notification#getSource() source}
* is an ObjectName that matches the pattern.
*
* <dt>{@code QueryNotificationFilter("Source.canonicalName like
* 'com.example.mydomain:%'")}
* <dd>Another way to write the previous example.
*
* <dt>{@code QueryNotificationFilter(MBeanServerNotification.class,
* "Type = 'JMX.mbean.registered' and MBeanName.canonicalName like
* 'com.example.mydomain:%'")}
* <dd>Notifications of class {@link MBeanServerNotification} representing
* an object registered in the domain {@code com.example.mydomain}.
*
* </dl>
*
* <h4>How it works</h4>
*
* <p>Although the examples above are clear, looking closely at the
* Query API reveals a subtlety. A {@link QueryExp} is evaluated on
* an {@link ObjectName}, not a {@code Notification}.</p>
*
* <p>Every time a {@code Notification} is to be filtered by a
* {@code QueryNotificationFilter}, a special {@link MBeanServer} is created.
* This {@code MBeanServer} contains exactly one MBean, which represents the
* {@code Notification}. If the {@linkplain Notification#getSource()
* source} of the notification is an {@code ObjectName}, which is
* recommended practice, then the name of the MBean representing the
* {@code Notification} will be this {@code ObjectName}. Otherwise the
* name is unspecified.</p>
*
* <p>The query specified in the {@code QueryNotificationFilter} constructor
* is evaluated against this {@code MBeanServer} and {@code ObjectName},
* and the filter returns true if and only if the query does. If the
* query throws an exception, then the filter will return false.</p>
*
* <p>The MBean representing the {@code Notification} has one attribute for
* every property of the {@code Notification}. Specifically, for every public
* method {@code T getX()} in the {@code NotificationClass}, the MBean will
* have an attribute called {@code X} of type {@code T}. For example, if the
* {@code Notification} is an {@code AttributeChangeNotification}, then the
* MBean will have an attribute called {@code AttributeName} of type
* {@code "java.lang.String"}, corresponding to the method {@link
* AttributeChangeNotification#getAttributeName}.</p>
*
* <p>Query evaluation usually involves calls to the methods of {@code
* MBeanServer}. The methods have the following behavior:</p>
*
* <ul>
* <li>The {@link MBeanServer#getAttribute getAttribute} method returns the
* value of the corresponding property.
* <li>The {@link MBeanServer#getObjectInstance getObjectInstance}
* method returns an {@link ObjectInstance} where the {@link
* ObjectInstance#getObjectName ObjectName} is the name of the MBean and the
* {@link ObjectInstance#getClassName ClassName} is the class name of the
* {@code Notification}.
* <li>The {@link MBeanServer#isInstanceOf isInstanceOf} method returns true
* if and only if the {@code Notification}'s {@code ClassLoader} can load the
* named class, and the {@code Notification} is an {@linkplain Class#isInstance
* instance} of that class.
* </ul>
*
* <p>These are the only {@code MBeanServer} methods that are needed to
* evaluate standard queries. The behavior of the other {@code MBeanServer}
* methods is unspecified.</p>
*
* @since 1.7
*/
public
class
QueryNotificationFilter
implements
NotificationFilter
{
private
static
final
long
serialVersionUID
=
-
8408613922660635231L
;
private
static
final
ObjectName
DEFAULT_NAME
=
Util
.
newObjectName
(
":type=Notification"
);
private
static
final
QueryExp
trueQuery
;
static
{
ValueExp
zero
=
Query
.
value
(
0
);
trueQuery
=
Query
.
eq
(
zero
,
zero
);
}
private
final
QueryExp
query
;
/**
* Construct a {@code QueryNotificationFilter} that evaluates the given
* {@code QueryExp} to determine whether to accept a notification.
*
* @param query the {@code QueryExp} to evaluate. Can be null,
* in which case all notifications are accepted.
*/
public
QueryNotificationFilter
(
QueryExp
query
)
{
if
(
query
==
null
)
this
.
query
=
trueQuery
;
else
this
.
query
=
query
;
}
/**
* Construct a {@code QueryNotificationFilter} that evaluates the query
* in the given string to determine whether to accept a notification.
* The string is converted into a {@code QueryExp} using
* {@link Query#fromString Query.fromString}.
*
* @param query the string specifying the query to evaluate. Can be null,
* in which case all notifications are accepted.
*
* @throws IllegalArgumentException if the string is not a valid
* query string.
*/
public
QueryNotificationFilter
(
String
query
)
{
this
(
Query
.
fromString
(
query
));
}
/**
* <p>Construct a {@code QueryNotificationFilter} that evaluates the query
* in the given string to determine whether to accept a notification,
* and where the notification must also be an instance of the given class.
* The string is converted into a {@code QueryExp} using
* {@link Query#fromString Query.fromString}.</p>
*
* @param notifClass the class that the notification must be an instance of.
* Cannot be null.
*
* @param query the string specifying the query to evaluate. Can be null,
* in which case all notifications are accepted.
*
* @throws IllegalArgumentException if the string is not a valid
* query string, or if {@code notifClass} is null.
*/
public
QueryNotificationFilter
(
Class
<?
extends
Notification
>
notifClass
,
String
query
)
{
this
(
Query
.
and
(
Query
.
isInstanceOf
(
Query
.
value
(
notNull
(
notifClass
).
getName
())),
Query
.
fromString
(
query
)));
}
private
static
<
T
>
T
notNull
(
T
x
)
{
if
(
x
==
null
)
throw
new
IllegalArgumentException
(
"Null argument"
);
return
x
;
}
/**
* Retrieve the query that this notification filter will evaluate for
* each notification.
*
* @return the query.
*/
public
QueryExp
getQuery
()
{
return
query
;
}
public
boolean
isNotificationEnabled
(
Notification
notification
)
{
ObjectName
name
;
Object
source
=
notification
.
getSource
();
if
(
source
instanceof
ObjectName
)
name
=
(
ObjectName
)
source
;
else
name
=
DEFAULT_NAME
;
MBS
mbsImpl
=
new
MBS
(
notification
,
name
);
MBeanServer
mbs
=
(
MBeanServer
)
Proxy
.
newProxyInstance
(
MBeanServer
.
class
.
getClassLoader
(),
new
Class
<?>[]
{
MBeanServer
.
class
},
new
ForwardIH
(
mbsImpl
));
return
evalQuery
(
query
,
mbs
,
name
);
}
private
static
boolean
evalQuery
(
QueryExp
query
,
MBeanServer
mbs
,
ObjectName
name
)
{
MBeanServer
oldMBS
=
QueryEval
.
getMBeanServer
();
try
{
if
(
mbs
!=
null
)
query
.
setMBeanServer
(
mbs
);
return
query
.
apply
(
name
);
}
catch
(
Exception
e
)
{
return
false
;
}
finally
{
query
.
setMBeanServer
(
oldMBS
);
}
}
private
static
class
ForwardIH
implements
InvocationHandler
{
private
final
MBS
mbs
;
ForwardIH
(
MBS
mbs
)
{
this
.
mbs
=
mbs
;
}
public
Object
invoke
(
Object
proxy
,
Method
method
,
Object
[]
args
)
throws
Throwable
{
Method
forward
;
try
{
forward
=
MBS
.
class
.
getMethod
(
method
.
getName
(),
method
.
getParameterTypes
());
}
catch
(
NoSuchMethodException
e
)
{
throw
new
UnsupportedOperationException
(
method
.
getName
());
}
try
{
return
forward
.
invoke
(
mbs
,
args
);
}
catch
(
InvocationTargetException
e
)
{
throw
e
.
getCause
();
}
}
}
private
static
class
MBS
{
private
final
Notification
notification
;
private
final
ObjectName
objectName
;
private
final
ObjectInstance
objectInstance
;
private
volatile
DynamicMBean
mbean
;
MBS
(
Notification
n
,
ObjectName
name
)
{
this
.
notification
=
n
;
this
.
objectName
=
name
;
this
.
objectInstance
=
new
ObjectInstance
(
name
,
n
.
getClass
().
getName
());
}
private
void
checkName
(
ObjectName
name
)
throws
InstanceNotFoundException
{
if
(!
objectName
.
equals
(
name
))
throw
new
InstanceNotFoundException
(
String
.
valueOf
(
name
));
}
private
DynamicMBean
mbean
(
ObjectName
name
)
throws
InstanceNotFoundException
,
ReflectionException
{
if
(
mbean
==
null
)
{
try
{
mbean
=
new
NotificationMBeanSupport
(
notification
);
}
catch
(
NotCompliantMBeanException
e
)
{
throw
new
ReflectionException
(
e
);
}
}
return
mbean
;
}
public
ObjectInstance
getObjectInstance
(
ObjectName
name
)
throws
InstanceNotFoundException
{
checkName
(
name
);
return
objectInstance
;
}
public
Set
<
ObjectInstance
>
queryMBeans
(
ObjectName
name
,
QueryExp
query
)
{
Set
<
ObjectName
>
names
=
queryNames
(
name
,
query
);
switch
(
names
.
size
())
{
case
0
:
return
Collections
.
emptySet
();
case
1
:
return
Collections
.
singleton
(
objectInstance
);
default
:
throw
new
UnsupportedOperationException
(
"Internal error"
);
}
}
public
Set
<
ObjectName
>
queryNames
(
ObjectName
name
,
QueryExp
query
)
{
if
((
name
!=
null
&&
!
name
.
apply
(
objectName
))
||
(
query
!=
null
&&
!
evalQuery
(
query
,
null
,
name
)))
return
Collections
.
emptySet
();
return
Collections
.
singleton
(
objectName
);
}
public
boolean
isRegistered
(
ObjectName
name
)
{
return
objectName
.
equals
(
name
);
}
public
Integer
getMBeanCount
()
{
return
1
;
}
public
Object
getAttribute
(
ObjectName
name
,
String
attribute
)
throws
MBeanException
,
AttributeNotFoundException
,
InstanceNotFoundException
,
ReflectionException
{
return
mbean
(
name
).
getAttribute
(
attribute
);
}
public
AttributeList
getAttributes
(
ObjectName
name
,
String
[]
attributes
)
throws
InstanceNotFoundException
,
ReflectionException
{
return
mbean
(
name
).
getAttributes
(
attributes
);
}
public
String
getDefaultDomain
()
{
return
objectName
.
getDomain
();
}
public
String
[]
getDomains
()
{
return
new
String
[]
{
objectName
.
getDomain
()};
}
public
MBeanInfo
getMBeanInfo
(
ObjectName
name
)
throws
InstanceNotFoundException
,
ReflectionException
{
return
mbean
(
name
).
getMBeanInfo
();
}
public
boolean
isInstanceOf
(
ObjectName
name
,
String
className
)
throws
InstanceNotFoundException
{
try
{
mbean
(
name
);
ClassLoader
loader
=
notification
.
getClass
().
getClassLoader
();
Class
<?>
c
=
Class
.
forName
(
className
,
false
,
loader
);
return
c
.
isInstance
(
notification
);
}
catch
(
ReflectionException
e
)
{
return
false
;
}
catch
(
ClassNotFoundException
e
)
{
return
false
;
}
}
public
ClassLoader
getClassLoaderFor
(
ObjectName
mbeanName
)
throws
InstanceNotFoundException
{
checkName
(
mbeanName
);
return
notification
.
getClass
().
getClassLoader
();
}
}
}
test/javax/management/query/QueryNotifFilterTest.java
0 → 100644
浏览文件 @
f799712d
/*
* Copyright 2007 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
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"
);
}
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录