weblogic-jmx4r 0.1.9

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,16 @@
1
+
2
+ module JMX
3
+ module JDKHelper
4
+ module JDK4
5
+
6
+ class << self
7
+ def method_missing(method, *args, &block)
8
+ raise "JDK (>= 5.0) implementation is not available - \
9
+ maybe only JREs or older JDKs are installed properly."
10
+ end
11
+ end
12
+
13
+ end
14
+ end
15
+ end
16
+
@@ -0,0 +1,34 @@
1
+
2
+ module JMX
3
+ module JDKHelper
4
+ module JDK5
5
+ java_import sun.jvmstat.monitor.HostIdentifier
6
+ java_import sun.jvmstat.monitor.MonitoredHost
7
+ java_import sun.jvmstat.monitor.MonitoredVmUtil
8
+ java_import sun.jvmstat.monitor.VmIdentifier
9
+ java_import sun.management.ConnectorAddressLink
10
+
11
+ class << self
12
+
13
+ def find_local_url(command_pattern)
14
+ host_id = HostIdentifier.new(nil)
15
+ host = MonitoredHost.get_monitored_host(host_id)
16
+
17
+ host.active_vms.each do |vmid_int|
18
+ vmid = VmIdentifier.new(vmid_int.to_s)
19
+ vm = host.get_monitored_vm(vmid)
20
+ command = MonitoredVmUtil.command_line(vm)
21
+ if command_pattern === command
22
+ return ConnectorAddressLink.import_from(vmid_int)
23
+ end
24
+ end
25
+
26
+ nil
27
+ end
28
+
29
+ end
30
+
31
+ end
32
+ end
33
+ end
34
+
@@ -0,0 +1,69 @@
1
+
2
+ module JMX
3
+ module JDKHelper
4
+ module JDK6
5
+ java_import com.sun.tools.attach.VirtualMachine
6
+
7
+ class << self
8
+ def find_local_url(command_pattern)
9
+ target_vmd = VirtualMachine.list.find do |vmd|
10
+ command_pattern === vmd.display_name
11
+ end
12
+
13
+ if target_vmd
14
+ local_connector_address(target_vmd)
15
+ end
16
+ end
17
+
18
+ private
19
+
20
+ def local_connector_address(vm_descriptor)
21
+ vm = VirtualMachine.attach(vm_descriptor)
22
+
23
+ address = nil
24
+ agent_loaded = false
25
+
26
+ lambda {
27
+ address = vm.get_agent_properties.get(
28
+ "com.sun.management.jmxremote.localConnectorAddress")
29
+
30
+ unless address || agent_loaded
31
+ load_management_agent(vm)
32
+ agent_loaded = true
33
+ redo
34
+ end
35
+ }.call
36
+
37
+ vm.detach
38
+
39
+ address
40
+ end
41
+
42
+ def load_management_agent(vm)
43
+ home =
44
+ vm.get_system_properties.get_property 'java.home'
45
+
46
+ try_load_management_agent(vm, [home, 'jre', 'lib']) or
47
+ try_load_management_agent(vm, [home, 'lib']) or
48
+ raise "management agent not found"
49
+ end
50
+
51
+ def try_load_management_agent(vm, path)
52
+ sep = vm.get_system_properties.get_property 'file.separator'
53
+
54
+ path = path.dup
55
+ path << 'management-agent.jar'
56
+
57
+ file = Java::java.io.File.new(path.join(sep))
58
+ if file.exists
59
+ vm.load_agent(file.get_canonical_path,
60
+ "com.sun.management.jmxremote")
61
+ true
62
+ end
63
+ end
64
+
65
+ end
66
+ end
67
+ end
68
+ end
69
+
@@ -0,0 +1,69 @@
1
+
2
+ module JMX
3
+ module JDKHelper
4
+ java_import java.lang.System
5
+
6
+ class << self
7
+
8
+ def method_missing(method, *args, &block)
9
+ init unless @jdk
10
+ @jdk.send method, *args, &block
11
+ end
12
+
13
+ private
14
+
15
+ def init
16
+ @jdk =
17
+ case
18
+ when has_java_class?("com.sun.tools.attach.VirtualMachine")
19
+ require "jdk/jdk6"
20
+ JDK6
21
+ when has_java_class?('sun.jvmstat.monitor.MonitoredHost')
22
+ require "jdk/jdk5"
23
+ JDK5
24
+ else
25
+ require "jdk/jdk4"
26
+ JDK4
27
+ end
28
+ end
29
+
30
+ def has_java_class?(name)
31
+ begin
32
+ java_import name
33
+ true
34
+ rescue
35
+ retry if load_tools_jar
36
+ false
37
+ end
38
+ end
39
+
40
+ def load_tools_jar
41
+ unless @tools_loaded
42
+ home = System.get_property 'java.home'
43
+ paths = [
44
+ [home, '..', 'lib'],
45
+ [home, 'lib'],
46
+ ]
47
+ try_load_jar('tools.jar', paths)
48
+ @tools_loaded = true
49
+ true
50
+ end
51
+ end
52
+
53
+ def try_load_jar(jar_file, paths)
54
+ sep = System.get_property 'file.separator'
55
+ paths = paths.dup
56
+ begin
57
+ path = paths.shift
58
+ require path.join(sep) + sep + jar_file
59
+ true
60
+ rescue LoadError
61
+ retry unless paths.empty?
62
+ false
63
+ end
64
+ end
65
+ end
66
+
67
+ end
68
+ end
69
+
@@ -0,0 +1,304 @@
1
+ # Copyright 2007 Jeff Mesnil (http://jmesnil.net)
2
+ require 'java'
3
+
4
+ class String
5
+ # Transform a CamelCase String to a snake_case String.
6
+ #--
7
+ # Code has been taken from ActiveRecord
8
+ def snake_case
9
+ self.to_s.gsub(/::/, '/').
10
+ gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
11
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').
12
+ tr("-", "_").
13
+ downcase
14
+ end
15
+
16
+ # Transform a snake_case String to a camelCase String with a lowercase initial.
17
+ #--
18
+ # Code has been taken from ActiveSupport
19
+ def camel_case
20
+ name = gsub(/\/(.?)/) { "::#{$1.upcase}" }.gsub(/(?:^|_)(.)/) { $1.upcase }
21
+ name[0].chr.downcase + name[1..-1]
22
+ end
23
+ end
24
+
25
+ module JMX
26
+ require 'dynamic_mbean'
27
+ require 'open_data_helper'
28
+ require 'objectname_helper'
29
+ require 'jdk_helper'
30
+ require 'jruby'
31
+ require 'jars/wlthint3client.jar'
32
+
33
+ class MBeanServerConnectionProxy
34
+ attr_reader :connector
35
+
36
+ # Adds a connector attribute to Java's native MBeanServerConnection class.
37
+ #
38
+ # The connector attribute can be used to manage the connection (e.g, to close it).
39
+ # Why this isn't included in the native MBeanServerConnection class is beyond me.
40
+ #
41
+ # connector:: JMXConnector instance as returned by JMXConnectorFactory.connect.
42
+ def initialize(connector)
43
+ @connector = connector
44
+ @connection = connector.getMBeanServerConnection
45
+ end
46
+
47
+ # Close the connection (an unfortunate omission from the MBeanServerConnection class, imho)
48
+ def close
49
+ @connector.close
50
+ end
51
+
52
+ # Forward all other method messages to the underlying MBeanServerConnection instance.
53
+ def method_missing(method, *args, &block)
54
+ @connection.send method, *args, &block
55
+ end
56
+ end
57
+
58
+ class MBean
59
+ java_import java.util.HashMap
60
+ java_import javax.naming.Context
61
+ java_import javax.management.Attribute
62
+ java_import javax.management.ObjectName
63
+ java_import javax.management.remote.JMXConnector
64
+ java_import javax.management.remote.JMXConnectorFactory
65
+ java_import javax.management.remote.JMXServiceURL
66
+ JThread = java.lang.Thread
67
+
68
+ attr_reader :object_name, :operations, :attributes, :connection
69
+
70
+ def metaclass; class << self; self; end; end
71
+ def meta_def name, &blk
72
+ metaclass.instance_eval do
73
+ define_method name, &blk
74
+ end
75
+ end
76
+
77
+ # Creates a new MBean.
78
+ #
79
+ # object_name:: a string corresponding to a valid ObjectName
80
+ # connection:: a connection to a MBean server. If none is passed,
81
+ # use the global connection created by
82
+ # MBean.establish_connection
83
+ def initialize(object_name, connection=nil)
84
+ @connection = connection || @@connection
85
+ @object_name = object_name
86
+ info = @connection.getMBeanInfo @object_name
87
+ @attributes = Hash.new
88
+ info.attributes.each do | mbean_attr |
89
+ @attributes[mbean_attr.name.snake_case] = mbean_attr.name
90
+ end
91
+ @operations = Hash.new
92
+ info.operations.each do |mbean_op|
93
+ param_types = mbean_op.signature.map {|param| param.type}
94
+ @operations[mbean_op.name.snake_case] = [mbean_op.name, param_types]
95
+ end
96
+ end
97
+
98
+ def method_missing(method, *args, &block) #:nodoc:
99
+ method_in_snake_case = method.to_s.snake_case # this way Java/JRuby styles are compatible
100
+
101
+ if @operations.keys.include?(method_in_snake_case)
102
+ op_name, param_types = @operations[method_in_snake_case]
103
+ @connection.invoke @object_name,
104
+ op_name,
105
+ args.to_java(:Object),
106
+ param_types.to_java(:String)
107
+ else
108
+ super
109
+ end
110
+ end
111
+
112
+ @@connection = nil
113
+
114
+ # establish a connection to a remote MBean server which will
115
+ # be used by all subsequent MBeans.
116
+ #
117
+ # See MBean.create_connection for a list of the keys that are
118
+ # accepted in arguments.
119
+ #
120
+ # Examples
121
+ #
122
+ # JMX::MBean.establish_connection :port => "node23", :port => 1090
123
+ # JMX::MBean.establish_connection :port => "node23", :username => "jeff", :password => "secret"
124
+ # JMX::MBean.establish_connection :command => /jconsole/i
125
+ def self.establish_connection(args={})
126
+ @@connection ||= create_connection args
127
+ end
128
+
129
+ def self.remove_connection(args={})
130
+ if @@connection
131
+ @@connection.close rescue nil
132
+ end
133
+ @@connection = nil
134
+ end
135
+
136
+ def self.connection(args={})
137
+ if args.has_key? :host or args.has_key? :port
138
+ return create_connection(args)
139
+ else
140
+ @@connection ||= MBean.establish_connection(args)
141
+ end
142
+ end
143
+
144
+ # Create a connection to a remote MBean server.
145
+ #
146
+ # The args accepts the following keys:
147
+ #
148
+ # [:host] the host of the MBean server (defaults to "localhost")
149
+ #
150
+ # [:port] the port of the MBean server (defaults to 3000)
151
+ #
152
+ # [:url] the url of the MBean server.
153
+ # No default.
154
+ # if the url is specified, the host & port parameters are
155
+ # not taken into account
156
+ #
157
+ # [:command] the pattern matches the command line of the local
158
+ # JVM process including the MBean server.
159
+ # (command lines are listed on the connection dialog
160
+ # in JConsole).
161
+ # No default.
162
+ # this feature needs a JDK (>=5) installed on the local
163
+ # system.
164
+ # if the command is specified, the host & port or the url
165
+ # parameters are not taken into account
166
+ #
167
+ # [:username] the name of the user (if the MBean server requires authentication).
168
+ # No default
169
+ #
170
+ # [:password] the password of the user (if the MBean server requires authentication).
171
+ # No default
172
+ #
173
+ # [:credentials] custom credentials (if the MBean server requires authentication).
174
+ # No default. It has precedence over :username and :password (i.e. if
175
+ # :credentials is specified, :username & :password are ignored)
176
+ #
177
+ # [:provider_package] use to fill the JMXConnectorFactory::PROTOCOL_PROVIDER_PACKAGES.
178
+ # No default
179
+ #
180
+ def self.create_connection(args={})
181
+ host= args[:host] || "localhost"
182
+ port = args[:port] || 3000
183
+ username = args[:username]
184
+ password = args[:password]
185
+ credentials = args[:credentials]
186
+ provider_package = args[:provider_package]
187
+
188
+ if args[:command]
189
+ url = JDKHelper.find_local_url(args[:command]) or
190
+ raise "no locally attacheable VMs"
191
+ else
192
+ # host & port are not taken into account if url is set (see issue #7)
193
+ standard_url = "service:jmx:rmi:///jndi/rmi://#{host}:#{port}/jmxrmi"
194
+ url = args[:url] || standard_url
195
+ end
196
+
197
+ unless credentials
198
+ if !username.nil? and username.length > 0
199
+ user_password_credentials = [username, password]
200
+ credentials = user_password_credentials.to_java(:String)
201
+ end
202
+ end
203
+
204
+ env = HashMap.new
205
+ env.put(JMXConnector::CREDENTIALS, credentials) if credentials
206
+ # only fill the Context and JMXConnectorFactory properties if provider_package is set
207
+ if provider_package
208
+ env.put(Context::SECURITY_PRINCIPAL, username) if username
209
+ env.put(Context::SECURITY_CREDENTIALS, password) if password
210
+ env.put(JMXConnectorFactory::PROTOCOL_PROVIDER_PACKAGES, provider_package)
211
+ end
212
+
213
+ # the context class loader is set to JRuby's classloader when
214
+ # creating the JMX Connection so that classes loaded using
215
+ # JRuby "require" (and not from its classpath) can also be
216
+ # accessed (see issue #6)
217
+ begin
218
+ context_class_loader = JThread.current_thread.context_class_loader
219
+ JThread.current_thread.context_class_loader = JRuby.runtime.getJRubyClassLoader
220
+
221
+ puts url
222
+ puts $CLASSPATH
223
+
224
+ connector = JMXConnectorFactory::connect JMXServiceURL.new(url), env
225
+ MBeanServerConnectionProxy.new connector
226
+ ensure
227
+ # ... and we reset the previous context class loader
228
+ JThread.current_thread.context_class_loader = context_class_loader
229
+ end
230
+ end
231
+
232
+ # Returns an array of MBeans corresponding to all the MBeans
233
+ # registered for the ObjectName passed in parameter (which may be
234
+ # a pattern).
235
+ #
236
+ # The args accepts the same keys than #create_connection and an
237
+ # additional one:
238
+ #
239
+ # [:connection] a MBean server connection (as returned by #create_connection)
240
+ # No default. It has precedence over :host and :port (i.e if
241
+ # :connection is specified, :host and :port are ignored)
242
+ #
243
+ def self.find_all_by_name(name, args={})
244
+ object_name = ObjectName.new(name)
245
+ connection = args[:connection] || MBean.connection(args)
246
+ object_names = connection.queryNames(object_name, nil)
247
+ object_names.map { |on| create_mbean on, connection }
248
+ end
249
+
250
+ # Same as #find_all_by_name but the ObjectName passed in parameter
251
+ # can not be a pattern.
252
+ # Only one single MBean is returned.
253
+ def self.find_by_name(name, args={})
254
+ connection = args[:connection] || MBean.connection(args)
255
+ create_mbean ObjectName.new(name), connection
256
+ end
257
+
258
+ def self.create_mbean(object_name, connection)
259
+ info = connection.getMBeanInfo object_name
260
+ mbean = MBean.new object_name, connection
261
+ # define attribute accessor methods for the mbean
262
+ info.attributes.each do |mbean_attr|
263
+ mbean.meta_def mbean_attr.name.snake_case do
264
+ connection.getAttribute object_name, mbean_attr.name
265
+ end
266
+ if mbean_attr.isWritable
267
+ mbean.meta_def "#{mbean_attr.name.snake_case}=" do |value|
268
+ attribute = Attribute.new mbean_attr.name, value
269
+ connection.setAttribute object_name, attribute
270
+ end
271
+ end
272
+ end
273
+ mbean
274
+ end
275
+
276
+ def self.pretty_print (object_name, args={})
277
+ connection = args[:connection] || MBean.connection(args)
278
+ info = connection.getMBeanInfo ObjectName.new(object_name)
279
+ puts "object_name: #{object_name}"
280
+ puts "class: #{info.class_name}"
281
+ puts "description: #{info.description}"
282
+ puts "operations:"
283
+ info.operations.each do | op |
284
+ puts " #{op.name}"
285
+ op.signature.each do | param |
286
+ puts " #{param.name} (#{param.type} #{param.description})"
287
+ end
288
+ puts " ----"
289
+ puts " description: #{op.description}"
290
+ puts " return_type: #{op.return_type}"
291
+ puts " impact: #{op.impact}"
292
+ end
293
+ puts "attributes:"
294
+ info.attributes.each do | attr |
295
+ puts " #{attr.name}"
296
+ puts " description: #{attr.description}"
297
+ puts " type: #{attr.type}"
298
+ puts " readable: #{attr.readable}"
299
+ puts " writable: #{attr.writable}"
300
+ puts " is: #{attr.is}"
301
+ end
302
+ end
303
+ end
304
+ end