jmx 0.1 → 0.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|