You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@struts.apache.org by mu...@apache.org on 2009/09/28 03:55:35 UTC
svn commit: r819444 [22/27] - in /struts/struts2/trunk/plugins/embeddedjsp:
./ src/main/java/org/apache/struts2/el/
src/main/java/org/apache/struts2/el/lang/
src/main/java/org/apache/struts2/el/parser/
src/main/java/org/apache/struts2/el/util/ src/main...
Added: struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/runtime/PageContextImpl.java
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/runtime/PageContextImpl.java?rev=819444&view=auto
==============================================================================
--- struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/runtime/PageContextImpl.java (added)
+++ struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/runtime/PageContextImpl.java Mon Sep 28 01:55:26 2009
@@ -0,0 +1,951 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.struts2.jasper.runtime;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.util.Enumeration;
+import java.util.HashMap;
+
+import javax.el.ELContext;
+import javax.el.ExpressionFactory;
+import javax.el.ValueExpression;
+import javax.servlet.Servlet;
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.JspFactory;
+import javax.servlet.jsp.JspWriter;
+import javax.servlet.jsp.PageContext;
+import javax.servlet.jsp.el.ELException;
+import javax.servlet.jsp.el.ExpressionEvaluator;
+import javax.servlet.jsp.el.VariableResolver;
+import javax.servlet.jsp.tagext.BodyContent;
+
+import org.apache.struts2.jasper.Constants;
+import org.apache.struts2.jasper.compiler.Localizer;
+import org.apache.struts2.jasper.el.ELContextImpl;
+import org.apache.struts2.jasper.el.ExpressionEvaluatorImpl;
+import org.apache.struts2.jasper.el.FunctionMapperImpl;
+import org.apache.struts2.jasper.el.VariableResolverImpl;
+import org.apache.struts2.jasper.security.SecurityUtil;
+import org.apache.struts2.jasper.util.Enumerator;
+
+/**
+ * Implementation of the PageContext class from the JSP spec. Also doubles as a
+ * VariableResolver for the EL.
+ *
+ * @author Anil K. Vijendran
+ * @author Larry Cable
+ * @author Hans Bergsten
+ * @author Pierre Delisle
+ * @author Mark Roth
+ * @author Jan Luehe
+ * @author Jacob Hookom
+ */
+public class PageContextImpl extends PageContext {
+
+ private static final JspFactory jspf = JspFactory.getDefaultFactory();
+
+ private BodyContentImpl[] outs;
+
+ private int depth;
+
+ // per-servlet state
+ private Servlet servlet;
+
+ private ServletConfig config;
+
+ private ServletContext context;
+
+ private JspApplicationContextImpl applicationContext;
+
+ private String errorPageURL;
+
+ // page-scope attributes
+ private transient HashMap<String, Object> attributes;
+
+ // per-request state
+ private transient ServletRequest request;
+
+ private transient ServletResponse response;
+
+ private transient HttpSession session;
+
+ private transient ELContextImpl elContext;
+
+ private boolean isIncluded;
+
+
+ // initial output stream
+ private transient JspWriter out;
+
+ private transient JspWriterImpl baseOut;
+
+ /*
+ * Constructor.
+ */
+ PageContextImpl() {
+ this.outs = new BodyContentImpl[0];
+ this.attributes = new HashMap<String, Object>(16);
+ this.depth = -1;
+ }
+
+ public void initialize(Servlet servlet, ServletRequest request,
+ ServletResponse response, String errorPageURL,
+ boolean needsSession, int bufferSize, boolean autoFlush)
+ throws IOException {
+
+ _initialize(servlet, request, response, errorPageURL, needsSession,
+ bufferSize, autoFlush);
+ }
+
+ private void _initialize(Servlet servlet, ServletRequest request,
+ ServletResponse response, String errorPageURL,
+ boolean needsSession, int bufferSize, boolean autoFlush)
+ throws IOException {
+
+ // initialize state
+ this.servlet = servlet;
+ this.config = servlet.getServletConfig();
+ this.context = config.getServletContext();
+ this.errorPageURL = errorPageURL;
+ this.request = request;
+ this.response = response;
+
+ // initialize application context
+ this.applicationContext = JspApplicationContextImpl.getInstance(context);
+
+ // Setup session (if required)
+ if (request instanceof HttpServletRequest && needsSession)
+ this.session = ((HttpServletRequest) request).getSession();
+ if (needsSession && session == null)
+ throw new IllegalStateException(
+ "Page needs a session and none is available");
+
+ // initialize the initial out ...
+ depth = -1;
+ if (this.baseOut == null) {
+ this.baseOut = new JspWriterImpl(response, bufferSize, autoFlush);
+ } else {
+ this.baseOut.init(response, bufferSize, autoFlush);
+ }
+ this.out = baseOut;
+
+ // register names/values as per spec
+ setAttribute(OUT, this.out);
+ setAttribute(REQUEST, request);
+ setAttribute(RESPONSE, response);
+
+ if (session != null)
+ setAttribute(SESSION, session);
+
+ setAttribute(PAGE, servlet);
+ setAttribute(CONFIG, config);
+ setAttribute(PAGECONTEXT, this);
+ setAttribute(APPLICATION, context);
+
+ isIncluded = request.getAttribute("javax.servlet.include.servlet_path") != null;
+ }
+
+ public void release() {
+ out = baseOut;
+ try {
+ if (isIncluded) {
+ ((JspWriterImpl) out).flushBuffer();
+ // push it into the including jspWriter
+ } else {
+ // Old code:
+ // out.flush();
+ // Do not flush the buffer even if we're not included (i.e.
+ // we are the main page. The servlet will flush it and close
+ // the stream.
+ ((JspWriterImpl) out).flushBuffer();
+ }
+ } catch (IOException ex) {
+ IllegalStateException ise = new IllegalStateException(Localizer.getMessage("jsp.error.flush"), ex);
+ throw ise;
+ } finally {
+ servlet = null;
+ config = null;
+ context = null;
+ applicationContext = null;
+ elContext = null;
+ errorPageURL = null;
+ request = null;
+ response = null;
+ depth = -1;
+ baseOut.recycle();
+ session = null;
+ attributes.clear();
+ }
+ }
+
+ public Object getAttribute(final String name) {
+
+ if (name == null) {
+ throw new NullPointerException(Localizer
+ .getMessage("jsp.error.attribute.null_name"));
+ }
+
+ if (SecurityUtil.isPackageProtectionEnabled()) {
+ return AccessController.doPrivileged(new PrivilegedAction() {
+ public Object run() {
+ return doGetAttribute(name);
+ }
+ });
+ } else {
+ return doGetAttribute(name);
+ }
+
+ }
+
+ private Object doGetAttribute(String name) {
+ return attributes.get(name);
+ }
+
+ public Object getAttribute(final String name, final int scope) {
+
+ if (name == null) {
+ throw new NullPointerException(Localizer
+ .getMessage("jsp.error.attribute.null_name"));
+ }
+
+ if (SecurityUtil.isPackageProtectionEnabled()) {
+ return AccessController.doPrivileged(new PrivilegedAction() {
+ public Object run() {
+ return doGetAttribute(name, scope);
+ }
+ });
+ } else {
+ return doGetAttribute(name, scope);
+ }
+
+ }
+
+ private Object doGetAttribute(String name, int scope) {
+ switch (scope) {
+ case PAGE_SCOPE:
+ return attributes.get(name);
+
+ case REQUEST_SCOPE:
+ return request.getAttribute(name);
+
+ case SESSION_SCOPE:
+ if (session == null) {
+ throw new IllegalStateException(Localizer
+ .getMessage("jsp.error.page.noSession"));
+ }
+ return session.getAttribute(name);
+
+ case APPLICATION_SCOPE:
+ return context.getAttribute(name);
+
+ default:
+ throw new IllegalArgumentException("Invalid scope");
+ }
+ }
+
+ public void setAttribute(final String name, final Object attribute) {
+
+ if (name == null) {
+ throw new NullPointerException(Localizer
+ .getMessage("jsp.error.attribute.null_name"));
+ }
+
+ if (SecurityUtil.isPackageProtectionEnabled()) {
+ AccessController.doPrivileged(new PrivilegedAction() {
+ public Object run() {
+ doSetAttribute(name, attribute);
+ return null;
+ }
+ });
+ } else {
+ doSetAttribute(name, attribute);
+ }
+ }
+
+ private void doSetAttribute(String name, Object attribute) {
+ if (attribute != null) {
+ attributes.put(name, attribute);
+ } else {
+ removeAttribute(name, PAGE_SCOPE);
+ }
+ }
+
+ public void setAttribute(final String name, final Object o, final int scope) {
+
+ if (name == null) {
+ throw new NullPointerException(Localizer
+ .getMessage("jsp.error.attribute.null_name"));
+ }
+
+ if (SecurityUtil.isPackageProtectionEnabled()) {
+ AccessController.doPrivileged(new PrivilegedAction() {
+ public Object run() {
+ doSetAttribute(name, o, scope);
+ return null;
+ }
+ });
+ } else {
+ doSetAttribute(name, o, scope);
+ }
+
+ }
+
+ private void doSetAttribute(String name, Object o, int scope) {
+ if (o != null) {
+ switch (scope) {
+ case PAGE_SCOPE:
+ attributes.put(name, o);
+ break;
+
+ case REQUEST_SCOPE:
+ request.setAttribute(name, o);
+ break;
+
+ case SESSION_SCOPE:
+ if (session == null) {
+ throw new IllegalStateException(Localizer
+ .getMessage("jsp.error.page.noSession"));
+ }
+ session.setAttribute(name, o);
+ break;
+
+ case APPLICATION_SCOPE:
+ context.setAttribute(name, o);
+ break;
+
+ default:
+ throw new IllegalArgumentException("Invalid scope");
+ }
+ } else {
+ removeAttribute(name, scope);
+ }
+ }
+
+ public void removeAttribute(final String name, final int scope) {
+
+ if (name == null) {
+ throw new NullPointerException(Localizer
+ .getMessage("jsp.error.attribute.null_name"));
+ }
+ if (SecurityUtil.isPackageProtectionEnabled()) {
+ AccessController.doPrivileged(new PrivilegedAction() {
+ public Object run() {
+ doRemoveAttribute(name, scope);
+ return null;
+ }
+ });
+ } else {
+ doRemoveAttribute(name, scope);
+ }
+ }
+
+ private void doRemoveAttribute(String name, int scope) {
+ switch (scope) {
+ case PAGE_SCOPE:
+ attributes.remove(name);
+ break;
+
+ case REQUEST_SCOPE:
+ request.removeAttribute(name);
+ break;
+
+ case SESSION_SCOPE:
+ if (session == null) {
+ throw new IllegalStateException(Localizer
+ .getMessage("jsp.error.page.noSession"));
+ }
+ session.removeAttribute(name);
+ break;
+
+ case APPLICATION_SCOPE:
+ context.removeAttribute(name);
+ break;
+
+ default:
+ throw new IllegalArgumentException("Invalid scope");
+ }
+ }
+
+ public int getAttributesScope(final String name) {
+
+ if (name == null) {
+ throw new NullPointerException(Localizer
+ .getMessage("jsp.error.attribute.null_name"));
+ }
+
+ if (SecurityUtil.isPackageProtectionEnabled()) {
+ return ((Integer) AccessController
+ .doPrivileged(new PrivilegedAction() {
+ public Object run() {
+ return new Integer(doGetAttributeScope(name));
+ }
+ })).intValue();
+ } else {
+ return doGetAttributeScope(name);
+ }
+ }
+
+ private int doGetAttributeScope(String name) {
+ if (attributes.get(name) != null)
+ return PAGE_SCOPE;
+
+ if (request.getAttribute(name) != null)
+ return REQUEST_SCOPE;
+
+ if (session != null) {
+ try {
+ if (session.getAttribute(name) != null)
+ return SESSION_SCOPE;
+ } catch(IllegalStateException ise) {
+ // Session has been invalidated.
+ // Ignore and fall through to application scope.
+ }
+ }
+
+ if (context.getAttribute(name) != null)
+ return APPLICATION_SCOPE;
+
+ return 0;
+ }
+
+ public Object findAttribute(final String name) {
+ if (SecurityUtil.isPackageProtectionEnabled()) {
+ return AccessController.doPrivileged(new PrivilegedAction() {
+ public Object run() {
+ if (name == null) {
+ throw new NullPointerException(Localizer
+ .getMessage("jsp.error.attribute.null_name"));
+ }
+
+ return doFindAttribute(name);
+ }
+ });
+ } else {
+ if (name == null) {
+ throw new NullPointerException(Localizer
+ .getMessage("jsp.error.attribute.null_name"));
+ }
+
+ return doFindAttribute(name);
+ }
+ }
+
+ private Object doFindAttribute(String name) {
+
+ Object o = attributes.get(name);
+ if (o != null)
+ return o;
+
+ o = request.getAttribute(name);
+ if (o != null)
+ return o;
+
+ if (session != null) {
+ try {
+ o = session.getAttribute(name);
+ } catch(IllegalStateException ise) {
+ // Session has been invalidated.
+ // Ignore and fall through to application scope.
+ }
+ if (o != null)
+ return o;
+ }
+
+ return context.getAttribute(name);
+ }
+
+ public Enumeration<String> getAttributeNamesInScope(final int scope) {
+ if (SecurityUtil.isPackageProtectionEnabled()) {
+ return (Enumeration) AccessController
+ .doPrivileged(new PrivilegedAction() {
+ public Object run() {
+ return doGetAttributeNamesInScope(scope);
+ }
+ });
+ } else {
+ return doGetAttributeNamesInScope(scope);
+ }
+ }
+
+ private Enumeration doGetAttributeNamesInScope(int scope) {
+ switch (scope) {
+ case PAGE_SCOPE:
+ return new Enumerator(attributes.keySet().iterator());
+
+ case REQUEST_SCOPE:
+ return request.getAttributeNames();
+
+ case SESSION_SCOPE:
+ if (session == null) {
+ throw new IllegalStateException(Localizer
+ .getMessage("jsp.error.page.noSession"));
+ }
+ return session.getAttributeNames();
+
+ case APPLICATION_SCOPE:
+ return context.getAttributeNames();
+
+ default:
+ throw new IllegalArgumentException("Invalid scope");
+ }
+ }
+
+ public void removeAttribute(final String name) {
+
+ if (name == null) {
+ throw new NullPointerException(Localizer
+ .getMessage("jsp.error.attribute.null_name"));
+ }
+
+ if (SecurityUtil.isPackageProtectionEnabled()) {
+ AccessController.doPrivileged(new PrivilegedAction() {
+ public Object run() {
+ doRemoveAttribute(name);
+ return null;
+ }
+ });
+ } else {
+ doRemoveAttribute(name);
+ }
+ }
+
+ private void doRemoveAttribute(String name) {
+ removeAttribute(name, PAGE_SCOPE);
+ removeAttribute(name, REQUEST_SCOPE);
+ if( session != null ) {
+ try {
+ removeAttribute(name, SESSION_SCOPE);
+ } catch(IllegalStateException ise) {
+ // Session has been invalidated.
+ // Ignore and fall throw to application scope.
+ }
+ }
+ removeAttribute(name, APPLICATION_SCOPE);
+ }
+
+ public JspWriter getOut() {
+ return out;
+ }
+
+ public HttpSession getSession() {
+ return session;
+ }
+
+ public Servlet getServlet() {
+ return servlet;
+ }
+
+ public ServletConfig getServletConfig() {
+ return config;
+ }
+
+ public ServletContext getServletContext() {
+ return config.getServletContext();
+ }
+
+ public ServletRequest getRequest() {
+ return request;
+ }
+
+ public ServletResponse getResponse() {
+ return response;
+ }
+
+ /**
+ * Returns the exception associated with this page context, if any. <p/>
+ * Added wrapping for Throwables to avoid ClassCastException: see Bugzilla
+ * 31171 for details.
+ *
+ * @return The Exception associated with this page context, if any.
+ */
+ public Exception getException() {
+ Throwable t = JspRuntimeLibrary.getThrowable(request);
+
+ // Only wrap if needed
+ if ((t != null) && (!(t instanceof Exception))) {
+ t = new JspException(t);
+ }
+
+ return (Exception) t;
+ }
+
+ public Object getPage() {
+ return servlet;
+ }
+
+ private final String getAbsolutePathRelativeToContext(String relativeUrlPath) {
+ String path = relativeUrlPath;
+
+ if (!path.startsWith("/")) {
+ String uri = (String) request
+ .getAttribute("javax.servlet.include.servlet_path");
+ if (uri == null)
+ uri = ((HttpServletRequest) request).getServletPath();
+ String baseURI = uri.substring(0, uri.lastIndexOf('/'));
+ path = baseURI + '/' + path;
+ }
+
+ return path;
+ }
+
+ public void include(String relativeUrlPath) throws ServletException,
+ IOException {
+ JspRuntimeLibrary
+ .include(request, response, relativeUrlPath, out, true);
+ }
+
+ public void include(final String relativeUrlPath, final boolean flush)
+ throws ServletException, IOException {
+ if (SecurityUtil.isPackageProtectionEnabled()) {
+ try {
+ AccessController.doPrivileged(new PrivilegedExceptionAction() {
+ public Object run() throws Exception {
+ doInclude(relativeUrlPath, flush);
+ return null;
+ }
+ });
+ } catch (PrivilegedActionException e) {
+ Exception ex = e.getException();
+ if (ex instanceof IOException) {
+ throw (IOException) ex;
+ } else {
+ throw (ServletException) ex;
+ }
+ }
+ } else {
+ doInclude(relativeUrlPath, flush);
+ }
+ }
+
+ private void doInclude(String relativeUrlPath, boolean flush)
+ throws ServletException, IOException {
+ JspRuntimeLibrary.include(request, response, relativeUrlPath, out,
+ flush);
+ }
+
+ public VariableResolver getVariableResolver() {
+ return new VariableResolverImpl(this.getELContext());
+ }
+
+ public void forward(final String relativeUrlPath) throws ServletException,
+ IOException {
+ if (SecurityUtil.isPackageProtectionEnabled()) {
+ try {
+ AccessController.doPrivileged(new PrivilegedExceptionAction() {
+ public Object run() throws Exception {
+ doForward(relativeUrlPath);
+ return null;
+ }
+ });
+ } catch (PrivilegedActionException e) {
+ Exception ex = e.getException();
+ if (ex instanceof IOException) {
+ throw (IOException) ex;
+ } else {
+ throw (ServletException) ex;
+ }
+ }
+ } else {
+ doForward(relativeUrlPath);
+ }
+ }
+
+ private void doForward(String relativeUrlPath) throws ServletException,
+ IOException {
+
+ // JSP.4.5 If the buffer was flushed, throw IllegalStateException
+ try {
+ out.clear();
+ } catch (IOException ex) {
+ IllegalStateException ise = new IllegalStateException(Localizer
+ .getMessage("jsp.error.attempt_to_clear_flushed_buffer"));
+ ise.initCause(ex);
+ throw ise;
+ }
+
+ // Make sure that the response object is not the wrapper for include
+ while (response instanceof ServletResponseWrapperInclude) {
+ response = ((ServletResponseWrapperInclude) response).getResponse();
+ }
+
+ final String path = getAbsolutePathRelativeToContext(relativeUrlPath);
+ String includeUri = (String) request
+ .getAttribute(Constants.INC_SERVLET_PATH);
+
+ if (includeUri != null)
+ request.removeAttribute(Constants.INC_SERVLET_PATH);
+ try {
+ context.getRequestDispatcher(path).forward(request, response);
+ } finally {
+ if (includeUri != null)
+ request.setAttribute(Constants.INC_SERVLET_PATH, includeUri);
+ }
+ }
+
+ public BodyContent pushBody() {
+ return (BodyContent) pushBody(null);
+ }
+
+ public JspWriter pushBody(Writer writer) {
+ depth++;
+ if (depth >= outs.length) {
+ BodyContentImpl[] newOuts = new BodyContentImpl[depth + 1];
+ for (int i = 0; i < outs.length; i++) {
+ newOuts[i] = outs[i];
+ }
+ newOuts[depth] = new BodyContentImpl(out);
+ outs = newOuts;
+ }
+
+ outs[depth].setWriter(writer);
+ out = outs[depth];
+
+ // Update the value of the "out" attribute in the page scope
+ // attribute namespace of this PageContext
+ setAttribute(OUT, out);
+
+ return outs[depth];
+ }
+
+ public JspWriter popBody() {
+ depth--;
+ if (depth >= 0) {
+ out = outs[depth];
+ } else {
+ out = baseOut;
+ }
+
+ // Update the value of the "out" attribute in the page scope
+ // attribute namespace of this PageContext
+ setAttribute(OUT, out);
+
+ return out;
+ }
+
+ /**
+ * Provides programmatic access to the ExpressionEvaluator. The JSP
+ * Container must return a valid instance of an ExpressionEvaluator that can
+ * parse EL expressions.
+ */
+ public ExpressionEvaluator getExpressionEvaluator() {
+ return new ExpressionEvaluatorImpl(this.applicationContext.getExpressionFactory());
+ }
+
+ public void handlePageException(Exception ex) throws IOException,
+ ServletException {
+ // Should never be called since handleException() called with a
+ // Throwable in the generated servlet.
+ handlePageException((Throwable) ex);
+ }
+
+ public void handlePageException(final Throwable t) throws IOException,
+ ServletException {
+ if (t == null)
+ throw new NullPointerException("null Throwable");
+
+ if (SecurityUtil.isPackageProtectionEnabled()) {
+ try {
+ AccessController.doPrivileged(new PrivilegedExceptionAction() {
+ public Object run() throws Exception {
+ doHandlePageException(t);
+ return null;
+ }
+ });
+ } catch (PrivilegedActionException e) {
+ Exception ex = e.getException();
+ if (ex instanceof IOException) {
+ throw (IOException) ex;
+ } else {
+ throw (ServletException) ex;
+ }
+ }
+ } else {
+ doHandlePageException(t);
+ }
+
+ }
+
+ private void doHandlePageException(Throwable t) throws IOException,
+ ServletException {
+
+ if (errorPageURL != null && !errorPageURL.equals("")) {
+
+ /*
+ * Set request attributes. Do not set the
+ * javax.servlet.error.exception attribute here (instead, set in the
+ * generated servlet code for the error page) in order to prevent
+ * the ErrorReportValve, which is invoked as part of forwarding the
+ * request to the error page, from throwing it if the response has
+ * not been committed (the response will have been committed if the
+ * error page is a JSP page).
+ */
+ request.setAttribute("javax.servlet.jsp.jspException", t);
+ request.setAttribute("javax.servlet.error.status_code",
+ new Integer(HttpServletResponse.SC_INTERNAL_SERVER_ERROR));
+ request.setAttribute("javax.servlet.error.request_uri",
+ ((HttpServletRequest) request).getRequestURI());
+ request.setAttribute("javax.servlet.error.servlet_name", config
+ .getServletName());
+ try {
+ forward(errorPageURL);
+ } catch (IllegalStateException ise) {
+ include(errorPageURL);
+ }
+
+ // The error page could be inside an include.
+
+ Object newException = request
+ .getAttribute("javax.servlet.error.exception");
+
+ // t==null means the attribute was not set.
+ if ((newException != null) && (newException == t)) {
+ request.removeAttribute("javax.servlet.error.exception");
+ }
+
+ // now clear the error code - to prevent double handling.
+ request.removeAttribute("javax.servlet.error.status_code");
+ request.removeAttribute("javax.servlet.error.request_uri");
+ request.removeAttribute("javax.servlet.error.status_code");
+ request.removeAttribute("javax.servlet.jsp.jspException");
+
+ } else {
+ // Otherwise throw the exception wrapped inside a ServletException.
+ // Set the exception as the root cause in the ServletException
+ // to get a stack trace for the real problem
+ if (t instanceof IOException)
+ throw (IOException) t;
+ if (t instanceof ServletException)
+ throw (ServletException) t;
+ if (t instanceof RuntimeException)
+ throw (RuntimeException) t;
+
+ Throwable rootCause = null;
+ if (t instanceof JspException) {
+ rootCause = ((JspException) t).getRootCause();
+ } else if (t instanceof ELException) {
+ rootCause = ((ELException) t).getRootCause();
+ }
+
+ if (rootCause != null) {
+ throw new ServletException(t.getClass().getName() + ": "
+ + t.getMessage(), rootCause);
+ }
+
+ throw new ServletException(t);
+ }
+ }
+
+ private static String XmlEscape(String s) {
+ if (s == null)
+ return null;
+ StringBuffer sb = new StringBuffer();
+ for (int i = 0; i < s.length(); i++) {
+ char c = s.charAt(i);
+ if (c == '<') {
+ sb.append("<");
+ } else if (c == '>') {
+ sb.append(">");
+ } else if (c == '\'') {
+ sb.append("'"); // '
+ } else if (c == '&') {
+ sb.append("&");
+ } else if (c == '"') {
+ sb.append("""); // "
+ } else {
+ sb.append(c);
+ }
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Proprietary method to evaluate EL expressions. XXX - This method should
+ * go away once the EL interpreter moves out of JSTL and into its own
+ * project. For now, this is necessary because the standard machinery is too
+ * slow.
+ *
+ * @param expression
+ * The expression to be evaluated
+ * @param expectedType
+ * The expected resulting type
+ * @param pageContext
+ * The page context
+ * @param functionMap
+ * Maps prefix and name to Method
+ * @return The result of the evaluation
+ */
+ public static Object proprietaryEvaluate(final String expression,
+ final Class expectedType, final PageContext pageContext,
+ final ProtectedFunctionMapper functionMap, final boolean escape)
+ throws ELException {
+ Object retValue;
+ final ExpressionFactory exprFactory = jspf.getJspApplicationContext(pageContext.getServletContext()).getExpressionFactory();
+ if (SecurityUtil.isPackageProtectionEnabled()) {
+ try {
+ retValue = AccessController
+ .doPrivileged(new PrivilegedExceptionAction() {
+
+ public Object run() throws Exception {
+ ELContextImpl ctx = (ELContextImpl) pageContext.getELContext();
+ ctx.setFunctionMapper(new FunctionMapperImpl(functionMap));
+ ValueExpression ve = exprFactory.createValueExpression(ctx, expression, expectedType);
+ return ve.getValue(ctx);
+ }
+ });
+ } catch (PrivilegedActionException ex) {
+ Exception realEx = ex.getException();
+ if (realEx instanceof ELException) {
+ throw (ELException) realEx;
+ } else {
+ throw new ELException(realEx);
+ }
+ }
+ } else {
+ ELContextImpl ctx = (ELContextImpl) pageContext.getELContext();
+ ctx.setFunctionMapper(new FunctionMapperImpl(functionMap));
+ ValueExpression ve = exprFactory.createValueExpression(ctx, expression, expectedType);
+ retValue = ve.getValue(ctx);
+ }
+ if (escape && retValue != null) {
+ retValue = XmlEscape(retValue.toString());
+ }
+
+ return retValue;
+ }
+
+ public ELContext getELContext() {
+ if (this.elContext == null) {
+ this.elContext = this.applicationContext.createELContext(this);
+ }
+ return this.elContext;
+ }
+
+}
Added: struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/runtime/PerThreadTagHandlerPool.java
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/runtime/PerThreadTagHandlerPool.java?rev=819444&view=auto
==============================================================================
--- struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/runtime/PerThreadTagHandlerPool.java (added)
+++ struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/runtime/PerThreadTagHandlerPool.java Mon Sep 28 01:55:26 2009
@@ -0,0 +1,134 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.struts2.jasper.runtime;
+
+import java.util.Enumeration;
+import java.util.Vector;
+
+import javax.servlet.ServletConfig;
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.tagext.Tag;
+
+import org.apache.struts2.jasper.Constants;
+
+/**
+ * Thread-local based pool of tag handlers that can be reused.
+ *
+ * @author Jan Luehe
+ * @author Costin Manolache
+ */
+public class PerThreadTagHandlerPool extends TagHandlerPool {
+
+ private int maxSize;
+
+ // For cleanup
+ private Vector perThreadDataVector;
+
+ private ThreadLocal perThread;
+
+ private static class PerThreadData {
+ Tag handlers[];
+ int current;
+ }
+
+ /**
+ * Constructs a tag handler pool with the default capacity.
+ */
+ public PerThreadTagHandlerPool() {
+ super();
+ perThreadDataVector = new Vector();
+ }
+
+ protected void init(ServletConfig config) {
+ maxSize = Constants.MAX_POOL_SIZE;
+ String maxSizeS = getOption(config, OPTION_MAXSIZE, null);
+ if (maxSizeS != null) {
+ maxSize = Integer.parseInt(maxSizeS);
+ if (maxSize < 0) {
+ maxSize = Constants.MAX_POOL_SIZE;
+ }
+ }
+
+ perThread = new ThreadLocal() {
+ protected Object initialValue() {
+ PerThreadData ptd = new PerThreadData();
+ ptd.handlers = new Tag[maxSize];
+ ptd.current = -1;
+ perThreadDataVector.addElement(ptd);
+ return ptd;
+ }
+ };
+ }
+
+ /**
+ * Gets the next available tag handler from this tag handler pool,
+ * instantiating one if this tag handler pool is empty.
+ *
+ * @param handlerClass Tag handler class
+ *
+ * @return Reused or newly instantiated tag handler
+ *
+ * @throws JspException if a tag handler cannot be instantiated
+ */
+ public Tag get(Class handlerClass) throws JspException {
+ PerThreadData ptd = (PerThreadData)perThread.get();
+ if(ptd.current >=0 ) {
+ return ptd.handlers[ptd.current--];
+ } else {
+ try {
+ return (Tag) handlerClass.newInstance();
+ } catch (Exception e) {
+ throw new JspException(e.getMessage(), e);
+ }
+ }
+ }
+
+ /**
+ * Adds the given tag handler to this tag handler pool, unless this tag
+ * handler pool has already reached its capacity, in which case the tag
+ * handler's release() method is called.
+ *
+ * @param handler Tag handler to add to this tag handler pool
+ */
+ public void reuse(Tag handler) {
+ PerThreadData ptd=(PerThreadData)perThread.get();
+ if (ptd.current < (ptd.handlers.length - 1)) {
+ ptd.handlers[++ptd.current] = handler;
+ } else {
+ handler.release();
+ }
+ }
+
+ /**
+ * Calls the release() method of all tag handlers in this tag handler pool.
+ */
+ public void release() {
+ Enumeration enumeration = perThreadDataVector.elements();
+ while (enumeration.hasMoreElements()) {
+ PerThreadData ptd = (PerThreadData)enumeration.nextElement();
+ if (ptd.handlers != null) {
+ for (int i=ptd.current; i>=0; i--) {
+ if (ptd.handlers[i] != null) {
+ ptd.handlers[i].release();
+ }
+ }
+ }
+ }
+ }
+}
+
Added: struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/runtime/ProtectedFunctionMapper.java
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/runtime/ProtectedFunctionMapper.java?rev=819444&view=auto
==============================================================================
--- struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/runtime/ProtectedFunctionMapper.java (added)
+++ struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/runtime/ProtectedFunctionMapper.java Mon Sep 28 01:55:26 2009
@@ -0,0 +1,196 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.struts2.jasper.runtime;
+
+import java.util.HashMap;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.security.PrivilegedExceptionAction;
+import java.security.PrivilegedActionException;
+import java.lang.reflect.Method;
+import javax.servlet.jsp.el.FunctionMapper;
+
+import org.apache.struts2.jasper.security.SecurityUtil;
+
+/**
+ * Maps EL functions to their Java method counterparts. Keeps the actual Method
+ * objects protected so that JSP pages can't indirectly do reflection.
+ *
+ * @author Mark Roth
+ * @author Kin-man Chung
+ */
+public final class ProtectedFunctionMapper extends javax.el.FunctionMapper
+ implements FunctionMapper {
+
+ /**
+ * Maps "prefix:name" to java.lang.Method objects.
+ */
+ private HashMap fnmap = null;
+
+ /**
+ * If there is only one function in the map, this is the Method for it.
+ */
+ private Method theMethod = null;
+
+ /**
+ * Constructor has protected access.
+ */
+ private ProtectedFunctionMapper() {
+ }
+
+ /**
+ * Generated Servlet and Tag Handler implementations call this method to
+ * retrieve an instance of the ProtectedFunctionMapper. This is necessary
+ * since generated code does not have access to create instances of classes
+ * in this package.
+ *
+ * @return A new protected function mapper.
+ */
+ public static ProtectedFunctionMapper getInstance() {
+ ProtectedFunctionMapper funcMapper;
+ if (SecurityUtil.isPackageProtectionEnabled()) {
+ funcMapper = (ProtectedFunctionMapper) AccessController
+ .doPrivileged(new PrivilegedAction() {
+ public Object run() {
+ return new ProtectedFunctionMapper();
+ }
+ });
+ } else {
+ funcMapper = new ProtectedFunctionMapper();
+ }
+ funcMapper.fnmap = new java.util.HashMap();
+ return funcMapper;
+ }
+
+ /**
+ * Stores a mapping from the given EL function prefix and name to the given
+ * Java method.
+ *
+ * @param fnQName
+ * The EL function qualified name (including prefix)
+ * @param c
+ * The class containing the Java method
+ * @param methodName
+ * The name of the Java method
+ * @param args
+ * The arguments of the Java method
+ * @throws RuntimeException
+ * if no method with the given signature could be found.
+ */
+ public void mapFunction(String fnQName, final Class c,
+ final String methodName, final Class[] args) {
+ java.lang.reflect.Method method;
+ if (SecurityUtil.isPackageProtectionEnabled()) {
+ try {
+ method = (java.lang.reflect.Method) AccessController
+ .doPrivileged(new PrivilegedExceptionAction() {
+
+ public Object run() throws Exception {
+ return c.getDeclaredMethod(methodName, args);
+ }
+ });
+ } catch (PrivilegedActionException ex) {
+ throw new RuntimeException(
+ "Invalid function mapping - no such method: "
+ + ex.getException().getMessage());
+ }
+ } else {
+ try {
+ method = c.getDeclaredMethod(methodName, args);
+ } catch (NoSuchMethodException e) {
+ throw new RuntimeException(
+ "Invalid function mapping - no such method: "
+ + e.getMessage());
+ }
+ }
+
+ this.fnmap.put(fnQName, method);
+ }
+
+ /**
+ * Creates an instance for this class, and stores the Method for the given
+ * EL function prefix and name. This method is used for the case when there
+ * is only one function in the EL expression.
+ *
+ * @param fnQName
+ * The EL function qualified name (including prefix)
+ * @param c
+ * The class containing the Java method
+ * @param methodName
+ * The name of the Java method
+ * @param args
+ * The arguments of the Java method
+ * @throws RuntimeException
+ * if no method with the given signature could be found.
+ */
+ public static ProtectedFunctionMapper getMapForFunction(String fnQName,
+ final Class c, final String methodName, final Class[] args) {
+ java.lang.reflect.Method method;
+ ProtectedFunctionMapper funcMapper;
+ if (SecurityUtil.isPackageProtectionEnabled()) {
+ funcMapper = (ProtectedFunctionMapper) AccessController
+ .doPrivileged(new PrivilegedAction() {
+ public Object run() {
+ return new ProtectedFunctionMapper();
+ }
+ });
+
+ try {
+ method = (java.lang.reflect.Method) AccessController
+ .doPrivileged(new PrivilegedExceptionAction() {
+
+ public Object run() throws Exception {
+ return c.getDeclaredMethod(methodName, args);
+ }
+ });
+ } catch (PrivilegedActionException ex) {
+ throw new RuntimeException(
+ "Invalid function mapping - no such method: "
+ + ex.getException().getMessage());
+ }
+ } else {
+ funcMapper = new ProtectedFunctionMapper();
+ try {
+ method = c.getDeclaredMethod(methodName, args);
+ } catch (NoSuchMethodException e) {
+ throw new RuntimeException(
+ "Invalid function mapping - no such method: "
+ + e.getMessage());
+ }
+ }
+ funcMapper.theMethod = method;
+ return funcMapper;
+ }
+
+ /**
+ * Resolves the specified local name and prefix into a Java.lang.Method.
+ * Returns null if the prefix and local name are not found.
+ *
+ * @param prefix
+ * the prefix of the function
+ * @param localName
+ * the short name of the function
+ * @return the result of the method mapping. Null means no entry found.
+ */
+ public Method resolveFunction(String prefix, String localName) {
+ if (this.fnmap != null) {
+ return (Method) this.fnmap.get(prefix + ":" + localName);
+ }
+ return theMethod;
+ }
+}
Added: struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/runtime/ServletResponseWrapperInclude.java
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/runtime/ServletResponseWrapperInclude.java?rev=819444&view=auto
==============================================================================
--- struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/runtime/ServletResponseWrapperInclude.java (added)
+++ struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/runtime/ServletResponseWrapperInclude.java Mon Sep 28 01:55:26 2009
@@ -0,0 +1,76 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.struts2.jasper.runtime;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+
+import javax.servlet.ServletOutputStream;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpServletResponseWrapper;
+import javax.servlet.jsp.JspWriter;
+
+/**
+ * ServletResponseWrapper used by the JSP 'include' action.
+ *
+ * This wrapper response object is passed to RequestDispatcher.include(), so
+ * that the output of the included resource is appended to that of the
+ * including page.
+ *
+ * @author Pierre Delisle
+ */
+
+public class ServletResponseWrapperInclude extends HttpServletResponseWrapper {
+
+ /**
+ * PrintWriter which appends to the JspWriter of the including page.
+ */
+ private PrintWriter printWriter;
+
+ private JspWriter jspWriter;
+
+ public ServletResponseWrapperInclude(ServletResponse response,
+ JspWriter jspWriter) {
+ super((HttpServletResponse)response);
+ this.printWriter = new PrintWriter(jspWriter);
+ this.jspWriter = jspWriter;
+ }
+
+ /**
+ * Returns a wrapper around the JspWriter of the including page.
+ */
+ public PrintWriter getWriter() throws IOException {
+ return printWriter;
+ }
+
+ public ServletOutputStream getOutputStream() throws IOException {
+ throw new IllegalStateException();
+ }
+
+ /**
+ * Clears the output buffer of the JspWriter associated with the including
+ * page.
+ */
+ public void resetBuffer() {
+ try {
+ jspWriter.clearBuffer();
+ } catch (IOException ioe) {
+ }
+ }
+}
Added: struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/runtime/TagHandlerPool.java
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/runtime/TagHandlerPool.java?rev=819444&view=auto
==============================================================================
--- struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/runtime/TagHandlerPool.java (added)
+++ struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/runtime/TagHandlerPool.java Mon Sep 28 01:55:26 2009
@@ -0,0 +1,191 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.struts2.jasper.runtime;
+
+import javax.servlet.ServletConfig;
+import javax.servlet.jsp.JspException;
+import javax.servlet.jsp.tagext.Tag;
+
+import org.apache.AnnotationProcessor;
+import org.apache.struts2.jasper.Constants;
+import org.apache.juli.logging.Log;
+import org.apache.juli.logging.LogFactory;
+
+/**
+ * Pool of tag handlers that can be reused.
+ *
+ * @author Jan Luehe
+ */
+public class TagHandlerPool {
+
+ private Tag[] handlers;
+
+ public static String OPTION_TAGPOOL="tagpoolClassName";
+ public static String OPTION_MAXSIZE="tagpoolMaxSize";
+
+ private Log log = LogFactory.getLog(TagHandlerPool.class);
+
+ // index of next available tag handler
+ private int current;
+ protected AnnotationProcessor annotationProcessor = null;
+
+ public static TagHandlerPool getTagHandlerPool( ServletConfig config) {
+ TagHandlerPool result=null;
+
+ String tpClassName=getOption( config, OPTION_TAGPOOL, null);
+ if( tpClassName != null ) {
+ try {
+ Class c=Class.forName( tpClassName );
+ result=(TagHandlerPool)c.newInstance();
+ } catch (Exception e) {
+ e.printStackTrace();
+ result=null;
+ }
+ }
+ if( result==null ) result=new TagHandlerPool();
+ result.init(config);
+
+ return result;
+ }
+
+ protected void init( ServletConfig config ) {
+ int maxSize=-1;
+ String maxSizeS=getOption(config, OPTION_MAXSIZE, null);
+ if( maxSizeS != null ) {
+ try {
+ maxSize=Integer.parseInt(maxSizeS);
+ } catch( Exception ex) {
+ maxSize=-1;
+ }
+ }
+ if( maxSize <0 ) {
+ maxSize=Constants.MAX_POOL_SIZE;
+ }
+ this.handlers = new Tag[maxSize];
+ this.current = -1;
+ this.annotationProcessor =
+ (AnnotationProcessor) config.getServletContext().getAttribute(AnnotationProcessor.class.getName());
+ }
+
+ /**
+ * Constructs a tag handler pool with the default capacity.
+ */
+ public TagHandlerPool() {
+ // Nothing - jasper generated servlets call the other constructor,
+ // this should be used in future + init .
+ }
+
+ /**
+ * Constructs a tag handler pool with the given capacity.
+ *
+ * @param capacity Tag handler pool capacity
+ * @deprecated Use static getTagHandlerPool
+ */
+ public TagHandlerPool(int capacity) {
+ this.handlers = new Tag[capacity];
+ this.current = -1;
+ }
+
+ /**
+ * Gets the next available tag handler from this tag handler pool,
+ * instantiating one if this tag handler pool is empty.
+ *
+ * @param handlerClass Tag handler class
+ *
+ * @return Reused or newly instantiated tag handler
+ *
+ * @throws JspException if a tag handler cannot be instantiated
+ */
+ public Tag get(Class handlerClass) throws JspException {
+ Tag handler = null;
+ synchronized( this ) {
+ if (current >= 0) {
+ handler = handlers[current--];
+ return handler;
+ }
+ }
+
+ // Out of sync block - there is no need for other threads to
+ // wait for us to construct a tag for this thread.
+ try {
+ Tag instance = (Tag) handlerClass.newInstance();
+ AnnotationHelper.postConstruct(annotationProcessor, instance);
+ return instance;
+ } catch (Exception e) {
+ throw new JspException(e.getMessage(), e);
+ }
+ }
+
+ /**
+ * Adds the given tag handler to this tag handler pool, unless this tag
+ * handler pool has already reached its capacity, in which case the tag
+ * handler's release() method is called.
+ *
+ * @param handler Tag handler to add to this tag handler pool
+ */
+ public void reuse(Tag handler) {
+ synchronized( this ) {
+ if (current < (handlers.length - 1)) {
+ handlers[++current] = handler;
+ return;
+ }
+ }
+ // There is no need for other threads to wait for us to release
+ handler.release();
+ if (annotationProcessor != null) {
+ try {
+ AnnotationHelper.preDestroy(annotationProcessor, handler);
+ } catch (Exception e) {
+ log.warn("Error processing preDestroy on tag instance of "
+ + handler.getClass().getName(), e);
+ }
+ }
+ }
+
+ /**
+ * Calls the release() method of all available tag handlers in this tag
+ * handler pool.
+ */
+ public synchronized void release() {
+ for (int i = current; i >= 0; i--) {
+ handlers[i].release();
+ if (annotationProcessor != null) {
+ try {
+ AnnotationHelper.preDestroy(annotationProcessor, handlers[i]);
+ } catch (Exception e) {
+ log.warn("Error processing preDestroy on tag instance of "
+ + handlers[i].getClass().getName(), e);
+ }
+ }
+ }
+ }
+
+ protected static String getOption( ServletConfig config, String name, String defaultV) {
+ if( config == null ) return defaultV;
+
+ String value=config.getInitParameter(name);
+ if( value != null ) return value;
+ if( config.getServletContext() ==null )
+ return defaultV;
+ value=config.getServletContext().getInitParameter(name);
+ if( value!=null ) return value;
+ return defaultV;
+ }
+
+}
+
Added: struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/security/SecurityClassLoad.java
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/security/SecurityClassLoad.java?rev=819444&view=auto
==============================================================================
--- struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/security/SecurityClassLoad.java (added)
+++ struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/security/SecurityClassLoad.java Mon Sep 28 01:55:26 2009
@@ -0,0 +1,111 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package org.apache.struts2.jasper.security;
+
+/**
+ * Static class used to preload java classes when using the
+ * Java SecurityManager so that the defineClassInPackage
+ * RuntimePermission does not trigger an AccessControlException.
+ *
+ * @author Jean-Francois Arcand
+ */
+
+public final class SecurityClassLoad {
+
+ private static org.apache.juli.logging.Log log=
+ org.apache.juli.logging.LogFactory.getLog( SecurityClassLoad.class );
+
+ public static void securityClassLoad(ClassLoader loader){
+
+ if( System.getSecurityManager() == null ){
+ return;
+ }
+
+ String basePackage = "org.apache.struts2.jasper.";
+ try {
+ loader.loadClass( basePackage +
+ "runtime.JspFactoryImpl$PrivilegedGetPageContext");
+ loader.loadClass( basePackage +
+ "runtime.JspFactoryImpl$PrivilegedReleasePageContext");
+
+ loader.loadClass( basePackage +
+ "runtime.JspRuntimeLibrary");
+ loader.loadClass( basePackage +
+ "runtime.JspRuntimeLibrary$PrivilegedIntrospectHelper");
+
+ loader.loadClass( basePackage +
+ "runtime.ServletResponseWrapperInclude");
+ loader.loadClass( basePackage +
+ "runtime.TagHandlerPool");
+ loader.loadClass( basePackage +
+ "runtime.JspFragmentHelper");
+
+ loader.loadClass( basePackage +
+ "runtime.ProtectedFunctionMapper");
+ loader.loadClass( basePackage +
+ "runtime.ProtectedFunctionMapper$1");
+ loader.loadClass( basePackage +
+ "runtime.ProtectedFunctionMapper$2");
+ loader.loadClass( basePackage +
+ "runtime.ProtectedFunctionMapper$3");
+ loader.loadClass( basePackage +
+ "runtime.ProtectedFunctionMapper$4");
+
+ loader.loadClass( basePackage +
+ "runtime.PageContextImpl");
+ loader.loadClass( basePackage +
+ "runtime.PageContextImpl$1");
+ loader.loadClass( basePackage +
+ "runtime.PageContextImpl$2");
+ loader.loadClass( basePackage +
+ "runtime.PageContextImpl$3");
+ loader.loadClass( basePackage +
+ "runtime.PageContextImpl$4");
+ loader.loadClass( basePackage +
+ "runtime.PageContextImpl$5");
+ loader.loadClass( basePackage +
+ "runtime.PageContextImpl$6");
+ loader.loadClass( basePackage +
+ "runtime.PageContextImpl$7");
+ loader.loadClass( basePackage +
+ "runtime.PageContextImpl$8");
+ loader.loadClass( basePackage +
+ "runtime.PageContextImpl$9");
+ loader.loadClass( basePackage +
+ "runtime.PageContextImpl$10");
+ loader.loadClass( basePackage +
+ "runtime.PageContextImpl$11");
+ loader.loadClass( basePackage +
+ "runtime.PageContextImpl$12");
+ loader.loadClass( basePackage +
+ "runtime.PageContextImpl$13");
+
+ loader.loadClass( basePackage +
+ "runtime.JspContextWrapper");
+
+ loader.loadClass( basePackage +
+ "servlet.JspServletWrapper");
+
+ loader.loadClass( basePackage +
+ "runtime.JspWriterImpl$1");
+ } catch (ClassNotFoundException ex) {
+ log.error("SecurityClassLoad", ex);
+ }
+ }
+}
Added: struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/security/SecurityUtil.java
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/security/SecurityUtil.java?rev=819444&view=auto
==============================================================================
--- struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/security/SecurityUtil.java (added)
+++ struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/security/SecurityUtil.java Mon Sep 28 01:55:26 2009
@@ -0,0 +1,81 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.struts2.jasper.security;
+
+import org.apache.struts2.jasper.Constants;
+
+/**
+ * Util class for Security related operations.
+ *
+ * @author Jean-Francois Arcand
+ */
+
+public final class SecurityUtil{
+
+ private static boolean packageDefinitionEnabled =
+ System.getProperty("package.definition") == null ? false : true;
+
+ /**
+ * Return the <code>SecurityManager</code> only if Security is enabled AND
+ * package protection mechanism is enabled.
+ */
+ public static boolean isPackageProtectionEnabled(){
+ if (packageDefinitionEnabled && Constants.IS_SECURITY_ENABLED){
+ return true;
+ }
+ return false;
+ }
+
+
+ /**
+ * Filter the specified message string for characters that are sensitive
+ * in HTML. This avoids potential attacks caused by including JavaScript
+ * codes in the request URL that is often reported in error messages.
+ *
+ * @param message The message string to be filtered
+ */
+ public static String filter(String message) {
+
+ if (message == null)
+ return (null);
+
+ char content[] = new char[message.length()];
+ message.getChars(0, message.length(), content, 0);
+ StringBuffer result = new StringBuffer(content.length + 50);
+ for (int i = 0; i < content.length; i++) {
+ switch (content[i]) {
+ case '<':
+ result.append("<");
+ break;
+ case '>':
+ result.append(">");
+ break;
+ case '&':
+ result.append("&");
+ break;
+ case '"':
+ result.append(""");
+ break;
+ default:
+ result.append(content[i]);
+ }
+ }
+ return (result.toString());
+
+ }
+
+}
Added: struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/servlet/JasperLoader.java
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/servlet/JasperLoader.java?rev=819444&view=auto
==============================================================================
--- struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/servlet/JasperLoader.java (added)
+++ struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/servlet/JasperLoader.java Mon Sep 28 01:55:26 2009
@@ -0,0 +1,172 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.struts2.jasper.servlet;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.security.CodeSource;
+import java.security.PermissionCollection;
+
+import org.apache.struts2.jasper.Constants;
+
+/**
+ * Class loader for loading servlet class files (corresponding to JSP files)
+ * and tag handler class files (corresponding to tag files).
+ *
+ * @author Anil K. Vijendran
+ * @author Harish Prabandham
+ * @author Jean-Francois Arcand
+ */
+public class JasperLoader extends URLClassLoader {
+
+ private PermissionCollection permissionCollection;
+ private CodeSource codeSource;
+ private String className;
+ private ClassLoader parent;
+ private SecurityManager securityManager;
+
+ public JasperLoader(URL[] urls, ClassLoader parent,
+ PermissionCollection permissionCollection,
+ CodeSource codeSource) {
+ super(urls, parent);
+ this.permissionCollection = permissionCollection;
+ this.codeSource = codeSource;
+ this.parent = parent;
+ this.securityManager = System.getSecurityManager();
+ }
+
+ /**
+ * Load the class with the specified name. This method searches for
+ * classes in the same manner as <code>loadClass(String, boolean)</code>
+ * with <code>false</code> as the second argument.
+ *
+ * @param name Name of the class to be loaded
+ *
+ * @exception ClassNotFoundException if the class was not found
+ */
+ public Class loadClass(String name) throws ClassNotFoundException {
+
+ return (loadClass(name, false));
+ }
+
+ /**
+ * Load the class with the specified name, searching using the following
+ * algorithm until it finds and returns the class. If the class cannot
+ * be found, returns <code>ClassNotFoundException</code>.
+ * <ul>
+ * <li>Call <code>findLoadedClass(String)</code> to check if the
+ * class has already been loaded. If it has, the same
+ * <code>Class</code> object is returned.</li>
+ * <li>If the <code>delegate</code> property is set to <code>true</code>,
+ * call the <code>loadClass()</code> method of the parent class
+ * loader, if any.</li>
+ * <li>Call <code>findClass()</code> to find this class in our locally
+ * defined repositories.</li>
+ * <li>Call the <code>loadClass()</code> method of our parent
+ * class loader, if any.</li>
+ * </ul>
+ * If the class was found using the above steps, and the
+ * <code>resolve</code> flag is <code>true</code>, this method will then
+ * call <code>resolveClass(Class)</code> on the resulting Class object.
+ *
+ * @param name Name of the class to be loaded
+ * @param resolve If <code>true</code> then resolve the class
+ *
+ * @exception ClassNotFoundException if the class was not found
+ */
+ public Class loadClass(final String name, boolean resolve)
+ throws ClassNotFoundException {
+
+ Class clazz = null;
+
+ // (0) Check our previously loaded class cache
+ clazz = findLoadedClass(name);
+ if (clazz != null) {
+ if (resolve)
+ resolveClass(clazz);
+ return (clazz);
+ }
+
+ // (.5) Permission to access this class when using a SecurityManager
+ if (securityManager != null) {
+ int dot = name.lastIndexOf('.');
+ if (dot >= 0) {
+ try {
+ // Do not call the security manager since by default, we grant that package.
+ if (!"org.apache.struts2.jasper.runtime".equalsIgnoreCase(name.substring(0,dot))){
+ securityManager.checkPackageAccess(name.substring(0,dot));
+ }
+ } catch (SecurityException se) {
+ String error = "Security Violation, attempt to use " +
+ "Restricted Class: " + name;
+ se.printStackTrace();
+ throw new ClassNotFoundException(error);
+ }
+ }
+ }
+
+ if( !name.startsWith(Constants.JSP_PACKAGE_NAME + '.') ) {
+ // Class is not in org.apache.jsp, therefore, have our
+ // parent load it
+ clazz = parent.loadClass(name);
+ if( resolve )
+ resolveClass(clazz);
+ return clazz;
+ }
+
+ return findClass(name);
+ }
+
+
+ /**
+ * Delegate to parent
+ *
+ * @see java.lang.ClassLoader#getResourceAsStream(java.lang.String)
+ */
+ public InputStream getResourceAsStream(String name) {
+ InputStream is = parent.getResourceAsStream(name);
+ if (is == null) {
+ URL url = findResource(name);
+ if (url != null) {
+ try {
+ is = url.openStream();
+ } catch (IOException e) {
+ is = null;
+ }
+ }
+ }
+ return is;
+ }
+
+
+ /**
+ * Get the Permissions for a CodeSource.
+ *
+ * Since this ClassLoader is only used for a JSP page in
+ * a web application context, we just return our preset
+ * PermissionCollection for the web app context.
+ *
+ * @param codeSource Code source where the code was loaded from
+ * @return PermissionCollection for CodeSource
+ */
+ public final PermissionCollection getPermissions(CodeSource codeSource) {
+ return permissionCollection;
+ }
+}
\ No newline at end of file
Added: struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/servlet/JspCServletContext.java
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/servlet/JspCServletContext.java?rev=819444&view=auto
==============================================================================
--- struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/servlet/JspCServletContext.java (added)
+++ struts/struts2/trunk/plugins/embeddedjsp/src/main/java/org/apache/struts2/jasper/servlet/JspCServletContext.java Mon Sep 28 01:55:26 2009
@@ -0,0 +1,425 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.struts2.jasper.servlet;
+
+
+import com.opensymphony.xwork2.util.finder.ClassLoaderInterface;
+import com.opensymphony.xwork2.ActionContext;
+
+import java.io.File;
+import java.io.InputStream;
+import java.io.PrintWriter;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Set;
+import java.util.Vector;
+
+import javax.servlet.RequestDispatcher;
+import javax.servlet.Servlet;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+
+import org.apache.struts2.ServletActionContext;
+
+
+/**
+ * Simple <code>ServletContext</code> implementation without
+ * HTTP-specific methods.
+ *
+ * @author Peter Rossbach (pr@webapp.de)
+ */
+
+public class JspCServletContext implements ServletContext {
+
+
+ // ----------------------------------------------------- Instance Variables
+
+
+ /**
+ * Servlet context attributes.
+ */
+ protected Hashtable myAttributes;
+
+
+ /**
+ * The log writer we will write log messages to.
+ */
+ protected PrintWriter myLogWriter;
+
+
+ /**
+ * The base URL (document root) for this context.
+ */
+ private ClassLoaderInterface classLoaderInterface;
+
+
+ // ----------------------------------------------------------- Constructors
+
+
+ /**
+ * Create a new instance of this ServletContext implementation.
+ *
+ * @param aLogWriter PrintWriter which is used for <code>log()</code> calls
+ * @param aResourceBaseURL Resource base URL
+ */
+ public JspCServletContext(PrintWriter aLogWriter, ClassLoaderInterface classLoaderInterface) {
+
+ myAttributes = new Hashtable();
+ myLogWriter = aLogWriter;
+ this.classLoaderInterface = classLoaderInterface;
+ }
+
+
+ // --------------------------------------------------------- Public Methods
+
+
+ /**
+ * Return the specified context attribute, if any.
+ *
+ * @param name Name of the requested attribute
+ */
+ public Object getAttribute(String name) {
+
+ return (myAttributes.get(name));
+
+ }
+
+
+ /**
+ * Return an enumeration of context attribute names.
+ */
+ public Enumeration getAttributeNames() {
+
+ return (myAttributes.keys());
+
+ }
+
+
+ /**
+ * Return the servlet context for the specified path.
+ *
+ * @param uripath Server-relative path starting with '/'
+ */
+ public ServletContext getContext(String uripath) {
+
+ return (null);
+
+ }
+
+
+ /**
+ * Return the context path.
+ */
+ public String getContextPath() {
+
+ return (null);
+
+ }
+
+
+ /**
+ * Return the specified context initialization parameter.
+ *
+ * @param name Name of the requested parameter
+ */
+ public String getInitParameter(String name) {
+
+ return (null);
+
+ }
+
+
+ /**
+ * Return an enumeration of the names of context initialization
+ * parameters.
+ */
+ public Enumeration getInitParameterNames() {
+
+ return (new Vector().elements());
+
+ }
+
+
+ /**
+ * Return the Servlet API major version number.
+ */
+ public int getMajorVersion() {
+
+ return (2);
+
+ }
+
+
+ /**
+ * Return the MIME type for the specified filename.
+ *
+ * @param file Filename whose MIME type is requested
+ */
+ public String getMimeType(String file) {
+
+ return (null);
+
+ }
+
+
+ /**
+ * Return the Servlet API minor version number.
+ */
+ public int getMinorVersion() {
+
+ return (3);
+
+ }
+
+
+ /**
+ * Return a request dispatcher for the specified servlet name.
+ *
+ * @param name Name of the requested servlet
+ */
+ public RequestDispatcher getNamedDispatcher(String name) {
+
+ return (null);
+
+ }
+
+
+ /**
+ * Return the real path for the specified context-relative
+ * virtual path.
+ *
+ * @param path The context-relative virtual path to resolve
+ */
+ public String getRealPath(String path) {
+ try {
+ return
+ (getResource(path).getFile().replace('/', File.separatorChar));
+ } catch (Throwable t) {
+ return (null);
+ }
+ }
+
+
+ /**
+ * Return a request dispatcher for the specified context-relative path.
+ *
+ * @param path Context-relative path for which to acquire a dispatcher
+ */
+ public RequestDispatcher getRequestDispatcher(String path) {
+
+ return (null);
+
+ }
+
+
+ /**
+ * Return a URL object of a resource that is mapped to the
+ * specified context-relative path.
+ *
+ * @param path Context-relative path of the desired resource
+ *
+ * @exception MalformedURLException if the resource path is
+ * not properly formed
+ */
+ public URL getResource(String path) throws MalformedURLException {
+ if ("/WEB-INF/web.xml".equals(path)) {
+ if (ActionContext.getContext() != null) {
+ ServletContext context = ServletActionContext.getServletContext();
+ return context.getResource(path);
+ }
+
+ return null;
+ }
+ return classLoaderInterface.getResource(path);
+ }
+
+
+ /**
+ * Return an InputStream allowing access to the resource at the
+ * specified context-relative path.
+ *
+ * @param path Context-relative path of the desired resource
+ */
+ public InputStream getResourceAsStream(String path) {
+ try {
+ return classLoaderInterface.getResourceAsStream(path);
+ } catch (Throwable t) {
+ return (null);
+ }
+ }
+
+
+ /**
+ * Return the set of resource paths for the "directory" at the
+ * specified context path.
+ *
+ * @param path Context-relative base path
+ */
+ public Set getResourcePaths(String path) {
+
+ Set thePaths = new HashSet();
+ if (!path.endsWith("/"))
+ path += "/";
+ String basePath = getRealPath(path);
+ if (basePath == null)
+ return (thePaths);
+ File theBaseDir = new File(basePath);
+ if (!theBaseDir.exists() || !theBaseDir.isDirectory())
+ return (thePaths);
+ String theFiles[] = theBaseDir.list();
+ for (int i = 0; i < theFiles.length; i++) {
+ File testFile = new File(basePath + File.separator + theFiles[i]);
+ if (testFile.isFile())
+ thePaths.add(path + theFiles[i]);
+ else if (testFile.isDirectory())
+ thePaths.add(path + theFiles[i] + "/");
+ }
+ return (thePaths);
+
+ }
+
+
+ /**
+ * Return descriptive information about this server.
+ */
+ public String getServerInfo() {
+
+ return ("JspCServletContext/1.0");
+
+ }
+
+
+ /**
+ * Return a null reference for the specified servlet name.
+ *
+ * @param name Name of the requested servlet
+ *
+ * @deprecated This method has been deprecated with no replacement
+ */
+ public Servlet getServlet(String name) throws ServletException {
+
+ return (null);
+
+ }
+
+
+ /**
+ * Return the name of this servlet context.
+ */
+ public String getServletContextName() {
+
+ return (getServerInfo());
+
+ }
+
+
+ /**
+ * Return an empty enumeration of servlet names.
+ *
+ * @deprecated This method has been deprecated with no replacement
+ */
+ public Enumeration getServletNames() {
+
+ return (new Vector().elements());
+
+ }
+
+
+ /**
+ * Return an empty enumeration of servlets.
+ *
+ * @deprecated This method has been deprecated with no replacement
+ */
+ public Enumeration getServlets() {
+
+ return (new Vector().elements());
+
+ }
+
+
+ /**
+ * Log the specified message.
+ *
+ * @param message The message to be logged
+ */
+ public void log(String message) {
+
+ myLogWriter.println(message);
+
+ }
+
+
+ /**
+ * Log the specified message and exception.
+ *
+ * @param exception The exception to be logged
+ * @param message The message to be logged
+ *
+ * @deprecated Use log(String,Throwable) instead
+ */
+ public void log(Exception exception, String message) {
+
+ log(message, exception);
+
+ }
+
+
+ /**
+ * Log the specified message and exception.
+ *
+ * @param message The message to be logged
+ * @param exception The exception to be logged
+ */
+ public void log(String message, Throwable exception) {
+
+ myLogWriter.println(message);
+ exception.printStackTrace(myLogWriter);
+
+ }
+
+
+ /**
+ * Remove the specified context attribute.
+ *
+ * @param name Name of the attribute to remove
+ */
+ public void removeAttribute(String name) {
+
+ myAttributes.remove(name);
+
+ }
+
+
+ /**
+ * Set or replace the specified context attribute.
+ *
+ * @param name Name of the context attribute to set
+ * @param value Corresponding attribute value
+ */
+ public void setAttribute(String name, Object value) {
+
+ myAttributes.put(name, value);
+
+ }
+
+
+
+}