jmx 0.8 → 0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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=
|