blob: 9fdd644c5a906c963f57f678448881aa096e92cb [file] [log] [blame]
/* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.tomcat.jdbc.pool.jmx;
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;
import org.apache.tomcat.jdbc.pool.PoolConfiguration;
import org.apache.tomcat.jdbc.pool.PoolProperties.InterceptorDefinition;
import org.apache.tomcat.jdbc.pool.PoolUtilities;
import org.apache.tomcat.jdbc.pool.Validator;
public class ConnectionPool extends NotificationBroadcasterSupport implements ConnectionPoolMBean {
/**
* logger
*/
private static final Log log = LogFactory.getLog(ConnectionPool.class);
/**
* the connection pool
*/
protected org.apache.tomcat.jdbc.pool.ConnectionPool pool = null;
/**
* 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<>();
public ConnectionPool(org.apache.tomcat.jdbc.pool.ConnectionPool pool) {
super();
this.pool = pool;
}
public org.apache.tomcat.jdbc.pool.ConnectionPool getPool() {
return pool;
}
public PoolConfiguration getPoolProperties() {
return pool.getPoolProperties();
}
//=================================================================
// NOTIFICATION INFO
//=================================================================
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";
public static final String SUSPECT_ABANDONED_NOTIFICATION = "SUSPECT CONNECTION ABANDONED";
public static final String POOL_EMPTY = "POOL EMPTY";
public static final String SUSPECT_RETURNED_NOTIFICATION = "SUSPECT CONNECTION RETURNED";
@Override
public MBeanNotificationInfo[] getNotificationInfo() {
MBeanNotificationInfo[] pres = super.getNotificationInfo();
MBeanNotificationInfo[] loc = getDefaultNotificationInfo();
MBeanNotificationInfo[] aug = new MBeanNotificationInfo[pres.length + loc.length];
if (pres.length>0) System.arraycopy(pres, 0, aug, 0, pres.length);
if (loc.length >0) System.arraycopy(loc, 0, aug, pres.length, loc.length);
return aug;
}
public static MBeanNotificationInfo[] getDefaultNotificationInfo() {
String[] types = new String[] {NOTIFY_INIT, NOTIFY_CONNECT, NOTIFY_ABANDON, SLOW_QUERY_NOTIFICATION,
FAILED_QUERY_NOTIFICATION, SUSPECT_ABANDONED_NOTIFICATION, POOL_EMPTY, SUSPECT_RETURNED_NOTIFICATION};
String name = Notification.class.getName();
String description = "A connection pool error condition was met.";
MBeanNotificationInfo info = new MBeanNotificationInfo(types, name, description);
return new MBeanNotificationInfo[] {info};
}
/**
* Return true if the notification was sent successfully, false otherwise.
* @param type
* @param message
* @return true if the notification succeeded
*/
public boolean notify(final String type, String message) {
try {
Notification n = new Notification(
type,
this,
sequence.incrementAndGet(),
System.currentTimeMillis(),
"["+type+"] "+message);
sendNotification(n);
for (NotificationListener listener : listeners) {
listener.handleNotification(n,this);
}
return true;
}catch (Exception x) {
if (log.isDebugEnabled()) {
log.debug("Notify failed. Type="+type+"; Message="+message,x);
}
return false;
}
}
public void addListener(NotificationListener list) {
listeners.add(list);
}
public boolean removeListener(NotificationListener list) {
return listeners.remove(list);
}
//=================================================================
// POOL STATS
//=================================================================
@Override
public int getSize() {
return pool.getSize();
}
@Override
public int getIdle() {
return pool.getIdle();
}
@Override
public int getActive() {
return pool.getActive();
}
@Override
public int getNumIdle() {
return getIdle();
}
@Override
public int getNumActive() {
return getActive();
}
@Override
public int getWaitCount() {
return pool.getWaitCount();
}
@Override
public long getBorrowedCount() {
return pool.getBorrowedCount();
}
@Override
public long getReturnedCount() {
return pool.getReturnedCount();
}
@Override
public long getCreatedCount() {
return pool.getCreatedCount();
}
@Override
public long getReleasedCount() {
return pool.getReleasedCount();
}
@Override
public long getReconnectedCount() {
return pool.getReconnectedCount();
}
@Override
public long getRemoveAbandonedCount() {
return pool.getRemoveAbandonedCount();
}
@Override
public long getReleasedIdleCount() {
return pool.getReleasedIdleCount();
}
//=================================================================
// POOL OPERATIONS
//=================================================================
@Override
public void checkIdle() {
pool.checkIdle();
}
@Override
public void checkAbandoned() {
pool.checkAbandoned();
}
@Override
public void testIdle() {
pool.testAllIdle();
}
@Override
public void resetStats() {
pool.resetStats();
}
//=================================================================
// POOL PROPERTIES
//=================================================================
//=========================================================
// PROPERTIES / CONFIGURATION
//=========================================================
@Override
public String getConnectionProperties() {
return getPoolProperties().getConnectionProperties();
}
@Override
public Properties getDbProperties() {
return PoolUtilities.cloneWithoutPassword(getPoolProperties().getDbProperties());
}
@Override
public String getDefaultCatalog() {
return getPoolProperties().getDefaultCatalog();
}
@Override
public int getDefaultTransactionIsolation() {
return getPoolProperties().getDefaultTransactionIsolation();
}
@Override
public String getDriverClassName() {
return getPoolProperties().getDriverClassName();
}
@Override
public int getInitialSize() {
return getPoolProperties().getInitialSize();
}
@Override
public String getInitSQL() {
return getPoolProperties().getInitSQL();
}
@Override
public String getJdbcInterceptors() {
return getPoolProperties().getJdbcInterceptors();
}
@Override
public int getMaxActive() {
return getPoolProperties().getMaxActive();
}
@Override
public int getMaxIdle() {
return getPoolProperties().getMaxIdle();
}
@Override
public int getMaxWait() {
return getPoolProperties().getMaxWait();
}
@Override
public int getMinEvictableIdleTimeMillis() {
return getPoolProperties().getMinEvictableIdleTimeMillis();
}
@Override
public int getMinIdle() {
return getPoolProperties().getMinIdle();
}
@Override
public long getMaxAge() {
return getPoolProperties().getMaxAge();
}
@Override
public String getName() {
return this.getPoolName();
}
@Override
public int getNumTestsPerEvictionRun() {
return getPoolProperties().getNumTestsPerEvictionRun();
}
/**
* @return DOES NOT RETURN THE PASSWORD, IT WOULD SHOW UP IN JMX
*/
@Override
public String getPassword() {
return "Password not available as DataSource/JMX operation.";
}
@Override
public int getRemoveAbandonedTimeout() {
return getPoolProperties().getRemoveAbandonedTimeout();
}
@Override
public int getTimeBetweenEvictionRunsMillis() {
return getPoolProperties().getTimeBetweenEvictionRunsMillis();
}
@Override
public String getUrl() {
return getPoolProperties().getUrl();
}
@Override
public String getUsername() {
return getPoolProperties().getUsername();
}
@Override
public long getValidationInterval() {
return getPoolProperties().getValidationInterval();
}
@Override
public String getValidationQuery() {
return getPoolProperties().getValidationQuery();
}
@Override
public int getValidationQueryTimeout() {
return getPoolProperties().getValidationQueryTimeout();
}
/**
* {@inheritDoc}
*/
@Override
public String getValidatorClassName() {
return getPoolProperties().getValidatorClassName();
}
/**
* {@inheritDoc}
*/
@Override
public Validator getValidator() {
return getPoolProperties().getValidator();
}
@Override
public boolean isAccessToUnderlyingConnectionAllowed() {
return getPoolProperties().isAccessToUnderlyingConnectionAllowed();
}
@Override
public Boolean isDefaultAutoCommit() {
return getPoolProperties().isDefaultAutoCommit();
}
@Override
public Boolean isDefaultReadOnly() {
return getPoolProperties().isDefaultReadOnly();
}
@Override
public boolean isLogAbandoned() {
return getPoolProperties().isLogAbandoned();
}
@Override
public boolean isPoolSweeperEnabled() {
return getPoolProperties().isPoolSweeperEnabled();
}
@Override
public boolean isRemoveAbandoned() {
return getPoolProperties().isRemoveAbandoned();
}
@Override
public int getAbandonWhenPercentageFull() {
return getPoolProperties().getAbandonWhenPercentageFull();
}
@Override
public boolean isTestOnBorrow() {
return getPoolProperties().isTestOnBorrow();
}
@Override
public boolean isTestOnConnect() {
return getPoolProperties().isTestOnConnect();
}
@Override
public boolean isTestOnReturn() {
return getPoolProperties().isTestOnReturn();
}
@Override
public boolean isTestWhileIdle() {
return getPoolProperties().isTestWhileIdle();
}
@Override
public Boolean getDefaultAutoCommit() {
return getPoolProperties().getDefaultAutoCommit();
}
@Override
public Boolean getDefaultReadOnly() {
return getPoolProperties().getDefaultReadOnly();
}
@Override
public InterceptorDefinition[] getJdbcInterceptorsAsArray() {
return getPoolProperties().getJdbcInterceptorsAsArray();
}
@Override
public boolean getUseLock() {
return getPoolProperties().getUseLock();
}
@Override
public boolean isFairQueue() {
return getPoolProperties().isFairQueue();
}
@Override
public boolean isJmxEnabled() {
return getPoolProperties().isJmxEnabled();
}
@Override
public boolean isUseEquals() {
return getPoolProperties().isUseEquals();
}
@Override
public void setAbandonWhenPercentageFull(int percentage) {
getPoolProperties().setAbandonWhenPercentageFull(percentage);
}
@Override
public void setAccessToUnderlyingConnectionAllowed(boolean accessToUnderlyingConnectionAllowed) {
getPoolProperties().setAccessToUnderlyingConnectionAllowed(accessToUnderlyingConnectionAllowed);
}
@Override
public void setDbProperties(Properties dbProperties) {
getPoolProperties().setDbProperties(dbProperties);
}
@Override
public void setDefaultReadOnly(Boolean defaultReadOnly) {
getPoolProperties().setDefaultReadOnly(defaultReadOnly);
}
@Override
public void setMaxAge(long maxAge) {
getPoolProperties().setMaxAge(maxAge);
}
@Override
public void setName(String name) {
getPoolProperties().setName(name);
}
@Override
public String getPoolName() {
return getPoolProperties().getName();
}
@Override
public void setConnectionProperties(String connectionProperties) {
getPoolProperties().setConnectionProperties(connectionProperties);
}
@Override
public void setDefaultAutoCommit(Boolean defaultAutoCommit) {
getPoolProperties().setDefaultAutoCommit(defaultAutoCommit);
}
@Override
public void setDefaultCatalog(String defaultCatalog) {
getPoolProperties().setDefaultCatalog(defaultCatalog);
}
@Override
public void setDefaultTransactionIsolation(int defaultTransactionIsolation) {
getPoolProperties().setDefaultTransactionIsolation(defaultTransactionIsolation);
}
@Override
public void setDriverClassName(String driverClassName) {
getPoolProperties().setDriverClassName(driverClassName);
}
@Override
public void setFairQueue(boolean fairQueue) {
// noop - this pool is already running
throw new UnsupportedOperationException();
}
@Override
public void setInitialSize(int initialSize) {
// noop - this pool is already running
throw new UnsupportedOperationException();
}
@Override
public void setInitSQL(String initSQL) {
getPoolProperties().setInitSQL(initSQL);
}
@Override
public void setJdbcInterceptors(String jdbcInterceptors) {
// noop - this pool is already running
throw new UnsupportedOperationException();
}
@Override
public void setJmxEnabled(boolean jmxEnabled) {
// noop - this pool is already running and obviously jmx enabled
throw new UnsupportedOperationException();
}
@Override
public void setLogAbandoned(boolean logAbandoned) {
getPoolProperties().setLogAbandoned(logAbandoned);
}
@Override
public void setMaxActive(int maxActive) {
getPoolProperties().setMaxActive(maxActive);
//make sure the pool is properly configured
pool.checkPoolConfiguration(getPoolProperties());
}
@Override
public void setMaxIdle(int maxIdle) {
getPoolProperties().setMaxIdle(maxIdle);
//make sure the pool is properly configured
pool.checkPoolConfiguration(getPoolProperties());
}
@Override
public void setMaxWait(int maxWait) {
getPoolProperties().setMaxWait(maxWait);
}
@Override
public void setMinEvictableIdleTimeMillis(int minEvictableIdleTimeMillis) {
boolean wasEnabled = getPoolProperties().isPoolSweeperEnabled();
getPoolProperties().setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
boolean shouldBeEnabled = getPoolProperties().isPoolSweeperEnabled();
//make sure pool cleaner starts/stops when it should
if (!wasEnabled && shouldBeEnabled) pool.initializePoolCleaner(getPoolProperties());
else if (wasEnabled && !shouldBeEnabled) pool.terminatePoolCleaner();
}
@Override
public void setMinIdle(int minIdle) {
getPoolProperties().setMinIdle(minIdle);
//make sure the pool is properly configured
pool.checkPoolConfiguration(getPoolProperties());
}
@Override
public void setNumTestsPerEvictionRun(int numTestsPerEvictionRun) {
getPoolProperties().setNumTestsPerEvictionRun(numTestsPerEvictionRun);
}
@Override
public void setPassword(String password) {
getPoolProperties().setPassword(password);
}
@Override
public void setRemoveAbandoned(boolean removeAbandoned) {
boolean wasEnabled = getPoolProperties().isPoolSweeperEnabled();
getPoolProperties().setRemoveAbandoned(removeAbandoned);
boolean shouldBeEnabled = getPoolProperties().isPoolSweeperEnabled();
//make sure pool cleaner starts/stops when it should
if (!wasEnabled && shouldBeEnabled) pool.initializePoolCleaner(getPoolProperties());
else if (wasEnabled && !shouldBeEnabled) pool.terminatePoolCleaner();
}
@Override
public void setRemoveAbandonedTimeout(int removeAbandonedTimeout) {
boolean wasEnabled = getPoolProperties().isPoolSweeperEnabled();
getPoolProperties().setRemoveAbandonedTimeout(removeAbandonedTimeout);
boolean shouldBeEnabled = getPoolProperties().isPoolSweeperEnabled();
//make sure pool cleaner starts/stops when it should
if (!wasEnabled && shouldBeEnabled) pool.initializePoolCleaner(getPoolProperties());
else if (wasEnabled && !shouldBeEnabled) pool.terminatePoolCleaner();
}
@Override
public void setTestOnBorrow(boolean testOnBorrow) {
getPoolProperties().setTestOnBorrow(testOnBorrow);
}
@Override
public void setTestOnConnect(boolean testOnConnect) {
getPoolProperties().setTestOnConnect(testOnConnect);
}
@Override
public void setTestOnReturn(boolean testOnReturn) {
getPoolProperties().setTestOnReturn(testOnReturn);
}
@Override
public void setTestWhileIdle(boolean testWhileIdle) {
boolean wasEnabled = getPoolProperties().isPoolSweeperEnabled();
getPoolProperties().setTestWhileIdle(testWhileIdle);
boolean shouldBeEnabled = getPoolProperties().isPoolSweeperEnabled();
//make sure pool cleaner starts/stops when it should
if (!wasEnabled && shouldBeEnabled) pool.initializePoolCleaner(getPoolProperties());
else if (wasEnabled && !shouldBeEnabled) pool.terminatePoolCleaner();
}
@Override
public void setTimeBetweenEvictionRunsMillis(int timeBetweenEvictionRunsMillis) {
boolean wasEnabled = getPoolProperties().isPoolSweeperEnabled();
getPoolProperties().setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
boolean shouldBeEnabled = getPoolProperties().isPoolSweeperEnabled();
//make sure pool cleaner starts/stops when it should
if (!wasEnabled && shouldBeEnabled) {
pool.initializePoolCleaner(getPoolProperties());
} else if (wasEnabled) {
pool.terminatePoolCleaner();
if (shouldBeEnabled) {
pool.initializePoolCleaner(getPoolProperties());
}
}
}
@Override
public void setUrl(String url) {
getPoolProperties().setUrl(url);
}
@Override
public void setUseEquals(boolean useEquals) {
getPoolProperties().setUseEquals(useEquals);
}
@Override
public void setUseLock(boolean useLock) {
getPoolProperties().setUseLock(useLock);
}
@Override
public void setUsername(String username) {
getPoolProperties().setUsername(username);
}
@Override
public void setValidationInterval(long validationInterval) {
getPoolProperties().setValidationInterval(validationInterval);
}
@Override
public void setValidationQuery(String validationQuery) {
getPoolProperties().setValidationQuery(validationQuery);
}
@Override
public void setValidationQueryTimeout(int validationQueryTimeout) {
getPoolProperties().setValidationQueryTimeout(validationQueryTimeout);
}
/**
* {@inheritDoc}
*/
@Override
public void setValidatorClassName(String className) {
getPoolProperties().setValidatorClassName(className);
}
/**
* {@inheritDoc}
*/
@Override
public int getSuspectTimeout() {
return getPoolProperties().getSuspectTimeout();
}
/**
* {@inheritDoc}
*/
@Override
public void setSuspectTimeout(int seconds) {
getPoolProperties().setSuspectTimeout(seconds);
}
/**
* {@inheritDoc}
*/
@Override
public void setDataSource(Object ds) {
getPoolProperties().setDataSource(ds);
}
/**
* {@inheritDoc}
*/
@Override
public Object getDataSource() {
return getPoolProperties().getDataSource();
}
/**
* {@inheritDoc}
*/
@Override
public void setDataSourceJNDI(String jndiDS) {
getPoolProperties().setDataSourceJNDI(jndiDS);
}
/**
* {@inheritDoc}
*/
@Override
public String getDataSourceJNDI() {
return getPoolProperties().getDataSourceJNDI();
}
/**
* {@inheritDoc}
*/
@Override
public boolean isAlternateUsernameAllowed() {
return getPoolProperties().isAlternateUsernameAllowed();
}
/**
* {@inheritDoc}
*/
@Override
public void setAlternateUsernameAllowed(boolean alternateUsernameAllowed) {
getPoolProperties().setAlternateUsernameAllowed(alternateUsernameAllowed);
}
/**
* {@inheritDoc}
*/
@Override
public void setValidator(Validator validator) {
getPoolProperties().setValidator(validator);
}
/**
* {@inheritDoc}
*/
@Override
public void setCommitOnReturn(boolean commitOnReturn) {
getPoolProperties().setCommitOnReturn(commitOnReturn);
}
/**
* {@inheritDoc}
*/
@Override
public boolean getCommitOnReturn() {
return getPoolProperties().getCommitOnReturn();
}
/**
* {@inheritDoc}
*/
@Override
public void setRollbackOnReturn(boolean rollbackOnReturn) {
getPoolProperties().setRollbackOnReturn(rollbackOnReturn);
}
/**
* {@inheritDoc}
*/
@Override
public boolean getRollbackOnReturn() {
return getPoolProperties().getRollbackOnReturn();
}
/**
* {@inheritDoc}
*/
@Override
public void setUseDisposableConnectionFacade(boolean useDisposableConnectionFacade) {
getPoolProperties().setUseDisposableConnectionFacade(useDisposableConnectionFacade);
}
/**
* {@inheritDoc}
*/
@Override
public boolean getUseDisposableConnectionFacade() {
return getPoolProperties().getUseDisposableConnectionFacade();
}
/**
* {@inheritDoc}
*/
@Override
public void setLogValidationErrors(boolean logValidationErrors) {
getPoolProperties().setLogValidationErrors(logValidationErrors);
}
/**
* {@inheritDoc}
*/
@Override
public boolean getLogValidationErrors() {
return getPoolProperties().getLogValidationErrors();
}
/**
* {@inheritDoc}
*/
@Override
public boolean getPropagateInterruptState() {
return getPoolProperties().getPropagateInterruptState();
}
/**
* {@inheritDoc}
*/
@Override
public void setPropagateInterruptState(boolean propagateInterruptState) {
getPoolProperties().setPropagateInterruptState(propagateInterruptState);
}
/**
* {@inheritDoc}
*/
@Override
public boolean isIgnoreExceptionOnPreLoad() {
return getPoolProperties().isIgnoreExceptionOnPreLoad();
}
/**
* {@inheritDoc}
*/
@Override
public void setIgnoreExceptionOnPreLoad(boolean ignoreExceptionOnPreLoad) {
// noop - this pool is already running
throw new UnsupportedOperationException();
}
/**
* {@inheritDoc}
*/
@Override
public boolean getUseStatementFacade() {
return getPoolProperties().getUseStatementFacade();
}
/**
* {@inheritDoc}
*/
@Override
public void setUseStatementFacade(boolean useStatementFacade) {
getPoolProperties().setUseStatementFacade(useStatementFacade);
}
/**
* {@inheritDoc}
*/
@Override
public void purge() {
pool.purge();
}
/**
* {@inheritDoc}
*/
@Override
public void purgeOnReturn() {
pool.purgeOnReturn();
}
}