001: /* $Id: CallParamRule.java 471661 2006-11-06 08:09:25Z skitching $
002: *
003: * Licensed to the Apache Software Foundation (ASF) under one or more
004: * contributor license agreements. See the NOTICE file distributed with
005: * this work for additional information regarding copyright ownership.
006: * The ASF licenses this file to You under the Apache License, Version 2.0
007: * (the "License"); you may not use this file except in compliance with
008: * the License. You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing, software
013: * distributed under the License is distributed on an "AS IS" BASIS,
014: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015: * See the License for the specific language governing permissions and
016: * limitations under the License.
017: */
018:
019: package org.apache.commons.digester;
020:
021: import org.xml.sax.Attributes;
022:
023: import org.apache.commons.collections.ArrayStack;
024:
025: /**
026: * <p>Rule implementation that saves a parameter for use by a surrounding
027: * <code>CallMethodRule<code>.</p>
028: *
029: * <p>This parameter may be:
030: * <ul>
031: * <li>from an attribute of the current element
032: * See {@link #CallParamRule(int paramIndex, String attributeName)}
033: * <li>from current the element body
034: * See {@link #CallParamRule(int paramIndex)}
035: * <li>from the top object on the stack.
036: * See {@link #CallParamRule(int paramIndex, boolean fromStack)}
037: * <li>the current path being processed (separate <code>Rule</code>).
038: * See {@link PathCallParamRule}
039: * </ul>
040: * </p>
041: */
042:
043: public class CallParamRule extends Rule {
044:
045: // ----------------------------------------------------------- Constructors
046:
047: /**
048: * Construct a "call parameter" rule that will save the body text of this
049: * element as the parameter value.
050: *
051: * <p>Note that if the element is empty the an <i>empty string</i> is
052: * passed to the target method, not null. And if automatic type conversion
053: * is being applied (ie if the target function takes something other than
054: * a string as a parameter) then the conversion will fail if the converter
055: * class does not accept an empty string as valid input.</p>
056: *
057: * @param digester The associated Digester
058: * @param paramIndex The zero-relative parameter number
059: *
060: * @deprecated The digester instance is now set in the {@link Digester#addRule} method.
061: * Use {@link #CallParamRule(int paramIndex)} instead.
062: */
063: public CallParamRule(Digester digester, int paramIndex) {
064:
065: this (paramIndex);
066:
067: }
068:
069: /**
070: * Construct a "call parameter" rule that will save the value of the
071: * specified attribute as the parameter value.
072: *
073: * @param digester The associated Digester
074: * @param paramIndex The zero-relative parameter number
075: * @param attributeName The name of the attribute to save
076: *
077: * @deprecated The digester instance is now set in the {@link Digester#addRule} method.
078: * Use {@link #CallParamRule(int paramIndex, String attributeName)} instead.
079: */
080: public CallParamRule(Digester digester, int paramIndex,
081: String attributeName) {
082:
083: this (paramIndex, attributeName);
084:
085: }
086:
087: /**
088: * Construct a "call parameter" rule that will save the body text of this
089: * element as the parameter value.
090: *
091: * <p>Note that if the element is empty the an <i>empty string</i> is
092: * passed to the target method, not null. And if automatic type conversion
093: * is being applied (ie if the target function takes something other than
094: * a string as a parameter) then the conversion will fail if the converter
095: * class does not accept an empty string as valid input.</p>
096: *
097: * @param paramIndex The zero-relative parameter number
098: */
099: public CallParamRule(int paramIndex) {
100:
101: this (paramIndex, null);
102:
103: }
104:
105: /**
106: * Construct a "call parameter" rule that will save the value of the
107: * specified attribute as the parameter value.
108: *
109: * @param paramIndex The zero-relative parameter number
110: * @param attributeName The name of the attribute to save
111: */
112: public CallParamRule(int paramIndex, String attributeName) {
113:
114: this .paramIndex = paramIndex;
115: this .attributeName = attributeName;
116:
117: }
118:
119: /**
120: * Construct a "call parameter" rule.
121: *
122: * @param paramIndex The zero-relative parameter number
123: * @param fromStack should this parameter be taken from the top of the stack?
124: */
125: public CallParamRule(int paramIndex, boolean fromStack) {
126:
127: this .paramIndex = paramIndex;
128: this .fromStack = fromStack;
129:
130: }
131:
132: /**
133: * Constructs a "call parameter" rule which sets a parameter from the stack.
134: * If the stack contains too few objects, then the parameter will be set to null.
135: *
136: * @param paramIndex The zero-relative parameter number
137: * @param stackIndex the index of the object which will be passed as a parameter.
138: * The zeroth object is the top of the stack, 1 is the next object down and so on.
139: */
140: public CallParamRule(int paramIndex, int stackIndex) {
141:
142: this .paramIndex = paramIndex;
143: this .fromStack = true;
144: this .stackIndex = stackIndex;
145: }
146:
147: // ----------------------------------------------------- Instance Variables
148:
149: /**
150: * The attribute from which to save the parameter value
151: */
152: protected String attributeName = null;
153:
154: /**
155: * The zero-relative index of the parameter we are saving.
156: */
157: protected int paramIndex = 0;
158:
159: /**
160: * Is the parameter to be set from the stack?
161: */
162: protected boolean fromStack = false;
163:
164: /**
165: * The position of the object from the top of the stack
166: */
167: protected int stackIndex = 0;
168:
169: /**
170: * Stack is used to allow nested body text to be processed.
171: * Lazy creation.
172: */
173: protected ArrayStack bodyTextStack;
174:
175: // --------------------------------------------------------- Public Methods
176:
177: /**
178: * Process the start of this element.
179: *
180: * @param attributes The attribute list for this element
181: */
182: public void begin(Attributes attributes) throws Exception {
183:
184: Object param = null;
185:
186: if (attributeName != null) {
187:
188: param = attributes.getValue(attributeName);
189:
190: } else if (fromStack) {
191:
192: param = digester.peek(stackIndex);
193:
194: if (digester.log.isDebugEnabled()) {
195:
196: StringBuffer sb = new StringBuffer("[CallParamRule]{");
197: sb.append(digester.match);
198: sb.append("} Save from stack; from stack?").append(
199: fromStack);
200: sb.append("; object=").append(param);
201: digester.log.debug(sb.toString());
202: }
203: }
204:
205: // Have to save the param object to the param stack frame here.
206: // Can't wait until end(). Otherwise, the object will be lost.
207: // We can't save the object as instance variables, as
208: // the instance variables will be overwritten
209: // if this CallParamRule is reused in subsequent nesting.
210:
211: if (param != null) {
212: Object parameters[] = (Object[]) digester.peekParams();
213: parameters[paramIndex] = param;
214: }
215: }
216:
217: /**
218: * Process the body text of this element.
219: *
220: * @param bodyText The body text of this element
221: */
222: public void body(String bodyText) throws Exception {
223:
224: if (attributeName == null && !fromStack) {
225: // We must wait to set the parameter until end
226: // so that we can make sure that the right set of parameters
227: // is at the top of the stack
228: if (bodyTextStack == null) {
229: bodyTextStack = new ArrayStack();
230: }
231: bodyTextStack.push(bodyText.trim());
232: }
233:
234: }
235:
236: /**
237: * Process any body texts now.
238: */
239: public void end(String namespace, String name) {
240: if (bodyTextStack != null && !bodyTextStack.empty()) {
241: // what we do now is push one parameter onto the top set of parameters
242: Object parameters[] = (Object[]) digester.peekParams();
243: parameters[paramIndex] = bodyTextStack.pop();
244: }
245: }
246:
247: /**
248: * Render a printable version of this Rule.
249: */
250: public String toString() {
251:
252: StringBuffer sb = new StringBuffer("CallParamRule[");
253: sb.append("paramIndex=");
254: sb.append(paramIndex);
255: sb.append(", attributeName=");
256: sb.append(attributeName);
257: sb.append(", from stack=");
258: sb.append(fromStack);
259: sb.append("]");
260: return (sb.toString());
261:
262: }
263:
264: }
|