Author: fhanik Date: Wed Apr 15 04:58:06 2009 New Revision: 765051 URL: http://svn.apache.org/viewvc?rev=765051&view=rev Log: JMX needs to be handled a bit differently. Random object names are not all that great. In this way, one can control the JMX registration completely from the outside.
Modified: tomcat/trunk/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/ConnectionPool.java tomcat/trunk/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/DataSource.java tomcat/trunk/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/DataSourceProxy.java tomcat/trunk/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/interceptor/SlowQueryReportJmx.java tomcat/trunk/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/jmx/ConnectionPool.java tomcat/trunk/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/jmx/ConnectionPoolMBean.java tomcat/trunk/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/mbeans-descriptors.xml Modified: tomcat/trunk/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/ConnectionPool.java URL: http://svn.apache.org/viewvc/tomcat/trunk/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/ConnectionPool.java?rev=765051&r1=765050&r2=765051&view=diff ============================================================================== --- tomcat/trunk/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/ConnectionPool.java (original) +++ tomcat/trunk/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/ConnectionPool.java Wed Apr 15 04:58:06 2009 @@ -779,17 +779,18 @@ protected void finalize(PooledConnection con) { } + + public org.apache.tomcat.jdbc.pool.jmx.ConnectionPool getJmxPool() { + return jmxPool; + } protected void startJmx() { try { - MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); - ObjectName name = new ObjectName(POOL_JMX_TYPE_PREFIX+"ConnectionPool,name="+getName()); if ("1.5".equals(System.getProperty("java.specification.version"))) { jmxPool = new org.apache.tomcat.jdbc.pool.jmx.ConnectionPool(this); } else { jmxPool = new org.apache.tomcat.jdbc.pool.jmx.ConnectionPool(this,true); } - mbs.registerMBean(jmxPool, name); } catch (Exception x) { log.warn("Unable to start JMX integration for connection pool. Instance["+getName()+"] can't be monitored.",x); } @@ -797,10 +798,6 @@ protected void stopJmx() { try { - MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); - ObjectName name = new ObjectName(POOL_JMX_TYPE_PREFIX+"ConnectionPool,name="+getName()); - if (mbs.isRegistered(name)) - mbs.unregisterMBean(name); jmxPool = null; }catch (Exception x) { log.warn("Unable to stop JMX integration for connection pool. Instance["+getName()+"].",x); Modified: tomcat/trunk/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/DataSource.java URL: http://svn.apache.org/viewvc/tomcat/trunk/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/DataSource.java?rev=765051&r1=765050&r2=765051&view=diff ============================================================================== --- tomcat/trunk/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/DataSource.java (original) +++ tomcat/trunk/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/DataSource.java Wed Apr 15 04:58:06 2009 @@ -16,9 +16,19 @@ */ package org.apache.tomcat.jdbc.pool; +import java.lang.management.ManagementFactory; import java.sql.SQLException; +import java.util.Hashtable; import java.util.Properties; +import javax.management.InstanceNotFoundException; +import javax.management.MBeanRegistration; +import javax.management.MBeanServer; +import javax.management.MalformedObjectNameException; +import javax.management.ObjectName; + +import org.apache.tomcat.jdbc.pool.jmx.ConnectionPoolMBean; + /** * A DataSource that can be instantiated through IoC and implements the DataSource interface @@ -26,7 +36,7 @@ * @author Filip Hanik * @version 1.0 */ -public class DataSource extends DataSourceProxy implements javax.sql.DataSource, org.apache.tomcat.jdbc.pool.jmx.ConnectionPoolMBean { +public class DataSource extends DataSourceProxy implements MBeanRegistration,javax.sql.DataSource, org.apache.tomcat.jdbc.pool.jmx.ConnectionPoolMBean { public DataSource() { super(); @@ -37,6 +47,63 @@ } //=============================================================================== +// Register the actual pool itself under the tomcat.jdbc domain +//=============================================================================== + protected volatile ObjectName oname = null; + public void postDeregister() { + if (oname!=null) unregisterJmx(); + } + + public void postRegister(Boolean registrationDone) { + } + + + public void preDeregister() throws Exception { + } + + public ObjectName preRegister(MBeanServer server, ObjectName name) throws Exception { + try { + this.oname = createObjectName(name); + if (oname!=null) registerJmx(); + }catch (MalformedObjectNameException x) { + log.error("Unable to create object name for JDBC pool.",x); + } + return name; + } + + public ObjectName createObjectName(ObjectName original) throws MalformedObjectNameException { + String domain = "tomcat.jdbc"; + Hashtable<String,String> properties = original.getKeyPropertyList(); + String origDomain = original.getDomain(); + properties.put("type", "ConnectionPool"); + properties.put("class", this.getClass().getName()); + if (original.getKeyProperty("path")!=null) { + properties.put("engine", origDomain); + } + ObjectName name = new ObjectName(domain,properties); + return name; + } + + protected void registerJmx() { + try { + MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); + mbs.registerMBean(pool.getJmxPool(), oname); + } catch (Exception e) { + log.error("Unable to register JDBC pool with JMX",e); + } + } + + protected void unregisterJmx() { + try { + MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); + mbs.unregisterMBean(oname); + } catch (InstanceNotFoundException ignore) { + } catch (Exception e) { + log.error("Unable to unregister JDBC pool with JMX",e); + } + } + +//=============================================================================== // Expose JMX attributes through Tomcat's dynamic reflection //=============================================================================== public void checkAbandoned() { @@ -62,6 +129,10 @@ throw new RuntimeException(x); } } + + public int getNumActive() { + return getActive(); + } public String getConnectionProperties() { try { @@ -110,6 +181,10 @@ throw new RuntimeException(x); } } + + public int getNumIdle() { + return getIdle(); + } public int getInitialSize() { try { Modified: tomcat/trunk/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/DataSourceProxy.java URL: http://svn.apache.org/viewvc/tomcat/trunk/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/DataSourceProxy.java?rev=765051&r1=765050&r2=765051&view=diff ============================================================================== --- tomcat/trunk/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/DataSourceProxy.java (original) +++ tomcat/trunk/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/DataSourceProxy.java Wed Apr 15 04:58:06 2009 @@ -176,7 +176,9 @@ if (pool != null) { final ConnectionPool p = pool; pool = null; - if (p!=null) p.close(all); + if (p!=null) { + p.close(all); + } } }catch (Exception x) { log.warn("Error duing connection pool closure.", x); @@ -197,7 +199,7 @@ public String toString() { return super.toString()+"{"+getPoolProperties()+"}"; } - + /*-----------------------------------------------------------------------*/ // PROPERTIES WHEN NOT USED WITH FACTORY /*------------------------------------------------------------------------*/ Modified: tomcat/trunk/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/interceptor/SlowQueryReportJmx.java URL: http://svn.apache.org/viewvc/tomcat/trunk/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/interceptor/SlowQueryReportJmx.java?rev=765051&r1=765050&r2=765051&view=diff ============================================================================== --- tomcat/trunk/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/interceptor/SlowQueryReportJmx.java (original) +++ tomcat/trunk/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/interceptor/SlowQueryReportJmx.java Wed Apr 15 04:58:06 2009 @@ -50,8 +50,8 @@ * */ public class SlowQueryReportJmx extends SlowQueryReport { - public static final String SLOW_QUERY_NOTIFICATION = "Slow query"; - public static final String FAILED_QUERY_NOTIFICATION = "Failed query"; + public static final String SLOW_QUERY_NOTIFICATION = "SLOW QUERY"; + public static final String FAILED_QUERY_NOTIFICATION = "FAILED QUERY"; protected static CompositeType SLOW_QUERY_TYPE; @@ -65,6 +65,10 @@ protected static AtomicLong notifySequence = new AtomicLong(0); + protected boolean notifyPool = true; + + protected ConnectionPool pool = null; + protected static CompositeType getCompositeType() { if (SLOW_QUERY_TYPE==null) { try { @@ -85,7 +89,10 @@ public void reset(ConnectionPool parent, PooledConnection con) { // TODO Auto-generated method stub super.reset(parent, con); - if (parent!=null) poolName = parent.getName(); + if (parent!=null) { + poolName = parent.getName(); + pool = parent; + } } @@ -99,6 +106,7 @@ @Override public void poolStarted(ConnectionPool pool) { + this.pool = pool; super.poolStarted(pool); this.poolName = pool.getName(); registerJmx(); @@ -114,16 +122,23 @@ protected void notifyJmx(String query, String type) { try { DynamicMBean mbean = mbeans.get(poolName); - if (mbean!=null && mbean instanceof BaseModelMBean) { - BaseModelMBean bmbean = (BaseModelMBean)mbean; - long sequence = notifySequence.incrementAndGet(); - Notification notification = - new Notification(type, - mbean, - sequence, - System.currentTimeMillis(), - query); - bmbean.sendNotification(notification); + long sequence = notifySequence.incrementAndGet(); + + if (isNotifyPool()) { + if (this.pool!=null && this.pool.getJmxPool()!=null) { + this.pool.getJmxPool().notify(type, query); + } + } else { + if (mbean!=null && mbean instanceof BaseModelMBean) { + Notification notification = + new Notification(type, + mbean, + sequence, + System.currentTimeMillis(), + query); + BaseModelMBean bmbean = (BaseModelMBean)mbean; + bmbean.sendNotification(notification); + } } } catch (RuntimeOperationsException e) { if (log.isDebugEnabled()) { @@ -160,6 +175,16 @@ return poolName; } + + + public boolean isNotifyPool() { + return notifyPool; + } + + public void setNotifyPool(boolean notifyPool) { + this.notifyPool = notifyPool; + } + /** * JMX operation - remove all stats for this connection pool */ @@ -205,7 +230,6 @@ registry.unregisterComponent(oname); registry.removeManagedBean(managed); } - } } catch (MalformedObjectNameException e) { log.warn("Jmx deregistration failed.",e); @@ -217,7 +241,10 @@ protected void registerJmx() { try { - if (getCompositeType()!=null) { + //only if we notify the pool itself + if (isNotifyPool()) { + + } else if (getCompositeType()!=null) { ObjectName oname = new ObjectName(ConnectionPool.POOL_JMX_TYPE_PREFIX+"SlowQueryReport"+",name=" + poolName); Registry registry = Registry.getRegistry(null, null); registry.loadDescriptors(getClass().getPackage().getName(),getClass().getClassLoader()); Modified: tomcat/trunk/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/jmx/ConnectionPool.java URL: http://svn.apache.org/viewvc/tomcat/trunk/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/jmx/ConnectionPool.java?rev=765051&r1=765050&r2=765051&view=diff ============================================================================== --- tomcat/trunk/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/jmx/ConnectionPool.java (original) +++ tomcat/trunk/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/jmx/ConnectionPool.java Wed Apr 15 04:58:06 2009 @@ -17,12 +17,15 @@ /** * @author Filip Hanik */ +import java.util.Iterator; import java.util.Properties; +import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.atomic.AtomicInteger; import javax.management.MBeanNotificationInfo; import javax.management.Notification; import javax.management.NotificationBroadcasterSupport; +import javax.management.NotificationListener; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; @@ -41,6 +44,11 @@ * sequence for JMX notifications */ protected AtomicInteger sequence = new AtomicInteger(0); + + /** + * Listeners that are local and interested in our notifications, no need for JMX + */ + protected ConcurrentLinkedQueue<NotificationListener> listeners = new ConcurrentLinkedQueue<NotificationListener>(); public ConnectionPool(org.apache.tomcat.jdbc.pool.ConnectionPool pool) { super(); @@ -62,6 +70,8 @@ public static final String NOTIFY_INIT = "INIT FAILED"; public static final String NOTIFY_CONNECT = "CONNECTION FAILED"; public static final String NOTIFY_ABANDON = "CONNECTION ABANDONED"; + public static final String SLOW_QUERY_NOTIFICATION = "SLOW QUERY"; + public static final String FAILED_QUERY_NOTIFICATION = "FAILED QUERY"; @@ -76,7 +86,7 @@ } public static MBeanNotificationInfo[] getDefaultNotificationInfo() { - String[] types = new String[] {NOTIFY_INIT, NOTIFY_CONNECT, NOTIFY_ABANDON}; + String[] types = new String[] {NOTIFY_INIT, NOTIFY_CONNECT, NOTIFY_ABANDON, SLOW_QUERY_NOTIFICATION, FAILED_QUERY_NOTIFICATION}; String name = Notification.class.getName(); String description = "A connection pool error condition was met."; MBeanNotificationInfo info = new MBeanNotificationInfo(types, name, description); @@ -96,8 +106,11 @@ this, sequence.incrementAndGet(), System.currentTimeMillis(), - message!=null?message:""); + "["+type+"] "+message); sendNotification(n); + for (NotificationListener listener : listeners) { + listener.handleNotification(n,this); + } return true; }catch (Exception x) { if (log.isDebugEnabled()) { @@ -108,6 +121,14 @@ } + public void addListener(NotificationListener list) { + listeners.add(list); + } + + public boolean removeListener(NotificationListener list) { + return listeners.remove(list); + } + //================================================================= // POOL STATS //================================================================= @@ -127,6 +148,14 @@ public boolean isPoolSweeperEnabled() { return pool.getPoolProperties().isPoolSweeperEnabled(); } + + public int getNumIdle() { + return getIdle(); + } + + public int getNumActive() { + return getNumActive(); + } //================================================================= // POOL OPERATIONS Modified: tomcat/trunk/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/jmx/ConnectionPoolMBean.java URL: http://svn.apache.org/viewvc/tomcat/trunk/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/jmx/ConnectionPoolMBean.java?rev=765051&r1=765050&r2=765051&view=diff ============================================================================== --- tomcat/trunk/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/jmx/ConnectionPoolMBean.java (original) +++ tomcat/trunk/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/jmx/ConnectionPoolMBean.java Wed Apr 15 04:58:06 2009 @@ -30,7 +30,11 @@ public int getActive(); public boolean isPoolSweeperEnabled(); - + + public int getNumIdle(); + + public int getNumActive(); + //================================================================= // POOL OPERATIONS //================================================================= Modified: tomcat/trunk/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/mbeans-descriptors.xml URL: http://svn.apache.org/viewvc/tomcat/trunk/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/mbeans-descriptors.xml?rev=765051&r1=765050&r2=765051&view=diff ============================================================================== --- tomcat/trunk/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/mbeans-descriptors.xml (original) +++ tomcat/trunk/modules/jdbc-pool/java/org/apache/tomcat/jdbc/pool/mbeans-descriptors.xml Wed Apr 15 04:58:06 2009 @@ -15,7 +15,7 @@ --> <mbeans-descriptors> - <mbean name="DiagnosticsPool" + <mbean name="TomcatJDBCPool" description="Provides per diagnostic metrics and notifications for JDBC operations" domain="tomcat" group="jdbc" @@ -36,11 +36,21 @@ type="java.lang.Integer" writeable="false"/> + <attribute name="numIdle" + description="Same as the idle attribute" + type="java.lang.Integer" + writeable="false"/> + <attribute name="active" description="The number of established connections in the pool that are in use" type="java.lang.Integer" writeable="false"/> + <attribute name="numActive" + description="Same as the active attribute" + type="java.lang.Integer" + writeable="false"/> + <attribute name="poolSweeperEnabled" description="Returns true if the pool has a background thread running" type="java.lang.Boolean" @@ -216,15 +226,6 @@ description="forces a validation of abandoned connections" impact="ACTION" returnType="void" /> - - - <notification name="jdbc-diagnostic" - description="Notification issued when the request diagnostic actions kick in" > - <notification-type>INIT FAILED</notification-type> - <notification-type>CONNECTION FAILED</notification-type> - <notification-type>CONNECTION ABANDONED</notification-type> - </notification> - </mbean> </mbeans-descriptors> --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org