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 }