jmx 0.8 → 0.9
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE.txt +1 -1
- data/README.md +29 -4
- data/lib/jmx.rb +4 -176
- data/lib/jmx/composite_data.rb +21 -0
- data/lib/jmx/mbean_proxy.rb +164 -0
- data/lib/jmx/mbeans.rb +28 -0
- data/lib/jmx/notifier.rb +31 -0
- data/lib/jmx/object_name.rb +22 -0
- data/lib/jmx/server.rb +7 -17
- data/lib/jmx/util/string_utils.rb +15 -0
- data/lib/jmx/version.rb +1 -1
- data/test/jmx_client_test.rb +17 -0
- metadata +87 -64
data/LICENSE.txt
CHANGED
data/README.md
CHANGED
@@ -5,20 +5,40 @@
|
|
5
5
|
JMX is a library which allows you to access JMX MBeans as a client or create
|
6
6
|
your own MBeans as a Ruby class.
|
7
7
|
|
8
|
-
## FEATURES/PROBLEMS:
|
9
|
-
|
10
|
-
* Use '-J-Dcom.sun.management.jmxremote' to make jruby process accessible from a jruby command-line
|
11
|
-
|
12
8
|
## SYNOPSIS:
|
13
9
|
|
14
10
|
Connect to same JVM as client script and look at Memory MBean
|
15
11
|
|
12
|
+
```ruby
|
16
13
|
require 'jmx'
|
17
14
|
|
18
15
|
client = JMX.simple_connect(:port => 9999)
|
19
16
|
|
20
17
|
memory = client["java.lang:type=Memory"]
|
21
18
|
puts memory.attributes
|
19
|
+
```
|
20
|
+
|
21
|
+
You can also create your own MBeans and register them as well:
|
22
|
+
|
23
|
+
```ruby
|
24
|
+
require 'jmx'
|
25
|
+
|
26
|
+
class MyDynamicMBean < RubyDynamicMBean
|
27
|
+
rw_attribute :name, :string, "My sample attribute"
|
28
|
+
r_attribute :explicit_reader, :int, "Sample int with writer", :my_reader
|
29
|
+
|
30
|
+
operation "Doubles a value"
|
31
|
+
parameter :int, "a", "Value to double"
|
32
|
+
returns :int
|
33
|
+
def double(a)
|
34
|
+
a + a
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
dyna = MyDynamicMBean.new("domain.MySuperBean", "Heh")
|
39
|
+
domain = my_server.default_domain
|
40
|
+
my_server.register_mbean dyna, "#{@domain}:type=MyDynamicMBean"
|
41
|
+
```
|
22
42
|
|
23
43
|
## REQUIREMENTS:
|
24
44
|
|
@@ -27,3 +47,8 @@ Connect to same JVM as client script and look at Memory MBean
|
|
27
47
|
## INSTALL:
|
28
48
|
|
29
49
|
* jruby -S gem install jmx
|
50
|
+
|
51
|
+
## PROBLEMS:
|
52
|
+
|
53
|
+
* Use '-J-Dcom.sun.management.jmxremote' to make jruby process accessible from a jruby command-line
|
54
|
+
|
data/lib/jmx.rb
CHANGED
@@ -3,44 +3,10 @@ include Java
|
|
3
3
|
require 'rmi'
|
4
4
|
require 'jmx/dynamic_mbean'
|
5
5
|
require 'jmx/server'
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
java_import javax.management.DynamicMBean
|
11
|
-
|
12
|
-
module JMX
|
13
|
-
java_import javax.management.ObjectName
|
14
|
-
class ObjectName
|
15
|
-
def [](key)
|
16
|
-
get_key_property(key.to_s)
|
17
|
-
end
|
18
|
-
|
19
|
-
def info(server)
|
20
|
-
server.getMBeanInfo(self)
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
module javax::management::openmbean::CompositeData
|
26
|
-
include Enumerable
|
27
|
-
|
28
|
-
def [](key)
|
29
|
-
get(key.to_s)
|
30
|
-
end
|
31
|
-
|
32
|
-
def method_missing(name, *args)
|
33
|
-
self[name]
|
34
|
-
end
|
35
|
-
|
36
|
-
def each
|
37
|
-
get_composite_type.key_set.each { |key| yield key }
|
38
|
-
end
|
39
|
-
|
40
|
-
def each_pair
|
41
|
-
get_composite_type.key_set.each { |key| yield key, get(key) }
|
42
|
-
end
|
43
|
-
end
|
6
|
+
require 'jmx/object_name'
|
7
|
+
require 'jmx/composite_data'
|
8
|
+
require 'jmx/mbean_proxy'
|
9
|
+
require 'jmx/mbeans'
|
44
10
|
|
45
11
|
module JMX
|
46
12
|
##
|
@@ -74,142 +40,4 @@ module JMX
|
|
74
40
|
$registry = RMIRegistry.new port
|
75
41
|
@connector = JMX::MBeanServerConnector.new(url, JMX::MBeanServer.new).start
|
76
42
|
end
|
77
|
-
|
78
|
-
# Holder for beans created from retrieval (namespace protection [tm]).
|
79
|
-
# This also gives MBeans nicer names when inspected
|
80
|
-
module MBeans
|
81
|
-
##
|
82
|
-
# Create modules in this namespace for each package in the Java fully
|
83
|
-
# qualified name and return the deepest module along with the Java class
|
84
|
-
# name back to the caller.
|
85
|
-
def self.parent_for(java_class_fqn)
|
86
|
-
java_class_fqn.split(".").inject(MBeans) do |parent, segment|
|
87
|
-
# const_defined? will crash later if we don't remove $
|
88
|
-
segment.gsub!('$', 'Dollar') if segment =~ /\$/
|
89
|
-
# Note: We are boned if java class name is lower cased
|
90
|
-
return [parent, segment] if segment =~ /^[A-Z]/
|
91
|
-
|
92
|
-
segment.capitalize!
|
93
|
-
unless parent.const_defined? segment
|
94
|
-
parent.const_set segment, Module.new
|
95
|
-
else
|
96
|
-
parent.const_get segment
|
97
|
-
end
|
98
|
-
end
|
99
|
-
|
100
|
-
end
|
101
|
-
end
|
102
|
-
|
103
|
-
# Create a Ruby proxy based on the MBean represented by the object_name
|
104
|
-
class MBeanProxy
|
105
|
-
# Generate a friendly Ruby proxy for the MBean represented by object_name
|
106
|
-
def self.generate(server, object_name)
|
107
|
-
parent, class_name = MBeans.parent_for object_name.info(server).class_name
|
108
|
-
|
109
|
-
if parent.const_defined? class_name
|
110
|
-
proxy = parent.const_get(class_name)
|
111
|
-
else
|
112
|
-
proxy = Class.new MBeanProxy
|
113
|
-
parent.const_set class_name, proxy
|
114
|
-
end
|
115
|
-
|
116
|
-
proxy.new(server, object_name)
|
117
|
-
end
|
118
|
-
|
119
|
-
def initialize(server, object_name)
|
120
|
-
@server, @object_name = server, object_name
|
121
|
-
@info = @server.getMBeanInfo(@object_name)
|
122
|
-
|
123
|
-
define_attributes
|
124
|
-
define_operations
|
125
|
-
end
|
126
|
-
|
127
|
-
def attributes
|
128
|
-
@attributes ||= @info.attributes.inject([]) { |s,attr| s << attr.name }
|
129
|
-
end
|
130
|
-
|
131
|
-
def operations
|
132
|
-
@operations ||= @info.operations.inject([]) { |s,op| s << op.name }
|
133
|
-
end
|
134
|
-
|
135
|
-
# Get MBean attribute specified by name. If it is just a plain attribute then
|
136
|
-
# unwrap the attribute and just return the value.
|
137
|
-
def [](name)
|
138
|
-
attribute = @server.getAttribute(@object_name, name.to_s)
|
139
|
-
return attribute.value if attribute.kind_of? javax.management.Attribute
|
140
|
-
attribute
|
141
|
-
end
|
142
|
-
|
143
|
-
# Set MBean attribute specified by name to value
|
144
|
-
def []=(name, value)
|
145
|
-
@server.setAttribute @object_name, javax.management.Attribute.new(name.to_s, value)
|
146
|
-
end
|
147
|
-
|
148
|
-
def add_notification_listener(filter=nil, handback=nil, &listener)
|
149
|
-
@server.addNotificationListener @object_name, listener, filter, handback
|
150
|
-
end
|
151
|
-
|
152
|
-
def remove_notification_listener(listener)
|
153
|
-
@server.removeNotificationListener @object_name, listener
|
154
|
-
end
|
155
|
-
|
156
|
-
private
|
157
|
-
|
158
|
-
# Define ruby friendly methods for attributes. For odd attribute names or names
|
159
|
-
# that you want to call with the actual attribute name you can call aref/aset
|
160
|
-
def define_attributes
|
161
|
-
@info.attributes.each do |attr|
|
162
|
-
rname = underscore(attr.name)
|
163
|
-
self.class.__send__(:define_method, rname) { self[attr.name] } if attr.readable?
|
164
|
-
self.class.__send__(:define_method, rname + "=") {|v| self[attr.name] = v } if attr.writable?
|
165
|
-
end
|
166
|
-
end
|
167
|
-
|
168
|
-
def define_operations
|
169
|
-
@info.operations.each do |op|
|
170
|
-
self.class.__send__(:define_method, op.name) do |*args|
|
171
|
-
jargs, jtypes = java_args(op.signature, args)
|
172
|
-
@server.invoke @object_name, op.name, jargs, jtypes
|
173
|
-
end
|
174
|
-
end
|
175
|
-
end
|
176
|
-
|
177
|
-
# Given the signature and the parameters supplied do these signatures match.
|
178
|
-
# Repackage these parameters as Java objects in a primitive object array.
|
179
|
-
def java_args(signature, params)
|
180
|
-
return nil if params.nil?
|
181
|
-
|
182
|
-
jtypes = []
|
183
|
-
jargs = []
|
184
|
-
params.each_with_index do |param, i|
|
185
|
-
type = signature[i].get_type
|
186
|
-
jtypes << type
|
187
|
-
required_type = JavaClass.for_name(type)
|
188
|
-
|
189
|
-
java_arg = param.to_java(:object)
|
190
|
-
|
191
|
-
if (param.kind_of? Array)
|
192
|
-
java_arg = param.inject(ArrayList.new) {|l, element| l << element }
|
193
|
-
end
|
194
|
-
|
195
|
-
jargs << java_arg
|
196
|
-
|
197
|
-
arg_type = java_arg.java_class
|
198
|
-
|
199
|
-
raise TypeError.new("parameter #{signature[i].name} expected to be #{required_type}, but was #{arg_type}") if !required_type.assignable_from? arg_type
|
200
|
-
end
|
201
|
-
[jargs.to_java, jtypes.to_java(:string)]
|
202
|
-
end
|
203
|
-
|
204
|
-
# Convert a collection of java objects to their Java class name equivalents
|
205
|
-
def java_types(params)
|
206
|
-
return nil if params.nil?
|
207
|
-
|
208
|
-
params.map {|e| e.class.java_class.name }.to_java(:string)
|
209
|
-
end
|
210
|
-
|
211
|
-
def underscore(string)
|
212
|
-
string.gsub(/([a-z\d])([A-Z])/, '\1_\2').downcase
|
213
|
-
end
|
214
|
-
end
|
215
43
|
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'java'
|
2
|
+
|
3
|
+
module javax::management::openmbean::CompositeData
|
4
|
+
include Enumerable
|
5
|
+
|
6
|
+
def [](key)
|
7
|
+
get(key.to_s)
|
8
|
+
end
|
9
|
+
|
10
|
+
def method_missing(name, *args)
|
11
|
+
self[name]
|
12
|
+
end
|
13
|
+
|
14
|
+
def each
|
15
|
+
get_composite_type.key_set.each { |key| yield key }
|
16
|
+
end
|
17
|
+
|
18
|
+
def each_pair
|
19
|
+
get_composite_type.key_set.each { |key| yield key, get(key) }
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,164 @@
|
|
1
|
+
require 'java'
|
2
|
+
|
3
|
+
java_import java.util.ArrayList
|
4
|
+
|
5
|
+
module JMX
|
6
|
+
##
|
7
|
+
# Create a Ruby proxy based on the MBean represented by the object_name
|
8
|
+
# This proxy will be able to dispatch to the actual MBean to allow it to
|
9
|
+
# execute operations and read/update attributes. The primary mechanism
|
10
|
+
# for calling attributes or operations is to just call them as if they
|
11
|
+
# represented methods on the MBean. For example:
|
12
|
+
#
|
13
|
+
# memory = client["java.lang:type=Memory"]
|
14
|
+
# memory.gc
|
15
|
+
# memory.heap_memory_usage.used
|
16
|
+
#
|
17
|
+
# Here we first call an operation on this Memory heap called 'gc' and then
|
18
|
+
# we access an attribute 'heap_memory_usage' (Note: we can use snake-cased
|
19
|
+
# naming instead of actual 'HeapMemoryUsage'). In the case of a naming
|
20
|
+
# conflict (existing Ruby method, or same-named attribute as MBean operation),
|
21
|
+
# there there are long hand mechanisms:
|
22
|
+
#
|
23
|
+
# memory = client["java.lang:type=Memory"]
|
24
|
+
# memory.invoke(:gc)
|
25
|
+
# memory[:heap_memory_usage][:used]
|
26
|
+
#
|
27
|
+
class MBeanProxy
|
28
|
+
# Generate a friendly Ruby proxy for the MBean represented by object_name
|
29
|
+
def self.generate(server, object_name)
|
30
|
+
parent, class_name = MBeans.parent_for object_name.info(server).class_name
|
31
|
+
|
32
|
+
if parent.const_defined? class_name
|
33
|
+
proxy = parent.const_get(class_name)
|
34
|
+
else
|
35
|
+
proxy = Class.new MBeanProxy
|
36
|
+
parent.const_set class_name, proxy
|
37
|
+
end
|
38
|
+
|
39
|
+
proxy.new(server, object_name)
|
40
|
+
end
|
41
|
+
|
42
|
+
def initialize(server, object_name)
|
43
|
+
@server, @object_name = server, object_name
|
44
|
+
@info = @server.getMBeanInfo(@object_name)
|
45
|
+
|
46
|
+
define_attributes
|
47
|
+
define_operations
|
48
|
+
end
|
49
|
+
|
50
|
+
def attributes
|
51
|
+
@attributes ||= @info.attributes.inject([]) { |s,attr| s << attr.name }
|
52
|
+
end
|
53
|
+
|
54
|
+
def operations
|
55
|
+
@operations ||= @info.operations.inject([]) { |s,op| s << op.name }
|
56
|
+
end
|
57
|
+
|
58
|
+
##
|
59
|
+
# Get MBean attribute specified by name. If it is just a plain attribute
|
60
|
+
# then unwrap the attribute and just return the value.
|
61
|
+
def [](name)
|
62
|
+
attribute = @server.getAttribute(@object_name, name.to_s)
|
63
|
+
return attribute.value if attribute.kind_of? javax.management.Attribute
|
64
|
+
attribute
|
65
|
+
end
|
66
|
+
|
67
|
+
##
|
68
|
+
# Set MBean attribute specified by name to value
|
69
|
+
def []=(name, value)
|
70
|
+
@server.setAttribute @object_name, javax.management.Attribute.new(name.to_s, value)
|
71
|
+
end
|
72
|
+
|
73
|
+
##
|
74
|
+
# Invoke an operation. A NoMethodError will be thrown if this MBean
|
75
|
+
# cannot respond to the operation.
|
76
|
+
#
|
77
|
+
# FIXME: Add scoring to pick best match instead of first found
|
78
|
+
def invoke(name, *params)
|
79
|
+
op = @info.operations.find { |o| o.name == name.to_s }
|
80
|
+
|
81
|
+
raise NoMethodError.new("No such operation #{name}") unless op
|
82
|
+
|
83
|
+
jargs, jtypes = java_args(op.signature, params)
|
84
|
+
@server.invoke @object_name, op.name, jargs, jtypes
|
85
|
+
end
|
86
|
+
|
87
|
+
def add_notification_listener(filter=nil, handback=nil, &listener)
|
88
|
+
@server.addNotificationListener @object_name, listener, filter, handback
|
89
|
+
end
|
90
|
+
|
91
|
+
def remove_notification_listener(listener)
|
92
|
+
@server.removeNotificationListener @object_name, listener
|
93
|
+
end
|
94
|
+
|
95
|
+
private
|
96
|
+
|
97
|
+
# Define ruby friendly methods for attributes. For odd attribute names or
|
98
|
+
# names that you want to call with the actual attribute name you can call
|
99
|
+
# aref/aset ([], []=).
|
100
|
+
def define_attributes
|
101
|
+
@info.attributes.each do |attr|
|
102
|
+
rname = underscore(attr.name)
|
103
|
+
self.class.__send__(:define_method, rname) { self[attr.name] } if attr.readable?
|
104
|
+
self.class.__send__(:define_method, rname + "=") {|v| self[attr.name] = v } if attr.writable?
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
# Define ruby friendly methods for operations. For name conflicts you
|
109
|
+
# should call 'invoke(op_name, *args)'
|
110
|
+
def define_operations
|
111
|
+
@info.operations.each do |op|
|
112
|
+
self.class.__send__(:define_method, op.name) do |*params|
|
113
|
+
jargs, jtypes = java_args(op.signature, params)
|
114
|
+
@server.invoke @object_name, op.name, jargs, jtypes
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
PRIMITIVE_JAVA_TYPES = {
|
120
|
+
'int' => Java::java.lang.Integer,
|
121
|
+
'short' => Java::java.lang.Short,
|
122
|
+
'float' => Java::java.lang.Float,
|
123
|
+
'boolean' => Java::java.lang.Boolean
|
124
|
+
}
|
125
|
+
|
126
|
+
# Given the signature and the parameters supplied do these signatures match.
|
127
|
+
# Repackage these parameters as Java objects in a primitive object array.
|
128
|
+
def java_args(signature, params)
|
129
|
+
return nil if params.nil?
|
130
|
+
|
131
|
+
jtypes = []
|
132
|
+
jargs = []
|
133
|
+
params.each_with_index do |param, i|
|
134
|
+
type = signature[i].get_type
|
135
|
+
jtypes << type
|
136
|
+
required_type = JavaClass.for_name(type)
|
137
|
+
java_type = PRIMITIVE_JAVA_TYPES[required_type.name] || :object
|
138
|
+
java_arg = param.to_java(java_type)
|
139
|
+
|
140
|
+
if (param.kind_of? Array)
|
141
|
+
java_arg = param.inject(ArrayList.new) {|l, element| l << element }
|
142
|
+
end
|
143
|
+
|
144
|
+
jargs << java_arg
|
145
|
+
|
146
|
+
arg_type = java_arg.java_class
|
147
|
+
|
148
|
+
raise TypeError.new("parameter #{signature[i].name} expected to be #{required_type}, but was #{arg_type}") if !required_type.assignable_from? arg_type
|
149
|
+
end
|
150
|
+
[jargs.to_java, jtypes.to_java(:string)]
|
151
|
+
end
|
152
|
+
|
153
|
+
# Convert a collection of java objects to their Java class name equivalents
|
154
|
+
def java_types(params)
|
155
|
+
return nil if params.nil?
|
156
|
+
|
157
|
+
params.map {|e| e.class.java_class.name }.to_java(:string)
|
158
|
+
end
|
159
|
+
|
160
|
+
def underscore(string)
|
161
|
+
string.gsub(/([a-z\d])([A-Z])/, '\1_\2').downcase
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
data/lib/jmx/mbeans.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'java'
|
2
|
+
|
3
|
+
module JMX
|
4
|
+
# Holder for beans created from retrieval (namespace protection [tm]).
|
5
|
+
# This also gives MBeans nicer names when inspected
|
6
|
+
module MBeans
|
7
|
+
##
|
8
|
+
# Create modules in this namespace for each package in the Java fully
|
9
|
+
# qualified name and return the deepest module along with the Java class
|
10
|
+
# name back to the caller.
|
11
|
+
def self.parent_for(java_class_fqn)
|
12
|
+
java_class_fqn.split(".").inject(MBeans) do |parent, segment|
|
13
|
+
# const_defined? will crash later if we don't remove $
|
14
|
+
segment.gsub!('$', 'Dollar') if segment =~ /\$/
|
15
|
+
# Note: We are boned if java class name is lower cased
|
16
|
+
return [parent, segment] if segment =~ /^[A-Z]/
|
17
|
+
|
18
|
+
segment.capitalize!
|
19
|
+
unless parent.const_defined? segment
|
20
|
+
parent.const_set segment, Module.new
|
21
|
+
else
|
22
|
+
parent.const_get segment
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
data/lib/jmx/notifier.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
module JMX
|
2
|
+
module RubyNotificationEmitter
|
3
|
+
java_import javax.management.MBeanNotificationInfo
|
4
|
+
|
5
|
+
include javax.management.NotificationEmitter
|
6
|
+
|
7
|
+
def listeners
|
8
|
+
@listener ||= {}
|
9
|
+
end
|
10
|
+
|
11
|
+
# NotificationListener listener, NotificationFilter filter, Object handback
|
12
|
+
def addNotificationListener(listener, filter, handback)
|
13
|
+
listeners[listener] = [filter, handback]
|
14
|
+
end
|
15
|
+
|
16
|
+
def getNotificationInfo
|
17
|
+
[].to_java MBeanNotificationInfo
|
18
|
+
end
|
19
|
+
|
20
|
+
# NotificationListener listener, NotificationFilter filter, Object handback
|
21
|
+
def removeNotificationListener(listener, filter=nil, handback=nil)
|
22
|
+
found = false
|
23
|
+
listeners.delete_if do |clistener, (cfilter, chandback)|
|
24
|
+
v = listener == clistener && filter == cfilter && handback == chandback
|
25
|
+
found = true if v
|
26
|
+
v
|
27
|
+
end
|
28
|
+
raise javax.management.ListenerNotFoundException.new unless found
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'java'
|
2
|
+
java_import javax.management.ObjectName
|
3
|
+
|
4
|
+
class ObjectName
|
5
|
+
def [](key)
|
6
|
+
get_key_property(key.to_s)
|
7
|
+
end
|
8
|
+
|
9
|
+
def info(server)
|
10
|
+
server.getMBeanInfo(self)
|
11
|
+
end
|
12
|
+
|
13
|
+
##
|
14
|
+
# Make a new ObjectName unless it is already one
|
15
|
+
def self.make(name)
|
16
|
+
return name if name.kind_of? ObjectName
|
17
|
+
|
18
|
+
ObjectName.new name
|
19
|
+
rescue Exception
|
20
|
+
raise ArgumentError.new("Invalid ObjectName #{$!.message}")
|
21
|
+
end
|
22
|
+
end
|
data/lib/jmx/server.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'jmx/object_name'
|
2
|
+
|
1
3
|
module JMX
|
2
4
|
# The MBeanServer represents a connection to an MBean server
|
3
5
|
# rather than an actual MBean server. Depending upon how
|
@@ -33,7 +35,7 @@ module JMX
|
|
33
35
|
end
|
34
36
|
|
35
37
|
def [](object_name)
|
36
|
-
name =
|
38
|
+
name = ObjectName.make object_name
|
37
39
|
|
38
40
|
unless @server.isRegistered(name)
|
39
41
|
raise NoSuchBeanError.new("No name: #{object_name}")
|
@@ -45,7 +47,7 @@ module JMX
|
|
45
47
|
end
|
46
48
|
|
47
49
|
def []=(class_name, object_name)
|
48
|
-
name =
|
50
|
+
name = ObjectName.make object_name
|
49
51
|
|
50
52
|
@server.createMBean class_name, name, nil, nil
|
51
53
|
|
@@ -65,19 +67,17 @@ module JMX
|
|
65
67
|
end
|
66
68
|
|
67
69
|
def query_names(name=nil, query=nil)
|
68
|
-
object_name = name.nil? ? nil :
|
70
|
+
object_name = name.nil? ? nil : ObjectName.make(name)
|
69
71
|
|
70
72
|
@server.query_names(object_name, query)
|
71
73
|
end
|
72
74
|
|
73
75
|
def unregister_mbean(object_name)
|
74
|
-
|
75
|
-
@server.unregisterMBean(name)
|
76
|
-
|
76
|
+
@server.unregisterMBean(ObjectName.make(object_name))
|
77
77
|
end
|
78
78
|
|
79
79
|
def register_mbean(object, object_name)
|
80
|
-
name =
|
80
|
+
name = ObjectName.make(object_name)
|
81
81
|
@server.registerMBean(object, name)
|
82
82
|
MBeanProxy.generate(@server, name)
|
83
83
|
end
|
@@ -85,16 +85,6 @@ module JMX
|
|
85
85
|
def self.find(agent_id=nil)
|
86
86
|
MBeanServerFactory.findMBeanServer(agent_id)
|
87
87
|
end
|
88
|
-
|
89
|
-
private
|
90
|
-
|
91
|
-
def make_object_name(object_name)
|
92
|
-
return object_name if object_name.kind_of? ObjectName
|
93
|
-
|
94
|
-
ObjectName.new object_name
|
95
|
-
rescue Exception
|
96
|
-
raise ArgumentError.new("Invalid ObjectName #{$!.message}")
|
97
|
-
end
|
98
88
|
end
|
99
89
|
|
100
90
|
class NoSuchBeanError < RuntimeError
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module JMX
|
2
|
+
module StringUtils
|
3
|
+
def snakecase(string)
|
4
|
+
string.to_s.gsub(/([a-z\d])([A-Z])/, '\1_\2').downcase
|
5
|
+
end
|
6
|
+
|
7
|
+
def camelcase(string)
|
8
|
+
if string =~ /_/
|
9
|
+
string.to_s.gsub(/(?:^|_)(.)/) { $1.upcase }
|
10
|
+
else
|
11
|
+
string.to_s
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
data/lib/jmx/version.rb
CHANGED
data/test/jmx_client_test.rb
CHANGED
@@ -71,6 +71,23 @@ class JMXConnectorClientTest < Test::Unit::TestCase
|
|
71
71
|
|
72
72
|
assert(heap1.to_i >= heap2.to_i, "GC did not collect")
|
73
73
|
end
|
74
|
+
|
75
|
+
def test_simple_operation
|
76
|
+
memory = @client["java.lang:type=Memory"]
|
77
|
+
|
78
|
+
heap1 = memory[:HeapMemoryUsage][:used]
|
79
|
+
memory.invoke(:gc)
|
80
|
+
heap2 = memory[:HeapMemoryUsage][:used]
|
81
|
+
|
82
|
+
assert(heap1.to_i >= heap2.to_i, "GC did not collect")
|
83
|
+
end
|
84
|
+
|
85
|
+
def test_primitive_return_operation
|
86
|
+
threading = @client["java.lang:type=Threading"]
|
87
|
+
a_thread_id = threading[:AllThreadIds][0]
|
88
|
+
|
89
|
+
assert_not_nil threading.getThreadCpuTime(a_thread_id)
|
90
|
+
end
|
74
91
|
|
75
92
|
def test_query_names
|
76
93
|
names = @client.query_names("java.lang:type=MemoryPool,*")
|
metadata
CHANGED
@@ -1,83 +1,106 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: jmx
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
prerelease:
|
5
|
-
|
6
|
-
- 0
|
7
|
-
- 8
|
8
|
-
version: "0.8"
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease:
|
5
|
+
version: '0.9'
|
9
6
|
platform: ruby
|
10
|
-
authors:
|
7
|
+
authors:
|
11
8
|
- Thomas E. Enebo
|
12
|
-
autorequire:
|
9
|
+
autorequire:
|
13
10
|
bindir: bin
|
14
11
|
cert_chain: []
|
15
|
-
|
16
|
-
date: 2012-04-20 00:00:00 -05:00
|
17
|
-
default_executable:
|
12
|
+
date: 2012-06-11 00:00:00.000000000 Z
|
18
13
|
dependencies: []
|
19
|
-
|
20
14
|
description: Access and create MBeans in a friendly Ruby syntax
|
21
15
|
email: tom.enebo@gmail.com
|
22
16
|
executables: []
|
23
|
-
|
24
17
|
extensions: []
|
25
|
-
|
26
18
|
extra_rdoc_files: []
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
-
|
31
|
-
|
32
|
-
-
|
33
|
-
|
34
|
-
-
|
35
|
-
|
36
|
-
-
|
37
|
-
|
38
|
-
-
|
39
|
-
|
40
|
-
-
|
41
|
-
|
42
|
-
-
|
43
|
-
|
44
|
-
-
|
45
|
-
|
46
|
-
-
|
47
|
-
|
48
|
-
-
|
49
|
-
|
19
|
+
files:
|
20
|
+
- !binary |-
|
21
|
+
LmdpdGlnbm9yZQ==
|
22
|
+
- !binary |-
|
23
|
+
SGlzdG9yeS50eHQ=
|
24
|
+
- !binary |-
|
25
|
+
TElDRU5TRS50eHQ=
|
26
|
+
- !binary |-
|
27
|
+
TWFuaWZlc3QudHh0
|
28
|
+
- !binary |-
|
29
|
+
UkVBRE1FLm1k
|
30
|
+
- !binary |-
|
31
|
+
UmFrZWZpbGU=
|
32
|
+
- !binary |-
|
33
|
+
am14LmdlbXNwZWM=
|
34
|
+
- !binary |-
|
35
|
+
bGliL2pteC5yYg==
|
36
|
+
- !binary |-
|
37
|
+
bGliL2pteC9jb21wb3NpdGVfZGF0YS5yYg==
|
38
|
+
- !binary |-
|
39
|
+
bGliL2pteC9keW5hbWljX21iZWFuLnJi
|
40
|
+
- !binary |-
|
41
|
+
bGliL2pteC9tYmVhbl9wcm94eS5yYg==
|
42
|
+
- !binary |-
|
43
|
+
bGliL2pteC9tYmVhbnMucmI=
|
44
|
+
- !binary |-
|
45
|
+
bGliL2pteC9ub3RpZmllci5yYg==
|
46
|
+
- !binary |-
|
47
|
+
bGliL2pteC9vYmplY3RfbmFtZS5yYg==
|
48
|
+
- !binary |-
|
49
|
+
bGliL2pteC9zZXJ2ZXIucmI=
|
50
|
+
- !binary |-
|
51
|
+
bGliL2pteC91dGlsL3N0cmluZ191dGlscy5yYg==
|
52
|
+
- !binary |-
|
53
|
+
bGliL2pteC92ZXJzaW9uLnJi
|
54
|
+
- !binary |-
|
55
|
+
bGliL3JtaS5yYg==
|
56
|
+
- !binary |-
|
57
|
+
bmJwcm9qZWN0L3ByaXZhdGUvcHJpdmF0ZS54bWw=
|
58
|
+
- !binary |-
|
59
|
+
bmJwcm9qZWN0L3Byb2plY3QucHJvcGVydGllcw==
|
60
|
+
- !binary |-
|
61
|
+
bmJwcm9qZWN0L3Byb2plY3QueG1s
|
62
|
+
- !binary |-
|
63
|
+
c2FtcGxlcy9tZW1vcnkucmI=
|
64
|
+
- !binary |-
|
65
|
+
dGVzdC9qbXhfYXR0cmlidXRlX3Rlc3QucmI=
|
66
|
+
- !binary |-
|
67
|
+
dGVzdC9qbXhfY2xpZW50X3Rlc3QucmI=
|
68
|
+
- !binary |-
|
69
|
+
dGVzdC9qbXhfbWFuZ2xpbmdfdGVzdC5yYg==
|
70
|
+
- !binary |-
|
71
|
+
dGVzdC9qbXhfc2VydmVyX3Rlc3QucmI=
|
50
72
|
homepage: http://github.com/enebo/jmx
|
51
73
|
licenses: []
|
52
|
-
|
53
|
-
post_install_message:
|
74
|
+
post_install_message:
|
54
75
|
rdoc_options: []
|
55
|
-
|
56
|
-
require_paths:
|
76
|
+
require_paths:
|
57
77
|
- lib
|
58
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
59
|
-
requirements:
|
60
|
-
- -
|
61
|
-
- !ruby/object:Gem::Version
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
66
|
-
requirements:
|
67
|
-
- -
|
68
|
-
- !ruby/object:Gem::Version
|
69
|
-
|
70
|
-
|
71
|
-
|
78
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ! '>='
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: !binary |-
|
83
|
+
MA==
|
84
|
+
none: false
|
85
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ! '>='
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: !binary |-
|
90
|
+
MA==
|
91
|
+
none: false
|
72
92
|
requirements: []
|
73
|
-
|
74
93
|
rubyforge_project: jmx
|
75
|
-
rubygems_version: 1.
|
76
|
-
signing_key:
|
94
|
+
rubygems_version: 1.8.24
|
95
|
+
signing_key:
|
77
96
|
specification_version: 3
|
78
97
|
summary: Access and create MBeans in a friendly Ruby syntax
|
79
|
-
test_files:
|
80
|
-
-
|
81
|
-
|
82
|
-
-
|
83
|
-
|
98
|
+
test_files:
|
99
|
+
- !binary |-
|
100
|
+
dGVzdC9qbXhfYXR0cmlidXRlX3Rlc3QucmI=
|
101
|
+
- !binary |-
|
102
|
+
dGVzdC9qbXhfY2xpZW50X3Rlc3QucmI=
|
103
|
+
- !binary |-
|
104
|
+
dGVzdC9qbXhfbWFuZ2xpbmdfdGVzdC5yYg==
|
105
|
+
- !binary |-
|
106
|
+
dGVzdC9qbXhfc2VydmVyX3Rlc3QucmI=
|