You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by ps...@apache.org on 2015/02/16 21:18:39 UTC
svn commit: r1660195 - in /commons/proper/dbcp/trunk/src: changes/
main/java/org/apache/commons/dbcp2/ test/java/org/apache/commons/dbcp2/
Author: psteitz
Date: Mon Feb 16 20:18:38 2015
New Revision: 1660195
URL: http://svn.apache.org/r1660195
Log:
Added property name verification to BasicDataSourceFactory. References including
obsolete or unrecognized properties now generate log messages.
JIRA: DBCP-435
Thanks to Denixx Baykin.
Modified:
commons/proper/dbcp/trunk/src/changes/changes.xml
commons/proper/dbcp/trunk/src/main/java/org/apache/commons/dbcp2/BasicDataSourceFactory.java
commons/proper/dbcp/trunk/src/test/java/org/apache/commons/dbcp2/StackMessageLog.java
commons/proper/dbcp/trunk/src/test/java/org/apache/commons/dbcp2/TestBasicDataSourceFactory.java
Modified: commons/proper/dbcp/trunk/src/changes/changes.xml
URL: http://svn.apache.org/viewvc/commons/proper/dbcp/trunk/src/changes/changes.xml?rev=1660195&r1=1660194&r2=1660195&view=diff
==============================================================================
--- commons/proper/dbcp/trunk/src/changes/changes.xml (original)
+++ commons/proper/dbcp/trunk/src/changes/changes.xml Mon Feb 16 20:18:38 2015
@@ -114,6 +114,10 @@ The <action> type attribute can be add,u
<action dev="psteitz" type="update">
Eliminated synchronization in BasicDataSource getNumActive, getNumIdle methods.
</action>
+ <action issue="DBCP-435" type="update" due-to="Denixx Baykin">
+ Added property name verification to BasicDataSourceFactory. References including
+ obsolete or unrecognized properties now generate log messages.
+ </action>
</release>
<release version="2.0.1" date="24 May 2014" description="This is a bug fix release.">
<action dev="markt" type="fix">
Modified: commons/proper/dbcp/trunk/src/main/java/org/apache/commons/dbcp2/BasicDataSourceFactory.java
URL: http://svn.apache.org/viewvc/commons/proper/dbcp/trunk/src/main/java/org/apache/commons/dbcp2/BasicDataSourceFactory.java?rev=1660195&r1=1660194&r2=1660195&view=diff
==============================================================================
--- commons/proper/dbcp/trunk/src/main/java/org/apache/commons/dbcp2/BasicDataSourceFactory.java (original)
+++ commons/proper/dbcp/trunk/src/main/java/org/apache/commons/dbcp2/BasicDataSourceFactory.java Mon Feb 16 20:18:38 2015
@@ -17,13 +17,22 @@
package org.apache.commons.dbcp2;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.commons.pool2.impl.BaseObjectPoolConfig;
+import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
+
import java.io.ByteArrayInputStream;
import java.nio.charset.StandardCharsets;
import java.sql.Connection;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collection;
import java.util.Enumeration;
import java.util.Hashtable;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
import java.util.Properties;
import java.util.StringTokenizer;
@@ -52,6 +61,8 @@ import javax.naming.spi.ObjectFactory;
*/
public class BasicDataSourceFactory implements ObjectFactory {
+ private static final Log log = LogFactory.getLog(BasicDataSourceFactory.class);
+
private static final String PROP_DEFAULTAUTOCOMMIT = "defaultAutoCommit";
private static final String PROP_DEFAULTREADONLY = "defaultReadOnly";
private static final String PROP_DEFAULTTRANSACTIONISOLATION = "defaultTransactionIsolation";
@@ -105,6 +116,24 @@ public class BasicDataSourceFactory impl
*/
private static final String PROP_DISCONNECTION_SQL_CODES = "disconnectionSqlCodes";
+ /*
+ * Block with obsolete properties from DBCP 1.x.
+ * Warn users that these are ignored and they should use the 2.x properties.
+ */
+ private static final String NUPROP_MAXACTIVE = "maxActive";
+ private static final String NUPROP_REMOVEABANDONED = "removeAbandoned";
+ private static final String NUPROP_MAXWAIT = "maxWait";
+
+ /*
+ * Block with properties expected in a DataSource
+ * This props will not be listed as ignored - we know that they may appear in Resource,
+ * and not listing them as ignored.
+ */
+ private static final String SILENTPROP_FACTORY = "factory";
+ private static final String SILENTPROP_SCOPE = "scope";
+ private static final String SILENTPROP_SINGLETON = "singleton";
+ private static final String SILENTPROP_AUTH = "auth";
+
private static final String[] ALL_PROPERTIES = {
PROP_DEFAULTAUTOCOMMIT,
PROP_DEFAULTREADONLY,
@@ -150,6 +179,46 @@ public class BasicDataSourceFactory impl
PROP_DISCONNECTION_SQL_CODES
};
+ /**
+ * Obsolete properties from DBCP 1.x. with warning strings suggesting
+ * new properties. LinkedHashMap will guarantee that properties will be listed
+ * to output in order of insertion into map.
+ */
+ private static final Map<String, String> NUPROP_WARNTEXT = new LinkedHashMap<>();
+
+ static {
+ NUPROP_WARNTEXT.put(
+ NUPROP_MAXACTIVE,
+ "Property " + NUPROP_MAXACTIVE + " is not used in DBCP2, use " + PROP_MAXTOTAL + " instead. "
+ + PROP_MAXTOTAL + " default value is " + GenericObjectPoolConfig.DEFAULT_MAX_TOTAL+".");
+ NUPROP_WARNTEXT.put(
+ NUPROP_REMOVEABANDONED,
+ "Property " + NUPROP_REMOVEABANDONED + " is not used in DBCP2,"
+ + " use one or both of "
+ + PROP_REMOVEABANDONEDONBORROW + " or " + PROP_REMOVEABANDONEDONMAINTENANCE + " instead. "
+ + "Both have default value set to false.");
+ NUPROP_WARNTEXT.put(
+ NUPROP_MAXWAIT,
+ "Property " + NUPROP_MAXWAIT + " is not used in DBCP2"
+ + " , use " + PROP_MAXWAITMILLIS + " instead. "
+ + PROP_MAXWAITMILLIS + " default value is " + BaseObjectPoolConfig.DEFAULT_MAX_WAIT_MILLIS+".");
+ }
+
+ /**
+ * Silent Properties.
+ * These properties will not be listed as ignored - we know that they may appear in JDBC Resource references,
+ * and we will not list them as ignored.
+ */
+ private static final List<String> SILENT_PROPERTIES = new ArrayList<>();
+
+ static {
+ SILENT_PROPERTIES.add(SILENTPROP_FACTORY);
+ SILENT_PROPERTIES.add(SILENTPROP_SCOPE);
+ SILENT_PROPERTIES.add(SILENTPROP_SINGLETON);
+ SILENT_PROPERTIES.add(SILENTPROP_AUTH);
+
+ }
+
// -------------------------------------------------- ObjectFactory Methods
/**
@@ -181,6 +250,17 @@ public class BasicDataSourceFactory impl
return null;
}
+ // Check property names and log warnings about obsolete and / or unknown properties
+ final List<String> warnings = new ArrayList<String>();
+ final List<String> infoMessages = new ArrayList<String>();
+ validatePropertyNames(ref, name, warnings, infoMessages);
+ for (String warning : warnings) {
+ log.warn(warning);
+ }
+ for (String infoMessage : infoMessages) {
+ log.info(infoMessage);
+ }
+
Properties properties = new Properties();
for (String propertyName : ALL_PROPERTIES) {
RefAddr ra = ref.get(propertyName);
@@ -194,6 +274,58 @@ public class BasicDataSourceFactory impl
}
/**
+ * Collects warnings and info messages. Warnings are generated when an obsolete
+ * property is set. Unknown properties generate info messages.
+ *
+ * @param ref Reference to check properties of
+ * @param name Name provided to getObject
+ * @param warnings container for warning messages
+ * @param infoMessasges container for info messages
+ */
+ private void validatePropertyNames(Reference ref, Name name, List<String> warnings,
+ List<String> infoMessages) {
+ final List<String> allPropsAsList = Arrays.asList(ALL_PROPERTIES);
+ final String nameString = name != null ? "Name = " + name.toString() + " " : "";
+ if (NUPROP_WARNTEXT!=null && !NUPROP_WARNTEXT.keySet().isEmpty()) {
+ for (String propertyName : NUPROP_WARNTEXT.keySet()) {
+ final RefAddr ra = ref.get(propertyName);
+ if (ra != null && !allPropsAsList.contains(ra.getType())) {
+ final StringBuilder stringBuilder = new StringBuilder(nameString);
+ final String propertyValue = ra.getContent().toString();
+ stringBuilder.append(NUPROP_WARNTEXT.get(propertyName))
+ .append(" You have set value of \"")
+ .append(propertyValue)
+ .append("\" for \"")
+ .append(propertyName)
+ .append("\" property, which is being ignored.");
+ warnings.add(stringBuilder.toString());
+ }
+ }
+ }
+
+ final Enumeration<RefAddr> allRefAddrs = ref.getAll();
+ while (allRefAddrs.hasMoreElements()) {
+ final RefAddr ra = allRefAddrs.nextElement();
+ final String propertyName = ra.getType();
+ // If property name is not in the properties list, we haven't warned on it
+ // and it is not in the "silent" list, tell user we are ignoring it.
+ if (!(allPropsAsList.contains(propertyName)
+ || NUPROP_WARNTEXT.keySet().contains(propertyName)
+ || SILENT_PROPERTIES.contains(propertyName))) {
+ final String propertyValue = ra.getContent().toString();
+ final StringBuilder stringBuilder = new StringBuilder(nameString);
+ stringBuilder.append("Ignoring unknown property: ")
+ .append("value of \"")
+ .append(propertyValue)
+ .append("\" for \"")
+ .append(propertyName)
+ .append("\" property");
+ infoMessages.add(stringBuilder.toString());
+ }
+ }
+ }
+
+ /**
* Creates and configures a {@link BasicDataSource} instance based on the
* given properties.
*
Modified: commons/proper/dbcp/trunk/src/test/java/org/apache/commons/dbcp2/StackMessageLog.java
URL: http://svn.apache.org/viewvc/commons/proper/dbcp/trunk/src/test/java/org/apache/commons/dbcp2/StackMessageLog.java?rev=1660195&r1=1660194&r2=1660195&view=diff
==============================================================================
--- commons/proper/dbcp/trunk/src/test/java/org/apache/commons/dbcp2/StackMessageLog.java (original)
+++ commons/proper/dbcp/trunk/src/test/java/org/apache/commons/dbcp2/StackMessageLog.java Mon Feb 16 20:18:38 2015
@@ -17,7 +17,10 @@
package org.apache.commons.dbcp2;
+import java.util.ArrayList;
import java.util.EmptyStackException;
+import java.util.Iterator;
+import java.util.List;
import java.util.Stack;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
@@ -30,7 +33,7 @@ import org.apache.commons.logging.impl.S
*
* @version $Id$
*/
-public class StackMessageLog extends SimpleLog {
+public class StackMessageLog extends SimpleLog {
private static final long serialVersionUID = 1L;
private static Stack<String> messageStack = new Stack<String>();
@@ -80,6 +83,18 @@ public class StackMessageLog extends Sim
}
return ret;
}
+
+ /**
+ * Note: iterator is fail-fast, lock the stack first.
+ */
+ public static List<String> getAll() {
+ final Iterator<String> iterator = messageStack.iterator();
+ final List<String> messages = new ArrayList<String>();
+ while (iterator.hasNext()) {
+ messages.add(iterator.next());
+ }
+ return messages;
+ }
public static void clear() {
lock.lock();
Modified: commons/proper/dbcp/trunk/src/test/java/org/apache/commons/dbcp2/TestBasicDataSourceFactory.java
URL: http://svn.apache.org/viewvc/commons/proper/dbcp/trunk/src/test/java/org/apache/commons/dbcp2/TestBasicDataSourceFactory.java?rev=1660195&r1=1660194&r2=1660195&view=diff
==============================================================================
--- commons/proper/dbcp/trunk/src/test/java/org/apache/commons/dbcp2/TestBasicDataSourceFactory.java (original)
+++ commons/proper/dbcp/trunk/src/test/java/org/apache/commons/dbcp2/TestBasicDataSourceFactory.java Mon Feb 16 20:18:38 2015
@@ -22,7 +22,10 @@ import static org.junit.Assert.assertNot
import static org.junit.Assert.assertTrue;
import java.sql.Connection;
+import java.util.List;
import java.util.Properties;
+import javax.naming.Reference;
+import javax.naming.StringRefAddr;
import org.junit.Test;
@@ -118,4 +121,31 @@ public class TestBasicDataSourceFactory
assertTrue(ds.getDisconnectionSqlCodes().contains("XXX"));
assertTrue(ds.getDisconnectionSqlCodes().contains("YYY"));
}
+
+ @Test
+ public void testValidateProperties() throws Exception {
+ try {
+ StackMessageLog.lock();
+ final Reference ref = new Reference("javax.sql.DataSource",
+ BasicDataSourceFactory.class.getName(), null);
+ ref.add(new StringRefAddr("foo", "bar")); // Unknown
+ ref.add(new StringRefAddr("maxWait", "100")); // Changed
+ ref.add(new StringRefAddr("driverClassName", "org.apache.commons.dbcp2.TesterDriver")); //OK
+ final BasicDataSourceFactory basicDataSourceFactory = new BasicDataSourceFactory();
+ basicDataSourceFactory.getObjectInstance(ref, null, null, null);
+ final List<String> messages = StackMessageLog.getAll();
+ assertEquals(2,messages.size());
+ for (String message : messages) {
+ if (message.contains("maxWait")) {
+ assertTrue(message.contains("use maxWaitMillis"));
+ } else {
+ assertTrue(message.contains("foo"));
+ assertTrue(message.contains("Ignoring unknown property"));
+ }
+ }
+ } finally {
+ StackMessageLog.clear();
+ StackMessageLog.unLock();
+ }
+ }
}