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