1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.struts2.jasper.runtime;
19
20 import org.apache.commons.el.VariableResolverImpl;
21 import org.apache.struts2.jasper.compiler.Localizer;
22
23 import javax.servlet.*;
24 import javax.servlet.http.HttpSession;
25 import javax.servlet.jsp.JspContext;
26 import javax.servlet.jsp.JspWriter;
27 import javax.servlet.jsp.PageContext;
28 import javax.servlet.jsp.el.ELException;
29 import javax.servlet.jsp.el.ExpressionEvaluator;
30 import javax.servlet.jsp.el.VariableResolver;
31 import javax.servlet.jsp.tagext.BodyContent;
32 import javax.servlet.jsp.tagext.VariableInfo;
33 import java.io.IOException;
34 import java.io.Writer;
35 import java.util.*;
36
37 /***
38 * Implementation of a JSP Context Wrapper.
39 * <p/>
40 * The JSP Context Wrapper is a JspContext created and maintained by a tag
41 * handler implementation. It wraps the Invoking JSP Context, that is, the
42 * JspContext instance passed to the tag handler by the invoking page via
43 * setJspContext().
44 *
45 * @author Kin-man Chung
46 * @author Jan Luehe
47 */
48 public class JspContextWrapper
49 extends PageContext implements VariableResolver {
50
51
52 private PageContext invokingJspCtxt;
53
54 private transient Hashtable pageAttributes;
55
56
57 private ArrayList nestedVars;
58
59
60 private ArrayList atBeginVars;
61
62
63 private ArrayList atEndVars;
64
65 private Map aliases;
66
67 private Hashtable originalNestedVars;
68
69 /***
70 * The variable resolver, for evaluating EL expressions.
71 */
72 private VariableResolverImpl variableResolver
73 = new VariableResolverImpl(this);
74
75 public JspContextWrapper(JspContext jspContext, ArrayList nestedVars,
76 ArrayList atBeginVars, ArrayList atEndVars,
77 Map aliases) {
78 this.invokingJspCtxt = (PageContext) jspContext;
79 this.nestedVars = nestedVars;
80 this.atBeginVars = atBeginVars;
81 this.atEndVars = atEndVars;
82 this.pageAttributes = new Hashtable(16);
83 this.aliases = aliases;
84
85 if (nestedVars != null) {
86 this.originalNestedVars = new Hashtable(nestedVars.size());
87 }
88 syncBeginTagFile();
89 }
90
91 public void initialize(Servlet servlet, ServletRequest request,
92 ServletResponse response, String errorPageURL,
93 boolean needsSession, int bufferSize,
94 boolean autoFlush)
95 throws IOException, IllegalStateException, IllegalArgumentException {
96 }
97
98 public Object getAttribute(String name) {
99
100 if (name == null) {
101 throw new NullPointerException(
102 Localizer.getMessage("jsp.error.attribute.null_name"));
103 }
104
105 return pageAttributes.get(name);
106 }
107
108 public Object getAttribute(String name, int scope) {
109
110 if (name == null) {
111 throw new NullPointerException(
112 Localizer.getMessage("jsp.error.attribute.null_name"));
113 }
114
115 if (scope == PAGE_SCOPE) {
116 return pageAttributes.get(name);
117 }
118
119 return invokingJspCtxt.getAttribute(name, scope);
120 }
121
122 public void setAttribute(String name, Object value) {
123
124 if (name == null) {
125 throw new NullPointerException(
126 Localizer.getMessage("jsp.error.attribute.null_name"));
127 }
128
129 if (value != null) {
130 pageAttributes.put(name, value);
131 } else {
132 removeAttribute(name, PAGE_SCOPE);
133 }
134 }
135
136 public void setAttribute(String name, Object value, int scope) {
137
138 if (name == null) {
139 throw new NullPointerException(
140 Localizer.getMessage("jsp.error.attribute.null_name"));
141 }
142
143 if (scope == PAGE_SCOPE) {
144 if (value != null) {
145 pageAttributes.put(name, value);
146 } else {
147 removeAttribute(name, PAGE_SCOPE);
148 }
149 } else {
150 invokingJspCtxt.setAttribute(name, value, scope);
151 }
152 }
153
154 public Object findAttribute(String name) {
155
156 if (name == null) {
157 throw new NullPointerException(
158 Localizer.getMessage("jsp.error.attribute.null_name"));
159 }
160
161 Object o = pageAttributes.get(name);
162 if (o == null) {
163 o = invokingJspCtxt.getAttribute(name, REQUEST_SCOPE);
164 if (o == null) {
165 if (getSession() != null) {
166 o = invokingJspCtxt.getAttribute(name, SESSION_SCOPE);
167 }
168 if (o == null) {
169 o = invokingJspCtxt.getAttribute(name, APPLICATION_SCOPE);
170 }
171 }
172 }
173
174 return o;
175 }
176
177 public void removeAttribute(String name) {
178
179 if (name == null) {
180 throw new NullPointerException(
181 Localizer.getMessage("jsp.error.attribute.null_name"));
182 }
183
184 pageAttributes.remove(name);
185 invokingJspCtxt.removeAttribute(name, REQUEST_SCOPE);
186 if (getSession() != null) {
187 invokingJspCtxt.removeAttribute(name, SESSION_SCOPE);
188 }
189 invokingJspCtxt.removeAttribute(name, APPLICATION_SCOPE);
190 }
191
192 public void removeAttribute(String name, int scope) {
193
194 if (name == null) {
195 throw new NullPointerException(
196 Localizer.getMessage("jsp.error.attribute.null_name"));
197 }
198
199 if (scope == PAGE_SCOPE) {
200 pageAttributes.remove(name);
201 } else {
202 invokingJspCtxt.removeAttribute(name, scope);
203 }
204 }
205
206 public int getAttributesScope(String name) {
207
208 if (name == null) {
209 throw new NullPointerException(
210 Localizer.getMessage("jsp.error.attribute.null_name"));
211 }
212
213 if (pageAttributes.get(name) != null) {
214 return PAGE_SCOPE;
215 } else {
216 return invokingJspCtxt.getAttributesScope(name);
217 }
218 }
219
220 public Enumeration getAttributeNamesInScope(int scope) {
221 if (scope == PAGE_SCOPE) {
222 return pageAttributes.keys();
223 }
224
225 return invokingJspCtxt.getAttributeNamesInScope(scope);
226 }
227
228 public void release() {
229 invokingJspCtxt.release();
230 }
231
232 public JspWriter getOut() {
233 return invokingJspCtxt.getOut();
234 }
235
236 public HttpSession getSession() {
237 return invokingJspCtxt.getSession();
238 }
239
240 public Object getPage() {
241 return invokingJspCtxt.getPage();
242 }
243
244 public ServletRequest getRequest() {
245 return invokingJspCtxt.getRequest();
246 }
247
248 public ServletResponse getResponse() {
249 return invokingJspCtxt.getResponse();
250 }
251
252 public Exception getException() {
253 return invokingJspCtxt.getException();
254 }
255
256 public ServletConfig getServletConfig() {
257 return invokingJspCtxt.getServletConfig();
258 }
259
260 public ServletContext getServletContext() {
261 return invokingJspCtxt.getServletContext();
262 }
263
264 public void forward(String relativeUrlPath)
265 throws ServletException, IOException {
266 invokingJspCtxt.forward(relativeUrlPath);
267 }
268
269 public void include(String relativeUrlPath)
270 throws ServletException, IOException {
271 invokingJspCtxt.include(relativeUrlPath);
272 }
273
274 public void include(String relativeUrlPath, boolean flush)
275 throws ServletException, IOException {
276 include(relativeUrlPath, false);
277 }
278
279 public VariableResolver getVariableResolver() {
280 return this;
281 }
282
283 public BodyContent pushBody() {
284 return invokingJspCtxt.pushBody();
285 }
286
287 public JspWriter pushBody(Writer writer) {
288 return invokingJspCtxt.pushBody(writer);
289 }
290
291 public JspWriter popBody() {
292 return invokingJspCtxt.popBody();
293 }
294
295 public ExpressionEvaluator getExpressionEvaluator() {
296 return invokingJspCtxt.getExpressionEvaluator();
297 }
298
299 public void handlePageException(Exception ex)
300 throws IOException, ServletException {
301
302
303 handlePageException((Throwable) ex);
304 }
305
306 public void handlePageException(Throwable t)
307 throws IOException, ServletException {
308 invokingJspCtxt.handlePageException(t);
309 }
310
311 /***
312 * VariableResolver interface
313 */
314 public Object resolveVariable(String pName) throws ELException {
315 return variableResolver.resolveVariable(pName);
316 }
317
318 /***
319 * Synchronize variables at begin of tag file
320 */
321 public void syncBeginTagFile() {
322 saveNestedVariables();
323 }
324
325 /***
326 * Synchronize variables before fragment invokation
327 */
328 public void syncBeforeInvoke() {
329 copyTagToPageScope(VariableInfo.NESTED);
330 copyTagToPageScope(VariableInfo.AT_BEGIN);
331 }
332
333 /***
334 * Synchronize variables at end of tag file
335 */
336 public void syncEndTagFile() {
337 copyTagToPageScope(VariableInfo.AT_BEGIN);
338 copyTagToPageScope(VariableInfo.AT_END);
339 restoreNestedVariables();
340 }
341
342 /***
343 * Copies the variables of the given scope from the virtual page scope of
344 * this JSP context wrapper to the page scope of the invoking JSP context.
345 *
346 * @param scope variable scope (one of NESTED, AT_BEGIN, or AT_END)
347 */
348 private void copyTagToPageScope(int scope) {
349 Iterator iter = null;
350
351 switch (scope) {
352 case VariableInfo.NESTED:
353 if (nestedVars != null) {
354 iter = nestedVars.iterator();
355 }
356 break;
357 case VariableInfo.AT_BEGIN:
358 if (atBeginVars != null) {
359 iter = atBeginVars.iterator();
360 }
361 break;
362 case VariableInfo.AT_END:
363 if (atEndVars != null) {
364 iter = atEndVars.iterator();
365 }
366 break;
367 }
368
369 while ((iter != null) && iter.hasNext()) {
370 String varName = (String) iter.next();
371 Object obj = getAttribute(varName);
372 varName = findAlias(varName);
373 if (obj != null) {
374 invokingJspCtxt.setAttribute(varName, obj);
375 } else {
376 invokingJspCtxt.removeAttribute(varName, PAGE_SCOPE);
377 }
378 }
379 }
380
381 /***
382 * Saves the values of any NESTED variables that are present in
383 * the invoking JSP context, so they can later be restored.
384 */
385 private void saveNestedVariables() {
386 if (nestedVars != null) {
387 Iterator iter = nestedVars.iterator();
388 while (iter.hasNext()) {
389 String varName = (String) iter.next();
390 varName = findAlias(varName);
391 Object obj = invokingJspCtxt.getAttribute(varName);
392 if (obj != null) {
393 originalNestedVars.put(varName, obj);
394 }
395 }
396 }
397 }
398
399 /***
400 * Restores the values of any NESTED variables in the invoking JSP
401 * context.
402 */
403 private void restoreNestedVariables() {
404 if (nestedVars != null) {
405 Iterator iter = nestedVars.iterator();
406 while (iter.hasNext()) {
407 String varName = (String) iter.next();
408 varName = findAlias(varName);
409 Object obj = originalNestedVars.get(varName);
410 if (obj != null) {
411 invokingJspCtxt.setAttribute(varName, obj);
412 } else {
413 invokingJspCtxt.removeAttribute(varName, PAGE_SCOPE);
414 }
415 }
416 }
417 }
418
419 /***
420 * Checks to see if the given variable name is used as an alias, and if so,
421 * returns the variable name for which it is used as an alias.
422 *
423 * @param varName The variable name to check
424 * @return The variable name for which varName is used as an alias, or
425 * varName if it is not being used as an alias
426 */
427 private String findAlias(String varName) {
428
429 if (aliases == null)
430 return varName;
431
432 String alias = (String) aliases.get(varName);
433 if (alias == null) {
434 return varName;
435 }
436 return alias;
437 }
438 }
439