mirror of
https://github.com/alibaba/druid.git
synced 2023-03-04 19:17:16 +00:00
Merge branch 'master' of https://github.com/AlibabaTech/druid
This commit is contained in:
@@ -99,6 +99,7 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>2.3.2</version>
|
||||
<configuration>
|
||||
<encoding>UTF-8</encoding>
|
||||
<source>1.6</source>
|
||||
@@ -153,7 +154,7 @@
|
||||
</links>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<!--
|
||||
<plugin>
|
||||
<artifactId>maven-gpg-plugin</artifactId>
|
||||
<executions>
|
||||
@@ -166,9 +167,11 @@
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
-->
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
@@ -186,25 +189,10 @@
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring</artifactId>
|
||||
<version>2.5.6</version>
|
||||
<version>2.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.ibatis</groupId>
|
||||
<artifactId>ibatis-sqlmap</artifactId>
|
||||
<version>2.3.4.726</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<!--
|
||||
<dependency>
|
||||
<groupId>cglib</groupId>
|
||||
<artifactId>cglib</artifactId>
|
||||
<version>2.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
-->
|
||||
|
||||
<dependency>
|
||||
<groupId>log4j</groupId>
|
||||
<artifactId>log4j</artifactId>
|
||||
@@ -311,6 +299,12 @@
|
||||
<version>0.7.1-rc2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.jolbox</groupId>
|
||||
<artifactId>bonecp-test-commons</artifactId>
|
||||
<version>0.7.1-rc2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>proxool</groupId>
|
||||
@@ -332,4 +326,4 @@
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
</project>
|
||||
|
||||
@@ -714,14 +714,20 @@ public class StatFilter extends FilterEventAdapter implements StatFilterMBean {
|
||||
}
|
||||
|
||||
public JdbcSqlStat createSqlStat(StatementProxy statement, String sql) {
|
||||
|
||||
sql = mergeSql(sql);
|
||||
return dataSourceStat.createSqlStat(sql);
|
||||
}
|
||||
|
||||
public JdbcSqlStat getSqlCounter(String sql) {
|
||||
|
||||
sql = mergeSql(sql); //mergeSql
|
||||
return getSqlStat(sql);
|
||||
}
|
||||
|
||||
public JdbcSqlStat getSqlStat(String sql) {
|
||||
|
||||
sql = mergeSql(sql);
|
||||
return dataSourceStat.getSqlStat(sql);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,148 +0,0 @@
|
||||
package com.alibaba.druid.pool.console;
|
||||
|
||||
import java.io.Console;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.management.Attribute;
|
||||
import javax.management.AttributeList;
|
||||
import javax.management.MBeanAttributeInfo;
|
||||
import javax.management.MBeanInfo;
|
||||
import javax.management.ObjectName;
|
||||
|
||||
public class DruidConsole {
|
||||
|
||||
private ProxyClient proxy;
|
||||
private Console console;
|
||||
private PrintWriter out;
|
||||
private List<DataSourceEntry> entries = new ArrayList<DataSourceEntry>();
|
||||
|
||||
private DruidConsole(){
|
||||
console = System.console();
|
||||
out = console.writer();
|
||||
}
|
||||
|
||||
public void run() throws Exception {
|
||||
proxy = ProxyClient.getProxyClient("10.20.133.134", 9006, null, null);
|
||||
proxy.connect();
|
||||
|
||||
for (;;) {
|
||||
String line = console.readLine();
|
||||
if ("exit".equals(line)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if ("ls".equals(line)) {
|
||||
ls(line);
|
||||
}
|
||||
|
||||
if ("desc".equals(line)) {
|
||||
desc(line);
|
||||
}
|
||||
|
||||
if (line.startsWith("show ")) {
|
||||
show(line);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void show(String line) throws Exception {
|
||||
String[] items = line.split(" ");
|
||||
|
||||
DataSourceEntry current;
|
||||
{
|
||||
String arg = items[1];
|
||||
int index = Integer.parseInt(arg);
|
||||
current = entries.get(index);
|
||||
}
|
||||
|
||||
long interval = 0;
|
||||
{
|
||||
String tmp = items[2];
|
||||
interval = Long.parseLong(tmp);
|
||||
}
|
||||
|
||||
String[] attributes = new String[] { "CreateCount", "DestroyCount", "ActivePeak", "ActiveCount", "PoolingCount", "CommitCount", "RollbackCount" };
|
||||
String[] titles = attributes;
|
||||
|
||||
for (int i = 0; i < titles.length; ++i) {
|
||||
if (i != 0) {
|
||||
out.print("\t\t");
|
||||
}
|
||||
out.print(titles[i]);
|
||||
}
|
||||
out.println();
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
AttributeList values = proxy.getAttributes(current.getObjectName(), attributes);
|
||||
for (int j = 0; j < attributes.length; ++j) {
|
||||
Attribute attribute = (Attribute) values.get(j);
|
||||
if (j != 0) {
|
||||
out.print("\t\t");
|
||||
}
|
||||
out.print(attribute.getValue());
|
||||
}
|
||||
out.println();
|
||||
Thread.sleep(interval);
|
||||
}
|
||||
}
|
||||
|
||||
public void ls(String line) throws Exception {
|
||||
entries.clear();
|
||||
Map<ObjectName, MBeanInfo> beans = proxy.getMBeans(null);
|
||||
for (Map.Entry<ObjectName, MBeanInfo> entry : beans.entrySet()) {
|
||||
if ("com.alibaba.druid.pool.DruidDataSource".equals(entry.getValue().getClassName())) {
|
||||
entries.add(new DataSourceEntry(entry.getKey(), entry.getValue()));
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < entries.size(); ++i) {
|
||||
out.println(i + " : " + entries.get(i).getObjectName());
|
||||
}
|
||||
}
|
||||
|
||||
public void desc(String line) throws Exception {
|
||||
String arg = line.substring("desc ".length());
|
||||
int index = Integer.parseInt(arg);
|
||||
DataSourceEntry current = entries.get(index);
|
||||
|
||||
MBeanInfo mbeanInfo = current.getMbeanInfo();
|
||||
String[] attributes = new String[mbeanInfo.getAttributes().length];
|
||||
for (int i = 0; i < attributes.length; ++i) {
|
||||
MBeanAttributeInfo attr = mbeanInfo.getAttributes()[i];
|
||||
attributes[i] = attr.getName();
|
||||
}
|
||||
AttributeList values = proxy.getAttributes(current.getObjectName(), attributes);
|
||||
for (int i = 0; i < attributes.length; ++i) {
|
||||
out.println("\t" + attributes[i] + " : " + values.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
DruidConsole console = new DruidConsole();
|
||||
console.run();
|
||||
|
||||
}
|
||||
|
||||
static class DataSourceEntry {
|
||||
|
||||
private final ObjectName objectName;
|
||||
private final MBeanInfo mbeanInfo;
|
||||
|
||||
public DataSourceEntry(ObjectName objectName, MBeanInfo mbeanInfo){
|
||||
super();
|
||||
this.objectName = objectName;
|
||||
this.mbeanInfo = mbeanInfo;
|
||||
}
|
||||
|
||||
public ObjectName getObjectName() {
|
||||
return objectName;
|
||||
}
|
||||
|
||||
public MBeanInfo getMbeanInfo() {
|
||||
return mbeanInfo;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,90 +0,0 @@
|
||||
package com.alibaba.druid.pool.console;
|
||||
|
||||
|
||||
import java.beans.PropertyChangeListener;
|
||||
|
||||
import javax.management.MBeanServerConnection;
|
||||
|
||||
/**
|
||||
* {@code JConsoleContext} represents a JConsole connection to a target
|
||||
* application.
|
||||
* <p>
|
||||
* {@code JConsoleContext} notifies any {@code PropertyChangeListeners}
|
||||
* about the {@linkplain #CONNECTION_STATE_PROPERTY <i>ConnectionState</i>}
|
||||
* property change to {@link ConnectionState#CONNECTED CONNECTED} and
|
||||
* {@link ConnectionState#DISCONNECTED DISCONNECTED}.
|
||||
* The {@code JConsoleContext} instance will be the source for
|
||||
* any generated events.
|
||||
* <p>
|
||||
*
|
||||
* @since 1.6
|
||||
*/
|
||||
public interface JConsoleContext {
|
||||
/**
|
||||
* The {@link ConnectionState ConnectionState} bound property name.
|
||||
*/
|
||||
public static String CONNECTION_STATE_PROPERTY = "connectionState";
|
||||
|
||||
/**
|
||||
* Values for the {@linkplain #CONNECTION_STATE_PROPERTY
|
||||
* <i>ConnectionState</i>} bound property.
|
||||
*/
|
||||
public enum ConnectionState {
|
||||
/**
|
||||
* The connection has been successfully established.
|
||||
*/
|
||||
CONNECTED,
|
||||
/**
|
||||
* No connection present.
|
||||
*/
|
||||
DISCONNECTED,
|
||||
/**
|
||||
* The connection is being attempted.
|
||||
*/
|
||||
CONNECTING
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link MBeanServerConnection MBeanServerConnection} for the
|
||||
* connection to an application. The returned
|
||||
* {@code MBeanServerConnection} object becomes invalid when
|
||||
* the connection state is changed to the
|
||||
* {@link ConnectionState#DISCONNECTED DISCONNECTED} state.
|
||||
*
|
||||
* @return the {@code MBeanServerConnection} for the
|
||||
* connection to an application.
|
||||
*/
|
||||
public MBeanServerConnection getMBeanServerConnection();
|
||||
|
||||
/**
|
||||
* Returns the current connection state.
|
||||
* @return the current connection state.
|
||||
*/
|
||||
public ConnectionState getConnectionState();
|
||||
|
||||
/**
|
||||
* Add a {@link java.beans.PropertyChangeListener PropertyChangeListener}
|
||||
* to the listener list.
|
||||
* The listener is registered for all properties.
|
||||
* The same listener object may be added more than once, and will be called
|
||||
* as many times as it is added.
|
||||
* If {@code listener} is {@code null}, no exception is thrown and
|
||||
* no action is taken.
|
||||
*
|
||||
* @param listener The {@code PropertyChangeListener} to be added
|
||||
*/
|
||||
public void addPropertyChangeListener(PropertyChangeListener listener);
|
||||
|
||||
/**
|
||||
* Removes a {@link java.beans.PropertyChangeListener PropertyChangeListener}
|
||||
* from the listener list. This
|
||||
* removes a {@code PropertyChangeListener} that was registered for all
|
||||
* properties. If {@code listener} was added more than once to the same
|
||||
* event source, it will be notified one less time after being removed. If
|
||||
* {@code listener} is {@code null}, or was never added, no exception is
|
||||
* thrown and no action is taken.
|
||||
*
|
||||
* @param listener the {@code PropertyChangeListener} to be removed
|
||||
*/
|
||||
public void removePropertyChangeListener(PropertyChangeListener listener);
|
||||
}
|
||||
@@ -1,252 +0,0 @@
|
||||
package com.alibaba.druid.pool.console;
|
||||
|
||||
/*
|
||||
* %W% %E%
|
||||
*
|
||||
* Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved.
|
||||
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
|
||||
*/
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
|
||||
import sun.jvmstat.monitor.HostIdentifier;
|
||||
import sun.jvmstat.monitor.MonitorException;
|
||||
import sun.jvmstat.monitor.MonitoredHost;
|
||||
import sun.jvmstat.monitor.MonitoredVm;
|
||||
import sun.jvmstat.monitor.MonitoredVmUtil;
|
||||
import sun.jvmstat.monitor.VmIdentifier;
|
||||
import sun.management.ConnectorAddressLink;
|
||||
|
||||
import com.sun.tools.attach.AgentInitializationException;
|
||||
import com.sun.tools.attach.AgentLoadException;
|
||||
import com.sun.tools.attach.AttachNotSupportedException;
|
||||
import com.sun.tools.attach.VirtualMachine;
|
||||
import com.sun.tools.attach.VirtualMachineDescriptor;
|
||||
|
||||
@SuppressWarnings("restriction")
|
||||
public class LocalVirtualMachine {
|
||||
|
||||
private String address;
|
||||
private String commandLine;
|
||||
private String displayName;
|
||||
private int vmid;
|
||||
private boolean isAttachSupported;
|
||||
|
||||
public LocalVirtualMachine(int vmid, String commandLine, boolean canAttach, String connectorAddress){
|
||||
this.vmid = vmid;
|
||||
this.commandLine = commandLine;
|
||||
this.address = connectorAddress;
|
||||
this.isAttachSupported = canAttach;
|
||||
this.displayName = getDisplayName(commandLine);
|
||||
}
|
||||
|
||||
private static String getDisplayName(String commandLine) {
|
||||
// trim the pathname of jar file if it's a jar
|
||||
String[] res = commandLine.split(" ", 2);
|
||||
if (res[0].endsWith(".jar")) {
|
||||
File jarfile = new File(res[0]);
|
||||
String displayName = jarfile.getName();
|
||||
if (res.length == 2) {
|
||||
displayName += " " + res[1];
|
||||
}
|
||||
return displayName;
|
||||
}
|
||||
return commandLine;
|
||||
}
|
||||
|
||||
public int vmid() {
|
||||
return vmid;
|
||||
}
|
||||
|
||||
public boolean isManageable() {
|
||||
return (address != null);
|
||||
}
|
||||
|
||||
public boolean isAttachable() {
|
||||
return isAttachSupported;
|
||||
}
|
||||
|
||||
public void startManagementAgent() throws IOException {
|
||||
if (address != null) {
|
||||
// already started
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isAttachable()) {
|
||||
throw new IOException("This virtual machine \"" + vmid + "\" does not support dynamic attach.");
|
||||
}
|
||||
|
||||
loadManagementAgent();
|
||||
// fails to load or start the management agent
|
||||
if (address == null) {
|
||||
// should never reach here
|
||||
throw new IOException("Fails to find connector address");
|
||||
}
|
||||
}
|
||||
|
||||
public String connectorAddress() {
|
||||
// return null if not available or no JMX agent
|
||||
return address;
|
||||
}
|
||||
|
||||
public String displayName() {
|
||||
return displayName;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return commandLine;
|
||||
}
|
||||
|
||||
// This method returns the list of all virtual machines currently
|
||||
// running on the machine
|
||||
public static Map<Integer, LocalVirtualMachine> getAllVirtualMachines() {
|
||||
Map<Integer, LocalVirtualMachine> map = new HashMap<Integer, LocalVirtualMachine>();
|
||||
getMonitoredVMs(map);
|
||||
getAttachableVMs(map);
|
||||
return map;
|
||||
}
|
||||
|
||||
private static void getMonitoredVMs(Map<Integer, LocalVirtualMachine> map) {
|
||||
MonitoredHost host;
|
||||
Set<?> vms;
|
||||
try {
|
||||
host = MonitoredHost.getMonitoredHost(new HostIdentifier((String) null));
|
||||
vms = host.activeVms();
|
||||
} catch (java.net.URISyntaxException sx) {
|
||||
throw new InternalError(sx.getMessage());
|
||||
} catch (MonitorException mx) {
|
||||
throw new InternalError(mx.getMessage());
|
||||
}
|
||||
for (Object vmid : vms) {
|
||||
if (vmid instanceof Integer) {
|
||||
int pid = ((Integer) vmid).intValue();
|
||||
String name = vmid.toString(); // default to pid if name not available
|
||||
boolean attachable = false;
|
||||
String address = null;
|
||||
try {
|
||||
MonitoredVm mvm = host.getMonitoredVm(new VmIdentifier(name));
|
||||
// use the command line as the display name
|
||||
name = MonitoredVmUtil.commandLine(mvm);
|
||||
attachable = MonitoredVmUtil.isAttachable(mvm);
|
||||
address = ConnectorAddressLink.importFrom(pid);
|
||||
mvm.detach();
|
||||
} catch (Exception x) {
|
||||
// ignore
|
||||
}
|
||||
map.put((Integer) vmid, new LocalVirtualMachine(pid, name, attachable, address));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final String LOCAL_CONNECTOR_ADDRESS_PROP = "com.sun.management.jmxremote.localConnectorAddress";
|
||||
|
||||
private static void getAttachableVMs(Map<Integer, LocalVirtualMachine> map) {
|
||||
List<VirtualMachineDescriptor> vms = VirtualMachine.list();
|
||||
for (VirtualMachineDescriptor vmd : vms) {
|
||||
try {
|
||||
Integer vmid = Integer.valueOf(vmd.id());
|
||||
if (!map.containsKey(vmid)) {
|
||||
boolean attachable = false;
|
||||
String address = null;
|
||||
try {
|
||||
VirtualMachine vm = VirtualMachine.attach(vmd);
|
||||
attachable = true;
|
||||
Properties agentProps = vm.getAgentProperties();
|
||||
address = (String) agentProps.get(LOCAL_CONNECTOR_ADDRESS_PROP);
|
||||
vm.detach();
|
||||
} catch (AttachNotSupportedException x) {
|
||||
// not attachable
|
||||
} catch (IOException x) {
|
||||
// ignore
|
||||
}
|
||||
map.put(vmid, new LocalVirtualMachine(vmid.intValue(), vmd.displayName(), attachable, address));
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
// do not support vmid different than pid
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static LocalVirtualMachine getLocalVirtualMachine(int vmid) {
|
||||
Map<Integer, LocalVirtualMachine> map = getAllVirtualMachines();
|
||||
LocalVirtualMachine lvm = map.get(vmid);
|
||||
if (lvm == null) {
|
||||
// Check if the VM is attachable but not included in the list
|
||||
// if it's running with a different security context.
|
||||
// For example, Windows services running
|
||||
// local SYSTEM account are attachable if you have Adminstrator
|
||||
// privileges.
|
||||
boolean attachable = false;
|
||||
String address = null;
|
||||
String name = String.valueOf(vmid); // default display name to pid
|
||||
try {
|
||||
VirtualMachine vm = VirtualMachine.attach(name);
|
||||
attachable = true;
|
||||
Properties agentProps = vm.getAgentProperties();
|
||||
address = (String) agentProps.get(LOCAL_CONNECTOR_ADDRESS_PROP);
|
||||
vm.detach();
|
||||
lvm = new LocalVirtualMachine(vmid, name, attachable, address);
|
||||
} catch (AttachNotSupportedException x) {
|
||||
// not attachable
|
||||
x.printStackTrace();
|
||||
} catch (IOException x) {
|
||||
// ignore
|
||||
x.printStackTrace();
|
||||
}
|
||||
}
|
||||
return lvm;
|
||||
}
|
||||
|
||||
// load the management agent into the target VM
|
||||
private void loadManagementAgent() throws IOException {
|
||||
VirtualMachine vm = null;
|
||||
String name = String.valueOf(vmid);
|
||||
try {
|
||||
vm = VirtualMachine.attach(name);
|
||||
} catch (AttachNotSupportedException x) {
|
||||
IOException ioe = new IOException(x.getMessage());
|
||||
ioe.initCause(x);
|
||||
throw ioe;
|
||||
}
|
||||
|
||||
String home = vm.getSystemProperties().getProperty("java.home");
|
||||
|
||||
// Normally in ${java.home}/jre/lib/management-agent.jar but might
|
||||
// be in ${java.home}/lib in build environments.
|
||||
|
||||
String agent = home + File.separator + "jre" + File.separator + "lib" + File.separator + "management-agent.jar";
|
||||
File f = new File(agent);
|
||||
if (!f.exists()) {
|
||||
agent = home + File.separator + "lib" + File.separator + "management-agent.jar";
|
||||
f = new File(agent);
|
||||
if (!f.exists()) {
|
||||
throw new IOException("Management agent not found");
|
||||
}
|
||||
}
|
||||
|
||||
agent = f.getCanonicalPath();
|
||||
try {
|
||||
vm.loadAgent(agent, "com.sun.management.jmxremote");
|
||||
} catch (AgentLoadException x) {
|
||||
IOException ioe = new IOException(x.getMessage());
|
||||
ioe.initCause(x);
|
||||
throw ioe;
|
||||
} catch (AgentInitializationException x) {
|
||||
IOException ioe = new IOException(x.getMessage());
|
||||
ioe.initCause(x);
|
||||
throw ioe;
|
||||
}
|
||||
|
||||
// get the connector address
|
||||
Properties agentProps = vm.getAgentProperties();
|
||||
address = (String) agentProps.get(LOCAL_CONNECTOR_ADDRESS_PROP);
|
||||
|
||||
vm.detach();
|
||||
}
|
||||
}
|
||||
@@ -1,993 +0,0 @@
|
||||
package com.alibaba.druid.pool.console;
|
||||
|
||||
/*
|
||||
* %W% %E%
|
||||
*
|
||||
* Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved.
|
||||
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
|
||||
*/
|
||||
|
||||
import static java.lang.management.ManagementFactory.CLASS_LOADING_MXBEAN_NAME;
|
||||
import static java.lang.management.ManagementFactory.COMPILATION_MXBEAN_NAME;
|
||||
import static java.lang.management.ManagementFactory.GARBAGE_COLLECTOR_MXBEAN_DOMAIN_TYPE;
|
||||
import static java.lang.management.ManagementFactory.MEMORY_MXBEAN_NAME;
|
||||
import static java.lang.management.ManagementFactory.OPERATING_SYSTEM_MXBEAN_NAME;
|
||||
import static java.lang.management.ManagementFactory.RUNTIME_MXBEAN_NAME;
|
||||
import static java.lang.management.ManagementFactory.THREAD_MXBEAN_NAME;
|
||||
import static java.lang.management.ManagementFactory.newPlatformMXBeanProxy;
|
||||
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.io.IOException;
|
||||
import java.lang.management.ClassLoadingMXBean;
|
||||
import java.lang.management.CompilationMXBean;
|
||||
import java.lang.management.GarbageCollectorMXBean;
|
||||
import java.lang.management.ManagementFactory;
|
||||
import java.lang.management.MemoryMXBean;
|
||||
import java.lang.management.OperatingSystemMXBean;
|
||||
import java.lang.management.RuntimeMXBean;
|
||||
import java.lang.management.ThreadMXBean;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.rmi.NotBoundException;
|
||||
import java.rmi.Remote;
|
||||
import java.rmi.registry.LocateRegistry;
|
||||
import java.rmi.registry.Registry;
|
||||
import java.rmi.server.RMIClientSocketFactory;
|
||||
import java.rmi.server.RemoteObject;
|
||||
import java.rmi.server.RemoteObjectInvocationHandler;
|
||||
import java.rmi.server.RemoteRef;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import javax.management.Attribute;
|
||||
import javax.management.AttributeList;
|
||||
import javax.management.AttributeNotFoundException;
|
||||
import javax.management.InstanceNotFoundException;
|
||||
import javax.management.IntrospectionException;
|
||||
import javax.management.InvalidAttributeValueException;
|
||||
import javax.management.MBeanException;
|
||||
import javax.management.MBeanInfo;
|
||||
import javax.management.MBeanOperationInfo;
|
||||
import javax.management.MBeanServerConnection;
|
||||
import javax.management.MalformedObjectNameException;
|
||||
import javax.management.ObjectName;
|
||||
import javax.management.ReflectionException;
|
||||
import javax.management.remote.JMXConnector;
|
||||
import javax.management.remote.JMXConnectorFactory;
|
||||
import javax.management.remote.JMXServiceURL;
|
||||
import javax.management.remote.rmi.RMIConnector;
|
||||
import javax.management.remote.rmi.RMIServer;
|
||||
import javax.rmi.ssl.SslRMIClientSocketFactory;
|
||||
import javax.swing.event.SwingPropertyChangeSupport;
|
||||
|
||||
import sun.rmi.server.UnicastRef2;
|
||||
import sun.rmi.transport.LiveRef;
|
||||
|
||||
import com.sun.management.HotSpotDiagnosticMXBean;
|
||||
|
||||
@SuppressWarnings("restriction")
|
||||
public class ProxyClient implements JConsoleContext {
|
||||
|
||||
private ConnectionState connectionState = ConnectionState.DISCONNECTED;
|
||||
|
||||
// The SwingPropertyChangeSupport will fire events on the EDT
|
||||
private SwingPropertyChangeSupport propertyChangeSupport = new SwingPropertyChangeSupport(
|
||||
this,
|
||||
true);
|
||||
|
||||
private static Map<String, ProxyClient> cache = Collections.synchronizedMap(new HashMap<String, ProxyClient>());
|
||||
|
||||
private volatile boolean isDead = true;
|
||||
private String hostName = null;
|
||||
private int port = 0;
|
||||
private String userName = null;
|
||||
private String password = null;
|
||||
private boolean hasPlatformMXBeans = false;
|
||||
private boolean hasHotSpotDiagnosticMXBean = false;
|
||||
private boolean hasCompilationMXBean = false;
|
||||
private boolean supportsLockUsage = false;
|
||||
|
||||
// REVISIT: VMPanel and other places relying using getUrl().
|
||||
|
||||
// set only if it's created for local monitoring
|
||||
private LocalVirtualMachine lvm;
|
||||
|
||||
// set only if it's created from a given URL via the Advanced tab
|
||||
private String advancedUrl = null;
|
||||
|
||||
private JMXServiceURL jmxUrl = null;
|
||||
private MBeanServerConnection mbsc = null;
|
||||
private SnapshotMBeanServerConnection server = null;
|
||||
private JMXConnector jmxc = null;
|
||||
private RMIServer stub = null;
|
||||
private static final SslRMIClientSocketFactory sslRMIClientSocketFactory = new SslRMIClientSocketFactory();
|
||||
private String registryHostName = null;
|
||||
private int registryPort = 0;
|
||||
private boolean vmConnector = false;
|
||||
private boolean sslRegistry = false;
|
||||
private boolean sslStub = false;
|
||||
final private String connectionName;
|
||||
final private String displayName;
|
||||
|
||||
private ClassLoadingMXBean classLoadingMBean = null;
|
||||
private CompilationMXBean compilationMBean = null;
|
||||
private MemoryMXBean memoryMBean = null;
|
||||
private OperatingSystemMXBean operatingSystemMBean = null;
|
||||
private RuntimeMXBean runtimeMBean = null;
|
||||
private ThreadMXBean threadMBean = null;
|
||||
|
||||
private com.sun.management.OperatingSystemMXBean sunOperatingSystemMXBean = null;
|
||||
private HotSpotDiagnosticMXBean hotspotDiagnosticMXBean = null;
|
||||
|
||||
private List<GarbageCollectorMXBean> garbageCollectorMBeans = null;
|
||||
|
||||
final static private String HOTSPOT_DIAGNOSTIC_MXBEAN_NAME = "com.sun.management:type=HotSpotDiagnostic";
|
||||
|
||||
private ProxyClient(String hostName, int port, String userName, String password) throws IOException{
|
||||
this.connectionName = getConnectionName(hostName, port, userName);
|
||||
this.displayName = connectionName;
|
||||
if (hostName.equals("localhost") && port == 0) {
|
||||
// Monitor self
|
||||
this.hostName = hostName;
|
||||
this.port = port;
|
||||
} else {
|
||||
// Create an RMI connector client and connect it to
|
||||
// the RMI connector server
|
||||
final String urlPath = "/jndi/rmi://" + hostName + ":" + port + "/jmxrmi";
|
||||
JMXServiceURL url = new JMXServiceURL("rmi", "", 0, urlPath);
|
||||
setParameters(url, userName, password);
|
||||
vmConnector = true;
|
||||
registryHostName = hostName;
|
||||
registryPort = port;
|
||||
checkSslConfig();
|
||||
}
|
||||
}
|
||||
|
||||
private ProxyClient(String url, String userName, String password) throws IOException{
|
||||
this.advancedUrl = url;
|
||||
this.connectionName = getConnectionName(url, userName);
|
||||
this.displayName = connectionName;
|
||||
setParameters(new JMXServiceURL(url), userName, password);
|
||||
}
|
||||
|
||||
private ProxyClient(LocalVirtualMachine lvm) throws IOException{
|
||||
this.lvm = lvm;
|
||||
this.connectionName = getConnectionName(lvm);
|
||||
this.displayName = "pid: " + lvm.vmid() + " " + lvm.displayName();
|
||||
}
|
||||
|
||||
private void setParameters(JMXServiceURL url, String userName, String password) {
|
||||
this.jmxUrl = url;
|
||||
this.hostName = jmxUrl.getHost();
|
||||
this.port = jmxUrl.getPort();
|
||||
this.userName = userName;
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
private static void checkStub(Remote stub, Class<? extends Remote> stubClass) {
|
||||
// Check remote stub is from the expected class.
|
||||
//
|
||||
if (stub.getClass() != stubClass) {
|
||||
if (!Proxy.isProxyClass(stub.getClass())) {
|
||||
throw new SecurityException("Expecting a " + stubClass.getName() + " stub!");
|
||||
} else {
|
||||
InvocationHandler handler = Proxy.getInvocationHandler(stub);
|
||||
if (handler.getClass() != RemoteObjectInvocationHandler.class) {
|
||||
throw new SecurityException("Expecting a dynamic proxy instance with a "
|
||||
+ RemoteObjectInvocationHandler.class.getName()
|
||||
+ " invocation handler!");
|
||||
} else {
|
||||
stub = (Remote) handler;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Check RemoteRef in stub is from the expected class
|
||||
// "sun.rmi.server.UnicastRef2".
|
||||
//
|
||||
RemoteRef ref = ((RemoteObject) stub).getRef();
|
||||
if (ref.getClass() != UnicastRef2.class) {
|
||||
throw new SecurityException("Expecting a " + UnicastRef2.class.getName() + " remote reference in stub!");
|
||||
}
|
||||
// Check RMIClientSocketFactory in stub is from the expected class
|
||||
// "javax.rmi.ssl.SslRMIClientSocketFactory".
|
||||
//
|
||||
LiveRef liveRef = ((UnicastRef2) ref).getLiveRef();
|
||||
RMIClientSocketFactory csf = liveRef.getClientSocketFactory();
|
||||
if (csf == null || csf.getClass() != SslRMIClientSocketFactory.class) {
|
||||
throw new SecurityException("Expecting a " + SslRMIClientSocketFactory.class.getName()
|
||||
+ " RMI client socket factory in stub!");
|
||||
}
|
||||
}
|
||||
|
||||
private static final String rmiServerImplStubClassName = "javax.management.remote.rmi.RMIServerImpl_Stub";
|
||||
private static final Class<? extends Remote> rmiServerImplStubClass;
|
||||
|
||||
static {
|
||||
// FIXME: RMIServerImpl_Stub is generated at build time
|
||||
// after jconsole is built. We need to investigate if
|
||||
// the Makefile can be fixed to build jconsole in the
|
||||
// right order. As a workaround for now, we dynamically
|
||||
// load RMIServerImpl_Stub class instead of statically
|
||||
// referencing it.
|
||||
Class<? extends Remote> serverStubClass = null;
|
||||
try {
|
||||
serverStubClass = Class.forName(rmiServerImplStubClassName).asSubclass(Remote.class);
|
||||
} catch (ClassNotFoundException e) {
|
||||
// should never reach here
|
||||
throw (InternalError) new InternalError(e.getMessage()).initCause(e);
|
||||
}
|
||||
rmiServerImplStubClass = serverStubClass;
|
||||
}
|
||||
|
||||
private void checkSslConfig() throws IOException {
|
||||
// Get the reference to the RMI Registry and lookup RMIServer stub
|
||||
//
|
||||
Registry registry;
|
||||
try {
|
||||
registry = LocateRegistry.getRegistry(registryHostName, registryPort, sslRMIClientSocketFactory);
|
||||
try {
|
||||
stub = (RMIServer) registry.lookup("jmxrmi");
|
||||
} catch (NotBoundException nbe) {
|
||||
throw (IOException) new IOException(nbe.getMessage()).initCause(nbe);
|
||||
}
|
||||
sslRegistry = true;
|
||||
} catch (IOException e) {
|
||||
registry = LocateRegistry.getRegistry(registryHostName, registryPort);
|
||||
try {
|
||||
stub = (RMIServer) registry.lookup("jmxrmi");
|
||||
} catch (NotBoundException nbe) {
|
||||
throw (IOException) new IOException(nbe.getMessage()).initCause(nbe);
|
||||
}
|
||||
sslRegistry = false;
|
||||
}
|
||||
// Perform the checks for secure stub
|
||||
//
|
||||
try {
|
||||
checkStub(stub, rmiServerImplStubClass);
|
||||
sslStub = true;
|
||||
} catch (SecurityException e) {
|
||||
sslStub = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the underlying RMI registry is SSL-protected.
|
||||
*
|
||||
* @exception UnsupportedOperationException If this {@code ProxyClient} does not denote a JMX connector for a JMX VM
|
||||
* agent.
|
||||
*/
|
||||
public boolean isSslRmiRegistry() {
|
||||
// Check for VM connector
|
||||
//
|
||||
if (!isVmConnector()) {
|
||||
throw new UnsupportedOperationException("ProxyClient.isSslRmiRegistry() is only supported if this "
|
||||
+ "ProxyClient is a JMX connector for a JMX VM agent");
|
||||
}
|
||||
return sslRegistry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the retrieved RMI stub is SSL-protected.
|
||||
*
|
||||
* @exception UnsupportedOperationException If this {@code ProxyClient} does not denote a JMX connector for a JMX VM
|
||||
* agent.
|
||||
*/
|
||||
public boolean isSslRmiStub() {
|
||||
// Check for VM connector
|
||||
//
|
||||
if (!isVmConnector()) {
|
||||
throw new UnsupportedOperationException("ProxyClient.isSslRmiStub() is only supported if this "
|
||||
+ "ProxyClient is a JMX connector for a JMX VM agent");
|
||||
}
|
||||
return sslStub;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this {@code ProxyClient} denotes a JMX connector for a JMX VM agent.
|
||||
*/
|
||||
public boolean isVmConnector() {
|
||||
return vmConnector;
|
||||
}
|
||||
|
||||
private void setConnectionState(ConnectionState state) {
|
||||
ConnectionState oldState = this.connectionState;
|
||||
this.connectionState = state;
|
||||
propertyChangeSupport.firePropertyChange(CONNECTION_STATE_PROPERTY, oldState, state);
|
||||
}
|
||||
|
||||
public ConnectionState getConnectionState() {
|
||||
return this.connectionState;
|
||||
}
|
||||
|
||||
void flush() {
|
||||
if (server != null) {
|
||||
server.flush();
|
||||
}
|
||||
}
|
||||
|
||||
void connect() {
|
||||
setConnectionState(ConnectionState.CONNECTING);
|
||||
try {
|
||||
tryConnect();
|
||||
setConnectionState(ConnectionState.CONNECTED);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
setConnectionState(ConnectionState.DISCONNECTED);
|
||||
}
|
||||
}
|
||||
|
||||
private void tryConnect() throws IOException {
|
||||
if (jmxUrl == null && "localhost".equals(hostName) && port == 0) {
|
||||
// Monitor self
|
||||
this.jmxc = null;
|
||||
this.mbsc = ManagementFactory.getPlatformMBeanServer();
|
||||
this.server = Snapshot.newSnapshot(mbsc);
|
||||
} else {
|
||||
// Monitor another process
|
||||
if (lvm != null) {
|
||||
if (!lvm.isManageable()) {
|
||||
lvm.startManagementAgent();
|
||||
if (!lvm.isManageable()) {
|
||||
// FIXME: what to throw
|
||||
throw new IOException(lvm + "not manageable");
|
||||
}
|
||||
}
|
||||
if (this.jmxUrl == null) {
|
||||
this.jmxUrl = new JMXServiceURL(lvm.connectorAddress());
|
||||
}
|
||||
}
|
||||
// Need to pass in credentials ?
|
||||
if (userName == null && password == null) {
|
||||
if (isVmConnector()) {
|
||||
// Check for SSL config on reconnection only
|
||||
if (stub == null) {
|
||||
checkSslConfig();
|
||||
}
|
||||
this.jmxc = new RMIConnector(stub, null);
|
||||
jmxc.connect();
|
||||
} else {
|
||||
this.jmxc = JMXConnectorFactory.connect(jmxUrl);
|
||||
}
|
||||
} else {
|
||||
Map<String, String[]> env = new HashMap<String, String[]>();
|
||||
env.put(JMXConnector.CREDENTIALS, new String[] { userName, password });
|
||||
if (isVmConnector()) {
|
||||
// Check for SSL config on reconnection only
|
||||
if (stub == null) {
|
||||
checkSslConfig();
|
||||
}
|
||||
this.jmxc = new RMIConnector(stub, null);
|
||||
jmxc.connect(env);
|
||||
} else {
|
||||
this.jmxc = JMXConnectorFactory.connect(jmxUrl, env);
|
||||
}
|
||||
}
|
||||
this.mbsc = jmxc.getMBeanServerConnection();
|
||||
this.server = Snapshot.newSnapshot(mbsc);
|
||||
}
|
||||
this.isDead = false;
|
||||
|
||||
try {
|
||||
ObjectName on = new ObjectName(THREAD_MXBEAN_NAME);
|
||||
this.hasPlatformMXBeans = server.isRegistered(on);
|
||||
this.hasHotSpotDiagnosticMXBean = server.isRegistered(new ObjectName(HOTSPOT_DIAGNOSTIC_MXBEAN_NAME));
|
||||
// check if it has 6.0 new APIs
|
||||
if (this.hasPlatformMXBeans) {
|
||||
MBeanOperationInfo[] mopis = server.getMBeanInfo(on).getOperations();
|
||||
// look for findDeadlockedThreads operations;
|
||||
for (MBeanOperationInfo op : mopis) {
|
||||
if (op.getName().equals("findDeadlockedThreads")) {
|
||||
this.supportsLockUsage = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
on = new ObjectName(COMPILATION_MXBEAN_NAME);
|
||||
this.hasCompilationMXBean = server.isRegistered(on);
|
||||
}
|
||||
} catch (MalformedObjectNameException e) {
|
||||
// should not reach here
|
||||
throw new InternalError(e.getMessage());
|
||||
} catch (IntrospectionException e) {
|
||||
InternalError ie = new InternalError(e.getMessage());
|
||||
ie.initCause(e);
|
||||
throw ie;
|
||||
} catch (InstanceNotFoundException e) {
|
||||
InternalError ie = new InternalError(e.getMessage());
|
||||
ie.initCause(e);
|
||||
throw ie;
|
||||
} catch (ReflectionException e) {
|
||||
InternalError ie = new InternalError(e.getMessage());
|
||||
ie.initCause(e);
|
||||
throw ie;
|
||||
}
|
||||
|
||||
if (hasPlatformMXBeans) {
|
||||
// WORKAROUND for bug 5056632
|
||||
// Check if the access role is correct by getting a RuntimeMXBean
|
||||
getRuntimeMXBean();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a proxy client for a given local virtual machine.
|
||||
*/
|
||||
public static ProxyClient getProxyClient(LocalVirtualMachine lvm) throws IOException {
|
||||
final String key = getCacheKey(lvm);
|
||||
ProxyClient proxyClient = cache.get(key);
|
||||
if (proxyClient == null) {
|
||||
proxyClient = new ProxyClient(lvm);
|
||||
cache.put(key, proxyClient);
|
||||
}
|
||||
return proxyClient;
|
||||
}
|
||||
|
||||
public static String getConnectionName(LocalVirtualMachine lvm) {
|
||||
return Integer.toString(lvm.vmid());
|
||||
}
|
||||
|
||||
private static String getCacheKey(LocalVirtualMachine lvm) {
|
||||
return Integer.toString(lvm.vmid());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a proxy client for a given JMXServiceURL.
|
||||
*/
|
||||
public static ProxyClient getProxyClient(String url, String userName, String password) throws IOException {
|
||||
final String key = getCacheKey(url, userName, password);
|
||||
ProxyClient proxyClient = cache.get(key);
|
||||
if (proxyClient == null) {
|
||||
proxyClient = new ProxyClient(url, userName, password);
|
||||
cache.put(key, proxyClient);
|
||||
}
|
||||
return proxyClient;
|
||||
}
|
||||
|
||||
public static String getConnectionName(String url, String userName) {
|
||||
if (userName != null && userName.length() > 0) {
|
||||
return userName + "@" + url;
|
||||
} else {
|
||||
return url;
|
||||
}
|
||||
}
|
||||
|
||||
private static String getCacheKey(String url, String userName, String password) {
|
||||
return (url == null ? "" : url) + ":" + (userName == null ? "" : userName) + ":"
|
||||
+ (password == null ? "" : password);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a proxy client for a given "hostname:port".
|
||||
*/
|
||||
public static ProxyClient getProxyClient(String hostName, int port, String userName, String password)
|
||||
throws IOException {
|
||||
final String key = getCacheKey(hostName, port, userName, password);
|
||||
ProxyClient proxyClient = cache.get(key);
|
||||
if (proxyClient == null) {
|
||||
proxyClient = new ProxyClient(hostName, port, userName, password);
|
||||
cache.put(key, proxyClient);
|
||||
}
|
||||
return proxyClient;
|
||||
}
|
||||
|
||||
public static String getConnectionName(String hostName, int port, String userName) {
|
||||
String name = hostName + ":" + port;
|
||||
if (userName != null && userName.length() > 0) {
|
||||
return userName + "@" + name;
|
||||
} else {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
private static String getCacheKey(String hostName, int port, String userName, String password) {
|
||||
return (hostName == null ? "" : hostName) + ":" + port + ":" + (userName == null ? "" : userName) + ":"
|
||||
+ (password == null ? "" : password);
|
||||
}
|
||||
|
||||
public String connectionName() {
|
||||
return connectionName;
|
||||
}
|
||||
|
||||
public String getDisplayName() {
|
||||
return displayName;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
if (!isConnected()) {
|
||||
return displayName + " (disconnected)";
|
||||
} else {
|
||||
return displayName;
|
||||
}
|
||||
}
|
||||
|
||||
public MBeanServerConnection getMBeanServerConnection() {
|
||||
return mbsc;
|
||||
}
|
||||
|
||||
public SnapshotMBeanServerConnection getSnapshotMBeanServerConnection() {
|
||||
return server;
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return advancedUrl;
|
||||
}
|
||||
|
||||
public String getHostName() {
|
||||
return hostName;
|
||||
}
|
||||
|
||||
public int getPort() {
|
||||
return port;
|
||||
}
|
||||
|
||||
public int getVmid() {
|
||||
return (lvm != null) ? lvm.vmid() : 0;
|
||||
}
|
||||
|
||||
public String getUserName() {
|
||||
return userName;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public void disconnect() {
|
||||
// Reset remote stub
|
||||
stub = null;
|
||||
// Close MBeanServer connection
|
||||
if (jmxc != null) {
|
||||
try {
|
||||
jmxc.close();
|
||||
} catch (IOException e) {
|
||||
// Ignore ???
|
||||
}
|
||||
}
|
||||
// Reset platform MBean references
|
||||
classLoadingMBean = null;
|
||||
compilationMBean = null;
|
||||
memoryMBean = null;
|
||||
operatingSystemMBean = null;
|
||||
runtimeMBean = null;
|
||||
threadMBean = null;
|
||||
sunOperatingSystemMXBean = null;
|
||||
garbageCollectorMBeans = null;
|
||||
// Set connection state to DISCONNECTED
|
||||
if (!isDead) {
|
||||
isDead = true;
|
||||
setConnectionState(ConnectionState.DISCONNECTED);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of domains in which any MBean is currently registered.
|
||||
*/
|
||||
public String[] getDomains() throws IOException {
|
||||
return server.getDomains();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a map of MBeans with ObjectName as the key and MBeanInfo value of a given domain. If domain is
|
||||
* <tt>null</tt>, all MBeans are returned. If no MBean found, an empty map is returned.
|
||||
*/
|
||||
public Map<ObjectName, MBeanInfo> getMBeans(String domain) throws IOException {
|
||||
|
||||
ObjectName name = null;
|
||||
if (domain != null) {
|
||||
try {
|
||||
name = new ObjectName(domain + ":*");
|
||||
} catch (MalformedObjectNameException e) {
|
||||
// should not reach here
|
||||
assert (false);
|
||||
}
|
||||
}
|
||||
Set<ObjectName> mbeans = server.queryNames(name, null);
|
||||
Map<ObjectName, MBeanInfo> result = new HashMap<ObjectName, MBeanInfo>(mbeans.size());
|
||||
Iterator<ObjectName> iterator = mbeans.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
Object object = iterator.next();
|
||||
if (object instanceof ObjectName) {
|
||||
ObjectName o = (ObjectName) object;
|
||||
try {
|
||||
MBeanInfo info = server.getMBeanInfo(o);
|
||||
result.put(o, info);
|
||||
} catch (IntrospectionException e) {
|
||||
// TODO: should log the error
|
||||
} catch (InstanceNotFoundException e) {
|
||||
// TODO: should log the error
|
||||
} catch (ReflectionException e) {
|
||||
// TODO: should log the error
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of attributes of a named MBean.
|
||||
*/
|
||||
public AttributeList getAttributes(ObjectName name, String[] attributes) throws IOException {
|
||||
AttributeList list = null;
|
||||
try {
|
||||
list = server.getAttributes(name, attributes);
|
||||
} catch (InstanceNotFoundException e) {
|
||||
// TODO: A MBean may have been unregistered.
|
||||
// need to set up listener to listen for MBeanServerNotification.
|
||||
} catch (ReflectionException e) {
|
||||
// TODO: should log the error
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of a specific attribute of a named MBean.
|
||||
*/
|
||||
public void setAttribute(ObjectName name, Attribute attribute) throws InvalidAttributeValueException,
|
||||
MBeanException, IOException {
|
||||
try {
|
||||
server.setAttribute(name, attribute);
|
||||
} catch (InstanceNotFoundException e) {
|
||||
// TODO: A MBean may have been unregistered.
|
||||
} catch (AttributeNotFoundException e) {
|
||||
assert (false);
|
||||
} catch (ReflectionException e) {
|
||||
// TODO: should log the error
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes an operation of a named MBean.
|
||||
*
|
||||
* @throws MBeanException Wraps an exception thrown by the MBean's invoked method.
|
||||
*/
|
||||
public Object invoke(ObjectName name, String operationName, Object[] params, String[] signature)
|
||||
throws IOException,
|
||||
MBeanException {
|
||||
Object result = null;
|
||||
try {
|
||||
result = server.invoke(name, operationName, params, signature);
|
||||
} catch (InstanceNotFoundException e) {
|
||||
// TODO: A MBean may have been unregistered.
|
||||
} catch (ReflectionException e) {
|
||||
// TODO: should log the error
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public synchronized ClassLoadingMXBean getClassLoadingMXBean() throws IOException {
|
||||
if (hasPlatformMXBeans && classLoadingMBean == null) {
|
||||
classLoadingMBean = newPlatformMXBeanProxy(server, CLASS_LOADING_MXBEAN_NAME, ClassLoadingMXBean.class);
|
||||
}
|
||||
return classLoadingMBean;
|
||||
}
|
||||
|
||||
public synchronized CompilationMXBean getCompilationMXBean() throws IOException {
|
||||
if (hasCompilationMXBean && compilationMBean == null) {
|
||||
compilationMBean = newPlatformMXBeanProxy(server, COMPILATION_MXBEAN_NAME, CompilationMXBean.class);
|
||||
}
|
||||
return compilationMBean;
|
||||
}
|
||||
|
||||
public synchronized Collection<GarbageCollectorMXBean> getGarbageCollectorMXBeans() throws IOException {
|
||||
|
||||
// TODO: How to deal with changes to the list??
|
||||
if (garbageCollectorMBeans == null) {
|
||||
ObjectName gcName = null;
|
||||
try {
|
||||
gcName = new ObjectName(GARBAGE_COLLECTOR_MXBEAN_DOMAIN_TYPE + ",*");
|
||||
} catch (MalformedObjectNameException e) {
|
||||
// should not reach here
|
||||
assert (false);
|
||||
}
|
||||
Set<ObjectName> mbeans = server.queryNames(gcName, null);
|
||||
if (mbeans != null) {
|
||||
garbageCollectorMBeans = new ArrayList<GarbageCollectorMXBean>();
|
||||
Iterator<ObjectName> iterator = mbeans.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
ObjectName on = (ObjectName) iterator.next();
|
||||
String name = GARBAGE_COLLECTOR_MXBEAN_DOMAIN_TYPE + ",name=" + on.getKeyProperty("name");
|
||||
|
||||
GarbageCollectorMXBean mBean = newPlatformMXBeanProxy(server, name, GarbageCollectorMXBean.class);
|
||||
garbageCollectorMBeans.add(mBean);
|
||||
}
|
||||
}
|
||||
}
|
||||
return garbageCollectorMBeans;
|
||||
}
|
||||
|
||||
public synchronized MemoryMXBean getMemoryMXBean() throws IOException {
|
||||
if (hasPlatformMXBeans && memoryMBean == null) {
|
||||
memoryMBean = newPlatformMXBeanProxy(server, MEMORY_MXBEAN_NAME, MemoryMXBean.class);
|
||||
}
|
||||
return memoryMBean;
|
||||
}
|
||||
|
||||
public synchronized RuntimeMXBean getRuntimeMXBean() throws IOException {
|
||||
if (hasPlatformMXBeans && runtimeMBean == null) {
|
||||
runtimeMBean = newPlatformMXBeanProxy(server, RUNTIME_MXBEAN_NAME, RuntimeMXBean.class);
|
||||
}
|
||||
return runtimeMBean;
|
||||
}
|
||||
|
||||
public synchronized ThreadMXBean getThreadMXBean() throws IOException {
|
||||
if (hasPlatformMXBeans && threadMBean == null) {
|
||||
threadMBean = newPlatformMXBeanProxy(server, THREAD_MXBEAN_NAME, ThreadMXBean.class);
|
||||
}
|
||||
return threadMBean;
|
||||
}
|
||||
|
||||
public synchronized OperatingSystemMXBean getOperatingSystemMXBean() throws IOException {
|
||||
if (hasPlatformMXBeans && operatingSystemMBean == null) {
|
||||
operatingSystemMBean = newPlatformMXBeanProxy(server, OPERATING_SYSTEM_MXBEAN_NAME,
|
||||
OperatingSystemMXBean.class);
|
||||
}
|
||||
return operatingSystemMBean;
|
||||
}
|
||||
|
||||
public synchronized com.sun.management.OperatingSystemMXBean getSunOperatingSystemMXBean() throws IOException {
|
||||
|
||||
try {
|
||||
ObjectName on = new ObjectName(OPERATING_SYSTEM_MXBEAN_NAME);
|
||||
if (sunOperatingSystemMXBean == null) {
|
||||
if (server.isInstanceOf(on, "com.sun.management.OperatingSystemMXBean")) {
|
||||
sunOperatingSystemMXBean = newPlatformMXBeanProxy(server, OPERATING_SYSTEM_MXBEAN_NAME,
|
||||
com.sun.management.OperatingSystemMXBean.class);
|
||||
}
|
||||
}
|
||||
} catch (InstanceNotFoundException e) {
|
||||
return null;
|
||||
} catch (MalformedObjectNameException e) {
|
||||
return null; // should never reach here
|
||||
}
|
||||
return sunOperatingSystemMXBean;
|
||||
}
|
||||
|
||||
public synchronized HotSpotDiagnosticMXBean getHotSpotDiagnosticMXBean() throws IOException {
|
||||
if (hasHotSpotDiagnosticMXBean && hotspotDiagnosticMXBean == null) {
|
||||
hotspotDiagnosticMXBean = newPlatformMXBeanProxy(server, HOTSPOT_DIAGNOSTIC_MXBEAN_NAME,
|
||||
HotSpotDiagnosticMXBean.class);
|
||||
}
|
||||
return hotspotDiagnosticMXBean;
|
||||
}
|
||||
|
||||
public <T> T getMXBean(ObjectName objName, Class<T> interfaceClass) throws IOException {
|
||||
return newPlatformMXBeanProxy(server, objName.toString(), interfaceClass);
|
||||
|
||||
}
|
||||
|
||||
// Return thread IDs of deadlocked threads or null if any.
|
||||
// It finds deadlocks involving only monitors if it's a Tiger VM.
|
||||
// Otherwise, it finds deadlocks involving both monitors and
|
||||
// the concurrent locks.
|
||||
public long[] findDeadlockedThreads() throws IOException {
|
||||
ThreadMXBean tm = getThreadMXBean();
|
||||
if (supportsLockUsage && tm.isSynchronizerUsageSupported()) {
|
||||
return tm.findDeadlockedThreads();
|
||||
} else {
|
||||
return tm.findMonitorDeadlockedThreads();
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void markAsDead() {
|
||||
disconnect();
|
||||
}
|
||||
|
||||
public boolean isDead() {
|
||||
return isDead;
|
||||
}
|
||||
|
||||
boolean isConnected() {
|
||||
return !isDead();
|
||||
}
|
||||
|
||||
boolean hasPlatformMXBeans() {
|
||||
return this.hasPlatformMXBeans;
|
||||
}
|
||||
|
||||
boolean hasHotSpotDiagnosticMXBean() {
|
||||
return this.hasHotSpotDiagnosticMXBean;
|
||||
}
|
||||
|
||||
boolean isLockUsageSupported() {
|
||||
return supportsLockUsage;
|
||||
}
|
||||
|
||||
public boolean isRegistered(ObjectName name) throws IOException {
|
||||
return server.isRegistered(name);
|
||||
}
|
||||
|
||||
public void addPropertyChangeListener(PropertyChangeListener listener) {
|
||||
propertyChangeSupport.addPropertyChangeListener(listener);
|
||||
}
|
||||
|
||||
public void addWeakPropertyChangeListener(PropertyChangeListener listener) {
|
||||
if (!(listener instanceof WeakPCL)) {
|
||||
listener = new WeakPCL(listener);
|
||||
}
|
||||
propertyChangeSupport.addPropertyChangeListener(listener);
|
||||
}
|
||||
|
||||
public void removePropertyChangeListener(PropertyChangeListener listener) {
|
||||
if (!(listener instanceof WeakPCL)) {
|
||||
// Search for the WeakPCL holding this listener (if any)
|
||||
for (PropertyChangeListener pcl : propertyChangeSupport.getPropertyChangeListeners()) {
|
||||
if (pcl instanceof WeakPCL && ((WeakPCL) pcl).get() == listener) {
|
||||
listener = pcl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
propertyChangeSupport.removePropertyChangeListener(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* The PropertyChangeListener is handled via a WeakReference so as not to pin down the listener.
|
||||
*/
|
||||
private class WeakPCL extends WeakReference<PropertyChangeListener> implements PropertyChangeListener {
|
||||
|
||||
WeakPCL(PropertyChangeListener referent){
|
||||
super(referent);
|
||||
}
|
||||
|
||||
public void propertyChange(PropertyChangeEvent pce) {
|
||||
PropertyChangeListener pcl = get();
|
||||
|
||||
if (pcl == null) {
|
||||
// The referent listener was GC'ed, we're no longer
|
||||
// interested in PropertyChanges, remove the listener.
|
||||
dispose();
|
||||
} else {
|
||||
pcl.propertyChange(pce);
|
||||
}
|
||||
}
|
||||
|
||||
private void dispose() {
|
||||
removePropertyChangeListener(this);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Snapshot MBeanServerConnection:
|
||||
//
|
||||
// This is an object that wraps an existing MBeanServerConnection and adds
|
||||
// caching to it, as follows:
|
||||
//
|
||||
// - The first time an attribute is called in a given MBean, the result is
|
||||
// cached. Every subsequent time getAttribute is called for that attribute
|
||||
// the cached result is returned.
|
||||
//
|
||||
// - Before every call to VMPanel.update() or when the Refresh button in the
|
||||
// Attributes table is pressed down the attributes cache is flushed. Then
|
||||
// any subsequent call to getAttribute will retrieve all the values for
|
||||
// the attributes that are known to the cache.
|
||||
//
|
||||
// - The attributes cache uses a learning approach and only the attributes
|
||||
// that are in the cache will be retrieved between two subsequent updates.
|
||||
//
|
||||
|
||||
public interface SnapshotMBeanServerConnection extends MBeanServerConnection {
|
||||
|
||||
/**
|
||||
* Flush all cached values of attributes.
|
||||
*/
|
||||
public void flush();
|
||||
}
|
||||
|
||||
public static class Snapshot {
|
||||
|
||||
private Snapshot(){
|
||||
}
|
||||
|
||||
public static SnapshotMBeanServerConnection newSnapshot(MBeanServerConnection mbsc) {
|
||||
final InvocationHandler ih = new SnapshotInvocationHandler(mbsc);
|
||||
return (SnapshotMBeanServerConnection) Proxy.newProxyInstance(Snapshot.class.getClassLoader(),
|
||||
new Class[] { SnapshotMBeanServerConnection.class },
|
||||
ih);
|
||||
}
|
||||
}
|
||||
|
||||
static class SnapshotInvocationHandler implements InvocationHandler {
|
||||
|
||||
private final MBeanServerConnection conn;
|
||||
private Map<ObjectName, NameValueMap> cachedValues = newMap();
|
||||
private Map<ObjectName, Set<String>> cachedNames = newMap();
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
private static final class NameValueMap extends HashMap<String, Object> {
|
||||
}
|
||||
|
||||
SnapshotInvocationHandler(MBeanServerConnection conn){
|
||||
this.conn = conn;
|
||||
}
|
||||
|
||||
synchronized void flush() {
|
||||
cachedValues = newMap();
|
||||
}
|
||||
|
||||
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
|
||||
final String methodName = method.getName();
|
||||
if (methodName.equals("getAttribute")) {
|
||||
return getAttribute((ObjectName) args[0], (String) args[1]);
|
||||
} else if (methodName.equals("getAttributes")) {
|
||||
return getAttributes((ObjectName) args[0], (String[]) args[1]);
|
||||
} else if (methodName.equals("flush")) {
|
||||
flush();
|
||||
return null;
|
||||
} else {
|
||||
try {
|
||||
return method.invoke(conn, args);
|
||||
} catch (InvocationTargetException e) {
|
||||
throw e.getCause();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Object getAttribute(ObjectName objName, String attrName) throws MBeanException,
|
||||
InstanceNotFoundException,
|
||||
AttributeNotFoundException,
|
||||
ReflectionException, IOException {
|
||||
final NameValueMap values = getCachedAttributes(objName, Collections.singleton(attrName));
|
||||
Object value = values.get(attrName);
|
||||
if (value != null || values.containsKey(attrName)) {
|
||||
return value;
|
||||
}
|
||||
// Not in cache, presumably because it was omitted from the
|
||||
// getAttributes result because of an exception. Following
|
||||
// call will probably provoke the same exception.
|
||||
return conn.getAttribute(objName, attrName);
|
||||
}
|
||||
|
||||
private AttributeList getAttributes(ObjectName objName, String[] attrNames) throws InstanceNotFoundException,
|
||||
ReflectionException, IOException {
|
||||
final NameValueMap values = getCachedAttributes(objName, new TreeSet<String>(Arrays.asList(attrNames)));
|
||||
final AttributeList list = new AttributeList();
|
||||
for (String attrName : attrNames) {
|
||||
final Object value = values.get(attrName);
|
||||
if (value != null || values.containsKey(attrName)) {
|
||||
list.add(new Attribute(attrName, value));
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
private synchronized NameValueMap getCachedAttributes(ObjectName objName, Set<String> attrNames)
|
||||
throws InstanceNotFoundException,
|
||||
ReflectionException,
|
||||
IOException {
|
||||
NameValueMap values = cachedValues.get(objName);
|
||||
if (values != null && values.keySet().containsAll(attrNames)) {
|
||||
return values;
|
||||
}
|
||||
attrNames = new TreeSet<String>(attrNames);
|
||||
Set<String> oldNames = cachedNames.get(objName);
|
||||
if (oldNames != null) {
|
||||
attrNames.addAll(oldNames);
|
||||
}
|
||||
values = new NameValueMap();
|
||||
final AttributeList attrs = conn.getAttributes(objName, attrNames.toArray(new String[attrNames.size()]));
|
||||
for (Attribute attr : attrs.asList()) {
|
||||
values.put(attr.getName(), attr.getValue());
|
||||
}
|
||||
cachedValues.put(objName, values);
|
||||
cachedNames.put(objName, attrNames);
|
||||
return values;
|
||||
}
|
||||
|
||||
// See http://www.artima.com/weblogs/viewpost.jsp?thread=79394
|
||||
private static <K, V> Map<K, V> newMap() {
|
||||
return new HashMap<K, V>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -503,9 +503,11 @@ public class Lexer {
|
||||
token = LITERAL_CHARS;
|
||||
break;
|
||||
} else {
|
||||
System.arraycopy(buf, np + 1, sbuf, 0, sp);
|
||||
hasSpecial = true;
|
||||
putChar('\'');
|
||||
if (!hasSpecial) {
|
||||
System.arraycopy(buf, np + 1, sbuf, 0, sp);
|
||||
hasSpecial = true;
|
||||
}
|
||||
putChar('\'');
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,18 +34,18 @@ public class ParameterizedOutputVisitorUtils {
|
||||
|
||||
public static SQLASTOutputVisitor createParameterizedOutputVisitor(Appendable out, String dbType) {
|
||||
if (JdbcUtils.ORACLE.equals(dbType)) {
|
||||
return new OracleParameterizedOutputVisitor();
|
||||
return new OracleParameterizedOutputVisitor(out);
|
||||
}
|
||||
|
||||
if (JdbcUtils.MYSQL.equals(dbType)) {
|
||||
return new MySqlParameterizedOutputVisitor();
|
||||
return new MySqlParameterizedOutputVisitor(out);
|
||||
}
|
||||
|
||||
if (JdbcUtils.POSTGRESQL.equals(dbType)) {
|
||||
return new PGParameterizedOutputVisitor();
|
||||
return new PGParameterizedOutputVisitor(out);
|
||||
}
|
||||
|
||||
return new ParameterizedOutputVisitor();
|
||||
return new ParameterizedOutputVisitor(out);
|
||||
}
|
||||
|
||||
public static boolean visit(SQLASTOutputVisitor v, SQLInListExpr x) {
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
package com.alibaba.druid.stat;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
@@ -41,7 +42,7 @@ public class JdbcDataSourceStat implements JdbcDataSourceStatMBean {
|
||||
private final JdbcResultSetStat resultSetStat = new JdbcResultSetStat();
|
||||
private final JdbcStatementStat statementStat = new JdbcStatementStat();
|
||||
|
||||
private int maxSize = 1000 * 10;
|
||||
private int maxSize = 1000 * 1;
|
||||
|
||||
private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
|
||||
private final LinkedHashMap<String, JdbcSqlStat> sqlStatMap = new LinkedHashMap<String, JdbcSqlStat>(
|
||||
@@ -62,14 +63,21 @@ public class JdbcDataSourceStat implements JdbcDataSourceStatMBean {
|
||||
connectionStat.reset();
|
||||
statementStat.reset();
|
||||
resultSetStat.reset();
|
||||
|
||||
lock.readLock().lock();
|
||||
|
||||
lock.writeLock().lock();
|
||||
try {
|
||||
for (JdbcSqlStat stat : sqlStatMap.values()) {
|
||||
stat.reset();
|
||||
}
|
||||
Iterator<Map.Entry<String, JdbcSqlStat>> iter = sqlStatMap.entrySet().iterator();
|
||||
while (iter.hasNext()) {
|
||||
Map.Entry<String, JdbcSqlStat> entry = iter.next();
|
||||
JdbcSqlStat stat = entry.getValue();
|
||||
if (stat.getExecuteCount() == 0) {
|
||||
iter.remove();
|
||||
} else {
|
||||
stat.reset();
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
lock.readLock().unlock();
|
||||
lock.writeLock().unlock();
|
||||
}
|
||||
|
||||
for (JdbcConnectionStat.Entry connectionStat : connections.values()) {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
druid.filters.default=com.alibaba.druid.filter.stat.StatFilter
|
||||
druid.filters.stat=com.alibaba.druid.filter.stat.StatFilter
|
||||
druid.filters.mergeStat=com.alibaba.druid.filter.stat.MergeStatFilter
|
||||
druid.filters.counter=com.alibaba.druid.filter.stat.StatFilter
|
||||
druid.filters.encoding=com.alibaba.druid.filter.encoding.EncodingConvertFilter
|
||||
druid.filters.log4j=com.alibaba.druid.filter.logging.Log4jFilter
|
||||
|
||||
@@ -38,6 +38,7 @@ public class OracleSelectTest34 extends OracleTest {
|
||||
|
||||
OracleSchemaStatVisitor visitor = new OracleSchemaStatVisitor();
|
||||
statemen.accept(visitor);
|
||||
|
||||
|
||||
System.out.println("Tables : " + visitor.getTables());
|
||||
System.out.println("fields : " + visitor.getColumns());
|
||||
|
||||
@@ -27,4 +27,6 @@ public class OracleTest extends TestCase {
|
||||
}
|
||||
System.out.println(text);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -28,4 +28,29 @@ public class SQLLexerTest2 extends TestCase {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void test_lexer2() throws Exception {
|
||||
String sql = "SELECT substr('''a''bc',0,3) FROM dual";
|
||||
Lexer lexer = new Lexer(sql);
|
||||
for (;;) {
|
||||
lexer.nextToken();
|
||||
Token tok = lexer.token();
|
||||
|
||||
if (tok == Token.IDENTIFIER) {
|
||||
System.out.println(tok.name() + "\t\t" + lexer.stringVal());
|
||||
} else if (tok == Token.LITERAL_INT) {
|
||||
System.out.println(tok.name() + "\t\t" + lexer.numberString());
|
||||
} else if (tok == Token.LITERAL_CHARS) {
|
||||
System.out.println(tok.name() + "\t\t" + lexer.stringVal());
|
||||
}
|
||||
else {
|
||||
System.out.println(tok.name() + "\t\t\t" + tok.name);
|
||||
}
|
||||
|
||||
if (tok == Token.EOF) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user