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    }