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    }