Index: src/com/ibatis/sqlmap/engine/execution/DefaultSqlExecutor.java =================================================================== --- src/com/ibatis/sqlmap/engine/execution/DefaultSqlExecutor.java (Revision 773476) +++ src/com/ibatis/sqlmap/engine/execution/DefaultSqlExecutor.java (Arbeitskopie) @@ -19,8 +19,10 @@ import com.ibatis.sqlmap.engine.mapping.parameter.ParameterMap; import com.ibatis.sqlmap.engine.mapping.result.ResultMap; import com.ibatis.sqlmap.engine.mapping.result.ResultObjectFactoryUtil; +import com.ibatis.sqlmap.engine.mapping.result.RowHandlerCallback; +import com.ibatis.sqlmap.engine.mapping.result.RowHandlerCallbackFactory; +import com.ibatis.sqlmap.engine.mapping.result.RowHandlerCallbackFactoryUtil; import com.ibatis.sqlmap.engine.mapping.statement.MappedStatement; -import com.ibatis.sqlmap.engine.mapping.statement.RowHandlerCallback; import com.ibatis.sqlmap.engine.scope.ErrorContext; import com.ibatis.sqlmap.engine.scope.StatementScope; import com.ibatis.sqlmap.engine.scope.SessionScope; @@ -293,12 +295,9 @@ } // Multiple ResultSet handling - if (callback.getRowHandler() instanceof DefaultRowHandler) { + if (callback.canHandleMultipleResultSets()) { MappedStatement statement = statementScope.getStatement(); - DefaultRowHandler defaultRowHandler = ((DefaultRowHandler) callback.getRowHandler()); if (statement.hasMultipleResultMaps()) { - List multipleResults = new ArrayList(); - multipleResults.add(defaultRowHandler.getList()); ResultMap[] resultMaps = statement.getAdditionalResultMaps(); int i = 0; while (moveToNextResultsSafely(statementScope, ps)) { @@ -306,12 +305,10 @@ ResultMap rm = resultMaps[i]; statementScope.setResultMap(rm); rs = ps.getResultSet(); - DefaultRowHandler rh = new DefaultRowHandler(); - handleResults(statementScope, rs, skipResults, maxResults, new RowHandlerCallback(rm, null, rh)); - multipleResults.add(rh.getList()); + RowHandlerCallback handlerCallback = callback.getSubsequentRowHandlerCallback(rm); + handleResults(statementScope, rs, skipResults, maxResults, handlerCallback); i++; } - defaultRowHandler.setList(multipleResults); statementScope.setResultMap(statement.getResultMap()); } else { while (moveToNextResultsSafely(statementScope, ps)) ; @@ -397,7 +394,8 @@ SqlMapClientImpl client = (SqlMapClientImpl) statementScope.getSession().getSqlMapClient(); resultMap = client.getDelegate().getResultMap(mapping.getResultMapName()); DefaultRowHandler rowHandler = new DefaultRowHandler(); - RowHandlerCallback handlerCallback = new RowHandlerCallback(resultMap, null, rowHandler); + RowHandlerCallbackFactory handlerCallbackFactory = RowHandlerCallbackFactoryUtil.getRowHandlerCallbackFactory(); + RowHandlerCallback handlerCallback = handlerCallbackFactory.create(resultMap, null, rowHandler); handleOutputParameterResults(statementScope, resultMap, rs, handlerCallback); parameters[i] = rowHandler.getList(); } Index: src/com/ibatis/sqlmap/engine/execution/SqlExecutor.java =================================================================== --- src/com/ibatis/sqlmap/engine/execution/SqlExecutor.java (Revision 773476) +++ src/com/ibatis/sqlmap/engine/execution/SqlExecutor.java (Arbeitskopie) @@ -4,7 +4,7 @@ import java.sql.SQLException; import java.util.List; -import com.ibatis.sqlmap.engine.mapping.statement.RowHandlerCallback; +import com.ibatis.sqlmap.engine.mapping.result.RowHandlerCallback; import com.ibatis.sqlmap.engine.scope.SessionScope; import com.ibatis.sqlmap.engine.scope.StatementScope; Index: src/com/ibatis/sqlmap/engine/builder/xml/SqlMapConfigParser.java =================================================================== --- src/com/ibatis/sqlmap/engine/builder/xml/SqlMapConfigParser.java (Revision 773476) +++ src/com/ibatis/sqlmap/engine/builder/xml/SqlMapConfigParser.java (Arbeitskopie) @@ -31,6 +31,7 @@ addTransactionManagerNodelets(); addSqlMapNodelets(); addResultObjectFactoryNodelets(); + addRowHandlerCallbackFactory(); } @@ -299,5 +300,24 @@ } }); } + + private void addRowHandlerCallbackFactory() { + parser.addNodelet("/sqlMapConfig/rowHandlerCallbackFactory", new Nodelet() { + public void process(Node node) throws Exception { + Properties attributes = NodeletUtils.parseAttributes(node, state.getGlobalProps()); + String type = attributes.getProperty("type"); + state.getConfig().getErrorContext().setActivity("configuring the Row Handler Callback Factory"); + RowHandlerCallbackFactory factory; + try { + factory = (RowHandlerCallbackFactory) Resources.instantiate(type); + RowHandlerCallbackFactoryUtil.setRowHandlerCallbackFactory(factory); + } catch (Exception e) { + throw new SqlMapException("Error instantiating rowHandlerCallbackFactory: " + type, e); + } + } + }); + } + + } Index: src/com/ibatis/sqlmap/engine/builder/xml/sql-map-config-2.dtd =================================================================== --- src/com/ibatis/sqlmap/engine/builder/xml/sql-map-config-2.dtd (Revision 773476) +++ src/com/ibatis/sqlmap/engine/builder/xml/sql-map-config-2.dtd (Arbeitskopie) @@ -18,7 +18,7 @@ - + @@ -213,3 +213,11 @@ + + + + + Index: src/com/ibatis/sqlmap/engine/mapping/statement/RowHandlerCallback.java =================================================================== --- src/com/ibatis/sqlmap/engine/mapping/statement/RowHandlerCallback.java (Revision 773476) +++ src/com/ibatis/sqlmap/engine/mapping/statement/RowHandlerCallback.java (Arbeitskopie) @@ -1,105 +0,0 @@ -/* - * Copyright 2004 Clinton Begin - * - * Licensed 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 com.ibatis.sqlmap.engine.mapping.statement; - -import com.ibatis.sqlmap.client.event.RowHandler; -import com.ibatis.sqlmap.engine.mapping.result.ResultMap; -import com.ibatis.sqlmap.engine.scope.StatementScope; -import com.ibatis.sqlmap.engine.type.XmlTypeMarker; - -import org.w3c.dom.Document; - -import javax.xml.transform.*; -import javax.xml.transform.dom.DOMSource; -import javax.xml.transform.stream.StreamResult; -import java.io.StringWriter; -import java.sql.ResultSet; -import java.sql.SQLException; - -/** - * Class to manager row handler access - */ -public class RowHandlerCallback { - - private RowHandler rowHandler; - private ResultMap resultMap; - private Object resultObject; - - /** - * Constructor - * - * @param resultMap - the result map - * @param resultObject - the result object - * @param rowHandler - the row handler object - */ - public RowHandlerCallback(ResultMap resultMap, Object resultObject, RowHandler rowHandler) { - this.rowHandler = rowHandler; - this.resultMap = resultMap; - this.resultObject = resultObject; - } - - /** - * Prepares the row object, and passes it to the row handler - * - * @param statementScope - the request scope - * @param results - the result data - */ - public void handleResultObject(StatementScope statementScope, Object[] results, ResultSet rs) throws SQLException { - Object object; - - statementScope.setCurrentNestedKey(null); - object = resultMap.resolveSubMap(statementScope, rs).setResultObjectValues(statementScope, resultObject, results); - - if (object != ResultMap.NO_VALUE) { - // XML Only special processing. (converts elements to string for easy insertion). - int stackDepth = statementScope.getSession().getRequestStackDepth(); - if (stackDepth == 1) { - Class targetType = statementScope.getResultMap().getResultClass(); - if (XmlTypeMarker.class.isAssignableFrom(targetType) - && object instanceof Document) { - object = documentToString((Document) object); - } - } - - rowHandler.handleRow(object); - } - } - - private String documentToString(Document document) { - String s = null; - - try { - TransformerFactory tFactory = TransformerFactory.newInstance(); - Transformer transformer = tFactory.newTransformer(); - - DOMSource source = new DOMSource(document); - StringWriter writer = new StringWriter(); - StreamResult result = new StreamResult(writer); - transformer.transform(source, result); - s = writer.getBuffer().toString(); - - } catch (TransformerException e) { - throw new RuntimeException("Error occurred. Cause: " + e, e); - } - - return s; - } - - public RowHandler getRowHandler() { - return rowHandler; - } - -} Index: src/com/ibatis/sqlmap/engine/mapping/statement/MappedStatement.java =================================================================== --- src/com/ibatis/sqlmap/engine/mapping/statement/MappedStatement.java (Revision 773476) +++ src/com/ibatis/sqlmap/engine/mapping/statement/MappedStatement.java (Arbeitskopie) @@ -23,6 +23,9 @@ import com.ibatis.sqlmap.engine.execution.SqlExecutor; import com.ibatis.sqlmap.engine.mapping.parameter.ParameterMap; import com.ibatis.sqlmap.engine.mapping.result.ResultMap; +import com.ibatis.sqlmap.engine.mapping.result.RowHandlerCallback; +import com.ibatis.sqlmap.engine.mapping.result.RowHandlerCallbackFactory; +import com.ibatis.sqlmap.engine.mapping.result.RowHandlerCallbackFactoryUtil; import com.ibatis.sqlmap.engine.mapping.sql.Sql; import com.ibatis.sqlmap.engine.scope.ErrorContext; import com.ibatis.sqlmap.engine.scope.StatementScope; @@ -185,7 +188,8 @@ errorContext.setActivity("executing mapped statement"); errorContext.setMoreInfo("Check the SQL statement or the result map."); - RowHandlerCallback callback = new RowHandlerCallback(resultMap, resultObject, rowHandler); + RowHandlerCallbackFactory handlerCallbackFactory = RowHandlerCallbackFactoryUtil.getRowHandlerCallbackFactory(); + RowHandlerCallback callback = handlerCallbackFactory.create(resultMap, resultObject, rowHandler); sqlExecuteQuery(statementScope, conn, sqlString, parameters, skipResults, maxResults, callback); errorContext.setMoreInfo("Check the output parameters."); Index: src/com/ibatis/sqlmap/engine/mapping/statement/ProcedureStatement.java =================================================================== --- src/com/ibatis/sqlmap/engine/mapping/statement/ProcedureStatement.java (Revision 773476) +++ src/com/ibatis/sqlmap/engine/mapping/statement/ProcedureStatement.java (Arbeitskopie) @@ -15,6 +15,7 @@ */ package com.ibatis.sqlmap.engine.mapping.statement; +import com.ibatis.sqlmap.engine.mapping.result.RowHandlerCallback; import com.ibatis.sqlmap.engine.scope.StatementScope; import java.sql.Connection; Index: src/com/ibatis/sqlmap/engine/mapping/result/DefaultRowHandlerCallbackFactory.java =================================================================== --- src/com/ibatis/sqlmap/engine/mapping/result/DefaultRowHandlerCallbackFactory.java (Revision 0) +++ src/com/ibatis/sqlmap/engine/mapping/result/DefaultRowHandlerCallbackFactory.java (Revision 0) @@ -0,0 +1,16 @@ +package com.ibatis.sqlmap.engine.mapping.result; + +import com.ibatis.sqlmap.client.event.RowHandler; + +/** + * Default implementation of the {@link RowHandlerCallbackFactory} which creates + * {@link DefaultRowHandlerCallback}. + */ +public class DefaultRowHandlerCallbackFactory implements RowHandlerCallbackFactory { + + public RowHandlerCallback create(ResultMap resultMap, Object resultObject, + RowHandler rowHandler) { + return new DefaultRowHandlerCallback(resultMap, resultObject, rowHandler); + } + +} Index: src/com/ibatis/sqlmap/engine/mapping/result/RowHandlerCallback.java =================================================================== --- src/com/ibatis/sqlmap/engine/mapping/result/RowHandlerCallback.java (Revision 773476) +++ src/com/ibatis/sqlmap/engine/mapping/result/RowHandlerCallback.java (Arbeitskopie) @@ -1,105 +1,36 @@ -/* - * Copyright 2004 Clinton Begin - * - * Licensed 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 com.ibatis.sqlmap.engine.mapping.statement; +package com.ibatis.sqlmap.engine.mapping.result; -import com.ibatis.sqlmap.client.event.RowHandler; -import com.ibatis.sqlmap.engine.mapping.result.ResultMap; -import com.ibatis.sqlmap.engine.scope.StatementScope; -import com.ibatis.sqlmap.engine.type.XmlTypeMarker; - -import org.w3c.dom.Document; - -import javax.xml.transform.*; -import javax.xml.transform.dom.DOMSource; -import javax.xml.transform.stream.StreamResult; -import java.io.StringWriter; import java.sql.ResultSet; import java.sql.SQLException; +import com.ibatis.sqlmap.engine.scope.StatementScope; + /** - * Class to manager row handler access + * Handles result sets read from the database. */ -public class RowHandlerCallback { +public interface RowHandlerCallback { - private RowHandler rowHandler; - private ResultMap resultMap; - private Object resultObject; + /** + * Prepares the row object, and passes it to the row handler + * + * @param statementScope - the request scope + * @param results - the result data + * @param rs - the result set read from the database + */ + public void handleResultObject(StatementScope statementScope, Object[] results, ResultSet rs) throws SQLException; + - /** - * Constructor - * - * @param resultMap - the result map - * @param resultObject - the result object - * @param rowHandler - the row handler object - */ - public RowHandlerCallback(ResultMap resultMap, Object resultObject, RowHandler rowHandler) { - this.rowHandler = rowHandler; - this.resultMap = resultMap; - this.resultObject = resultObject; - } + /** + * Returns if this row handler callback can handle multiple result sets. + */ + boolean canHandleMultipleResultSets(); + + /** + * Returns a {@link RowHandlerCallback} which handles subsequent result sets with + * the given result map. + * + * @param resultMap the result map for the result set to handle + */ + RowHandlerCallback getSubsequentRowHandlerCallback(ResultMap resultMap); - /** - * Prepares the row object, and passes it to the row handler - * - * @param statementScope - the request scope - * @param results - the result data - */ - public void handleResultObject(StatementScope statementScope, Object[] results, ResultSet rs) throws SQLException { - Object object; - - statementScope.setCurrentNestedKey(null); - object = resultMap.resolveSubMap(statementScope, rs).setResultObjectValues(statementScope, resultObject, results); - - if (object != ResultMap.NO_VALUE) { - // XML Only special processing. (converts elements to string for easy insertion). - int stackDepth = statementScope.getSession().getRequestStackDepth(); - if (stackDepth == 1) { - Class targetType = statementScope.getResultMap().getResultClass(); - if (XmlTypeMarker.class.isAssignableFrom(targetType) - && object instanceof Document) { - object = documentToString((Document) object); - } - } - - rowHandler.handleRow(object); - } - } - - private String documentToString(Document document) { - String s = null; - - try { - TransformerFactory tFactory = TransformerFactory.newInstance(); - Transformer transformer = tFactory.newTransformer(); - - DOMSource source = new DOMSource(document); - StringWriter writer = new StringWriter(); - StreamResult result = new StreamResult(writer); - transformer.transform(source, result); - s = writer.getBuffer().toString(); - - } catch (TransformerException e) { - throw new RuntimeException("Error occurred. Cause: " + e, e); - } - - return s; - } - - public RowHandler getRowHandler() { - return rowHandler; - } - } Eigenschaftsänderungen: src/com/ibatis/sqlmap/engine/mapping/result/RowHandlerCallback.java ___________________________________________________________________ Hinzugefügt: svn:mergeinfo Index: src/com/ibatis/sqlmap/engine/mapping/result/DefaultRowHandlerCallback.java =================================================================== --- src/com/ibatis/sqlmap/engine/mapping/result/DefaultRowHandlerCallback.java (Revision 773476) +++ src/com/ibatis/sqlmap/engine/mapping/result/DefaultRowHandlerCallback.java (Arbeitskopie) @@ -13,10 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.ibatis.sqlmap.engine.mapping.statement; +package com.ibatis.sqlmap.engine.mapping.result; import com.ibatis.sqlmap.client.event.RowHandler; -import com.ibatis.sqlmap.engine.mapping.result.ResultMap; +import com.ibatis.sqlmap.engine.mapping.statement.DefaultRowHandler; import com.ibatis.sqlmap.engine.scope.StatementScope; import com.ibatis.sqlmap.engine.type.XmlTypeMarker; @@ -28,16 +28,21 @@ import java.io.StringWriter; import java.sql.ResultSet; import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; /** - * Class to manager row handler access + * Default implementation of the {@link RowHandlerCallback}. + *

+ * Creates objects from result maps and calls for each object the {@link RowHandler}. */ -public class RowHandlerCallback { +public class DefaultRowHandlerCallback implements RowHandlerCallback { private RowHandler rowHandler; private ResultMap resultMap; private Object resultObject; - + private List multiResultList; + /** * Constructor * @@ -45,12 +50,24 @@ * @param resultObject - the result object * @param rowHandler - the row handler object */ - public RowHandlerCallback(ResultMap resultMap, Object resultObject, RowHandler rowHandler) { + public DefaultRowHandlerCallback(ResultMap resultMap, Object resultObject, RowHandler rowHandler) { this.rowHandler = rowHandler; this.resultMap = resultMap; this.resultObject = resultObject; } + public RowHandler getRowHandler() { + return rowHandler; + } + + public Object getResultObject() { + return resultObject; + } + + public ResultMap getResultMap() { + return resultMap; + } + /** * Prepares the row object, and passes it to the row handler * @@ -58,26 +75,56 @@ * @param results - the result data */ public void handleResultObject(StatementScope statementScope, Object[] results, ResultSet rs) throws SQLException { - Object object; + handleResultObjectInternal(resultMap, rowHandler, resultObject, statementScope, results, rs); + } + + public boolean canHandleMultipleResultSets() { + return rowHandler instanceof DefaultRowHandler; + } - statementScope.setCurrentNestedKey(null); - object = resultMap.resolveSubMap(statementScope, rs).setResultObjectValues(statementScope, resultObject, results); + public RowHandlerCallback getSubsequentRowHandlerCallback(ResultMap rm) { + if (!canHandleMultipleResultSets()) { + throw new UnsupportedOperationException(); + } + + if (multiResultList == null) { + DefaultRowHandler defaultRowHandler = (DefaultRowHandler) rowHandler; + multiResultList = new ArrayList(); + multiResultList.add(defaultRowHandler.getList()); + defaultRowHandler.setList(multiResultList); + } + + return new SubsequenctHandlerCallback(rm); + } + + protected void handleResultObjectInternal(ResultMap rm, RowHandler rh, Object ro, StatementScope statementScope, Object[] results, ResultSet rs) + throws SQLException { + + statementScope.setCurrentNestedKey(null); + Object object = createObjectFromResult(rm, ro, statementScope, results, rs); - if (object != ResultMap.NO_VALUE) { - // XML Only special processing. (converts elements to string for easy insertion). - int stackDepth = statementScope.getSession().getRequestStackDepth(); - if (stackDepth == 1) { - Class targetType = statementScope.getResultMap().getResultClass(); - if (XmlTypeMarker.class.isAssignableFrom(targetType) - && object instanceof Document) { - object = documentToString((Document) object); - } - } + if (object != ResultMap.NO_VALUE) { + // XML Only special processing. (converts elements to string for easy insertion). + int stackDepth = statementScope.getSession().getRequestStackDepth(); + if (stackDepth == 1) { + Class targetType = statementScope.getResultMap().getResultClass(); + if (XmlTypeMarker.class.isAssignableFrom(targetType) + && object instanceof Document) { + object = documentToString((Document) object); + } + } - rowHandler.handleRow(object); - } + rh.handleRow(object); + } } + protected Object createObjectFromResult(ResultMap rm, Object ro, + StatementScope statementScope, Object[] results, ResultSet rs) + throws SQLException { + return rm.resolveSubMap(statementScope, rs).setResultObjectValues(statementScope, ro, results); + } + + private String documentToString(Document document) { String s = null; @@ -98,8 +145,33 @@ return s; } - public RowHandler getRowHandler() { - return rowHandler; + /** + * {@link RowHandlerCallback} which handles subsequent results from + * multiple result sets. + */ + protected class SubsequenctHandlerCallback implements RowHandlerCallback { + + private final ResultMap rm; + private final DefaultRowHandler rh; + + public SubsequenctHandlerCallback(ResultMap rm) { + this.rm = rm; + this.rh = new DefaultRowHandler(); + multiResultList.add(rh.getList()); + } + + public boolean canHandleMultipleResultSets() { + return false; + } + + public RowHandlerCallback getSubsequentRowHandlerCallback(ResultMap resultMap) { + throw new UnsupportedOperationException(); + } + + public void handleResultObject(StatementScope statementScope, Object[] results, ResultSet rs) throws SQLException { + handleResultObjectInternal(rm, rh, null, statementScope, results, rs); + } + } } Eigenschaftsänderungen: src/com/ibatis/sqlmap/engine/mapping/result/DefaultRowHandlerCallback.java ___________________________________________________________________ Hinzugefügt: svn:mergeinfo Index: src/com/ibatis/sqlmap/engine/mapping/result/RowHandlerCallbackFactoryUtil.java =================================================================== --- src/com/ibatis/sqlmap/engine/mapping/result/RowHandlerCallbackFactoryUtil.java (Revision 0) +++ src/com/ibatis/sqlmap/engine/mapping/result/RowHandlerCallbackFactoryUtil.java (Revision 0) @@ -0,0 +1,25 @@ +package com.ibatis.sqlmap.engine.mapping.result; + +import java.util.concurrent.atomic.AtomicReference; + +/** + * This class returns the factory to create {@link RowHandlerCallback} instances. + */ +public class RowHandlerCallbackFactoryUtil { + + private static AtomicReference rowHandlerCallbackFactoryRef = + new AtomicReference(new DefaultRowHandlerCallbackFactory()); + + + public static void setRowHandlerCallbackFactory(RowHandlerCallbackFactory rowHandlerCallbackFactory) { + if (rowHandlerCallbackFactory == null) { + throw new NullPointerException("rowHandlerCallbackFactory must not be null."); + } + rowHandlerCallbackFactoryRef.set(rowHandlerCallbackFactory); + } + + public static RowHandlerCallbackFactory getRowHandlerCallbackFactory() { + return rowHandlerCallbackFactoryRef.get(); + } + +} Index: src/com/ibatis/sqlmap/engine/mapping/result/RowHandlerCallbackFactory.java =================================================================== --- src/com/ibatis/sqlmap/engine/mapping/result/RowHandlerCallbackFactory.java (Revision 0) +++ src/com/ibatis/sqlmap/engine/mapping/result/RowHandlerCallbackFactory.java (Revision 0) @@ -0,0 +1,15 @@ +package com.ibatis.sqlmap.engine.mapping.result; + +import com.ibatis.sqlmap.client.event.RowHandler; + +/** + * Creates {@link RowHandlerCallback} instances. + */ +public interface RowHandlerCallbackFactory { + + /** + * Creates a new {@link RowHandlerCallback} instance from the given arguments. + */ + RowHandlerCallback create(ResultMap resultMap, Object resultObject, RowHandler rowHandler); + +}