1. /* $Id: CallParamRule.java,v 1.21.2.1 2004/07/30 20:11:00 rdonkin Exp $
  2. *
  3. * Copyright 2001-2004 The Apache Software Foundation.
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. */
  17. package org.apache.commons.digester;
  18. import org.xml.sax.Attributes;
  19. import org.apache.commons.collections.ArrayStack;
  20. /**
  21. * <p>Rule implementation that saves a parameter for use by a surrounding
  22. * <code>CallMethodRule<code>.</p>
  23. *
  24. * <p>This parameter may be:
  25. * <ul>
  26. * <li>from an attribute of the current element
  27. * See {@link #CallParamRule(int paramIndex, String attributeName)}
  28. * <li>from current the element body
  29. * See {@link #CallParamRule(int paramIndex)}
  30. * <li>from the top object on the stack.
  31. * See {@link #CallParamRule(int paramIndex, boolean fromStack)}
  32. * <li>the current path being processed (separate <code>Rule</code>).
  33. * See {@link PathCallParamRule}
  34. * </ul>
  35. * </p>
  36. */
  37. public class CallParamRule extends Rule {
  38. // ----------------------------------------------------------- Constructors
  39. /**
  40. * Construct a "call parameter" rule that will save the body text of this
  41. * element as the parameter value.
  42. *
  43. * @param digester The associated Digester
  44. * @param paramIndex The zero-relative parameter number
  45. *
  46. * @deprecated The digester instance is now set in the {@link Digester#addRule} method.
  47. * Use {@link #CallParamRule(int paramIndex)} instead.
  48. */
  49. public CallParamRule(Digester digester, int paramIndex) {
  50. this(paramIndex);
  51. }
  52. /**
  53. * Construct a "call parameter" rule that will save the value of the
  54. * specified attribute as the parameter value.
  55. *
  56. * @param digester The associated Digester
  57. * @param paramIndex The zero-relative parameter number
  58. * @param attributeName The name of the attribute to save
  59. *
  60. * @deprecated The digester instance is now set in the {@link Digester#addRule} method.
  61. * Use {@link #CallParamRule(int paramIndex, String attributeName)} instead.
  62. */
  63. public CallParamRule(Digester digester, int paramIndex,
  64. String attributeName) {
  65. this(paramIndex, attributeName);
  66. }
  67. /**
  68. * Construct a "call parameter" rule that will save the body text of this
  69. * element as the parameter value.
  70. *
  71. * @param paramIndex The zero-relative parameter number
  72. */
  73. public CallParamRule(int paramIndex) {
  74. this(paramIndex, null);
  75. }
  76. /**
  77. * Construct a "call parameter" rule that will save the value of the
  78. * specified attribute as the parameter value.
  79. *
  80. * @param paramIndex The zero-relative parameter number
  81. * @param attributeName The name of the attribute to save
  82. */
  83. public CallParamRule(int paramIndex,
  84. String attributeName) {
  85. this.paramIndex = paramIndex;
  86. this.attributeName = attributeName;
  87. }
  88. /**
  89. * Construct a "call parameter" rule.
  90. *
  91. * @param paramIndex The zero-relative parameter number
  92. * @param fromStack should this parameter be taken from the top of the stack?
  93. */
  94. public CallParamRule(int paramIndex, boolean fromStack) {
  95. this.paramIndex = paramIndex;
  96. this.fromStack = fromStack;
  97. }
  98. /**
  99. * Constructs a "call parameter" rule which sets a parameter from the stack.
  100. * If the stack contains too few objects, then the parameter will be set to null.
  101. *
  102. * @param paramIndex The zero-relative parameter number
  103. * @param stackIndex the index of the object which will be passed as a parameter.
  104. * The zeroth object is the top of the stack, 1 is the next object down and so on.
  105. */
  106. public CallParamRule(int paramIndex, int stackIndex) {
  107. this.paramIndex = paramIndex;
  108. this.fromStack = true;
  109. this.stackIndex = stackIndex;
  110. }
  111. // ----------------------------------------------------- Instance Variables
  112. /**
  113. * The attribute from which to save the parameter value
  114. */
  115. protected String attributeName = null;
  116. /**
  117. * The zero-relative index of the parameter we are saving.
  118. */
  119. protected int paramIndex = 0;
  120. /**
  121. * Is the parameter to be set from the stack?
  122. */
  123. protected boolean fromStack = false;
  124. /**
  125. * The position of the object from the top of the stack
  126. */
  127. protected int stackIndex = 0;
  128. /**
  129. * Stack is used to allow nested body text to be processed.
  130. * Lazy creation.
  131. */
  132. protected ArrayStack bodyTextStack;
  133. // --------------------------------------------------------- Public Methods
  134. /**
  135. * Process the start of this element.
  136. *
  137. * @param attributes The attribute list for this element
  138. */
  139. public void begin(Attributes attributes) throws Exception {
  140. Object param = null;
  141. if (attributeName != null) {
  142. param = attributes.getValue(attributeName);
  143. } else if(fromStack) {
  144. param = digester.peek(stackIndex);
  145. if (digester.log.isDebugEnabled()) {
  146. StringBuffer sb = new StringBuffer("[CallParamRule]{");
  147. sb.append(digester.match);
  148. sb.append("} Save from stack; from stack?").append(fromStack);
  149. sb.append("; object=").append(param);
  150. digester.log.debug(sb.toString());
  151. }
  152. }
  153. // Have to save the param object to the param stack frame here.
  154. // Can't wait until end(). Otherwise, the object will be lost.
  155. // We can't save the object as instance variables, as
  156. // the instance variables will be overwritten
  157. // if this CallParamRule is reused in subsequent nesting.
  158. if(param != null) {
  159. Object parameters[] = (Object[]) digester.peekParams();
  160. parameters[paramIndex] = param;
  161. }
  162. }
  163. /**
  164. * Process the body text of this element.
  165. *
  166. * @param bodyText The body text of this element
  167. */
  168. public void body(String bodyText) throws Exception {
  169. if (attributeName == null && !fromStack) {
  170. // We must wait to set the parameter until end
  171. // so that we can make sure that the right set of parameters
  172. // is at the top of the stack
  173. if (bodyTextStack == null) {
  174. bodyTextStack = new ArrayStack();
  175. }
  176. bodyTextStack.push(bodyText.trim());
  177. }
  178. }
  179. /**
  180. * Process any body texts now.
  181. */
  182. public void end(String namespace, String name) {
  183. if (bodyTextStack != null && !bodyTextStack.empty()) {
  184. // what we do now is push one parameter onto the top set of parameters
  185. Object parameters[] = (Object[]) digester.peekParams();
  186. parameters[paramIndex] = bodyTextStack.pop();
  187. }
  188. }
  189. /**
  190. * Render a printable version of this Rule.
  191. */
  192. public String toString() {
  193. StringBuffer sb = new StringBuffer("CallParamRule[");
  194. sb.append("paramIndex=");
  195. sb.append(paramIndex);
  196. sb.append(", attributeName=");
  197. sb.append(attributeName);
  198. sb.append(", from stack=");
  199. sb.append(fromStack);
  200. sb.append("]");
  201. return (sb.toString());
  202. }
  203. }