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 CHANGED
@@ -9,5 +9,6 @@ lib/jmx/version.rb
9
9
  lib/jmx.rb
10
10
  lib/rmi.rb
11
11
  samples/memory.rb
12
+ test/jmx_attribute_test.rb
12
13
  test/jmx_client_test.rb
13
14
  test/jmx_server_test.rb
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)
@@ -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
- :map => 'java.util.Map',
12
- :set => 'java.util.Set',
13
- :string => 'java.lang.String',
14
- :void => 'java.lang.Void'
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
- @info = MBeanInfo.new name, description, nil, nil, operations, nil
220
+ attributes = self.class.attributes.to_java(MBeanAttributeInfo)
221
+ @info = MBeanInfo.new name, description, attributes, nil, operations, nil
88
222
  end
89
223
 
90
- def getAttribute(attribute); $stderr.puts "getAttribute"; end
91
- def getAttributes(attributes); $stderr.puts "getAttributes"; end
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
- def setAttribute(attribute); $stderr.puts "setAttribute"; end
97
- def setAttributes(attributes); $stderr.puts "setAttributes"; end
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
@@ -1,3 +1,3 @@
1
1
  module JMX
2
- VERSION = "0.1"
2
+ VERSION = "0.2"
3
3
  end
@@ -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.1"
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-06-06 00:00:00 -05:00
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