diff --git a/src/main/java/com/alibaba/druid/pool/DruidPooledConnection.java b/src/main/java/com/alibaba/druid/pool/DruidPooledConnection.java index 0f56799e3d..69b6699a02 100644 --- a/src/main/java/com/alibaba/druid/pool/DruidPooledConnection.java +++ b/src/main/java/com/alibaba/druid/pool/DruidPooledConnection.java @@ -589,10 +589,13 @@ public class DruidPooledConnection implements javax.sql.PooledConnection, Connec conn.setAutoCommit(autoCommit); holder.setUnderlyingAutoCommit(autoCommit); } catch (SQLException ex) { + if ((!autoCommit) && holder.isUnderlyingAutoCommit()) { + + } handleException(ex); } } - + protected void transactionRecord(String sql) throws SQLException { if (transactionInfo == null && (!conn.getAutoCommit())) { DruidAbstractDataSource dataSource = holder.getDataSource(); diff --git a/src/main/java/com/alibaba/druid/pool/console/DruidConsole.java b/src/main/java/com/alibaba/druid/pool/console/DruidConsole.java new file mode 100644 index 0000000000..c4e0757c2e --- /dev/null +++ b/src/main/java/com/alibaba/druid/pool/console/DruidConsole.java @@ -0,0 +1,148 @@ +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 entries = new ArrayList(); + + 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 beans = proxy.getMBeans(null); + for (Map.Entry 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; + } + + } +} diff --git a/src/main/java/com/alibaba/druid/pool/console/JConsoleContext.java b/src/main/java/com/alibaba/druid/pool/console/JConsoleContext.java new file mode 100644 index 0000000000..b792a10229 --- /dev/null +++ b/src/main/java/com/alibaba/druid/pool/console/JConsoleContext.java @@ -0,0 +1,90 @@ +package com.alibaba.druid.pool.console; + + +import java.beans.PropertyChangeListener; + +import javax.management.MBeanServerConnection; + +/** + * {@code JConsoleContext} represents a JConsole connection to a target + * application. + *

+ * {@code JConsoleContext} notifies any {@code PropertyChangeListeners} + * about the {@linkplain #CONNECTION_STATE_PROPERTY ConnectionState} + * property change to {@link ConnectionState#CONNECTED CONNECTED} and + * {@link ConnectionState#DISCONNECTED DISCONNECTED}. + * The {@code JConsoleContext} instance will be the source for + * any generated events. + *

+ * + * @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 + * ConnectionState} 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); +} diff --git a/src/main/java/com/alibaba/druid/pool/console/LocalVirtualMachine.java b/src/main/java/com/alibaba/druid/pool/console/LocalVirtualMachine.java new file mode 100644 index 0000000000..1119c1f2b4 --- /dev/null +++ b/src/main/java/com/alibaba/druid/pool/console/LocalVirtualMachine.java @@ -0,0 +1,251 @@ +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; + +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 getAllVirtualMachines() { + Map map = new HashMap(); + getMonitoredVMs(map); + getAttachableVMs(map); + return map; + } + + private static void getMonitoredVMs(Map 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 map) { + List 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 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(); + } +} diff --git a/src/main/java/com/alibaba/druid/pool/console/ProxyClient.java b/src/main/java/com/alibaba/druid/pool/console/ProxyClient.java new file mode 100644 index 0000000000..d380ffd304 --- /dev/null +++ b/src/main/java/com/alibaba/druid/pool/console/ProxyClient.java @@ -0,0 +1,992 @@ +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; + +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 cache = Collections.synchronizedMap(new HashMap()); + + 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 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 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 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 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 env = new HashMap(); + 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 + * null, all MBeans are returned. If no MBean found, an empty map is returned. + */ + public Map 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 mbeans = server.queryNames(name, null); + Map result = new HashMap(mbeans.size()); + Iterator 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 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 mbeans = server.queryNames(gcName, null); + if (mbeans != null) { + garbageCollectorMBeans = new ArrayList(); + Iterator 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 getMXBean(ObjectName objName, Class 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 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 cachedValues = newMap(); + private Map> cachedNames = newMap(); + + @SuppressWarnings("serial") + private static final class NameValueMap extends HashMap { + } + + 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(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 attrNames) + throws InstanceNotFoundException, + ReflectionException, + IOException { + NameValueMap values = cachedValues.get(objName); + if (values != null && values.keySet().containsAll(attrNames)) { + return values; + } + attrNames = new TreeSet(attrNames); + Set 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 Map newMap() { + return new HashMap(); + } + } +} diff --git a/src/test/java/com/alibaba/druid/TestMySqlPing.java b/src/test/java/com/alibaba/druid/TestMySqlPing.java new file mode 100644 index 0000000000..2e3b03c420 --- /dev/null +++ b/src/test/java/com/alibaba/druid/TestMySqlPing.java @@ -0,0 +1,75 @@ +package com.alibaba.druid; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; +import java.sql.Statement; + +import junit.framework.TestCase; +import oracle.jdbc.OracleConnection; + + +public class TestMySqlPing extends TestCase { + private String jdbcUrl; + private String user; + private String password; + private String driverClass; + + protected void setUp() throws Exception { + // jdbcUrl = "jdbc:oracle:thin:@10.20.149.85:1521:ocnauto"; + // user = "alibaba"; + // password = "ccbuauto"; + // SQL = "SELECT * FROM WP_ORDERS WHERE ID = ?"; + + jdbcUrl = "jdbc:mysql://10.20.147.142:3308/dragoon_v25_masterdb"; + user = "dragoon_admin"; + password = "dragoon_root"; + + driverClass = "com.mysql.jdbc.Driver"; + } + + public void test_o() throws Exception { + Class.forName(driverClass); + + Connection conn = DriverManager.getConnection(jdbcUrl, user, password); + + com.mysql.jdbc.Connection oracleConn = (com.mysql.jdbc.Connection) conn; + + for (int i = 0; i < 10; ++i) { + ping_1000(oracleConn); + select_1000(oracleConn); + } + + conn.close(); + } + + private void ping_1000(com.mysql.jdbc.Connection oracleConn) throws SQLException { + long startMillis = System.currentTimeMillis(); + final int COUNT = 10000; + for (int i = 0; i < COUNT; ++i) { + pring(oracleConn); + } + long millis = System.currentTimeMillis() - startMillis; + System.out.println("ping : " + millis); + } + + private void select_1000(com.mysql.jdbc.Connection oracleConn) throws SQLException { + long startMillis = System.currentTimeMillis(); + final int COUNT = 10000; + for (int i = 0; i < COUNT; ++i) { + select(oracleConn); + } + long millis = System.currentTimeMillis() - startMillis; + System.out.println("select : " + millis); + } + + public void pring(com.mysql.jdbc.Connection oracleConn) throws SQLException { + oracleConn.ping(); + } + + public void select(com.mysql.jdbc.Connection oracleConn) throws SQLException { + Statement stmt = oracleConn.createStatement(); + stmt.execute("SELECT 'x'"); + stmt.close(); + } +} diff --git a/src/test/java/com/alibaba/druid/TestOraclePing.java b/src/test/java/com/alibaba/druid/TestOraclePing.java new file mode 100644 index 0000000000..8fee1d4c3a --- /dev/null +++ b/src/test/java/com/alibaba/druid/TestOraclePing.java @@ -0,0 +1,77 @@ +package com.alibaba.druid; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; +import java.sql.Statement; + +import junit.framework.TestCase; +import oracle.jdbc.OracleConnection; + +public class TestOraclePing extends TestCase { + + private String jdbcUrl; + private String user; + private String password; + private String driverClass; + private String SQL; + + protected void setUp() throws Exception { + // jdbcUrl = "jdbc:oracle:thin:@10.20.149.85:1521:ocnauto"; + // user = "alibaba"; + // password = "ccbuauto"; + // SQL = "SELECT * FROM WP_ORDERS WHERE ID = ?"; + + jdbcUrl = "jdbc:oracle:thin:@10.20.149.81:1521:ointest3"; + user = "alibaba"; + password = "deYcR7facWSJtCuDpm2r"; + SQL = "SELECT * FROM AV_INFO WHERE ID = ?"; + + driverClass = "oracle.jdbc.driver.OracleDriver"; + } + + public void test_o() throws Exception { + Class.forName(driverClass); + + Connection conn = DriverManager.getConnection(jdbcUrl, user, password); + + OracleConnection oracleConn = (OracleConnection) conn; + + for (int i = 0; i < 10; ++i) { + ping_1000(oracleConn); + select_1000(oracleConn); + } + + conn.close(); + } + + private void ping_1000(OracleConnection oracleConn) throws SQLException { + long startMillis = System.currentTimeMillis(); + final int COUNT = 1000; + for (int i = 0; i < COUNT; ++i) { + pring(oracleConn); + } + long millis = System.currentTimeMillis() - startMillis; + System.out.println("ping : " + millis); + } + + private void select_1000(OracleConnection oracleConn) throws SQLException { + long startMillis = System.currentTimeMillis(); + final int COUNT = 1000; + for (int i = 0; i < COUNT; ++i) { + select(oracleConn); + } + long millis = System.currentTimeMillis() - startMillis; + System.out.println("select : " + millis); + } + + public void pring(OracleConnection oracleConn) throws SQLException { + oracleConn.pingDatabase(1000); + } + + public void select(OracleConnection oracleConn) throws SQLException { + Statement stmt = oracleConn.createStatement(); + stmt.execute("SELECT 1 FROM DUAL"); + stmt.close(); + } +} diff --git a/src/test/java/com/alibaba/druid/bvt/bug/TestRollBack.java b/src/test/java/com/alibaba/druid/TestRollBack.java similarity index 76% rename from src/test/java/com/alibaba/druid/bvt/bug/TestRollBack.java rename to src/test/java/com/alibaba/druid/TestRollBack.java index a80e75e6ae..5d573168ec 100644 --- a/src/test/java/com/alibaba/druid/bvt/bug/TestRollBack.java +++ b/src/test/java/com/alibaba/druid/TestRollBack.java @@ -1,4 +1,4 @@ -package com.alibaba.druid.bvt.bug; +package com.alibaba.druid; import java.beans.PropertyVetoException; import java.sql.SQLException; @@ -26,9 +26,15 @@ public class TestRollBack { static Dao dao_c3p0; static Dao dao_druid; - static String url = "jdbc:oracle:thin:@10.20.149.85:1521:ocnauto"; - static String user = "alibaba"; - static String password = "ccbuauto"; +// static String url = "jdbc:oracle:thin:@10.20.149.85:1521:ocnauto"; +// static String user = "alibaba"; +// static String password = "ccbuauto"; +// static String driver = "oracle.jdbc.driver.OracleDriver"; + + static String url = "jdbc:jtds:sqlserver://10.16.16.30:1433/druid_db"; + static String user = "sa"; + static String password = "hello123"; + static String driver = "net.sourceforge.jtds.jdbc.Driver"; // jdbcUrl = "jdbc:oracle:thin:@10.20.149.85:1521:ocnauto"; // user = "alibaba"; @@ -37,7 +43,8 @@ public class TestRollBack { @BeforeClass public static void init() throws PropertyVetoException, SQLException { c3p0 = new ComboPooledDataSource(); - c3p0.setDriverClass("oracle.jdbc.driver.OracleDriver"); + //c3p0.setDriverClass("oracle.jdbc.driver.OracleDriver"); + c3p0.setDriverClass(driver); c3p0.setJdbcUrl(url); c3p0.setUser(user); c3p0.setPassword(password); @@ -52,7 +59,7 @@ public class TestRollBack { dao_c3p0 = new NutDao(c3p0); dao_druid = new NutDao(druid); if (!dao_c3p0.exists("msg")) { - dao_c3p0.execute(Sqls.create("create table msg(message varchar2(5))")); // 字段长度5 + dao_c3p0.execute(Sqls.create("create table msg(message varchar(5))")); // 字段长度5 } } @@ -80,6 +87,7 @@ public class TestRollBack { } }); } catch (Exception e) { + } // abc也跟着回滚了 Assert.assertNull(dao_c3p0.fetch("msg", Cnd.where("message", "=", "abc"))); @@ -96,7 +104,7 @@ public class TestRollBack { } }); } catch (Exception e) { - e.printStackTrace(); // 把这里的异常打印出来 + // e.printStackTrace(); // 把这里的异常打印出来 } // abc插了进去,没有回滚 Assert.assertNotNull(dao_druid.fetch("msg", Cnd.where("message", "=", "abc"))); diff --git a/src/test/java/com/alibaba/druid/TestSqlServer.java b/src/test/java/com/alibaba/druid/TestSqlServer.java new file mode 100644 index 0000000000..5fe0995d3a --- /dev/null +++ b/src/test/java/com/alibaba/druid/TestSqlServer.java @@ -0,0 +1,35 @@ +package com.alibaba.druid; + +import java.sql.Connection; +import java.sql.DriverManager; + +import junit.framework.TestCase; + + +public class TestSqlServer extends TestCase { + private String jdbcUrl; + private String user; + private String password; + private String driverClass; + private String SQL; + + protected void setUp() throws Exception { + // jdbcUrl = "jdbc:oracle:thin:@10.20.149.85:1521:ocnauto"; + // user = "alibaba"; + // password = "ccbuauto"; + // SQL = "SELECT * FROM WP_ORDERS WHERE ID = ?"; + + jdbcUrl = "jdbc:jtds:sqlserver://10.16.16.28:1433/druid_db"; + user = "sa"; + password = "hello123"; + SQL = "SELECT * FROM AV_INFO WHERE ID = ?"; + + driverClass = "net.sourceforge.jtds.jdbc.Driver"; + } + public void test_0 () throws Exception { + Class.forName(driverClass); + + Connection conn = DriverManager.getConnection(jdbcUrl, user, password); + conn.close(); + } +}