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 }