Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/jdk.jconsole/share/classes/sun/tools/jconsole/ProxyClient.java
40948 views
1
/*
2
* Copyright (c) 2004, 2014, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation. Oracle designates this
8
* particular file as subject to the "Classpath" exception as provided
9
* by Oracle in the LICENSE file that accompanied this code.
10
*
11
* This code is distributed in the hope that it will be useful, but WITHOUT
12
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14
* version 2 for more details (a copy is included in the LICENSE file that
15
* accompanied this code).
16
*
17
* You should have received a copy of the GNU General Public License version
18
* 2 along with this work; if not, write to the Free Software Foundation,
19
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20
*
21
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22
* or visit www.oracle.com if you need additional information or have any
23
* questions.
24
*/
25
26
package sun.tools.jconsole;
27
28
import com.sun.management.HotSpotDiagnosticMXBean;
29
import com.sun.tools.jconsole.JConsoleContext;
30
import java.beans.PropertyChangeListener;
31
import java.beans.PropertyChangeEvent;
32
import java.io.IOException;
33
import java.lang.management.*;
34
import static java.lang.management.ManagementFactory.*;
35
import java.lang.ref.WeakReference;
36
import java.lang.reflect.*;
37
import java.rmi.*;
38
import java.rmi.registry.*;
39
import java.rmi.server.*;
40
import java.util.*;
41
import javax.management.*;
42
import javax.management.remote.*;
43
import javax.management.remote.rmi.*;
44
import javax.rmi.ssl.SslRMIClientSocketFactory;
45
import javax.swing.event.SwingPropertyChangeSupport;
46
import sun.rmi.server.UnicastRef2;
47
import sun.rmi.transport.LiveRef;
48
49
public class ProxyClient implements JConsoleContext {
50
51
private ConnectionState connectionState = ConnectionState.DISCONNECTED;
52
53
// The SwingPropertyChangeSupport will fire events on the EDT
54
private SwingPropertyChangeSupport propertyChangeSupport =
55
new SwingPropertyChangeSupport(this, true);
56
57
private static Map<String, ProxyClient> cache =
58
Collections.synchronizedMap(new HashMap<String, ProxyClient>());
59
60
private volatile boolean isDead = true;
61
private String hostName = null;
62
private int port = 0;
63
private String userName = null;
64
private String password = null;
65
private boolean hasPlatformMXBeans = false;
66
private boolean hasHotSpotDiagnosticMXBean= false;
67
private boolean hasCompilationMXBean = false;
68
private boolean supportsLockUsage = false;
69
70
// REVISIT: VMPanel and other places relying using getUrl().
71
72
// set only if it's created for local monitoring
73
private LocalVirtualMachine lvm;
74
75
// set only if it's created from a given URL via the Advanced tab
76
private String advancedUrl = null;
77
78
private JMXServiceURL jmxUrl = null;
79
private MBeanServerConnection mbsc = null;
80
private SnapshotMBeanServerConnection server = null;
81
private JMXConnector jmxc = null;
82
private RMIServer stub = null;
83
private static final SslRMIClientSocketFactory sslRMIClientSocketFactory =
84
new SslRMIClientSocketFactory();
85
private String registryHostName = null;
86
private int registryPort = 0;
87
private boolean vmConnector = false;
88
private boolean sslRegistry = false;
89
private boolean sslStub = false;
90
private final String connectionName;
91
private final String displayName;
92
93
private ClassLoadingMXBean classLoadingMBean = null;
94
private CompilationMXBean compilationMBean = null;
95
private MemoryMXBean memoryMBean = null;
96
private OperatingSystemMXBean operatingSystemMBean = null;
97
private RuntimeMXBean runtimeMBean = null;
98
private ThreadMXBean threadMBean = null;
99
100
private com.sun.management.OperatingSystemMXBean sunOperatingSystemMXBean = null;
101
private HotSpotDiagnosticMXBean hotspotDiagnosticMXBean = null;
102
103
private List<MemoryPoolProxy> memoryPoolProxies = null;
104
private List<GarbageCollectorMXBean> garbageCollectorMBeans = null;
105
106
private static final String HOTSPOT_DIAGNOSTIC_MXBEAN_NAME =
107
"com.sun.management:type=HotSpotDiagnostic";
108
109
private ProxyClient(String hostName, int port,
110
String userName, String password) throws IOException {
111
this.connectionName = getConnectionName(hostName, port, userName);
112
this.displayName = connectionName;
113
if (hostName.equals("localhost") && port == 0) {
114
// Monitor self
115
this.hostName = hostName;
116
this.port = port;
117
} else {
118
// Create an RMI connector client and connect it to
119
// the RMI connector server
120
final String urlPath = "/jndi/rmi://" + hostName + ":" + port +
121
"/jmxrmi";
122
JMXServiceURL url = new JMXServiceURL("rmi", "", 0, urlPath);
123
setParameters(url, userName, password);
124
vmConnector = true;
125
registryHostName = hostName;
126
registryPort = port;
127
checkSslConfig();
128
}
129
}
130
131
private ProxyClient(String url,
132
String userName, String password) throws IOException {
133
this.advancedUrl = url;
134
this.connectionName = getConnectionName(url, userName);
135
this.displayName = connectionName;
136
setParameters(new JMXServiceURL(url), userName, password);
137
}
138
139
private ProxyClient(LocalVirtualMachine lvm) throws IOException {
140
this.lvm = lvm;
141
this.connectionName = getConnectionName(lvm);
142
this.displayName = "pid: " + lvm.vmid() + " " + lvm.displayName();
143
}
144
145
private void setParameters(JMXServiceURL url, String userName, String password) {
146
this.jmxUrl = url;
147
this.hostName = jmxUrl.getHost();
148
this.port = jmxUrl.getPort();
149
this.userName = userName;
150
this.password = password;
151
}
152
153
private static void checkStub(Remote stub,
154
Class<? extends Remote> stubClass) {
155
// Check remote stub is from the expected class.
156
//
157
if (stub.getClass() != stubClass) {
158
if (!Proxy.isProxyClass(stub.getClass())) {
159
throw new SecurityException(
160
"Expecting a " + stubClass.getName() + " stub!");
161
} else {
162
InvocationHandler handler = Proxy.getInvocationHandler(stub);
163
if (handler.getClass() != RemoteObjectInvocationHandler.class) {
164
throw new SecurityException(
165
"Expecting a dynamic proxy instance with a " +
166
RemoteObjectInvocationHandler.class.getName() +
167
" invocation handler!");
168
} else {
169
stub = (Remote) handler;
170
}
171
}
172
}
173
// Check RemoteRef in stub is from the expected class
174
// "sun.rmi.server.UnicastRef2".
175
//
176
RemoteRef ref = ((RemoteObject)stub).getRef();
177
if (ref.getClass() != UnicastRef2.class) {
178
throw new SecurityException(
179
"Expecting a " + UnicastRef2.class.getName() +
180
" remote reference in stub!");
181
}
182
// Check RMIClientSocketFactory in stub is from the expected class
183
// "javax.rmi.ssl.SslRMIClientSocketFactory".
184
//
185
LiveRef liveRef = ((UnicastRef2)ref).getLiveRef();
186
RMIClientSocketFactory csf = liveRef.getClientSocketFactory();
187
if (csf == null || csf.getClass() != SslRMIClientSocketFactory.class) {
188
throw new SecurityException(
189
"Expecting a " + SslRMIClientSocketFactory.class.getName() +
190
" RMI client socket factory in stub!");
191
}
192
}
193
194
private static final String rmiServerImplStubClassName =
195
"javax.management.remote.rmi.RMIServerImpl_Stub";
196
private static final Class<? extends Remote> rmiServerImplStubClass;
197
198
static {
199
// FIXME: RMIServerImpl_Stub is generated at build time
200
// after jconsole is built. We need to investigate if
201
// the Makefile can be fixed to build jconsole in the
202
// right order. As a workaround for now, we dynamically
203
// load RMIServerImpl_Stub class instead of statically
204
// referencing it.
205
Class<? extends Remote> serverStubClass = null;
206
try {
207
serverStubClass = Class.forName(rmiServerImplStubClassName).asSubclass(Remote.class);
208
} catch (ClassNotFoundException e) {
209
// should never reach here
210
throw new InternalError(e.getMessage(), e);
211
}
212
rmiServerImplStubClass = serverStubClass;
213
}
214
215
private void checkSslConfig() throws IOException {
216
// Get the reference to the RMI Registry and lookup RMIServer stub
217
//
218
Registry registry;
219
try {
220
registry =
221
LocateRegistry.getRegistry(registryHostName, registryPort,
222
sslRMIClientSocketFactory);
223
try {
224
stub = (RMIServer) registry.lookup("jmxrmi");
225
} catch (NotBoundException nbe) {
226
throw (IOException)
227
new IOException(nbe.getMessage()).initCause(nbe);
228
}
229
sslRegistry = true;
230
} catch (IOException e) {
231
registry =
232
LocateRegistry.getRegistry(registryHostName, registryPort);
233
try {
234
stub = (RMIServer) registry.lookup("jmxrmi");
235
} catch (NotBoundException nbe) {
236
throw (IOException)
237
new IOException(nbe.getMessage()).initCause(nbe);
238
}
239
sslRegistry = false;
240
}
241
// Perform the checks for secure stub
242
//
243
try {
244
checkStub(stub, rmiServerImplStubClass);
245
sslStub = true;
246
} catch (SecurityException e) {
247
sslStub = false;
248
}
249
}
250
251
/**
252
* Returns true if the underlying RMI registry is SSL-protected.
253
*
254
* @exception UnsupportedOperationException If this {@code ProxyClient}
255
* does not denote a JMX connector for a JMX VM agent.
256
*/
257
public boolean isSslRmiRegistry() {
258
// Check for VM connector
259
//
260
if (!isVmConnector()) {
261
throw new UnsupportedOperationException(
262
"ProxyClient.isSslRmiRegistry() is only supported if this " +
263
"ProxyClient is a JMX connector for a JMX VM agent");
264
}
265
return sslRegistry;
266
}
267
268
/**
269
* Returns true if the retrieved RMI stub is SSL-protected.
270
*
271
* @exception UnsupportedOperationException If this {@code ProxyClient}
272
* does not denote a JMX connector for a JMX VM agent.
273
*/
274
public boolean isSslRmiStub() {
275
// Check for VM connector
276
//
277
if (!isVmConnector()) {
278
throw new UnsupportedOperationException(
279
"ProxyClient.isSslRmiStub() is only supported if this " +
280
"ProxyClient is a JMX connector for a JMX VM agent");
281
}
282
return sslStub;
283
}
284
285
/**
286
* Returns true if this {@code ProxyClient} denotes
287
* a JMX connector for a JMX VM agent.
288
*/
289
public boolean isVmConnector() {
290
return vmConnector;
291
}
292
293
private void setConnectionState(ConnectionState state) {
294
ConnectionState oldState = this.connectionState;
295
this.connectionState = state;
296
propertyChangeSupport.firePropertyChange(CONNECTION_STATE_PROPERTY,
297
oldState, state);
298
}
299
300
public ConnectionState getConnectionState() {
301
return this.connectionState;
302
}
303
304
void flush() {
305
if (server != null) {
306
server.flush();
307
}
308
}
309
310
void connect(boolean requireSSL) {
311
setConnectionState(ConnectionState.CONNECTING);
312
try {
313
tryConnect(requireSSL);
314
setConnectionState(ConnectionState.CONNECTED);
315
} catch (Exception e) {
316
if (JConsole.isDebug()) {
317
e.printStackTrace();
318
}
319
setConnectionState(ConnectionState.DISCONNECTED);
320
}
321
}
322
323
private void tryConnect(boolean requireRemoteSSL) throws IOException {
324
if (jmxUrl == null && "localhost".equals(hostName) && port == 0) {
325
// Monitor self
326
this.jmxc = null;
327
this.mbsc = ManagementFactory.getPlatformMBeanServer();
328
this.server = Snapshot.newSnapshot(mbsc);
329
} else {
330
// Monitor another process
331
if (lvm != null) {
332
if (!lvm.isManageable()) {
333
lvm.startManagementAgent();
334
if (!lvm.isManageable()) {
335
// FIXME: what to throw
336
throw new IOException(lvm + "not manageable");
337
}
338
}
339
if (this.jmxUrl == null) {
340
this.jmxUrl = new JMXServiceURL(lvm.connectorAddress());
341
}
342
}
343
Map<String, Object> env = new HashMap<String, Object>();
344
if (requireRemoteSSL) {
345
env.put("jmx.remote.x.check.stub", "true");
346
}
347
// Need to pass in credentials ?
348
if (userName == null && password == null) {
349
if (isVmConnector()) {
350
// Check for SSL config on reconnection only
351
if (stub == null) {
352
checkSslConfig();
353
}
354
this.jmxc = new RMIConnector(stub, null);
355
jmxc.connect(env);
356
} else {
357
this.jmxc = JMXConnectorFactory.connect(jmxUrl, env);
358
}
359
} else {
360
env.put(JMXConnector.CREDENTIALS,
361
new String[] {userName, password});
362
if (isVmConnector()) {
363
// Check for SSL config on reconnection only
364
if (stub == null) {
365
checkSslConfig();
366
}
367
this.jmxc = new RMIConnector(stub, null);
368
jmxc.connect(env);
369
} else {
370
this.jmxc = JMXConnectorFactory.connect(jmxUrl, env);
371
}
372
}
373
this.mbsc = jmxc.getMBeanServerConnection();
374
this.server = Snapshot.newSnapshot(mbsc);
375
}
376
this.isDead = false;
377
378
try {
379
ObjectName on = new ObjectName(THREAD_MXBEAN_NAME);
380
this.hasPlatformMXBeans = server.isRegistered(on);
381
this.hasHotSpotDiagnosticMXBean =
382
server.isRegistered(new ObjectName(HOTSPOT_DIAGNOSTIC_MXBEAN_NAME));
383
// check if it has 6.0 new APIs
384
if (this.hasPlatformMXBeans) {
385
MBeanOperationInfo[] mopis = server.getMBeanInfo(on).getOperations();
386
// look for findDeadlockedThreads operations;
387
for (MBeanOperationInfo op : mopis) {
388
if (op.getName().equals("findDeadlockedThreads")) {
389
this.supportsLockUsage = true;
390
break;
391
}
392
}
393
394
on = new ObjectName(COMPILATION_MXBEAN_NAME);
395
this.hasCompilationMXBean = server.isRegistered(on);
396
}
397
} catch (MalformedObjectNameException e) {
398
// should not reach here
399
throw new InternalError(e.getMessage());
400
} catch (IntrospectionException |
401
InstanceNotFoundException |
402
ReflectionException e) {
403
throw new InternalError(e.getMessage(), e);
404
}
405
406
if (hasPlatformMXBeans) {
407
// WORKAROUND for bug 5056632
408
// Check if the access role is correct by getting a RuntimeMXBean
409
getRuntimeMXBean();
410
}
411
}
412
413
/**
414
* Gets a proxy client for a given local virtual machine.
415
*/
416
public static ProxyClient getProxyClient(LocalVirtualMachine lvm)
417
throws IOException {
418
final String key = getCacheKey(lvm);
419
ProxyClient proxyClient = cache.get(key);
420
if (proxyClient == null) {
421
proxyClient = new ProxyClient(lvm);
422
cache.put(key, proxyClient);
423
}
424
return proxyClient;
425
}
426
427
public static String getConnectionName(LocalVirtualMachine lvm) {
428
return Integer.toString(lvm.vmid());
429
}
430
431
private static String getCacheKey(LocalVirtualMachine lvm) {
432
return Integer.toString(lvm.vmid());
433
}
434
435
/**
436
* Gets a proxy client for a given JMXServiceURL.
437
*/
438
public static ProxyClient getProxyClient(String url,
439
String userName, String password)
440
throws IOException {
441
final String key = getCacheKey(url, userName, password);
442
ProxyClient proxyClient = cache.get(key);
443
if (proxyClient == null) {
444
proxyClient = new ProxyClient(url, userName, password);
445
cache.put(key, proxyClient);
446
}
447
return proxyClient;
448
}
449
450
public static String getConnectionName(String url,
451
String userName) {
452
if (userName != null && userName.length() > 0) {
453
return userName + "@" + url;
454
} else {
455
return url;
456
}
457
}
458
459
private static String getCacheKey(String url,
460
String userName, String password) {
461
return (url == null ? "" : url) + ":" +
462
(userName == null ? "" : userName) + ":" +
463
(password == null ? "" : password);
464
}
465
466
/**
467
* Gets a proxy client for a given "hostname:port".
468
*/
469
public static ProxyClient getProxyClient(String hostName, int port,
470
String userName, String password)
471
throws IOException {
472
final String key = getCacheKey(hostName, port, userName, password);
473
ProxyClient proxyClient = cache.get(key);
474
if (proxyClient == null) {
475
proxyClient = new ProxyClient(hostName, port, userName, password);
476
cache.put(key, proxyClient);
477
}
478
return proxyClient;
479
}
480
481
public static String getConnectionName(String hostName, int port,
482
String userName) {
483
String name = hostName + ":" + port;
484
if (userName != null && userName.length() > 0) {
485
return userName + "@" + name;
486
} else {
487
return name;
488
}
489
}
490
491
private static String getCacheKey(String hostName, int port,
492
String userName, String password) {
493
return (hostName == null ? "" : hostName) + ":" +
494
port + ":" +
495
(userName == null ? "" : userName) + ":" +
496
(password == null ? "" : password);
497
}
498
499
public String connectionName() {
500
return connectionName;
501
}
502
503
public String getDisplayName() {
504
return displayName;
505
}
506
507
public String toString() {
508
if (!isConnected()) {
509
return Resources.format(Messages.CONNECTION_NAME__DISCONNECTED_, displayName);
510
} else {
511
return displayName;
512
}
513
}
514
515
public MBeanServerConnection getMBeanServerConnection() {
516
return mbsc;
517
}
518
519
public SnapshotMBeanServerConnection getSnapshotMBeanServerConnection() {
520
return server;
521
}
522
523
public String getUrl() {
524
return advancedUrl;
525
}
526
527
public String getHostName() {
528
return hostName;
529
}
530
531
public int getPort() {
532
return port;
533
}
534
535
public int getVmid() {
536
return (lvm != null) ? lvm.vmid() : 0;
537
}
538
539
public String getUserName() {
540
return userName;
541
}
542
543
public String getPassword() {
544
return password;
545
}
546
547
public void disconnect() {
548
// Reset remote stub
549
stub = null;
550
// Close MBeanServer connection
551
if (jmxc != null) {
552
try {
553
jmxc.close();
554
} catch (IOException e) {
555
// Ignore ???
556
}
557
}
558
// Reset platform MBean references
559
classLoadingMBean = null;
560
compilationMBean = null;
561
memoryMBean = null;
562
operatingSystemMBean = null;
563
runtimeMBean = null;
564
threadMBean = null;
565
sunOperatingSystemMXBean = null;
566
garbageCollectorMBeans = null;
567
// Set connection state to DISCONNECTED
568
if (!isDead) {
569
isDead = true;
570
setConnectionState(ConnectionState.DISCONNECTED);
571
}
572
}
573
574
/**
575
* Returns the list of domains in which any MBean is
576
* currently registered.
577
*/
578
public String[] getDomains() throws IOException {
579
return server.getDomains();
580
}
581
582
/**
583
* Returns a map of MBeans with ObjectName as the key and MBeanInfo value
584
* of a given domain. If domain is {@code null}, all MBeans
585
* are returned. If no MBean found, an empty map is returned.
586
*
587
*/
588
public Map<ObjectName, MBeanInfo> getMBeans(String domain)
589
throws IOException {
590
591
ObjectName name = null;
592
if (domain != null) {
593
try {
594
name = new ObjectName(domain + ":*");
595
} catch (MalformedObjectNameException e) {
596
// should not reach here
597
assert(false);
598
}
599
}
600
Set<ObjectName> mbeans = server.queryNames(name, null);
601
Map<ObjectName,MBeanInfo> result =
602
new HashMap<ObjectName,MBeanInfo>(mbeans.size());
603
Iterator<ObjectName> iterator = mbeans.iterator();
604
while (iterator.hasNext()) {
605
Object object = iterator.next();
606
if (object instanceof ObjectName) {
607
ObjectName o = (ObjectName)object;
608
try {
609
MBeanInfo info = server.getMBeanInfo(o);
610
result.put(o, info);
611
} catch (IntrospectionException e) {
612
// TODO: should log the error
613
} catch (InstanceNotFoundException e) {
614
// TODO: should log the error
615
} catch (ReflectionException e) {
616
// TODO: should log the error
617
}
618
}
619
}
620
return result;
621
}
622
623
/**
624
* Returns a list of attributes of a named MBean.
625
*
626
*/
627
public AttributeList getAttributes(ObjectName name, String[] attributes)
628
throws IOException {
629
AttributeList list = null;
630
try {
631
list = server.getAttributes(name, attributes);
632
} catch (InstanceNotFoundException e) {
633
// TODO: A MBean may have been unregistered.
634
// need to set up listener to listen for MBeanServerNotification.
635
} catch (ReflectionException e) {
636
// TODO: should log the error
637
}
638
return list;
639
}
640
641
/**
642
* Set the value of a specific attribute of a named MBean.
643
*/
644
public void setAttribute(ObjectName name, Attribute attribute)
645
throws InvalidAttributeValueException,
646
MBeanException,
647
IOException {
648
try {
649
server.setAttribute(name, attribute);
650
} catch (InstanceNotFoundException e) {
651
// TODO: A MBean may have been unregistered.
652
} catch (AttributeNotFoundException e) {
653
assert(false);
654
} catch (ReflectionException e) {
655
// TODO: should log the error
656
}
657
}
658
659
/**
660
* Invokes an operation of a named MBean.
661
*
662
* @throws MBeanException Wraps an exception thrown by
663
* the MBean's invoked method.
664
*/
665
public Object invoke(ObjectName name, String operationName,
666
Object[] params, String[] signature)
667
throws IOException, MBeanException {
668
Object result = null;
669
try {
670
result = server.invoke(name, operationName, params, signature);
671
} catch (InstanceNotFoundException e) {
672
// TODO: A MBean may have been unregistered.
673
} catch (ReflectionException e) {
674
// TODO: should log the error
675
}
676
return result;
677
}
678
679
public synchronized ClassLoadingMXBean getClassLoadingMXBean() throws IOException {
680
if (hasPlatformMXBeans && classLoadingMBean == null) {
681
classLoadingMBean =
682
newPlatformMXBeanProxy(server, CLASS_LOADING_MXBEAN_NAME,
683
ClassLoadingMXBean.class);
684
}
685
return classLoadingMBean;
686
}
687
688
public synchronized CompilationMXBean getCompilationMXBean() throws IOException {
689
if (hasCompilationMXBean && compilationMBean == null) {
690
compilationMBean =
691
newPlatformMXBeanProxy(server, COMPILATION_MXBEAN_NAME,
692
CompilationMXBean.class);
693
}
694
return compilationMBean;
695
}
696
697
public Collection<MemoryPoolProxy> getMemoryPoolProxies()
698
throws IOException {
699
700
// TODO: How to deal with changes to the list??
701
if (memoryPoolProxies == null) {
702
ObjectName poolName = null;
703
try {
704
poolName = new ObjectName(MEMORY_POOL_MXBEAN_DOMAIN_TYPE + ",*");
705
} catch (MalformedObjectNameException e) {
706
// should not reach here
707
assert(false);
708
}
709
Set<ObjectName> mbeans = server.queryNames(poolName, null);
710
if (mbeans != null) {
711
memoryPoolProxies = new ArrayList<MemoryPoolProxy>();
712
Iterator<ObjectName> iterator = mbeans.iterator();
713
while (iterator.hasNext()) {
714
ObjectName objName = iterator.next();
715
MemoryPoolProxy p = new MemoryPoolProxy(this, objName);
716
memoryPoolProxies.add(p);
717
}
718
}
719
}
720
return memoryPoolProxies;
721
}
722
723
public synchronized Collection<GarbageCollectorMXBean> getGarbageCollectorMXBeans()
724
throws IOException {
725
726
// TODO: How to deal with changes to the list??
727
if (garbageCollectorMBeans == null) {
728
ObjectName gcName = null;
729
try {
730
gcName = new ObjectName(GARBAGE_COLLECTOR_MXBEAN_DOMAIN_TYPE + ",*");
731
} catch (MalformedObjectNameException e) {
732
// should not reach here
733
assert(false);
734
}
735
Set<ObjectName> mbeans = server.queryNames(gcName, null);
736
if (mbeans != null) {
737
garbageCollectorMBeans = new ArrayList<GarbageCollectorMXBean>();
738
Iterator<ObjectName> iterator = mbeans.iterator();
739
while (iterator.hasNext()) {
740
ObjectName on = iterator.next();
741
String name = GARBAGE_COLLECTOR_MXBEAN_DOMAIN_TYPE +
742
",name=" + on.getKeyProperty("name");
743
744
GarbageCollectorMXBean mBean =
745
newPlatformMXBeanProxy(server, name,
746
GarbageCollectorMXBean.class);
747
garbageCollectorMBeans.add(mBean);
748
}
749
}
750
}
751
return garbageCollectorMBeans;
752
}
753
754
public synchronized MemoryMXBean getMemoryMXBean() throws IOException {
755
if (hasPlatformMXBeans && memoryMBean == null) {
756
memoryMBean =
757
newPlatformMXBeanProxy(server, MEMORY_MXBEAN_NAME,
758
MemoryMXBean.class);
759
}
760
return memoryMBean;
761
}
762
763
public synchronized RuntimeMXBean getRuntimeMXBean() throws IOException {
764
if (hasPlatformMXBeans && runtimeMBean == null) {
765
runtimeMBean =
766
newPlatformMXBeanProxy(server, RUNTIME_MXBEAN_NAME,
767
RuntimeMXBean.class);
768
}
769
return runtimeMBean;
770
}
771
772
773
public synchronized ThreadMXBean getThreadMXBean() throws IOException {
774
if (hasPlatformMXBeans && threadMBean == null) {
775
threadMBean =
776
newPlatformMXBeanProxy(server, THREAD_MXBEAN_NAME,
777
ThreadMXBean.class);
778
}
779
return threadMBean;
780
}
781
782
public synchronized OperatingSystemMXBean getOperatingSystemMXBean() throws IOException {
783
if (hasPlatformMXBeans && operatingSystemMBean == null) {
784
operatingSystemMBean =
785
newPlatformMXBeanProxy(server, OPERATING_SYSTEM_MXBEAN_NAME,
786
OperatingSystemMXBean.class);
787
}
788
return operatingSystemMBean;
789
}
790
791
public synchronized com.sun.management.OperatingSystemMXBean
792
getSunOperatingSystemMXBean() throws IOException {
793
794
try {
795
ObjectName on = new ObjectName(OPERATING_SYSTEM_MXBEAN_NAME);
796
if (sunOperatingSystemMXBean == null) {
797
if (server.isInstanceOf(on,
798
"com.sun.management.OperatingSystemMXBean")) {
799
sunOperatingSystemMXBean =
800
newPlatformMXBeanProxy(server,
801
OPERATING_SYSTEM_MXBEAN_NAME,
802
com.sun.management.OperatingSystemMXBean.class);
803
}
804
}
805
} catch (InstanceNotFoundException e) {
806
return null;
807
} catch (MalformedObjectNameException e) {
808
return null; // should never reach here
809
}
810
return sunOperatingSystemMXBean;
811
}
812
813
public synchronized HotSpotDiagnosticMXBean getHotSpotDiagnosticMXBean() throws IOException {
814
if (hasHotSpotDiagnosticMXBean && hotspotDiagnosticMXBean == null) {
815
hotspotDiagnosticMXBean =
816
newPlatformMXBeanProxy(server, HOTSPOT_DIAGNOSTIC_MXBEAN_NAME,
817
HotSpotDiagnosticMXBean.class);
818
}
819
return hotspotDiagnosticMXBean;
820
}
821
822
public <T> T getMXBean(ObjectName objName, Class<T> interfaceClass)
823
throws IOException {
824
return newPlatformMXBeanProxy(server,
825
objName.toString(),
826
interfaceClass);
827
828
}
829
830
// Return thread IDs of deadlocked threads or null if any.
831
// It finds deadlocks involving only monitors if it's a Tiger VM.
832
// Otherwise, it finds deadlocks involving both monitors and
833
// the concurrent locks.
834
public long[] findDeadlockedThreads() throws IOException {
835
ThreadMXBean tm = getThreadMXBean();
836
if (supportsLockUsage && tm.isSynchronizerUsageSupported()) {
837
return tm.findDeadlockedThreads();
838
} else {
839
return tm.findMonitorDeadlockedThreads();
840
}
841
}
842
843
public synchronized void markAsDead() {
844
disconnect();
845
}
846
847
public boolean isDead() {
848
return isDead;
849
}
850
851
boolean isConnected() {
852
return !isDead();
853
}
854
855
boolean hasPlatformMXBeans() {
856
return this.hasPlatformMXBeans;
857
}
858
859
boolean hasHotSpotDiagnosticMXBean() {
860
return this.hasHotSpotDiagnosticMXBean;
861
}
862
863
boolean isLockUsageSupported() {
864
return supportsLockUsage;
865
}
866
867
public boolean isRegistered(ObjectName name) throws IOException {
868
return server.isRegistered(name);
869
}
870
871
public void addPropertyChangeListener(PropertyChangeListener listener) {
872
propertyChangeSupport.addPropertyChangeListener(listener);
873
}
874
875
public void addWeakPropertyChangeListener(PropertyChangeListener listener) {
876
if (!(listener instanceof WeakPCL)) {
877
listener = new WeakPCL(listener);
878
}
879
propertyChangeSupport.addPropertyChangeListener(listener);
880
}
881
882
public void removePropertyChangeListener(PropertyChangeListener listener) {
883
if (!(listener instanceof WeakPCL)) {
884
// Search for the WeakPCL holding this listener (if any)
885
for (PropertyChangeListener pcl : propertyChangeSupport.getPropertyChangeListeners()) {
886
if (pcl instanceof WeakPCL && ((WeakPCL)pcl).get() == listener) {
887
listener = pcl;
888
break;
889
}
890
}
891
}
892
propertyChangeSupport.removePropertyChangeListener(listener);
893
}
894
895
/**
896
* The PropertyChangeListener is handled via a WeakReference
897
* so as not to pin down the listener.
898
*/
899
private class WeakPCL extends WeakReference<PropertyChangeListener>
900
implements PropertyChangeListener {
901
WeakPCL(PropertyChangeListener referent) {
902
super(referent);
903
}
904
905
public void propertyChange(PropertyChangeEvent pce) {
906
PropertyChangeListener pcl = get();
907
908
if (pcl == null) {
909
// The referent listener was GC'ed, we're no longer
910
// interested in PropertyChanges, remove the listener.
911
dispose();
912
} else {
913
pcl.propertyChange(pce);
914
}
915
}
916
917
private void dispose() {
918
removePropertyChangeListener(this);
919
}
920
}
921
922
//
923
// Snapshot MBeanServerConnection:
924
//
925
// This is an object that wraps an existing MBeanServerConnection and adds
926
// caching to it, as follows:
927
//
928
// - The first time an attribute is called in a given MBean, the result is
929
// cached. Every subsequent time getAttribute is called for that attribute
930
// the cached result is returned.
931
//
932
// - Before every call to VMPanel.update() or when the Refresh button in the
933
// Attributes table is pressed down the attributes cache is flushed. Then
934
// any subsequent call to getAttribute will retrieve all the values for
935
// the attributes that are known to the cache.
936
//
937
// - The attributes cache uses a learning approach and only the attributes
938
// that are in the cache will be retrieved between two subsequent updates.
939
//
940
941
public interface SnapshotMBeanServerConnection
942
extends MBeanServerConnection {
943
/**
944
* Flush all cached values of attributes.
945
*/
946
public void flush();
947
}
948
949
public static class Snapshot {
950
private Snapshot() {
951
}
952
public static SnapshotMBeanServerConnection
953
newSnapshot(MBeanServerConnection mbsc) {
954
final InvocationHandler ih = new SnapshotInvocationHandler(mbsc);
955
return (SnapshotMBeanServerConnection) Proxy.newProxyInstance(
956
Snapshot.class.getClassLoader(),
957
new Class<?>[] {SnapshotMBeanServerConnection.class},
958
ih);
959
}
960
}
961
962
static class SnapshotInvocationHandler implements InvocationHandler {
963
964
private final MBeanServerConnection conn;
965
private Map<ObjectName, NameValueMap> cachedValues = newMap();
966
private Map<ObjectName, Set<String>> cachedNames = newMap();
967
968
@SuppressWarnings("serial")
969
private static final class NameValueMap
970
extends HashMap<String, Object> {}
971
972
SnapshotInvocationHandler(MBeanServerConnection conn) {
973
this.conn = conn;
974
}
975
976
synchronized void flush() {
977
cachedValues = newMap();
978
}
979
980
public Object invoke(Object proxy, Method method, Object[] args)
981
throws Throwable {
982
final String methodName = method.getName();
983
if (methodName.equals("getAttribute")) {
984
return getAttribute((ObjectName) args[0], (String) args[1]);
985
} else if (methodName.equals("getAttributes")) {
986
return getAttributes((ObjectName) args[0], (String[]) args[1]);
987
} else if (methodName.equals("flush")) {
988
flush();
989
return null;
990
} else {
991
try {
992
return method.invoke(conn, args);
993
} catch (InvocationTargetException e) {
994
throw e.getCause();
995
}
996
}
997
}
998
999
private Object getAttribute(ObjectName objName, String attrName)
1000
throws MBeanException, InstanceNotFoundException,
1001
AttributeNotFoundException, ReflectionException, IOException {
1002
final NameValueMap values = getCachedAttributes(
1003
objName, Collections.singleton(attrName));
1004
Object value = values.get(attrName);
1005
if (value != null || values.containsKey(attrName)) {
1006
return value;
1007
}
1008
// Not in cache, presumably because it was omitted from the
1009
// getAttributes result because of an exception. Following
1010
// call will probably provoke the same exception.
1011
return conn.getAttribute(objName, attrName);
1012
}
1013
1014
private AttributeList getAttributes(
1015
ObjectName objName, String[] attrNames) throws
1016
InstanceNotFoundException, ReflectionException, IOException {
1017
final NameValueMap values = getCachedAttributes(
1018
objName,
1019
new TreeSet<String>(Arrays.asList(attrNames)));
1020
final AttributeList list = new AttributeList();
1021
for (String attrName : attrNames) {
1022
final Object value = values.get(attrName);
1023
if (value != null || values.containsKey(attrName)) {
1024
list.add(new Attribute(attrName, value));
1025
}
1026
}
1027
return list;
1028
}
1029
1030
private synchronized NameValueMap getCachedAttributes(
1031
ObjectName objName, Set<String> attrNames) throws
1032
InstanceNotFoundException, ReflectionException, IOException {
1033
NameValueMap values = cachedValues.get(objName);
1034
if (values != null && values.keySet().containsAll(attrNames)) {
1035
return values;
1036
}
1037
attrNames = new TreeSet<String>(attrNames);
1038
Set<String> oldNames = cachedNames.get(objName);
1039
if (oldNames != null) {
1040
attrNames.addAll(oldNames);
1041
}
1042
values = new NameValueMap();
1043
final AttributeList attrs = conn.getAttributes(
1044
objName,
1045
attrNames.toArray(new String[attrNames.size()]));
1046
for (Attribute attr : attrs.asList()) {
1047
values.put(attr.getName(), attr.getValue());
1048
}
1049
cachedValues.put(objName, values);
1050
cachedNames.put(objName, attrNames);
1051
return values;
1052
}
1053
1054
// See http://www.artima.com/weblogs/viewpost.jsp?thread=79394
1055
private static <K, V> Map<K, V> newMap() {
1056
return new HashMap<K, V>();
1057
}
1058
}
1059
}
1060
1061