jmx 0.1 → 0.2
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/Manifest.txt +1 -0
- data/lib/jmx.rb +1 -1
- data/lib/jmx/dynamic_mbean.rb +167 -16
- data/lib/jmx/server.rb +10 -0
- data/lib/jmx/version.rb +1 -1
- data/test/jmx_attribute_test.rb +156 -0
- metadata +3 -2
data/Manifest.txt
CHANGED
data/lib/jmx.rb
CHANGED
@@ -135,7 +135,7 @@ module JMX
|
|
135
135
|
|
136
136
|
# Set MBean attribute specified by name to value
|
137
137
|
def []=(name, value)
|
138
|
-
@server.setAttribute @object_name, Attribute.new(name.to_s, value)
|
138
|
+
@server.setAttribute @object_name, javax.management.Attribute.new(name.to_s, value)
|
139
139
|
end
|
140
140
|
|
141
141
|
def add_notification_listener(filter=nil, handback=nil, &listener)
|
data/lib/jmx/dynamic_mbean.rb
CHANGED
@@ -1,21 +1,31 @@
|
|
1
1
|
module JMX
|
2
2
|
import javax.management.MBeanParameterInfo
|
3
3
|
import javax.management.MBeanOperationInfo
|
4
|
+
import javax.management.MBeanAttributeInfo
|
4
5
|
import javax.management.MBeanInfo
|
5
6
|
|
7
|
+
# Module that is used to bridge java to ruby and ruby to java types.
|
6
8
|
module JavaTypeAware
|
9
|
+
# Current list of types we understand If it's not in this list we are
|
10
|
+
# assuming that we are going to convert to a java.object
|
7
11
|
SIMPLE_TYPES = {
|
8
|
-
:int => 'java.lang.Integer',
|
9
|
-
:list => 'java.util.List',
|
10
|
-
:long => 'java.lang.Long',
|
11
|
-
:
|
12
|
-
:
|
13
|
-
:
|
14
|
-
:
|
12
|
+
:int => ['java.lang.Integer', lambda {|param| param.to_i}],
|
13
|
+
:list => ['java.util.List', lambda {|param| param.to_a}],
|
14
|
+
:long => ['java.lang.Long', lambda {|param| param.to_i}],
|
15
|
+
:float => ['java.lang.Float', lambda {|param| param.to_f}],
|
16
|
+
:map => ['java.util.Map', lambda {|param| param}],
|
17
|
+
:set => ['java.util.Set', lambda {|param| param}],
|
18
|
+
:string => ['java.lang.String', lambda {|param| "'#{param.to_s}'"}],
|
19
|
+
:void => ['java.lang.Void', lambda {|param| nil}]
|
15
20
|
}
|
16
21
|
|
17
22
|
def to_java_type(type_name)
|
18
|
-
SIMPLE_TYPES[type_name] || type_name
|
23
|
+
SIMPLE_TYPES[type_name][0] || type_name
|
24
|
+
end
|
25
|
+
#TODO: I'm not sure this is strictly needed, but funky things can happen if you
|
26
|
+
# are expecting your attributes (from the ruby side) to be ruby types and they are java types.
|
27
|
+
def to_ruby(type_name)
|
28
|
+
SIMPLE_TYPES[type_name][1] || lambda {|param| param}
|
19
29
|
end
|
20
30
|
end
|
21
31
|
|
@@ -44,29 +54,138 @@ module JMX
|
|
44
54
|
MBeanOperationInfo.new name.to_s, description, java_parameters.to_java(javax.management.MBeanParameterInfo), to_java_type(return_type), impact
|
45
55
|
end
|
46
56
|
end
|
57
|
+
|
58
|
+
class Attribute < Struct.new(:name, :type, :description, :is_reader, :is_writer, :is_iser)
|
59
|
+
include JavaTypeAware
|
60
|
+
|
61
|
+
def initialize(name, type, description, is_rdr, is_wrtr)
|
62
|
+
super
|
63
|
+
self.description, self.type, self.name = description, type, name
|
64
|
+
self.is_reader,self.is_writer, self.is_iser = is_rdr, is_wrtr, false
|
65
|
+
end
|
66
|
+
|
67
|
+
def to_jmx
|
68
|
+
MBeanAttributeInfo.new(name.to_s, to_java_type(type), description, is_reader, is_writer, is_iser)
|
69
|
+
end
|
70
|
+
end
|
47
71
|
end
|
48
72
|
|
73
|
+
# The Ruby-Java JMX utilities work throught the DynamicMBean concept. Creators of Ruby based MBeans must inherit this
|
74
|
+
# class (<tt>RubyDynamicMBean</tt>) in their own bean classes and then register them with a JMX mbean server.
|
75
|
+
# Here is an example:
|
76
|
+
# class MyMBean < DynamicMBean
|
77
|
+
# rw_attribute :status, :string, "Status information for this process"
|
78
|
+
#
|
79
|
+
# operation "Shutdown this process"
|
80
|
+
# parameter :string, "user_name", "Name of user requesting shutdown"
|
81
|
+
# returns :string
|
82
|
+
# def shutdown(user_name)
|
83
|
+
# "shutdown requests more time"
|
84
|
+
# end
|
85
|
+
# end
|
86
|
+
# Once you have defined your bean class you can start declaring attributes and operations. Attributes come in three flavors:
|
87
|
+
# read, write, and read write. Simmilar to the <tt>attr*</tt> helpers, there are helpers that are used to create management
|
88
|
+
# attributes. Use +r_attribute+, +w_attribute+, and +rw_attribute+ to declare attributes, and the +operation+, +returns+, and +parameter+
|
89
|
+
# helpers to define a management operation.
|
90
|
+
# Creating attributes with the *_attribute convention ALSO creates ruby accessors
|
91
|
+
# (it invokes the attr_accessor/attr_reader/attr_writer ruby helpers) to create ruby methods like: user_name= and username.
|
92
|
+
# So in your ruby code you can treat the attributes as "regular" ruby accessors
|
49
93
|
class RubyDynamicMBean
|
50
94
|
import javax.management.MBeanOperationInfo
|
95
|
+
import javax.management.MBeanAttributeInfo
|
96
|
+
include JMX::JavaTypeAware
|
51
97
|
|
52
98
|
# TODO: preserve any original method_added?
|
53
99
|
# TODO: Error handling here when it all goes wrong?
|
54
|
-
def self.method_added(name)
|
100
|
+
def self.method_added(name) #:nodoc:
|
55
101
|
return if Thread.current[:op].nil?
|
56
102
|
Thread.current[:op].name = name
|
57
103
|
operations << Thread.current[:op].to_jmx
|
58
104
|
Thread.current[:op] = nil
|
59
105
|
end
|
60
106
|
|
61
|
-
def self.attributes
|
107
|
+
def self.attributes #:nodoc:
|
62
108
|
Thread.current[:attrs] ||= []
|
63
109
|
end
|
64
110
|
|
65
|
-
def self.operations
|
111
|
+
def self.operations #:nodoc:
|
66
112
|
Thread.current[:ops] ||= []
|
67
113
|
end
|
68
114
|
|
115
|
+
# the <tt>rw_attribute</tt> method is used to declare a JMX read write attribute.
|
116
|
+
# see the +JavaSimpleTypes+ module for more information about acceptable types
|
117
|
+
# usage:
|
118
|
+
# rw_attribute :attribute_name, :string, "Description displayed in a JMX console"
|
119
|
+
#--methods used to create an attribute. They are modeled on the attrib_accessor
|
120
|
+
# patterns of creating getters and setters in ruby
|
121
|
+
#++
|
122
|
+
def self.rw_attribute(name, type, description)
|
123
|
+
#QUESTION: Is this here to ensure that our type implements the interface?
|
124
|
+
include DynamicMBean
|
125
|
+
attributes << JMX::Attribute.new(name, type, description, true, true).to_jmx
|
126
|
+
attr_accessor name
|
127
|
+
#create a "java" oriented accessor method
|
128
|
+
define_method("jmx_get_#{name.to_s.downcase}") do
|
129
|
+
begin
|
130
|
+
#attempt conversion
|
131
|
+
java_type = to_java_type(type)
|
132
|
+
value = eval "#{java_type}.new(@#{name.to_s})"
|
133
|
+
rescue
|
134
|
+
#otherwise turn it into a java Object type for now.
|
135
|
+
value = eval "Java.ruby_to_java(@#{name.to_s})"
|
136
|
+
end
|
137
|
+
attribute = javax.management.Attribute.new(name.to_s, value)
|
138
|
+
end
|
139
|
+
|
140
|
+
define_method("jmx_set_#{name.to_s.downcase}") do |value|
|
141
|
+
blck = to_ruby(type)
|
142
|
+
eval "@#{name.to_s} = #{blck.call(value)}"
|
143
|
+
end
|
144
|
+
|
145
|
+
end
|
146
|
+
# the <tt>r_attribute</tt> method is used to declare a JMX read only attribute.
|
147
|
+
# see the +JavaSimpleTypes+ module for more information about acceptable types
|
148
|
+
# usage:
|
149
|
+
# r_attribute :attribute_name, :string, "Description displayed in a JMX console"
|
150
|
+
def self.r_attribute(name, type, description)
|
151
|
+
include DynamicMBean
|
152
|
+
attributes << JMX::Attribute.new(name, type, description, true, false).to_jmx
|
153
|
+
attr_reader name
|
154
|
+
#create a "java" oriented accessor method
|
155
|
+
define_method("jmx_get_#{name.to_s.downcase}") do
|
156
|
+
begin
|
157
|
+
#attempt conversion
|
158
|
+
java_type = to_java_type(type)
|
159
|
+
value = eval "#{java_type}.new(@#{name.to_s})"
|
160
|
+
rescue
|
161
|
+
#otherwise turn it into a java Object type for now.
|
162
|
+
value = eval "Java.ruby_to_java(@#{name.to_s})"
|
163
|
+
end
|
164
|
+
attribute = javax.management.Attribute.new(name.to_s, value)
|
165
|
+
end
|
166
|
+
end
|
167
|
+
# the <tt>w_attribute</tt> method is used to declare a JMX write only attribute.
|
168
|
+
# see the +JavaSimpleTypes+ module for more information about acceptable types
|
169
|
+
# usage:
|
170
|
+
# w_attribute :attribute_name, :string, "Description displayed in a JMX console"
|
171
|
+
def self.w_attribute(name, type, description)
|
172
|
+
include DynamicMBean
|
173
|
+
attributes << JMX::Attribute.new(name, type, description, false, true).to_jmx
|
174
|
+
attr_writer name
|
175
|
+
define_method("jmx_set_#{name.to_s.downcase}") do |value|
|
176
|
+
blck = to_ruby(type)
|
177
|
+
eval "@#{name.to_s} = #{blck.call(value)}"
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
# Use the operation method to declare the start of an operation
|
182
|
+
# It takes as an argument the description for the operation
|
183
|
+
# operation "Used to start the service"
|
184
|
+
# def start
|
185
|
+
# end
|
186
|
+
#--
|
69
187
|
# Last operation wins if more than one
|
188
|
+
#++
|
70
189
|
def self.operation(description)
|
71
190
|
include DynamicMBean
|
72
191
|
|
@@ -74,27 +193,59 @@ class RubyDynamicMBean
|
|
74
193
|
Thread.current[:op] = JMX::Operation.new description
|
75
194
|
end
|
76
195
|
|
196
|
+
# Used to declare a parameter (you can declare more than one in succession) that
|
197
|
+
# is associated with the currently declared operation.
|
198
|
+
# operation "Used to update the name of a service"
|
199
|
+
# parameter :string, "name", "Set the new name of the service"
|
200
|
+
# def start
|
201
|
+
# end
|
77
202
|
def self.parameter(type, name=nil, description=nil)
|
78
203
|
Thread.current[:op].parameters << JMX::Parameter.new(type, name, description)
|
79
204
|
end
|
80
205
|
|
206
|
+
# Used to declare the return type of the operation
|
207
|
+
# operation "Used to update the name of a service"
|
208
|
+
# parameter :string, "name", "Set the new name of the service"
|
209
|
+
# returns :void
|
210
|
+
# def set_name
|
211
|
+
# end
|
81
212
|
def self.returns(type)
|
82
213
|
Thread.current[:op].return_type = type
|
83
214
|
end
|
84
215
|
|
216
|
+
# when creating a dynamic MBean we need to provide it with a
|
217
|
+
# name and a description.
|
85
218
|
def initialize(name, description)
|
86
219
|
operations = self.class.operations.to_java(MBeanOperationInfo)
|
87
|
-
|
220
|
+
attributes = self.class.attributes.to_java(MBeanAttributeInfo)
|
221
|
+
@info = MBeanInfo.new name, description, attributes, nil, operations, nil
|
88
222
|
end
|
89
223
|
|
90
|
-
|
91
|
-
def
|
224
|
+
# Retrieve the value of the requested attribute (where attribute is a javax.management.Attribute class)
|
225
|
+
def getAttribute(attribute)
|
226
|
+
send("jmx_get_"+attribute.downcase)
|
227
|
+
end
|
228
|
+
|
229
|
+
def getAttributes(attributes)
|
230
|
+
attrs = javax.management.AttributeList.new
|
231
|
+
attributes.each { |attribute| attrs.add(getAttribute(attribute)) }
|
232
|
+
attrs
|
233
|
+
end
|
234
|
+
|
92
235
|
def getMBeanInfo; @info; end
|
236
|
+
|
93
237
|
def invoke(actionName, params=nil, signature=nil)
|
94
238
|
send(actionName, *params)
|
95
239
|
end
|
96
|
-
|
97
|
-
def
|
240
|
+
|
241
|
+
def setAttribute(attribute)
|
242
|
+
send("jmx_set_#{attribute.name.downcase}", attribute.value)
|
243
|
+
end
|
244
|
+
|
245
|
+
def setAttributes(attributes)
|
246
|
+
attributes.each { |attribute| setAttribute attribute}
|
247
|
+
end
|
248
|
+
|
98
249
|
def to_s; toString; end
|
99
250
|
def inspect; toString; end
|
100
251
|
def toString; "#@info.class_name: #@info.description"; end
|
data/lib/jmx/server.rb
CHANGED
@@ -1,5 +1,11 @@
|
|
1
1
|
module JMX
|
2
|
+
# The MBeanServer represents a connection to an MBean server
|
3
|
+
# rather than an actual MBean server. Depending upon how
|
4
|
+
# this object is constructed you can either talk to the
|
5
|
+
# PlatformMBeanServer or any "remote" MBean server.
|
6
|
+
#--
|
2
7
|
# Represents both MBeanServer and MBeanServerConnection
|
8
|
+
#++
|
3
9
|
class MBeanServer
|
4
10
|
import javax.management.Attribute
|
5
11
|
import javax.management.MBeanServerFactory
|
@@ -9,6 +15,10 @@ module JMX
|
|
9
15
|
attr_accessor :server
|
10
16
|
@@classes = {}
|
11
17
|
|
18
|
+
# when creatinga new MBeanServer you can optionally specify a location, username, and password
|
19
|
+
# if specify these values (or at least the location) the MBeanServer instance will connect to
|
20
|
+
# an existing (and remote ) MBean server and register the mbeans there.
|
21
|
+
# otherwise the server will connect to to the local Platform MBean Server.
|
12
22
|
def initialize(location=nil, username=nil, password=nil)
|
13
23
|
if (location)
|
14
24
|
env = username ?
|
data/lib/jmx/version.rb
CHANGED
@@ -0,0 +1,156 @@
|
|
1
|
+
|
2
|
+
$:.unshift File.join(File.dirname(__FILE__),'..','lib')
|
3
|
+
|
4
|
+
require 'test/unit'
|
5
|
+
require 'rmi'
|
6
|
+
require 'jmx'
|
7
|
+
|
8
|
+
|
9
|
+
class MyAttributeDynamicBean < RubyDynamicMBean
|
10
|
+
rw_attribute :name1, :string, "My sample attribute"
|
11
|
+
r_attribute :number1, :int, "My sample integer based attribute that is read only"
|
12
|
+
w_attribute :number2, :int, "My sample integer based attribute that is write only"
|
13
|
+
|
14
|
+
def intialize(type, text)
|
15
|
+
super(type,text)
|
16
|
+
end
|
17
|
+
def set_number1(val)
|
18
|
+
@number1 = val
|
19
|
+
end
|
20
|
+
|
21
|
+
def fetch_number2
|
22
|
+
@number2
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
class JMXAttributeTest < Test::Unit::TestCase
|
27
|
+
|
28
|
+
def setup
|
29
|
+
@madb = MyAttributeDynamicBean.new("test.MyTestBean","Mwahahahahahah")
|
30
|
+
end
|
31
|
+
|
32
|
+
#make sure we didn't break anything from a ruby perspective
|
33
|
+
def test_can_create_bean_and_access_accessor_type_methods
|
34
|
+
@madb.set_number1 4
|
35
|
+
assert_nil(@madb.name1)
|
36
|
+
@madb.name1 = "Name"
|
37
|
+
assert_equal("Name", @madb.name1)
|
38
|
+
assert_equal(4, @madb.number1)
|
39
|
+
@madb.number2 = 4
|
40
|
+
assert_equal(4, @madb.fetch_number2)
|
41
|
+
assert_raise(NoMethodError) { @madb.number2 }
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_get_attributes_via_dynamicmbeaninterface
|
45
|
+
@madb.set_number1 4
|
46
|
+
@madb.name1 = "Name"
|
47
|
+
|
48
|
+
assert_equal(@madb.name1, @madb.getAttribute("name1").get_value.to_s)
|
49
|
+
assert_equal(@madb.number1, @madb.getAttribute("number1").get_value)
|
50
|
+
atts = ["name1", "number1"]
|
51
|
+
retrieved = @madb.getAttributes(atts)
|
52
|
+
assert_equal(2, retrieved.length)
|
53
|
+
#TODO: assertion comparing the types in teh array to java types
|
54
|
+
end
|
55
|
+
|
56
|
+
def test_set_attributes_via_dynamicbeaninterface
|
57
|
+
@madb.name1 = "blue"
|
58
|
+
red = java.lang.String.new("red")
|
59
|
+
attribute = javax.management.Attribute.new("name1", red)
|
60
|
+
@madb.setAttribute(attribute)
|
61
|
+
|
62
|
+
assert_equal("String", @madb.name1.class.to_s )
|
63
|
+
assert_equal("red", @madb.name1)
|
64
|
+
end
|
65
|
+
|
66
|
+
def test_set_multiple_attributes_via_dynamicbeaninterface
|
67
|
+
@madb.name1 = "blue"
|
68
|
+
three = java.lang.Integer.new(3)
|
69
|
+
red = java.lang.String.new("red")
|
70
|
+
attribute1 = javax.management.Attribute.new("name1", red)
|
71
|
+
attribute2 = javax.management.Attribute.new("number2", three)
|
72
|
+
|
73
|
+
@madb.setAttributes([attribute1, attribute2])
|
74
|
+
assert_equal("red", @madb.name1)
|
75
|
+
assert_equal(3, @madb.fetch_number2)
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
|
80
|
+
$:.unshift File.join(File.dirname(__FILE__),'..','lib')
|
81
|
+
|
82
|
+
require 'test/unit'
|
83
|
+
require 'rmi'
|
84
|
+
require 'jmx'
|
85
|
+
|
86
|
+
|
87
|
+
class MyAttributeDynamicBean < RubyDynamicMBean
|
88
|
+
rw_attribute :name1, :string, "My sample attribute"
|
89
|
+
r_attribute :number1, :int, "My sample integer based attribute that is read only"
|
90
|
+
w_attribute :number2, :int, "My sample integer based attribute that is write only"
|
91
|
+
|
92
|
+
def intialize(type, text)
|
93
|
+
super(type,text)
|
94
|
+
end
|
95
|
+
def set_number1(val)
|
96
|
+
@number1 = val
|
97
|
+
end
|
98
|
+
|
99
|
+
def fetch_number2
|
100
|
+
@number2
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
class JMXAttributeTest < Test::Unit::TestCase
|
105
|
+
|
106
|
+
def setup
|
107
|
+
@madb = MyAttributeDynamicBean.new("test.MyTestBean","Mwahahahahahah")
|
108
|
+
end
|
109
|
+
|
110
|
+
#make sure we didn't break anything from a ruby perspective
|
111
|
+
def test_can_create_bean_and_access_accessor_type_methods
|
112
|
+
@madb.set_number1 4
|
113
|
+
assert_nil(@madb.name1)
|
114
|
+
@madb.name1 = "Name"
|
115
|
+
assert_equal("Name", @madb.name1)
|
116
|
+
assert_equal(4, @madb.number1)
|
117
|
+
@madb.number2 = 4
|
118
|
+
assert_equal(4, @madb.fetch_number2)
|
119
|
+
assert_raise(NoMethodError) { @madb.number2 }
|
120
|
+
end
|
121
|
+
|
122
|
+
def test_get_attributes_via_dynamicmbeaninterface
|
123
|
+
@madb.set_number1 4
|
124
|
+
@madb.name1 = "Name"
|
125
|
+
|
126
|
+
assert_equal(@madb.name1, @madb.getAttribute("name1").get_value.to_s)
|
127
|
+
assert_equal(@madb.number1, @madb.getAttribute("number1").get_value)
|
128
|
+
atts = ["name1", "number1"]
|
129
|
+
retrieved = @madb.getAttributes(atts)
|
130
|
+
assert_equal(2, retrieved.length)
|
131
|
+
#TODO: assertion comparing the types in teh array to java types
|
132
|
+
end
|
133
|
+
|
134
|
+
def test_set_attributes_via_dynamicbeaninterface
|
135
|
+
@madb.name1 = "blue"
|
136
|
+
red = java.lang.String.new("red")
|
137
|
+
attribute = javax.management.Attribute.new("name1", red)
|
138
|
+
@madb.setAttribute(attribute)
|
139
|
+
|
140
|
+
assert_equal("String", @madb.name1.class.to_s )
|
141
|
+
assert_equal("red", @madb.name1)
|
142
|
+
end
|
143
|
+
|
144
|
+
def test_set_multiple_attributes_via_dynamicbeaninterface
|
145
|
+
@madb.name1 = "blue"
|
146
|
+
three = java.lang.Integer.new(3)
|
147
|
+
red = java.lang.String.new("red")
|
148
|
+
attribute1 = javax.management.Attribute.new("name1", red)
|
149
|
+
attribute2 = javax.management.Attribute.new("number2", three)
|
150
|
+
|
151
|
+
@madb.setAttributes([attribute1, attribute2])
|
152
|
+
assert_equal("red", @madb.name1)
|
153
|
+
assert_equal(3, @madb.fetch_number2)
|
154
|
+
end
|
155
|
+
|
156
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jmx
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: "0.
|
4
|
+
version: "0.2"
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Thomas Enebo
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2008-
|
12
|
+
date: 2008-07-28 00:00:00 +09:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
@@ -35,6 +35,7 @@ files:
|
|
35
35
|
- lib/jmx.rb
|
36
36
|
- lib/rmi.rb
|
37
37
|
- samples/memory.rb
|
38
|
+
- test/jmx_attribute_test.rb
|
38
39
|
- test/jmx_client_test.rb
|
39
40
|
- test/jmx_server_test.rb
|
40
41
|
has_rdoc: true
|