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