1. /*
  2. * Copyright 2002-2004 the original author or authors.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package org.springframework.jdbc.object;
  17. import java.util.List;
  18. import java.util.Map;
  19. import org.springframework.jdbc.core.CallableStatementCreator;
  20. import org.springframework.jdbc.core.CallableStatementCreatorFactory;
  21. import org.springframework.jdbc.core.ParameterMapper;
  22. import org.springframework.jdbc.core.SqlParameter;
  23. import org.springframework.jdbc.core.SqlReturnResultSet;
  24. /**
  25. * RdbmsOperation using a JdbcTemplate and representing a SQL-based
  26. * call such as a stored procedure or a stored function.
  27. *
  28. * <p>Configures a CallableStatementCreatorFactory based on the declared
  29. * parameters.
  30. *
  31. * @author Rod Johnson
  32. * @author Thomas Risberg
  33. * @version $Id: SqlCall.java,v 1.8 2004/04/21 18:43:22 jhoeller Exp $
  34. */
  35. public abstract class SqlCall extends RdbmsOperation {
  36. /**
  37. * Object enabling us to create CallableStatementCreators
  38. * efficiently, based on this class's declared parameters.
  39. */
  40. private CallableStatementCreatorFactory callableStatementFactory;
  41. /**
  42. * Flag used to indicate that this call is for a function and to
  43. * use the {? = call get_invoice_count(?)} syntax.
  44. */
  45. private boolean function = false;
  46. /**
  47. * Flag used to indicate that the sql for this call should be used exactly as it is
  48. * defined. No need to add the escape syntax and parameter place holders.
  49. */
  50. private boolean sqlReadyForUse = false;
  51. /**
  52. * Call string as defined in java.sql.CallableStatement.
  53. * String of form {call add_invoice(?, ?, ?)}
  54. * or {? = call get_invoice_count(?)} if isFunction is set to true
  55. * Updated after each parameter is added.
  56. */
  57. private String callString;
  58. /**
  59. * Set whether this call is for a function.
  60. */
  61. public void setFunction(boolean function) {
  62. this.function = function;
  63. }
  64. /**
  65. * Get whether this call is for a function.
  66. */
  67. public boolean isFunction() {
  68. return function;
  69. }
  70. /**
  71. * Set whether the SQL can be used as is.
  72. */
  73. public void setSqlReadyForUse(boolean sqlReadyForUse) {
  74. this.sqlReadyForUse = sqlReadyForUse;
  75. }
  76. /**
  77. * Return whether the SQL can be used as is.
  78. */
  79. public boolean isSqlReadyForUse() {
  80. return sqlReadyForUse;
  81. }
  82. /**
  83. * Return a CallableStatementCreator to perform an operation
  84. * with this parameters.
  85. * @param inParams parameters. May be null.
  86. */
  87. protected CallableStatementCreator newCallableStatementCreator(Map inParams) {
  88. return this.callableStatementFactory.newCallableStatementCreator(inParams);
  89. }
  90. /**
  91. * Return a CallableStatementCreator to perform an operation
  92. * with the parameters returned from this ParameterMapper.
  93. * @param inParamMapper parametermapper. May not be null.
  94. */
  95. protected CallableStatementCreator newCallableStatementCreator(ParameterMapper inParamMapper) {
  96. return this.callableStatementFactory.newCallableStatementCreator(inParamMapper);
  97. }
  98. /**
  99. * Overridden method to configure the CallableStatementCreatorFactory
  100. * based on our declared parameters.
  101. * @see RdbmsOperation#compileInternal()
  102. */
  103. protected final void compileInternal() {
  104. if (isSqlReadyForUse()) {
  105. this.callString = getSql();
  106. }
  107. else {
  108. List parameters = getDeclaredParameters();
  109. int firstParameter = 0;
  110. if (isFunction()) {
  111. this.callString = "{? = call " + getSql() + "(";
  112. firstParameter = 1;
  113. }
  114. else {
  115. this.callString = "{call " + getSql() + "(";
  116. }
  117. for (int i = firstParameter; i < parameters.size(); i++) {
  118. SqlParameter p = (SqlParameter) parameters.get(i);
  119. if ((p instanceof SqlReturnResultSet)) {
  120. firstParameter++;
  121. }
  122. else {
  123. if (i > firstParameter) {
  124. this.callString += ", ";
  125. }
  126. this.callString += "?";
  127. }
  128. }
  129. this.callString += ")}";
  130. }
  131. if (logger.isInfoEnabled()) {
  132. logger.info("Compiled stored procedure. Call string is [" + getCallString() + "]");
  133. }
  134. this.callableStatementFactory = new CallableStatementCreatorFactory(getCallString(), getDeclaredParameters());
  135. onCompileInternal();
  136. }
  137. /**
  138. * Get the call string.
  139. */
  140. public String getCallString() {
  141. return this.callString;
  142. }
  143. /**
  144. * Hook method that subclasses may override to react to compilation.
  145. * This implementation does nothing.
  146. */
  147. protected void onCompileInternal() {
  148. }
  149. }