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