1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements.  See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License.  You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */

17 package org.apache.tomcat.util.digester;
18
19 import org.xml.sax.Attributes;
20
21 /**
22  * <p>Rule implementation that saves a parameter for use by a surrounding
23  * <code>CallMethodRule</code>.</p>
24  *
25  * <p>This parameter may be:</p>
26  * <ul>
27  * <li>from an attribute of the current element
28  * See {@link #CallParamRule(int paramIndex, String attributeName)}
29  * <li>from current the element body
30  * See {@link #CallParamRule(int paramIndex)}
31  * </ul>
32  */

33 public class CallParamRule extends Rule {
34
35     // ----------------------------------------------------------- Constructors
36
37     /**
38      * Construct a "call parameter" rule that will save the body text of this
39      * element as the parameter value.
40      *
41      * @param paramIndex The zero-relative parameter number
42      */

43     public CallParamRule(int paramIndex) {
44         this(paramIndex, null);
45     }
46
47
48     /**
49      * Construct a "call parameter" rule that will save the value of the
50      * specified attribute as the parameter value.
51      *
52      * @param paramIndex The zero-relative parameter number
53      * @param attributeName The name of the attribute to save
54      */

55     public CallParamRule(int paramIndex,
56                          String attributeName) {
57         this(attributeName, paramIndex, 0, false);
58     }
59
60
61     private CallParamRule(String attributeName, int paramIndex, int stackIndex,
62             boolean fromStack) {
63         this.attributeName = attributeName;
64         this.paramIndex = paramIndex;
65         this.stackIndex = stackIndex;
66         this.fromStack = fromStack;
67     }
68
69
70     // ----------------------------------------------------- Instance Variables
71
72
73     /**
74      * The attribute from which to save the parameter value
75      */

76     protected final String attributeName;
77
78
79     /**
80      * The zero-relative index of the parameter we are saving.
81      */

82     protected final int paramIndex;
83
84
85     /**
86      * Is the parameter to be set from the stack?
87      */

88     protected final boolean fromStack;
89
90     /**
91      * The position of the object from the top of the stack
92      */

93     protected final int stackIndex;
94
95     /**
96      * Stack is used to allow nested body text to be processed.
97      * Lazy creation.
98      */

99     protected ArrayStack<String> bodyTextStack;
100
101     // --------------------------------------------------------- Public Methods
102
103
104     /**
105      * Process the start of this element.
106      *
107      * @param namespace the namespace URI of the matching element, or an
108      *   empty string if the parser is not namespace aware or the element has
109      *   no namespace
110      * @param name the local name if the parser is namespace aware, or just
111      *   the element name otherwise
112      * @param attributes The attribute list for this element
113      */

114     @Override
115     public void begin(String namespace, String name, Attributes attributes)
116             throws Exception {
117
118         Object param = null;
119
120         if (attributeName != null) {
121
122             param = attributes.getValue(attributeName);
123
124         } else if(fromStack) {
125
126             param = digester.peek(stackIndex);
127
128             if (digester.log.isDebugEnabled()) {
129
130                 StringBuilder sb = new StringBuilder("[CallParamRule]{");
131                 sb.append(digester.match);
132                 sb.append("} Save from stack; from stack?").append(fromStack);
133                 sb.append("; object=").append(param);
134                 digester.log.debug(sb.toString());
135             }
136         }
137
138         // Have to save the param object to the param stack frame here.
139         // Can't wait until end(). Otherwise, the object will be lost.
140         // We can't save the object as instance variables, as
141         // the instance variables will be overwritten
142         // if this CallParamRule is reused in subsequent nesting.
143
144         if(param != null) {
145             Object parameters[] = (Object[]) digester.peekParams();
146             parameters[paramIndex] = param;
147         }
148     }
149
150
151     /**
152      * Process the body text of this element.
153      *
154      * @param namespace the namespace URI of the matching element, or an
155      *   empty string if the parser is not namespace aware or the element has
156      *   no namespace
157      * @param name the local name if the parser is namespace aware, or just
158      *   the element name otherwise
159      * @param bodyText The body text of this element
160      */

161     @Override
162     public void body(String namespace, String name, String bodyText)
163             throws Exception {
164
165         if (attributeName == null && !fromStack) {
166             // We must wait to set the parameter until end
167             // so that we can make sure that the right set of parameters
168             // is at the top of the stack
169             if (bodyTextStack == null) {
170                 bodyTextStack = new ArrayStack<>();
171             }
172             bodyTextStack.push(bodyText.trim());
173         }
174
175     }
176
177     /**
178      * Process any body texts now.
179      */

180     @Override
181     public void end(String namespace, String name) {
182         if (bodyTextStack != null && !bodyTextStack.empty()) {
183             // what we do now is push one parameter onto the top set of parameters
184             Object parameters[] = (Object[]) digester.peekParams();
185             parameters[paramIndex] = bodyTextStack.pop();
186         }
187     }
188
189     /**
190      * Render a printable version of this Rule.
191      */

192     @Override
193     public String toString() {
194         StringBuilder sb = new StringBuilder("CallParamRule[");
195         sb.append("paramIndex=");
196         sb.append(paramIndex);
197         sb.append(", attributeName=");
198         sb.append(attributeName);
199         sb.append(", from stack=");
200         sb.append(fromStack);
201         sb.append("]");
202         return sb.toString();
203     }
204
205
206 }
207