001: /*
002: * Copyright 1999,2004 The Apache Software Foundation.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package org.apache.jasper.runtime;
018:
019: import java.io.IOException;
020: import java.io.Writer;
021: import java.util.ArrayList;
022: import java.util.Enumeration;
023: import java.util.Hashtable;
024: import java.util.Iterator;
025: import java.util.Map;
026:
027: import javax.servlet.Servlet;
028: import javax.servlet.ServletConfig;
029: import javax.servlet.ServletContext;
030: import javax.servlet.ServletException;
031: import javax.servlet.ServletRequest;
032: import javax.servlet.ServletResponse;
033: import javax.servlet.http.HttpSession;
034: import javax.servlet.jsp.JspContext;
035: import javax.servlet.jsp.JspWriter;
036: import javax.servlet.jsp.PageContext;
037: import javax.servlet.jsp.el.ELException;
038: import javax.servlet.jsp.el.ExpressionEvaluator;
039: import javax.servlet.jsp.el.VariableResolver;
040: import javax.servlet.jsp.tagext.BodyContent;
041: import javax.servlet.jsp.tagext.VariableInfo;
042:
043: import org.apache.commons.el.VariableResolverImpl;
044: import org.apache.jasper.compiler.Localizer;
045:
046: /**
047: * Implementation of a JSP Context Wrapper.
048: *
049: * The JSP Context Wrapper is a JspContext created and maintained by a tag
050: * handler implementation. It wraps the Invoking JSP Context, that is, the
051: * JspContext instance passed to the tag handler by the invoking page via
052: * setJspContext().
053: *
054: * @author Kin-man Chung
055: * @author Jan Luehe
056: */
057: public class JspContextWrapper extends PageContext implements
058: VariableResolver {
059:
060: // Invoking JSP context
061: private PageContext invokingJspCtxt;
062:
063: private transient Hashtable pageAttributes;
064:
065: // ArrayList of NESTED scripting variables
066: private ArrayList nestedVars;
067:
068: // ArrayList of AT_BEGIN scripting variables
069: private ArrayList atBeginVars;
070:
071: // ArrayList of AT_END scripting variables
072: private ArrayList atEndVars;
073:
074: private Map aliases;
075:
076: private Hashtable originalNestedVars;
077:
078: /**
079: * The variable resolver, for evaluating EL expressions.
080: */
081: private VariableResolverImpl variableResolver = new VariableResolverImpl(
082: this );
083:
084: public JspContextWrapper(JspContext jspContext,
085: ArrayList nestedVars, ArrayList atBeginVars,
086: ArrayList atEndVars, Map aliases) {
087: this .invokingJspCtxt = (PageContext) jspContext;
088: this .nestedVars = nestedVars;
089: this .atBeginVars = atBeginVars;
090: this .atEndVars = atEndVars;
091: this .pageAttributes = new Hashtable(16);
092: this .aliases = aliases;
093:
094: if (nestedVars != null) {
095: this .originalNestedVars = new Hashtable(nestedVars.size());
096: }
097: syncBeginTagFile();
098: }
099:
100: public void initialize(Servlet servlet, ServletRequest request,
101: ServletResponse response, String errorPageURL,
102: boolean needsSession, int bufferSize, boolean autoFlush)
103: throws IOException, IllegalStateException,
104: IllegalArgumentException {
105: }
106:
107: public Object getAttribute(String name) {
108:
109: if (name == null) {
110: throw new NullPointerException(Localizer
111: .getMessage("jsp.error.attribute.null_name"));
112: }
113:
114: return pageAttributes.get(name);
115: }
116:
117: public Object getAttribute(String name, int scope) {
118:
119: if (name == null) {
120: throw new NullPointerException(Localizer
121: .getMessage("jsp.error.attribute.null_name"));
122: }
123:
124: if (scope == PAGE_SCOPE) {
125: return pageAttributes.get(name);
126: }
127:
128: return invokingJspCtxt.getAttribute(name, scope);
129: }
130:
131: public void setAttribute(String name, Object value) {
132:
133: if (name == null) {
134: throw new NullPointerException(Localizer
135: .getMessage("jsp.error.attribute.null_name"));
136: }
137:
138: if (value != null) {
139: pageAttributes.put(name, value);
140: } else {
141: removeAttribute(name, PAGE_SCOPE);
142: }
143: }
144:
145: public void setAttribute(String name, Object value, int scope) {
146:
147: if (name == null) {
148: throw new NullPointerException(Localizer
149: .getMessage("jsp.error.attribute.null_name"));
150: }
151:
152: if (scope == PAGE_SCOPE) {
153: if (value != null) {
154: pageAttributes.put(name, value);
155: } else {
156: removeAttribute(name, PAGE_SCOPE);
157: }
158: } else {
159: invokingJspCtxt.setAttribute(name, value, scope);
160: }
161: }
162:
163: public Object findAttribute(String name) {
164:
165: if (name == null) {
166: throw new NullPointerException(Localizer
167: .getMessage("jsp.error.attribute.null_name"));
168: }
169:
170: Object o = pageAttributes.get(name);
171: if (o == null) {
172: o = invokingJspCtxt.getAttribute(name, REQUEST_SCOPE);
173: if (o == null) {
174: if (getSession() != null) {
175: o = invokingJspCtxt.getAttribute(name,
176: SESSION_SCOPE);
177: }
178: if (o == null) {
179: o = invokingJspCtxt.getAttribute(name,
180: APPLICATION_SCOPE);
181: }
182: }
183: }
184:
185: return o;
186: }
187:
188: public void removeAttribute(String name) {
189:
190: if (name == null) {
191: throw new NullPointerException(Localizer
192: .getMessage("jsp.error.attribute.null_name"));
193: }
194:
195: pageAttributes.remove(name);
196: invokingJspCtxt.removeAttribute(name, REQUEST_SCOPE);
197: if (getSession() != null) {
198: invokingJspCtxt.removeAttribute(name, SESSION_SCOPE);
199: }
200: invokingJspCtxt.removeAttribute(name, APPLICATION_SCOPE);
201: }
202:
203: public void removeAttribute(String name, int scope) {
204:
205: if (name == null) {
206: throw new NullPointerException(Localizer
207: .getMessage("jsp.error.attribute.null_name"));
208: }
209:
210: if (scope == PAGE_SCOPE) {
211: pageAttributes.remove(name);
212: } else {
213: invokingJspCtxt.removeAttribute(name, scope);
214: }
215: }
216:
217: public int getAttributesScope(String name) {
218:
219: if (name == null) {
220: throw new NullPointerException(Localizer
221: .getMessage("jsp.error.attribute.null_name"));
222: }
223:
224: if (pageAttributes.get(name) != null) {
225: return PAGE_SCOPE;
226: } else {
227: return invokingJspCtxt.getAttributesScope(name);
228: }
229: }
230:
231: public Enumeration getAttributeNamesInScope(int scope) {
232: if (scope == PAGE_SCOPE) {
233: return pageAttributes.keys();
234: }
235:
236: return invokingJspCtxt.getAttributeNamesInScope(scope);
237: }
238:
239: public void release() {
240: invokingJspCtxt.release();
241: }
242:
243: public JspWriter getOut() {
244: return invokingJspCtxt.getOut();
245: }
246:
247: public HttpSession getSession() {
248: return invokingJspCtxt.getSession();
249: }
250:
251: public Object getPage() {
252: return invokingJspCtxt.getPage();
253: }
254:
255: public ServletRequest getRequest() {
256: return invokingJspCtxt.getRequest();
257: }
258:
259: public ServletResponse getResponse() {
260: return invokingJspCtxt.getResponse();
261: }
262:
263: public Exception getException() {
264: return invokingJspCtxt.getException();
265: }
266:
267: public ServletConfig getServletConfig() {
268: return invokingJspCtxt.getServletConfig();
269: }
270:
271: public ServletContext getServletContext() {
272: return invokingJspCtxt.getServletContext();
273: }
274:
275: public void forward(String relativeUrlPath)
276: throws ServletException, IOException {
277: invokingJspCtxt.forward(relativeUrlPath);
278: }
279:
280: public void include(String relativeUrlPath)
281: throws ServletException, IOException {
282: invokingJspCtxt.include(relativeUrlPath);
283: }
284:
285: public void include(String relativeUrlPath, boolean flush)
286: throws ServletException, IOException {
287: include(relativeUrlPath, false); // XXX
288: }
289:
290: public VariableResolver getVariableResolver() {
291: return this ;
292: }
293:
294: public BodyContent pushBody() {
295: return invokingJspCtxt.pushBody();
296: }
297:
298: public JspWriter pushBody(Writer writer) {
299: return invokingJspCtxt.pushBody(writer);
300: }
301:
302: public JspWriter popBody() {
303: return invokingJspCtxt.popBody();
304: }
305:
306: public ExpressionEvaluator getExpressionEvaluator() {
307: return invokingJspCtxt.getExpressionEvaluator();
308: }
309:
310: public void handlePageException(Exception ex) throws IOException,
311: ServletException {
312: // Should never be called since handleException() called with a
313: // Throwable in the generated servlet.
314: handlePageException((Throwable) ex);
315: }
316:
317: public void handlePageException(Throwable t) throws IOException,
318: ServletException {
319: invokingJspCtxt.handlePageException(t);
320: }
321:
322: /**
323: * VariableResolver interface
324: */
325: public Object resolveVariable(String pName) throws ELException {
326: return variableResolver.resolveVariable(pName);
327: }
328:
329: /**
330: * Synchronize variables at begin of tag file
331: */
332: public void syncBeginTagFile() {
333: saveNestedVariables();
334: }
335:
336: /**
337: * Synchronize variables before fragment invokation
338: */
339: public void syncBeforeInvoke() {
340: copyTagToPageScope(VariableInfo.NESTED);
341: copyTagToPageScope(VariableInfo.AT_BEGIN);
342: }
343:
344: /**
345: * Synchronize variables at end of tag file
346: */
347: public void syncEndTagFile() {
348: copyTagToPageScope(VariableInfo.AT_BEGIN);
349: copyTagToPageScope(VariableInfo.AT_END);
350: restoreNestedVariables();
351: }
352:
353: /**
354: * Copies the variables of the given scope from the virtual page scope of
355: * this JSP context wrapper to the page scope of the invoking JSP context.
356: *
357: * @param scope variable scope (one of NESTED, AT_BEGIN, or AT_END)
358: */
359: private void copyTagToPageScope(int scope) {
360: Iterator iter = null;
361:
362: switch (scope) {
363: case VariableInfo.NESTED:
364: if (nestedVars != null) {
365: iter = nestedVars.iterator();
366: }
367: break;
368: case VariableInfo.AT_BEGIN:
369: if (atBeginVars != null) {
370: iter = atBeginVars.iterator();
371: }
372: break;
373: case VariableInfo.AT_END:
374: if (atEndVars != null) {
375: iter = atEndVars.iterator();
376: }
377: break;
378: }
379:
380: while ((iter != null) && iter.hasNext()) {
381: String varName = (String) iter.next();
382: Object obj = getAttribute(varName);
383: varName = findAlias(varName);
384: if (obj != null) {
385: invokingJspCtxt.setAttribute(varName, obj);
386: } else {
387: invokingJspCtxt.removeAttribute(varName, PAGE_SCOPE);
388: }
389: }
390: }
391:
392: /**
393: * Saves the values of any NESTED variables that are present in
394: * the invoking JSP context, so they can later be restored.
395: */
396: private void saveNestedVariables() {
397: if (nestedVars != null) {
398: Iterator iter = nestedVars.iterator();
399: while (iter.hasNext()) {
400: String varName = (String) iter.next();
401: varName = findAlias(varName);
402: Object obj = invokingJspCtxt.getAttribute(varName);
403: if (obj != null) {
404: originalNestedVars.put(varName, obj);
405: }
406: }
407: }
408: }
409:
410: /**
411: * Restores the values of any NESTED variables in the invoking JSP
412: * context.
413: */
414: private void restoreNestedVariables() {
415: if (nestedVars != null) {
416: Iterator iter = nestedVars.iterator();
417: while (iter.hasNext()) {
418: String varName = (String) iter.next();
419: varName = findAlias(varName);
420: Object obj = originalNestedVars.get(varName);
421: if (obj != null) {
422: invokingJspCtxt.setAttribute(varName, obj);
423: } else {
424: invokingJspCtxt
425: .removeAttribute(varName, PAGE_SCOPE);
426: }
427: }
428: }
429: }
430:
431: /**
432: * Checks to see if the given variable name is used as an alias, and if so,
433: * returns the variable name for which it is used as an alias.
434: *
435: * @param varName The variable name to check
436: * @return The variable name for which varName is used as an alias, or
437: * varName if it is not being used as an alias
438: */
439: private String findAlias(String varName) {
440:
441: if (aliases == null)
442: return varName;
443:
444: String alias = (String) aliases.get(varName);
445: if (alias == null) {
446: return varName;
447: }
448: return alias;
449: }
450: }
|