2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2016 - 2017 AT&T
6 * ================================================================================
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 * ============LICENSE_END=========================================================
22 * Licensed to the Apache Software Foundation (ASF) under one or more
23 * contributor license agreements. See the NOTICE file distributed with
24 * this work for additional information regarding copyright ownership.
25 * The ASF licenses this file to You under the Apache License, Version 2.0
26 * (the "License"); you may not use this file except in compliance with
27 * the License. You may obtain a copy of the License at
29 * http://www.apache.org/licenses/LICENSE-2.0
31 * Unless required by applicable law or agreed to in writing, software
32 * distributed under the License is distributed on an "AS IS" BASIS,
33 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
34 * See the License for the specific language governing permissions and
35 * limitations under the License.
37 package org.apache.tomcat.jdbc.pool;
39 import java.io.ByteArrayInputStream;
40 import java.io.IOException;
41 import java.io.Serializable;
42 import java.lang.reflect.Method;
43 import java.util.HashMap;
44 import java.util.Locale;
46 import java.util.Properties;
47 import java.util.concurrent.atomic.AtomicInteger;
50 import org.apache.juli.logging.Log;
51 import org.apache.juli.logging.LogFactory;
53 public class PoolProperties implements PoolConfiguration, Cloneable, Serializable {
55 private static final long serialVersionUID = -8519283440854213745L;
56 private static final Log log = LogFactory.getLog(PoolProperties.class);
58 public static final int DEFAULT_MAX_ACTIVE = 100;
60 protected static final AtomicInteger poolCounter = new AtomicInteger(0);
61 private volatile Properties dbProperties = new Properties();
62 private volatile String url = null;
63 private volatile String driverClassName = null;
64 private volatile Boolean defaultAutoCommit = null;
65 private volatile Boolean defaultReadOnly = null;
66 private volatile int defaultTransactionIsolation = DataSourceFactory.UNKNOWN_TRANSACTIONISOLATION;
67 private volatile String defaultCatalog = null;
68 private volatile String connectionProperties;
69 private volatile int initialSize = 10;
70 private volatile int maxActive = DEFAULT_MAX_ACTIVE;
71 private volatile int maxIdle = maxActive;
72 private volatile int minIdle = initialSize;
73 private volatile int maxWait = 30000;
74 private volatile String validationQuery;
75 private volatile int validationQueryTimeout = -1;
76 private volatile String validatorClassName;
77 private volatile Validator validator;
78 private volatile boolean testOnBorrow = false;
79 private volatile boolean testOnReturn = false;
80 private volatile boolean testWhileIdle = false;
81 private volatile int timeBetweenEvictionRunsMillis = 5000;
82 private volatile int numTestsPerEvictionRun;
83 private volatile int minEvictableIdleTimeMillis = 60000;
84 private volatile boolean accessToUnderlyingConnectionAllowed = true;
85 private volatile boolean removeAbandoned = false;
86 private volatile int removeAbandonedTimeout = 60;
87 private volatile boolean logAbandoned = false;
88 private volatile String name = "Tomcat Connection Pool["+(poolCounter.addAndGet(1))+"-"+System.identityHashCode(PoolProperties.class)+"]";
89 private volatile String password;
90 private volatile String username;
91 private volatile long validationInterval = 3000;
92 private volatile boolean jmxEnabled = true;
93 private volatile String initSQL;
94 private volatile boolean testOnConnect =false;
95 private volatile String jdbcInterceptors=null;
96 private volatile boolean fairQueue = true;
97 private volatile boolean useEquals = true;
98 private volatile int abandonWhenPercentageFull = 0;
99 private volatile long maxAge = 0;
100 private volatile boolean useLock = false;
101 private volatile InterceptorDefinition[] interceptors = null;
102 private volatile int suspectTimeout = 0;
103 private volatile Object dataSource = null;
104 private volatile String dataSourceJNDI = null;
105 private volatile boolean alternateUsernameAllowed = false;
106 private volatile boolean commitOnReturn = false;
107 private volatile boolean rollbackOnReturn = false;
108 private volatile boolean useDisposableConnectionFacade = true;
109 private volatile boolean logValidationErrors = false;
110 private volatile boolean propagateInterruptState = false;
111 private volatile boolean ignoreExceptionOnPreLoad = false;
117 public void setAbandonWhenPercentageFull(int percentage) {
118 if (percentage<0) abandonWhenPercentageFull = 0;
119 else if (percentage>100) abandonWhenPercentageFull = 100;
120 else abandonWhenPercentageFull = percentage;
127 public int getAbandonWhenPercentageFull() {
128 return abandonWhenPercentageFull;
135 public boolean isFairQueue() {
143 public void setFairQueue(boolean fairQueue) {
144 this.fairQueue = fairQueue;
151 public boolean isAccessToUnderlyingConnectionAllowed() {
152 return accessToUnderlyingConnectionAllowed;
160 public String getConnectionProperties() {
161 return connectionProperties;
169 public Properties getDbProperties() {
178 public Boolean isDefaultAutoCommit() {
179 return defaultAutoCommit;
187 public String getDefaultCatalog() {
188 return defaultCatalog;
196 public Boolean isDefaultReadOnly() {
197 return defaultReadOnly;
205 public int getDefaultTransactionIsolation() {
206 return defaultTransactionIsolation;
214 public String getDriverClassName() {
215 return driverClassName;
223 public int getInitialSize() {
232 public boolean isLogAbandoned() {
241 public int getMaxActive() {
250 public int getMaxIdle() {
259 public int getMaxWait() {
268 public int getMinEvictableIdleTimeMillis() {
269 return minEvictableIdleTimeMillis;
277 public int getMinIdle() {
286 public String getName() {
295 public int getNumTestsPerEvictionRun() {
296 return numTestsPerEvictionRun;
304 public String getPassword() {
313 public String getPoolName() {
322 public boolean isRemoveAbandoned() {
323 return removeAbandoned;
331 public int getRemoveAbandonedTimeout() {
332 return removeAbandonedTimeout;
340 public boolean isTestOnBorrow() {
349 public boolean isTestOnReturn() {
358 public boolean isTestWhileIdle() {
359 return testWhileIdle;
367 public int getTimeBetweenEvictionRunsMillis() {
368 return timeBetweenEvictionRunsMillis;
376 public String getUrl() {
385 public String getUsername() {
394 public String getValidationQuery() {
395 return validationQuery;
402 public int getValidationQueryTimeout() {
403 return validationQueryTimeout;
410 public void setValidationQueryTimeout(int validationQueryTimeout) {
411 this.validationQueryTimeout = validationQueryTimeout;
419 public String getValidatorClassName() {
420 return validatorClassName;
428 public Validator getValidator() {
436 public void setValidator(Validator validator) {
437 this.validator = validator;
438 if (validator!=null) {
439 this.validatorClassName = validator.getClass().getName();
441 this.validatorClassName = null;
451 public long getValidationInterval() {
452 return validationInterval;
460 public String getInitSQL() {
469 public boolean isTestOnConnect() {
470 return testOnConnect;
478 public String getJdbcInterceptors() {
479 return jdbcInterceptors;
487 public InterceptorDefinition[] getJdbcInterceptorsAsArray() {
488 if (interceptors == null) {
489 if (jdbcInterceptors==null) {
490 interceptors = new InterceptorDefinition[0];
492 String[] interceptorValues = jdbcInterceptors.split(";");
493 InterceptorDefinition[] definitions = new InterceptorDefinition[interceptorValues.length+1];
494 //always add the trap interceptor to the mix
495 definitions[0] = new InterceptorDefinition(TrapException.class);
496 for (int i=0; i<interceptorValues.length; i++) {
497 int propIndex = interceptorValues[i].indexOf('(');
498 int endIndex = interceptorValues[i].indexOf(')');
499 if (propIndex<0 || endIndex<0 || endIndex <= propIndex) {
500 definitions[i+1] = new InterceptorDefinition(interceptorValues[i].trim());
502 String name = interceptorValues[i].substring(0,propIndex).trim();
503 definitions[i+1] = new InterceptorDefinition(name);
504 String propsAsString = interceptorValues[i].substring(propIndex+1, endIndex);
505 String[] props = propsAsString.split(",");
506 for (int j=0; j<props.length; j++) {
507 int pidx = props[j].indexOf('=');
508 String propName = props[j].substring(0,pidx).trim();
509 String propValue = props[j].substring(pidx+1).trim();
510 definitions[i+1].addProperty(new InterceptorProperty(propName,propValue));
514 interceptors = definitions;
525 public void setAccessToUnderlyingConnectionAllowed(boolean accessToUnderlyingConnectionAllowed) {
534 public void setConnectionProperties(String connectionProperties) {
535 this.connectionProperties = connectionProperties;
536 getProperties(connectionProperties, getDbProperties());
544 public void setDbProperties(Properties dbProperties) {
545 this.dbProperties = dbProperties;
553 public void setDefaultAutoCommit(Boolean defaultAutoCommit) {
554 this.defaultAutoCommit = defaultAutoCommit;
562 public void setDefaultCatalog(String defaultCatalog) {
563 this.defaultCatalog = defaultCatalog;
571 public void setDefaultReadOnly(Boolean defaultReadOnly) {
572 this.defaultReadOnly = defaultReadOnly;
580 public void setDefaultTransactionIsolation(int defaultTransactionIsolation) {
581 this.defaultTransactionIsolation = defaultTransactionIsolation;
589 public void setDriverClassName(String driverClassName) {
590 this.driverClassName = driverClassName;
598 public void setInitialSize(int initialSize) {
599 this.initialSize = initialSize;
607 public void setLogAbandoned(boolean logAbandoned) {
608 this.logAbandoned = logAbandoned;
616 public void setMaxActive(int maxActive) {
617 this.maxActive = maxActive;
625 public void setMaxIdle(int maxIdle) {
626 this.maxIdle = maxIdle;
634 public void setMaxWait(int maxWait) {
635 this.maxWait = maxWait;
643 public void setMinEvictableIdleTimeMillis(int minEvictableIdleTimeMillis) {
644 this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis;
652 public void setMinIdle(int minIdle) {
653 this.minIdle = minIdle;
661 public void setName(String name) {
670 public void setNumTestsPerEvictionRun(int numTestsPerEvictionRun) {
671 this.numTestsPerEvictionRun = numTestsPerEvictionRun;
679 public void setPassword(String password) {
680 this.password = password;
688 public void setRemoveAbandoned(boolean removeAbandoned) {
689 this.removeAbandoned = removeAbandoned;
697 public void setRemoveAbandonedTimeout(int removeAbandonedTimeout) {
698 this.removeAbandonedTimeout = removeAbandonedTimeout;
706 public void setTestOnBorrow(boolean testOnBorrow) {
707 this.testOnBorrow = testOnBorrow;
715 public void setTestWhileIdle(boolean testWhileIdle) {
716 this.testWhileIdle = testWhileIdle;
724 public void setTestOnReturn(boolean testOnReturn) {
725 this.testOnReturn = testOnReturn;
733 public void setTimeBetweenEvictionRunsMillis(int
734 timeBetweenEvictionRunsMillis) {
735 this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis;
743 public void setUrl(String url) {
752 public void setUsername(String username) {
753 this.username = username;
761 public void setValidationInterval(long validationInterval) {
762 this.validationInterval = validationInterval;
770 public void setValidationQuery(String validationQuery) {
771 this.validationQuery = validationQuery;
779 public void setValidatorClassName(String className) {
780 this.validatorClassName = className;
784 if (className == null) {
789 @SuppressWarnings("unchecked")
790 Class<Validator> validatorClass = (Class<Validator>)ClassLoaderUtil.loadClass(
792 PoolProperties.class.getClassLoader(),
793 Thread.currentThread().getContextClassLoader()
795 validator = validatorClass.newInstance();
796 } catch (ClassNotFoundException e) {
797 log.warn("The class "+className+" cannot be found.", e);
798 } catch (ClassCastException e) {
799 log.warn("The class "+className+" does not implement the Validator interface.", e);
800 } catch (InstantiationException e) {
801 log.warn("An object of class "+className+" cannot be instantiated. Make sure that "+
802 "it includes an implicit or explicit no-arg constructor.", e);
803 } catch (IllegalAccessException e) {
804 log.warn("The class "+className+" or its no-arg constructor are inaccessible.", e);
813 public void setInitSQL(String initSQL) {
814 this.initSQL = initSQL!=null && initSQL.trim().length()>0 ? initSQL : null;
822 public void setTestOnConnect(boolean testOnConnect) {
823 this.testOnConnect = testOnConnect;
831 public void setJdbcInterceptors(String jdbcInterceptors) {
832 this.jdbcInterceptors = jdbcInterceptors;
833 this.interceptors = null;
838 public String toString() {
839 StringBuilder buf = new StringBuilder("ConnectionPool[");
841 String[] fields = DataSourceFactory.ALL_PROPERTIES;
842 for (String field: fields) {
843 final String[] prefix = new String[] {"get","is"};
844 for (int j=0; j<prefix.length; j++) {
846 String name = prefix[j]
847 + field.substring(0, 1).toUpperCase(Locale.ENGLISH)
848 + field.substring(1);
851 m = getClass().getMethod(name);
852 }catch (NoSuchMethodException nm) {
857 if (DataSourceFactory.PROP_PASSWORD.equals(field)) {
858 buf.append("********");
860 buf.append(m.invoke(this, new Object[0]));
866 }catch (Exception x) {
868 log.debug("toString() call failed", x);
870 return buf.toString();
873 public static int getPoolCounter() {
874 return poolCounter.get();
882 public boolean isJmxEnabled() {
891 public void setJmxEnabled(boolean jmxEnabled) {
892 this.jmxEnabled = jmxEnabled;
900 public Boolean getDefaultAutoCommit() {
901 return defaultAutoCommit;
909 public Boolean getDefaultReadOnly() {
910 return defaultReadOnly;
919 public int getSuspectTimeout() {
920 return this.suspectTimeout;
928 public void setSuspectTimeout(int seconds) {
929 this.suspectTimeout = seconds;
937 public boolean isPoolSweeperEnabled() {
938 boolean timer = getTimeBetweenEvictionRunsMillis()>0;
939 boolean result = timer && (isRemoveAbandoned() && getRemoveAbandonedTimeout()>0);
940 result = result || (timer && getSuspectTimeout()>0);
941 result = result || (timer && isTestWhileIdle() && getValidationQuery()!=null);
942 result = result || (timer && getMinEvictableIdleTimeMillis()>0);
947 public static class InterceptorDefinition implements Serializable {
948 private static final long serialVersionUID = 1L;
949 protected String className;
950 protected Map<String,InterceptorProperty> properties = new HashMap<>();
951 protected volatile Class<?> clazz = null;
952 public InterceptorDefinition(String className) {
953 this.className = className;
956 public InterceptorDefinition(Class<?> cl) {
961 public String getClassName() {
964 public void addProperty(String name, String value) {
965 InterceptorProperty p = new InterceptorProperty(name,value);
969 public void addProperty(InterceptorProperty p) {
970 properties.put(p.getName(), p);
973 public Map<String,InterceptorProperty> getProperties() {
977 @SuppressWarnings("unchecked")
978 public Class<? extends JdbcInterceptor> getInterceptorClass() throws ClassNotFoundException {
980 if (getClassName().indexOf('.')<0) {
981 if (log.isDebugEnabled()) {
982 log.debug("Loading interceptor class:"+PoolConfiguration.PKG_PREFIX+getClassName());
984 clazz = ClassLoaderUtil.loadClass(
985 PoolConfiguration.PKG_PREFIX+getClassName(),
986 PoolProperties.class.getClassLoader(),
987 Thread.currentThread().getContextClassLoader()
990 if (log.isDebugEnabled()) {
991 log.debug("Loading interceptor class:"+getClassName());
993 clazz = ClassLoaderUtil.loadClass(
995 PoolProperties.class.getClassLoader(),
996 Thread.currentThread().getContextClassLoader()
1000 return (Class<? extends JdbcInterceptor>)clazz;
1004 public static class InterceptorProperty implements Serializable {
1005 private static final long serialVersionUID = 1L;
1008 public InterceptorProperty(String name, String value) {
1013 public String getName() {
1016 public String getValue() {
1020 public boolean getValueAsBoolean(boolean def) {
1021 if (value==null) return def;
1022 if ("true".equals(value)) return true;
1023 if ("false".equals(value)) return false;
1027 public int getValueAsInt(int def) {
1028 if (value==null) return def;
1030 int v = Integer.parseInt(value);
1032 }catch (NumberFormatException nfe) {
1037 public long getValueAsLong(long def) {
1038 if (value==null) return def;
1040 return Long.parseLong(value);
1041 }catch (NumberFormatException nfe) {
1046 public byte getValueAsByte(byte def) {
1047 if (value==null) return def;
1049 return Byte.parseByte(value);
1050 }catch (NumberFormatException nfe) {
1055 public short getValueAsShort(short def) {
1056 if (value==null) return def;
1058 return Short.parseShort(value);
1059 }catch (NumberFormatException nfe) {
1064 public float getValueAsFloat(float def) {
1065 if (value==null) return def;
1067 return Float.parseFloat(value);
1068 }catch (NumberFormatException nfe) {
1073 public double getValueAsDouble(double def) {
1074 if (value==null) return def;
1076 return Double.parseDouble(value);
1077 }catch (NumberFormatException nfe) {
1082 public char getValueAschar(char def) {
1083 if (value==null) return def;
1085 return value.charAt(0);
1086 }catch (StringIndexOutOfBoundsException nfe) {
1092 public int hashCode() {
1093 return name.hashCode();
1097 public boolean equals(Object o) {
1098 if (o==this) return true;
1099 if (o instanceof InterceptorProperty) {
1100 InterceptorProperty other = (InterceptorProperty)o;
1101 return other.name.equals(this.name);
1112 public boolean isUseEquals() {
1121 public void setUseEquals(boolean useEquals) {
1122 this.useEquals = useEquals;
1130 public long getMaxAge() {
1139 public void setMaxAge(long maxAge) {
1140 this.maxAge = maxAge;
1148 public boolean getUseLock() {
1157 public void setUseLock(boolean useLock) {
1158 this.useLock = useLock;
1166 public void setDataSource(Object ds) {
1167 if (ds instanceof DataSourceProxy) {
1168 throw new IllegalArgumentException("Layered pools are not allowed.");
1170 this.dataSource = ds;
1177 public Object getDataSource() {
1186 public void setDataSourceJNDI(String jndiDS) {
1187 this.dataSourceJNDI = jndiDS;
1194 public String getDataSourceJNDI() {
1195 return this.dataSourceJNDI;
1199 public static Properties getProperties(String propText, Properties props) {
1200 if (props==null) props = new Properties();
1201 if (propText != null) {
1203 props.load(new ByteArrayInputStream(propText.replace(';', '\n').getBytes()));
1204 }catch (IOException x) {
1205 throw new RuntimeException(x);
1215 public boolean isAlternateUsernameAllowed() {
1216 return alternateUsernameAllowed;
1223 public void setAlternateUsernameAllowed(boolean alternateUsernameAllowed) {
1224 this.alternateUsernameAllowed = alternateUsernameAllowed;
1232 public void setCommitOnReturn(boolean commitOnReturn) {
1233 this.commitOnReturn = commitOnReturn;
1240 public boolean getCommitOnReturn() {
1241 return this.commitOnReturn;
1248 public void setRollbackOnReturn(boolean rollbackOnReturn) {
1249 this.rollbackOnReturn = rollbackOnReturn;
1256 public boolean getRollbackOnReturn() {
1257 return this.rollbackOnReturn;
1264 public void setUseDisposableConnectionFacade(boolean useDisposableConnectionFacade) {
1265 this.useDisposableConnectionFacade = useDisposableConnectionFacade;
1272 public boolean getUseDisposableConnectionFacade() {
1273 return useDisposableConnectionFacade;
1280 public void setLogValidationErrors(boolean logValidationErrors) {
1281 this.logValidationErrors = logValidationErrors;
1288 public boolean getLogValidationErrors() {
1289 return this.logValidationErrors;
1296 public boolean getPropagateInterruptState() {
1297 return propagateInterruptState;
1304 public void setPropagateInterruptState(boolean propagateInterruptState) {
1305 this.propagateInterruptState = propagateInterruptState;
1312 public boolean isIgnoreExceptionOnPreLoad() {
1313 return ignoreExceptionOnPreLoad;
1320 public void setIgnoreExceptionOnPreLoad(boolean ignoreExceptionOnPreLoad) {
1321 this.ignoreExceptionOnPreLoad = ignoreExceptionOnPreLoad;
1325 protected Object clone() throws CloneNotSupportedException {
1326 // TODO Auto-generated method stub
1327 return super.clone();