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;
import
java.util.HashSet
;
import
java.util.WeakHashMap
;
import
java.lang.ref.WeakReference
;
import
java.io.PrintWriter
;
import
java.io.StringWriter
;
import
java.security.AccessControlContext
;
import
java.security.Permission
;
import
java.security.ProtectionDomain
;
...
...
@@ -51,7 +49,6 @@ import javax.management.InstanceAlreadyExistsException;
import
javax.management.InstanceNotFoundException
;
import
javax.management.IntrospectionException
;
import
javax.management.InvalidAttributeValueException
;
import
javax.management.JMException
;
import
javax.management.JMRuntimeException
;
import
javax.management.ListenerNotFoundException
;
import
javax.management.MalformedObjectNameException
;
...
...
@@ -84,11 +81,10 @@ import static com.sun.jmx.defaults.JmxProperties.MBEANSERVER_LOGGER;
import
com.sun.jmx.mbeanserver.DynamicMBean2
;
import
com.sun.jmx.mbeanserver.ModifiableClassLoaderRepository
;
import
com.sun.jmx.mbeanserver.MBeanInstantiator
;
import
com.sun.jmx.mbeanserver.MXBeanSupport
;
import
com.sun.jmx.mbeanserver.Repository
;
import
com.sun.jmx.mbeanserver.NamedObject
;
import
com.sun.jmx.defaults.ServiceName
;
import
com.sun.jmx.mbeanserver.Introspector
;
import
com.sun.jmx.mbeanserver.Util
;
import
com.sun.jmx.remote.util.EnvHelp
;
/**
...
...
@@ -623,18 +619,9 @@ public class DefaultMBeanServerInterceptor implements MBeanServerInterceptor {
List
<
String
>
result
=
new
ArrayList
<
String
>(
domains
.
length
);
for
(
int
i
=
0
;
i
<
domains
.
length
;
i
++)
{
try
{
ObjectName
domain
=
new
ObjectName
(
domains
[
i
]
+
":x=x"
);
ObjectName
domain
=
Util
.
new
ObjectName
(
domains
[
i
]
+
":x=x"
);
checkMBeanPermission
((
String
)
null
,
null
,
domain
,
"getDomains"
);
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
)
{
// 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> {
private
MBeanAnalyzer
(
Class
<?>
mbeanInterface
,
MBeanIntrospector
<
M
>
introspector
)
throws
NotCompliantMBeanException
{
if
(!
mbeanInterface
.
isInterface
())
{
throw
new
NotCompliantMBeanException
(
"Not an interface: "
+
mbeanInterface
.
getName
());
}
introspector
.
checkCompliance
(
mbeanInterface
);
try
{
initMaps
(
mbeanInterface
,
introspector
);
...
...
@@ -121,11 +118,10 @@ class MBeanAnalyzer<M> {
// 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
{
final
Method
[]
methodArray
=
mbeanInterface
.
getMethods
();
final
List
<
Method
>
methods
=
eliminateCovariantMethods
(
methodArray
);
final
List
<
Method
>
methods1
=
introspector
.
getMethods
(
mbeanType
);
final
List
<
Method
>
methods
=
eliminateCovariantMethods
(
methods1
);
/* Run through the methods to detect inconsistencies and to enable
us to give getter and setter together to visitAttribute. */
...
...
@@ -234,13 +230,13 @@ class MBeanAnalyzer<M> {
but existing code may depend on it and users may be used to seeing
operations or attributes appear in a particular order. */
static
List
<
Method
>
eliminateCovariantMethods
(
Method
[]
methodArray
)
{
eliminateCovariantMethods
(
List
<
Method
>
startMethods
)
{
// We are assuming that you never have very many methods with the
// same name, so it is OK to use algorithms that are quadratic
// in the number of methods with the same name.
final
int
len
=
methodArray
.
length
;
final
Method
[]
sorted
=
methodArray
.
clone
(
);
final
int
len
=
startMethods
.
size
()
;
final
Method
[]
sorted
=
startMethods
.
toArray
(
new
Method
[
len
]
);
Arrays
.
sort
(
sorted
,
MethodOrder
.
instance
);
final
Set
<
Method
>
overridden
=
newSet
();
for
(
int
i
=
1
;
i
<
len
;
i
++)
{
...
...
@@ -259,7 +255,7 @@ class MBeanAnalyzer<M> {
}
}
final
List
<
Method
>
methods
=
newList
(
Arrays
.
asList
(
methodArray
)
);
final
List
<
Method
>
methods
=
newList
(
startMethods
);
methods
.
removeAll
(
overridden
);
return
methods
;
}
...
...
src/share/classes/com/sun/jmx/mbeanserver/MBeanIntrospector.java
浏览文件 @
f799712d
...
...
@@ -34,6 +34,7 @@ import java.lang.reflect.Constructor;
import
java.lang.reflect.InvocationTargetException
;
import
java.lang.reflect.Method
;
import
java.lang.reflect.Type
;
import
java.util.Arrays
;
import
java.util.List
;
import
java.util.WeakHashMap
;
...
...
@@ -169,6 +170,19 @@ abstract class MBeanIntrospector<M> {
*/
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
)
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 {
c
.
getClassLoader
()
==
null
);
final
List
<
Method
>
methods
=
MBeanAnalyzer
.
eliminateCovariantMethods
(
c
.
getMethods
(
));
MBeanAnalyzer
.
eliminateCovariantMethods
(
Arrays
.
asList
(
c
.
getMethods
()
));
final
SortedMap
<
String
,
Method
>
getterMap
=
newSortedMap
();
/* 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 {
boolean
to_default_domain
=
false
;
// Set domain to default if domain is empty and not already set
if
(
dom
.
length
()
==
0
)
{
try
{
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
);
}
}
}
if
(
dom
.
length
()
==
0
)
name
=
Util
.
newObjectName
(
domain
+
name
.
toString
());
// Do we have default domain ?
if
(
dom
==
domain
)
{
...
...
src/share/classes/com/sun/jmx/mbeanserver/Util.java
浏览文件 @
f799712d
...
...
@@ -38,6 +38,8 @@ import java.util.Map;
import
java.util.Set
;
import
java.util.SortedMap
;
import
java.util.TreeMap
;
import
javax.management.MalformedObjectNameException
;
import
javax.management.ObjectName
;
public
class
Util
{
static
<
K
,
V
>
Map
<
K
,
V
>
newMap
()
{
...
...
@@ -85,6 +87,14 @@ public class Util {
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
* allowed checked casts. Rather than marking the whole method containing
* 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 @@
package
javax.management
;
import
com.sun.jmx.mbeanserver.GetPropertyAction
;
import
com.sun.jmx.mbeanserver.Util
;
import
java.io.IOException
;
import
java.io.InvalidObjectException
;
import
java.io.ObjectInputStream
;
...
...
@@ -1386,12 +1387,7 @@ public class ObjectName extends ToQueryString
throws
NullPointerException
{
if
(
name
.
getClass
().
equals
(
ObjectName
.
class
))
return
name
;
try
{
return
new
ObjectName
(
name
.
getSerializedNameString
());
}
catch
(
MalformedObjectNameException
e
)
{
throw
new
IllegalArgumentException
(
"Unexpected: "
+
e
);
// can't happen
}
return
Util
.
newObjectName
(
name
.
getSerializedNameString
());
}
/**
...
...
@@ -1950,14 +1946,7 @@ public class ObjectName extends ToQueryString
*
* @since 1.6
*/
public
static
final
ObjectName
WILDCARD
;
static
{
try
{
WILDCARD
=
new
ObjectName
(
"*:*"
);
}
catch
(
MalformedObjectNameException
e
)
{
throw
new
Error
(
"Can't initialize wildcard name"
,
e
);
}
}
public
static
final
ObjectName
WILDCARD
=
Util
.
newObjectName
(
"*:*"
);
// 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.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录