    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    }