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 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