Author: jgbutler
Date: Fri Oct 3 09:15:37 2008
New Revision: 701431
URL: http://svn.apache.org/viewvc?rev=701431&view=rev
Log:
Fixes for IBATIS-540: memory leaks in ResultObjectFactoryUtil
Modified:
ibatis/trunk/java/ibatis-2/ibatis-2-core/build/version.properties
ibatis/trunk/java/ibatis-2/ibatis-2-core/doc/release.txt
ibatis/trunk/java/ibatis-2/ibatis-2-core/src/com/ibatis/sqlmap/engine/execution/SqlExecutor.java
ibatis/trunk/java/ibatis-2/ibatis-2-core/src/com/ibatis/sqlmap/engine/mapping/result/ResultObjectFactoryUtil.java
Modified: ibatis/trunk/java/ibatis-2/ibatis-2-core/build/version.properties
URL:
http://svn.apache.org/viewvc/ibatis/trunk/java/ibatis-2/ibatis-2-core/build/version.properties?rev=701431&r1=701430&r2=701431&view=diff
==============================================================================
--- ibatis/trunk/java/ibatis-2/ibatis-2-core/build/version.properties (original)
+++ ibatis/trunk/java/ibatis-2/ibatis-2-core/build/version.properties Fri Oct
3 09:15:37 2008
@@ -1,5 +1,5 @@
#Build version info
-#Tue Sep 09 09:43:13 MDT 2008
+#Fri Oct 03 10:04:40 CDT 2008
version=2.3.4
-buildDate=2008/09/09 09\:43
-buildNum=726
+buildDate=2008/10/03 10\:04
+buildNum=730
Modified: ibatis/trunk/java/ibatis-2/ibatis-2-core/doc/release.txt
URL:
http://svn.apache.org/viewvc/ibatis/trunk/java/ibatis-2/ibatis-2-core/doc/release.txt?rev=701431&r1=701430&r2=701431&view=diff
==============================================================================
--- ibatis/trunk/java/ibatis-2/ibatis-2-core/doc/release.txt (original)
+++ ibatis/trunk/java/ibatis-2/ibatis-2-core/doc/release.txt Fri Oct 3
09:15:37 2008
@@ -5,7 +5,7 @@
Next Version
------------------------------
- o
+ o iBATIS-540 - cleanup result object factory after use to avoid leaks
------------------------------
2.3.4
Modified:
ibatis/trunk/java/ibatis-2/ibatis-2-core/src/com/ibatis/sqlmap/engine/execution/SqlExecutor.java
URL:
http://svn.apache.org/viewvc/ibatis/trunk/java/ibatis-2/ibatis-2-core/src/com/ibatis/sqlmap/engine/execution/SqlExecutor.java?rev=701431&r1=701430&r2=701431&view=diff
==============================================================================
---
ibatis/trunk/java/ibatis-2/ibatis-2-core/src/com/ibatis/sqlmap/engine/execution/SqlExecutor.java
(original)
+++
ibatis/trunk/java/ibatis-2/ibatis-2-core/src/com/ibatis/sqlmap/engine/execution/SqlExecutor.java
Fri Oct 3 09:15:37 2008
@@ -81,6 +81,7 @@
rows = ps.getUpdateCount();
} finally {
closeStatement(statementScope.getSession(), ps);
+ cleanupResultObjectFactory();
}
return rows;
}
@@ -193,6 +194,7 @@
closeResultSet(rs);
} finally {
closeStatement(statementScope.getSession(), ps);
+ cleanupResultObjectFactory();
}
}
@@ -232,6 +234,7 @@
retrieveOutputParameters(statementScope, cs, mappings, parameters, null);
} finally {
closeStatement(statementScope.getSession(), cs);
+ cleanupResultObjectFactory();
}
return rows;
}
@@ -289,6 +292,7 @@
closeResultSet(rs);
} finally {
closeStatement(statementScope.getSession(), cs);
+ cleanupResultObjectFactory();
}
}
}
@@ -676,7 +680,11 @@
private void setupResultObjectFactory(StatementScope statementScope) {
SqlMapClientImpl client = (SqlMapClientImpl)
statementScope.getSession().getSqlMapClient();
-
ResultObjectFactoryUtil.setResultObjectFactory(client.getResultObjectFactory());
-
ResultObjectFactoryUtil.setStatementId(statementScope.getStatement().getId());
+
ResultObjectFactoryUtil.setupResultObjectFactory(client.getResultObjectFactory(),
+ statementScope.getStatement().getId());
+ }
+
+ private void cleanupResultObjectFactory() {
+ ResultObjectFactoryUtil.cleanupResultObjectFactory();
}
}
Modified:
ibatis/trunk/java/ibatis-2/ibatis-2-core/src/com/ibatis/sqlmap/engine/mapping/result/ResultObjectFactoryUtil.java
URL:
http://svn.apache.org/viewvc/ibatis/trunk/java/ibatis-2/ibatis-2-core/src/com/ibatis/sqlmap/engine/mapping/result/ResultObjectFactoryUtil.java?rev=701431&r1=701430&r2=701431&view=diff
==============================================================================
---
ibatis/trunk/java/ibatis-2/ibatis-2-core/src/com/ibatis/sqlmap/engine/mapping/result/ResultObjectFactoryUtil.java
(original)
+++
ibatis/trunk/java/ibatis-2/ibatis-2-core/src/com/ibatis/sqlmap/engine/mapping/result/ResultObjectFactoryUtil.java
Fri Oct 3 09:15:37 2008
@@ -84,7 +84,7 @@
public static Object createObjectThroughFactory(Class clazz) throws
InstantiationException,
IllegalAccessException {
- FactorySettings fs = getFactorySettings();
+ FactorySettings fs = getCurrentFactorySettings();
Object obj;
if (fs.getResultObjectFactory() == null) {
@@ -124,19 +124,52 @@
return obj;
}
- public static void setResultObjectFactory(ResultObjectFactory
resultObjectFactory) {
- getFactorySettings().setResultObjectFactory(resultObjectFactory);
+ /**
+ * This method pushes a new result object factory configuration onto the
stack.
+ * We use a stack because the method can be called in a "nested" fashion if
there
+ * are sub-selects. Calls to this method should be equally balanced
+ * with calls to cleanupResultObjectFactory().
+ *
+ * @param resultObjectFactory
+ * @param statementId
+ */
+ public static void setupResultObjectFactory(ResultObjectFactory
resultObjectFactory, String statementId) {
+ Stack<FactorySettings> fss = (Stack<FactorySettings>)
factorySettings.get();
+ if (fss == null) {
+ fss = new Stack<FactorySettings>();
+ factorySettings.set(fss);
+ }
+
+ FactorySettings fs = new FactorySettings();
+ fs.setResultObjectFactory(resultObjectFactory);
+ fs.setStatementId(statementId);
+ fss.push(fs);
}
- public static void setStatementId(String statementId) {
- getFactorySettings().setStatementId(statementId);
+ /**
+ * Removes the FactorySettings bound to the current thread to avoid
classloader leak issues.
+ * This method pops the top item off the stack, and kills the stack if there
+ * are no items left.
+ */
+ public static void cleanupResultObjectFactory(){
+ Stack<FactorySettings> fss = (Stack<FactorySettings>)
factorySettings.get();
+ if (!fss.empty()) {
+ fss.pop();
+ }
+
+ if (fss.empty()) {
+ factorySettings.remove();
+ }
}
- private static FactorySettings getFactorySettings() {
- FactorySettings fs = (FactorySettings) factorySettings.get();
- if (fs == null) {
+ private static FactorySettings getCurrentFactorySettings() {
+ Stack<FactorySettings> fss = (Stack<FactorySettings>)
factorySettings.get();
+ FactorySettings fs;
+ if (fss == null || fss.empty()) {
+ // this shouldn't happen if the SqlExecuter is behaving correctly
fs = new FactorySettings();
- factorySettings.set(fs);
+ } else {
+ fs = fss.peek();
}
return fs;