This commit is contained in:
2024-11-30 19:03:49 +08:00
commit 1e6763c160
3806 changed files with 737676 additions and 0 deletions

View File

@@ -0,0 +1,707 @@
/*
* 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.jasper.runtime;
import java.io.CharArrayReader;
import java.io.IOException;
import java.io.Reader;
import java.io.Writer;
import java.security.AccessController;
import java.security.PrivilegedAction;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.tagext.BodyContent;
import org.apache.jasper.Constants;
/**
* Write text to a character-output stream, buffering characters so as
* to provide for the efficient writing of single characters, arrays,
* and strings.
*
* Provide support for discarding for the output that has been buffered.
*
* @author Rajiv Mordani
* @author Jan Luehe
*/
public class BodyContentImpl extends BodyContent {
private static final boolean LIMIT_BUFFER;
private static final int TAG_BUFFER_SIZE;
static {
if (System.getSecurityManager() == null) {
LIMIT_BUFFER = Boolean.parseBoolean(System.getProperty(
"org.apache.jasper.runtime.BodyContentImpl.LIMIT_BUFFER", "false"));
TAG_BUFFER_SIZE = Integer.getInteger(
"org.apache.jasper.runtime.BodyContentImpl.BUFFER_SIZE",
Constants.DEFAULT_TAG_BUFFER_SIZE).intValue();
} else {
LIMIT_BUFFER = AccessController.doPrivileged(
new PrivilegedAction<Boolean>() {
@Override
public Boolean run() {
return Boolean.valueOf(System.getProperty(
"org.apache.jasper.runtime.BodyContentImpl.LIMIT_BUFFER",
"false"));
}
}
).booleanValue();
TAG_BUFFER_SIZE = AccessController.doPrivileged(
new PrivilegedAction<Integer>() {
@Override
public Integer run() {
return Integer.getInteger(
"org.apache.jasper.runtime.BodyContentImpl.BUFFER_SIZE",
Constants.DEFAULT_TAG_BUFFER_SIZE);
}
}
).intValue();
}
}
private char[] cb;
private int nextChar;
private boolean closed;
/**
* Enclosed writer to which any output is written
*/
private Writer writer;
/**
* Constructor.
* @param enclosingWriter The wrapped writer
*/
public BodyContentImpl(JspWriter enclosingWriter) {
super(enclosingWriter);
cb = new char[TAG_BUFFER_SIZE];
bufferSize = cb.length;
nextChar = 0;
closed = false;
}
/**
* Write a single character.
* @param c The char to write
* @throws IOException Error writing to wrapped writer
*/
@Override
public void write(int c) throws IOException {
if (writer != null) {
writer.write(c);
} else {
ensureOpen();
if (nextChar >= bufferSize) {
reAllocBuff (1);
}
cb[nextChar++] = (char) c;
}
}
/**
* Write a portion of an array of characters.
*
* <p> Ordinarily this method stores characters from the given array into
* this stream's buffer, flushing the buffer to the underlying stream as
* needed. If the requested length is at least as large as the buffer,
* however, then this method will flush the buffer and write the characters
* directly to the underlying stream. Thus redundant
* <code>DiscardableBufferedWriter</code>s will not copy data
* unnecessarily.
*
* @param cbuf A character array
* @param off Offset from which to start reading characters
* @param len Number of characters to write
* @throws IOException Error writing to wrapped writer
*/
@Override
public void write(char[] cbuf, int off, int len) throws IOException {
if (writer != null) {
writer.write(cbuf, off, len);
} else {
ensureOpen();
if ((off < 0) || (off > cbuf.length) || (len < 0) ||
((off + len) > cbuf.length) || ((off + len) < 0)) {
throw new IndexOutOfBoundsException();
} else if (len == 0) {
return;
}
if (len >= bufferSize - nextChar)
reAllocBuff (len);
System.arraycopy(cbuf, off, cb, nextChar, len);
nextChar+=len;
}
}
/**
* Write an array of characters. This method cannot be inherited from the
* Writer class because it must suppress I/O exceptions.
* @param buf Content to write
* @throws IOException Error writing to wrapped writer
*/
@Override
public void write(char[] buf) throws IOException {
if (writer != null) {
writer.write(buf);
} else {
write(buf, 0, buf.length);
}
}
/**
* Write a portion of a String.
*
* @param s String to be written
* @param off Offset from which to start reading characters
* @param len Number of characters to be written
* @throws IOException Error writing to wrapped writer
*/
@Override
public void write(String s, int off, int len) throws IOException {
if (writer != null) {
writer.write(s, off, len);
} else {
ensureOpen();
if (len >= bufferSize - nextChar)
reAllocBuff(len);
s.getChars(off, off + len, cb, nextChar);
nextChar += len;
}
}
/**
* Write a string. This method cannot be inherited from the Writer class
* because it must suppress I/O exceptions.
* @param s String to be written
* @throws IOException Error writing to wrapped writer
*/
@Override
public void write(String s) throws IOException {
if (writer != null) {
writer.write(s);
} else {
write(s, 0, s.length());
}
}
/**
* Write a line separator. The line separator string is defined by the
* system property <code>line.separator</code>, and is not necessarily a
* single newline ('\n') character.
*
* @throws IOException Error writing to wrapped writer
*/
@Override
public void newLine() throws IOException {
if (writer != null) {
writer.write(System.lineSeparator());
} else {
write(System.lineSeparator());
}
}
/**
* Print a boolean value. The string produced by <code>{@link
* java.lang.String#valueOf(boolean)}</code> is translated into bytes
* according to the platform's default character encoding, and these bytes
* are written in exactly the manner of the <code>{@link
* #write(int)}</code> method.
*
* @param b The <code>boolean</code> to be printed
* @throws IOException Error writing to wrapped writer
*/
@Override
public void print(boolean b) throws IOException {
if (writer != null) {
writer.write(b ? "true" : "false");
} else {
write(b ? "true" : "false");
}
}
/**
* Print a character. The character is translated into one or more bytes
* according to the platform's default character encoding, and these bytes
* are written in exactly the manner of the <code>{@link
* #write(int)}</code> method.
*
* @param c The <code>char</code> to be printed
* @throws IOException Error writing to wrapped writer
*/
@Override
public void print(char c) throws IOException {
if (writer != null) {
writer.write(String.valueOf(c));
} else {
write(String.valueOf(c));
}
}
/**
* Print an integer. The string produced by <code>{@link
* java.lang.String#valueOf(int)}</code> is translated into bytes according
* to the platform's default character encoding, and these bytes are
* written in exactly the manner of the <code>{@link #write(int)}</code>
* method.
*
* @param i The <code>int</code> to be printed
* @throws IOException Error writing to wrapped writer
*/
@Override
public void print(int i) throws IOException {
if (writer != null) {
writer.write(String.valueOf(i));
} else {
write(String.valueOf(i));
}
}
/**
* Print a long integer. The string produced by <code>{@link
* java.lang.String#valueOf(long)}</code> is translated into bytes
* according to the platform's default character encoding, and these bytes
* are written in exactly the manner of the
* <code>{@link #write(int)}</code> method.
*
* @param l The <code>long</code> to be printed
* @throws IOException Error writing to wrapped writer
*/
@Override
public void print(long l) throws IOException {
if (writer != null) {
writer.write(String.valueOf(l));
} else {
write(String.valueOf(l));
}
}
/**
* Print a floating-point number. The string produced by <code>{@link
* java.lang.String#valueOf(float)}</code> is translated into bytes
* according to the platform's default character encoding, and these bytes
* are written in exactly the manner of the
* <code>{@link #write(int)}</code> method.
*
* @param f The <code>float</code> to be printed
* @throws IOException Error writing to wrapped writer
*/
@Override
public void print(float f) throws IOException {
if (writer != null) {
writer.write(String.valueOf(f));
} else {
write(String.valueOf(f));
}
}
/**
* Print a double-precision floating-point number. The string produced by
* <code>{@link java.lang.String#valueOf(double)}</code> is translated into
* bytes according to the platform's default character encoding, and these
* bytes are written in exactly the manner of the <code>{@link
* #write(int)}</code> method.
*
* @param d The <code>double</code> to be printed
* @throws IOException Error writing to wrapped writer
*/
@Override
public void print(double d) throws IOException {
if (writer != null) {
writer.write(String.valueOf(d));
} else {
write(String.valueOf(d));
}
}
/**
* Print an array of characters. The characters are converted into bytes
* according to the platform's default character encoding, and these bytes
* are written in exactly the manner of the
* <code>{@link #write(int)}</code> method.
*
* @param s The array of chars to be printed
*
* @throws NullPointerException If <code>s</code> is <code>null</code>
* @throws IOException Error writing to wrapped writer
*/
@Override
public void print(char[] s) throws IOException {
if (writer != null) {
writer.write(s);
} else {
write(s);
}
}
/**
* Print a string. If the argument is <code>null</code> then the string
* <code>"null"</code> is printed. Otherwise, the string's characters are
* converted into bytes according to the platform's default character
* encoding, and these bytes are written in exactly the manner of the
* <code>{@link #write(int)}</code> method.
*
* @param s The <code>String</code> to be printed
* @throws IOException Error writing to wrapped writer
*/
@Override
public void print(String s) throws IOException {
if (s == null) s = "null";
if (writer != null) {
writer.write(s);
} else {
write(s);
}
}
/**
* Print an object. The string produced by the <code>{@link
* java.lang.String#valueOf(Object)}</code> method is translated into bytes
* according to the platform's default character encoding, and these bytes
* are written in exactly the manner of the
* <code>{@link #write(int)}</code> method.
*
* @param obj The <code>Object</code> to be printed
* @throws IOException Error writing to wrapped writer
*/
@Override
public void print(Object obj) throws IOException {
if (writer != null) {
writer.write(String.valueOf(obj));
} else {
write(String.valueOf(obj));
}
}
/**
* Terminate the current line by writing the line separator string. The
* line separator string is defined by the system property
* <code>line.separator</code>, and is not necessarily a single newline
* character (<code>'\n'</code>).
*
* @throws IOException Error writing to wrapped writer
*/
@Override
public void println() throws IOException {
newLine();
}
/**
* Print a boolean value and then terminate the line. This method behaves
* as though it invokes <code>{@link #print(boolean)}</code> and then
* <code>{@link #println()}</code>.
*
* @param x The <code>boolean</code> to be printed
* @throws IOException Error writing to wrapped writer
*/
@Override
public void println(boolean x) throws IOException {
print(x);
println();
}
/**
* Print a character and then terminate the line. This method behaves as
* though it invokes <code>{@link #print(char)}</code> and then
* <code>{@link #println()}</code>.
*
* @param x The <code>char</code> to be printed
* @throws IOException Error writing to wrapped writer
*/
@Override
public void println(char x) throws IOException {
print(x);
println();
}
/**
* Print an integer and then terminate the line. This method behaves as
* though it invokes <code>{@link #print(int)}</code> and then
* <code>{@link #println()}</code>.
*
* @param x The <code>int</code> to be printed
* @throws IOException Error writing to wrapped writer
*/
@Override
public void println(int x) throws IOException {
print(x);
println();
}
/**
* Print a long integer and then terminate the line. This method behaves
* as though it invokes <code>{@link #print(long)}</code> and then
* <code>{@link #println()}</code>.
*
* @param x The <code>long</code> to be printed
* @throws IOException Error writing to wrapped writer
*/
@Override
public void println(long x) throws IOException {
print(x);
println();
}
/**
* Print a floating-point number and then terminate the line. This method
* behaves as though it invokes <code>{@link #print(float)}</code> and then
* <code>{@link #println()}</code>.
*
* @param x The <code>float</code> to be printed
* @throws IOException Error writing to wrapped writer
*/
@Override
public void println(float x) throws IOException {
print(x);
println();
}
/**
* Print a double-precision floating-point number and then terminate the
* line. This method behaves as though it invokes <code>{@link
* #print(double)}</code> and then <code>{@link #println()}</code>.
*
* @param x The <code>double</code> to be printed
* @throws IOException Error writing to wrapped writer
*/
@Override
public void println(double x) throws IOException{
print(x);
println();
}
/**
* Print an array of characters and then terminate the line. This method
* behaves as though it invokes <code>{@link #print(char[])}</code> and
* then <code>{@link #println()}</code>.
*
* @param x The <code>char</code> array to be printed
* @throws IOException Error writing to wrapped writer
*/
@Override
public void println(char x[]) throws IOException {
print(x);
println();
}
/**
* Print a String and then terminate the line. This method behaves as
* though it invokes <code>{@link #print(String)}</code> and then
* <code>{@link #println()}</code>.
*
* @param x The string to be printed
* @throws IOException Error writing to wrapped writer
*/
@Override
public void println(String x) throws IOException {
print(x);
println();
}
/**
* Print an Object and then terminate the line. This method behaves as
* though it invokes <code>{@link #print(Object)}</code> and then
* <code>{@link #println()}</code>.
*
* @param x The object to be printed
* @throws IOException Error writing to wrapped writer
*/
@Override
public void println(Object x) throws IOException {
print(x);
println();
}
/**
* Clear the contents of the buffer. If the buffer has been already
* been flushed then the clear operation shall throw an IOException
* to signal the fact that some data has already been irrevocably
* written to the client response stream.
*
* @throws IOException If there is no wrapped writer
*/
@Override
public void clear() throws IOException {
if (writer != null) {
throw new IOException();
} else {
nextChar = 0;
if (LIMIT_BUFFER && (cb.length > TAG_BUFFER_SIZE)) {
cb = new char[TAG_BUFFER_SIZE];
bufferSize = cb.length;
}
}
}
/**
* Clears the current contents of the buffer. Unlike clear(), this
* method will not throw an IOException if the buffer has already been
* flushed. It merely clears the current content of the buffer and
* returns.
*
* @throws IOException Should not happen
*/
@Override
public void clearBuffer() throws IOException {
if (writer == null) {
this.clear();
}
}
/**
* Close the stream, flushing it first. Once a stream has been closed,
* further write() or flush() invocations will cause an IOException to be
* thrown. Closing a previously-closed stream, however, has no effect.
*
* @throws IOException Error writing to wrapped writer
*/
@Override
public void close() throws IOException {
if (writer != null) {
writer.close();
} else {
closed = true;
}
}
/**
* This method returns the size of the buffer used by the JspWriter.
*
* @return the size of the buffer in bytes, or 0 is unbuffered.
*/
@Override
public int getBufferSize() {
// According to the spec, the JspWriter returned by
// JspContext.pushBody(java.io.Writer writer) must behave as
// though it were unbuffered. This means that its getBufferSize()
// must always return 0.
return (writer == null) ? bufferSize : 0;
}
/**
* @return the number of bytes unused in the buffer
*/
@Override
public int getRemaining() {
return (writer == null) ? bufferSize-nextChar : 0;
}
/**
* Return the value of this BodyJspWriter as a Reader.
* Note: this is after evaluation!! There are no scriptlets,
* etc in this stream.
*
* @return the value of this BodyJspWriter as a Reader
*/
@Override
public Reader getReader() {
return (writer == null) ? new CharArrayReader (cb, 0, nextChar) : null;
}
/**
* Return the value of the BodyJspWriter as a String.
* Note: this is after evaluation!! There are no scriptlets,
* etc in this stream.
*
* @return the value of the BodyJspWriter as a String
*/
@Override
public String getString() {
return (writer == null) ? new String(cb, 0, nextChar) : null;
}
/**
* Write the contents of this BodyJspWriter into a Writer.
* Subclasses are likely to do interesting things with the
* implementation so some things are extra efficient.
*
* @param out The writer into which to place the contents of this body
* evaluation
* @throws IOException Error writing to writer
*/
@Override
public void writeOut(Writer out) throws IOException {
if (writer == null) {
out.write(cb, 0, nextChar);
// Flush not called as the writer passed could be a BodyContent and
// it doesn't allow to flush.
}
}
/**
* Sets the writer to which all output is written.
*/
void setWriter(Writer writer) {
this.writer = writer;
closed = false;
if (writer == null) {
clearBody();
}
}
/**
* This method shall "reset" the internal state of a BodyContentImpl,
* releasing all internal references, and preparing it for potential
* reuse by a later invocation of {@link PageContextImpl#pushBody(Writer)}.
*
* <p>Note, that BodyContentImpl instances are usually owned by a
* PageContextImpl instance, and PageContextImpl instances are recycled
* and reused.
*
* @see PageContextImpl#release()
*/
protected void recycle() {
this.writer = null;
try {
this.clear();
} catch (IOException ex) {
// ignore
}
}
private void ensureOpen() throws IOException {
if (closed) throw new IOException("Stream closed");
}
/**
* Reallocates buffer since the spec requires it to be unbounded.
*/
private void reAllocBuff(int len) {
if (bufferSize + len <= cb.length) {
bufferSize = cb.length;
return;
}
if (len < cb.length) {
len = cb.length;
}
char[] tmp = new char[cb.length + len];
System.arraycopy(cb, 0, tmp, 0, cb.length);
cb = tmp;
bufferSize = cb.length;
}
}

View File

@@ -0,0 +1,60 @@
/*
* 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.jasper.runtime;
import java.lang.reflect.InvocationTargetException;
/**
* Utilities for handling Throwables and Exceptions.
*/
public class ExceptionUtils {
/**
* Checks whether the supplied Throwable is one that needs to be
* rethrown and swallows all others.
* @param t the Throwable to check
*/
public static void handleThrowable(Throwable t) {
if (t instanceof ThreadDeath) {
throw (ThreadDeath) t;
}
if (t instanceof StackOverflowError) {
// Swallow silently - it should be recoverable
return;
}
if (t instanceof VirtualMachineError) {
throw (VirtualMachineError) t;
}
// All other instances of Throwable will be silently swallowed
}
/**
* Checks whether the supplied Throwable is an instance of
* <code>InvocationTargetException</code> and returns the throwable that is
* wrapped by it, if there is any.
*
* @param t the Throwable to check
* @return <code>t</code> or <code>t.getCause()</code>
*/
public static Throwable unwrapInvocationTargetException(Throwable t) {
if (t instanceof InvocationTargetException && t.getCause() != null) {
return t.getCause();
}
return t;
}
}

View File

@@ -0,0 +1,91 @@
/*
* 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.jasper.runtime;
import java.io.IOException;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.jsp.HttpJspPage;
import org.apache.jasper.compiler.Localizer;
/**
* This is the super class of all JSP-generated servlets.
*
* @author Anil K. Vijendran
*/
public abstract class HttpJspBase extends HttpServlet implements HttpJspPage {
private static final long serialVersionUID = 1L;
protected HttpJspBase() {
}
@Override
public final void init(ServletConfig config)
throws ServletException
{
super.init(config);
jspInit();
_jspInit();
}
@Override
public String getServletInfo() {
return Localizer.getMessage("jsp.engine.info");
}
@Override
public final void destroy() {
jspDestroy();
_jspDestroy();
}
/**
* Entry point into service.
*/
@Override
public final void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
_jspService(request, response);
}
@Override
public void jspInit() {
}
public void _jspInit() {
}
@Override
public void jspDestroy() {
}
protected void _jspDestroy() {
}
@Override
public abstract void _jspService(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException;
}

View File

@@ -0,0 +1,37 @@
/*
* 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.jasper.runtime;
import javax.servlet.ServletConfig;
import org.apache.tomcat.InstanceManager;
public class InstanceManagerFactory {
private InstanceManagerFactory() {
}
public static InstanceManager getInstanceManager(ServletConfig config) {
InstanceManager instanceManager =
(InstanceManager) config.getServletContext().getAttribute(InstanceManager.class.getName());
if (instanceManager == null) {
throw new IllegalStateException("No org.apache.tomcat.InstanceManager set in ServletContext");
}
return instanceManager;
}
}

View File

@@ -0,0 +1,144 @@
/*
* 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.jasper.runtime;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.List;
import javax.el.CompositeELResolver;
import javax.el.ELContext;
import javax.el.ELContextEvent;
import javax.el.ELContextListener;
import javax.el.ELResolver;
import javax.el.ExpressionFactory;
import javax.servlet.ServletContext;
import javax.servlet.jsp.JspApplicationContext;
import javax.servlet.jsp.JspContext;
import org.apache.jasper.Constants;
import org.apache.jasper.el.ELContextImpl;
import org.apache.jasper.el.JasperELResolver;
/**
* Implementation of JspApplicationContext
*
* @author Jacob Hookom
*/
public class JspApplicationContextImpl implements JspApplicationContext {
private static final String KEY = JspApplicationContextImpl.class.getName();
private final ExpressionFactory expressionFactory =
ExpressionFactory.newInstance();
private final List<ELContextListener> contextListeners = new ArrayList<>();
private final List<ELResolver> resolvers = new ArrayList<>();
private boolean instantiated = false;
private ELResolver resolver;
public JspApplicationContextImpl() {
}
@Override
public void addELContextListener(ELContextListener listener) {
if (listener == null) {
throw new IllegalArgumentException("ELContextListener was null");
}
this.contextListeners.add(listener);
}
public static JspApplicationContextImpl getInstance(ServletContext context) {
if (context == null) {
throw new IllegalArgumentException("ServletContext was null");
}
JspApplicationContextImpl impl = (JspApplicationContextImpl) context
.getAttribute(KEY);
if (impl == null) {
impl = new JspApplicationContextImpl();
context.setAttribute(KEY, impl);
}
return impl;
}
public ELContextImpl createELContext(JspContext context) {
if (context == null) {
throw new IllegalArgumentException("JspContext was null");
}
// create ELContext for JspContext
final ELResolver r = this.createELResolver();
ELContextImpl ctx;
if (Constants.IS_SECURITY_ENABLED) {
ctx = AccessController.doPrivileged(
new PrivilegedAction<ELContextImpl>() {
@Override
public ELContextImpl run() {
return new ELContextImpl(r);
}
});
} else {
ctx = new ELContextImpl(r);
}
ctx.putContext(JspContext.class, context);
// alert all ELContextListeners
fireListeners(ctx);
return ctx;
}
protected void fireListeners(ELContext elContext) {
ELContextEvent event = new ELContextEvent(elContext);
for (int i = 0; i < this.contextListeners.size(); i++) {
this.contextListeners.get(i).contextCreated(event);
}
}
private ELResolver createELResolver() {
this.instantiated = true;
if (this.resolver == null) {
CompositeELResolver r = new JasperELResolver(this.resolvers,
expressionFactory.getStreamELResolver());
this.resolver = r;
}
return this.resolver;
}
@Override
public void addELResolver(ELResolver resolver) throws IllegalStateException {
if (resolver == null) {
throw new IllegalArgumentException("ELResolver was null");
}
if (this.instantiated) {
throw new IllegalStateException(
"cannot call addELResolver after the first request has been made");
}
this.resolvers.add(resolver);
}
@Override
public ExpressionFactory getExpressionFactory() {
return expressionFactory;
}
}

View File

@@ -0,0 +1,662 @@
/*
* 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.jasper.runtime;
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import javax.el.ELContext;
import javax.el.ELResolver;
import javax.el.EvaluationListener;
import javax.el.FunctionMapper;
import javax.el.ImportHandler;
import javax.el.VariableMapper;
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.HttpSession;
import javax.servlet.jsp.JspApplicationContext;
import javax.servlet.jsp.JspContext;
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 javax.servlet.jsp.tagext.JspTag;
import javax.servlet.jsp.tagext.VariableInfo;
import org.apache.jasper.compiler.Localizer;
/**
* Implementation of a JSP Context Wrapper.
*
* The JSP Context Wrapper is a JspContext created and maintained by a tag
* handler implementation. It wraps the Invoking JSP Context, that is, the
* JspContext instance passed to the tag handler by the invoking page via
* setJspContext().
*
* @author Kin-man Chung
* @author Jan Luehe
* @author Jacob Hookom
*/
@SuppressWarnings("deprecation") // Have to support old JSP EL API
public class JspContextWrapper extends PageContext implements VariableResolver {
private final JspTag jspTag;
// Invoking JSP context
private final PageContext invokingJspCtxt;
private final transient HashMap<String, Object> pageAttributes;
// ArrayList of NESTED scripting variables
private final ArrayList<String> nestedVars;
// ArrayList of AT_BEGIN scripting variables
private final ArrayList<String> atBeginVars;
// ArrayList of AT_END scripting variables
private final ArrayList<String> atEndVars;
private final Map<String,String> aliases;
private final HashMap<String, Object> originalNestedVars;
private ServletContext servletContext = null;
private ELContext elContext = null;
private final PageContext rootJspCtxt;
public JspContextWrapper(JspTag jspTag, JspContext jspContext,
ArrayList<String> nestedVars, ArrayList<String> atBeginVars,
ArrayList<String> atEndVars, Map<String,String> aliases) {
this.jspTag = jspTag;
this.invokingJspCtxt = (PageContext) jspContext;
if (jspContext instanceof JspContextWrapper) {
rootJspCtxt = ((JspContextWrapper)jspContext).rootJspCtxt;
}
else {
rootJspCtxt = invokingJspCtxt;
}
this.nestedVars = nestedVars;
this.atBeginVars = atBeginVars;
this.atEndVars = atEndVars;
this.pageAttributes = new HashMap<>(16);
this.aliases = aliases;
if (nestedVars != null) {
this.originalNestedVars = new HashMap<>(nestedVars.size());
} else {
this.originalNestedVars = null;
}
syncBeginTagFile();
}
@Override
public void initialize(Servlet servlet, ServletRequest request,
ServletResponse response, String errorPageURL,
boolean needsSession, int bufferSize, boolean autoFlush)
throws IOException, IllegalStateException, IllegalArgumentException {
}
@Override
public Object getAttribute(String name) {
if (name == null) {
throw new NullPointerException(Localizer
.getMessage("jsp.error.attribute.null_name"));
}
return pageAttributes.get(name);
}
@Override
public Object getAttribute(String name, int scope) {
if (name == null) {
throw new NullPointerException(Localizer
.getMessage("jsp.error.attribute.null_name"));
}
if (scope == PAGE_SCOPE) {
return pageAttributes.get(name);
}
return rootJspCtxt.getAttribute(name, scope);
}
@Override
public void setAttribute(String name, Object value) {
if (name == null) {
throw new NullPointerException(Localizer
.getMessage("jsp.error.attribute.null_name"));
}
if (value != null) {
pageAttributes.put(name, value);
} else {
removeAttribute(name, PAGE_SCOPE);
}
}
@Override
public void setAttribute(String name, Object value, int scope) {
if (name == null) {
throw new NullPointerException(Localizer
.getMessage("jsp.error.attribute.null_name"));
}
if (scope == PAGE_SCOPE) {
if (value != null) {
pageAttributes.put(name, value);
} else {
removeAttribute(name, PAGE_SCOPE);
}
} else {
rootJspCtxt.setAttribute(name, value, scope);
}
}
@Override
public Object findAttribute(String name) {
if (name == null) {
throw new NullPointerException(Localizer
.getMessage("jsp.error.attribute.null_name"));
}
Object o = pageAttributes.get(name);
if (o == null) {
o = rootJspCtxt.getAttribute(name, REQUEST_SCOPE);
if (o == null) {
if (getSession() != null) {
o = rootJspCtxt.getAttribute(name, SESSION_SCOPE);
}
if (o == null) {
o = rootJspCtxt.getAttribute(name, APPLICATION_SCOPE);
}
}
}
return o;
}
@Override
public void removeAttribute(String name) {
if (name == null) {
throw new NullPointerException(Localizer
.getMessage("jsp.error.attribute.null_name"));
}
pageAttributes.remove(name);
rootJspCtxt.removeAttribute(name, REQUEST_SCOPE);
if (getSession() != null) {
rootJspCtxt.removeAttribute(name, SESSION_SCOPE);
}
rootJspCtxt.removeAttribute(name, APPLICATION_SCOPE);
}
@Override
public void removeAttribute(String name, int scope) {
if (name == null) {
throw new NullPointerException(Localizer
.getMessage("jsp.error.attribute.null_name"));
}
if (scope == PAGE_SCOPE) {
pageAttributes.remove(name);
} else {
rootJspCtxt.removeAttribute(name, scope);
}
}
@Override
public int getAttributesScope(String name) {
if (name == null) {
throw new NullPointerException(Localizer
.getMessage("jsp.error.attribute.null_name"));
}
if (pageAttributes.get(name) != null) {
return PAGE_SCOPE;
} else {
return rootJspCtxt.getAttributesScope(name);
}
}
@Override
public Enumeration<String> getAttributeNamesInScope(int scope) {
if (scope == PAGE_SCOPE) {
return Collections.enumeration(pageAttributes.keySet());
}
return rootJspCtxt.getAttributeNamesInScope(scope);
}
@Override
public void release() {
invokingJspCtxt.release();
}
@Override
public JspWriter getOut() {
return rootJspCtxt.getOut();
}
@Override
public HttpSession getSession() {
return rootJspCtxt.getSession();
}
@Override
public Object getPage() {
return invokingJspCtxt.getPage();
}
@Override
public ServletRequest getRequest() {
return invokingJspCtxt.getRequest();
}
@Override
public ServletResponse getResponse() {
return rootJspCtxt.getResponse();
}
@Override
public Exception getException() {
return invokingJspCtxt.getException();
}
@Override
public ServletConfig getServletConfig() {
return invokingJspCtxt.getServletConfig();
}
@Override
public ServletContext getServletContext() {
if (servletContext == null) {
servletContext = rootJspCtxt.getServletContext();
}
return servletContext;
}
@Override
public void forward(String relativeUrlPath) throws ServletException,
IOException {
invokingJspCtxt.forward(relativeUrlPath);
}
@Override
public void include(String relativeUrlPath) throws ServletException,
IOException {
invokingJspCtxt.include(relativeUrlPath);
}
@Override
public void include(String relativeUrlPath, boolean flush)
throws ServletException, IOException {
invokingJspCtxt.include(relativeUrlPath, false);
}
@Override
@Deprecated
public VariableResolver getVariableResolver() {
return this;
}
@Override
public BodyContent pushBody() {
return invokingJspCtxt.pushBody();
}
@Override
public JspWriter pushBody(Writer writer) {
return invokingJspCtxt.pushBody(writer);
}
@Override
public JspWriter popBody() {
return invokingJspCtxt.popBody();
}
@Override
@Deprecated
public ExpressionEvaluator getExpressionEvaluator() {
return invokingJspCtxt.getExpressionEvaluator();
}
@Override
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);
}
@Override
public void handlePageException(Throwable t) throws IOException,
ServletException {
invokingJspCtxt.handlePageException(t);
}
/**
* VariableResolver interface
*/
@Override
@Deprecated
public Object resolveVariable(String pName) throws ELException {
ELContext ctx = this.getELContext();
return ctx.getELResolver().getValue(ctx, null, pName);
}
/**
* Synchronize variables at begin of tag file
*/
public void syncBeginTagFile() {
saveNestedVariables();
}
/**
* Synchronize variables before fragment invocation
*/
public void syncBeforeInvoke() {
copyTagToPageScope(VariableInfo.NESTED);
copyTagToPageScope(VariableInfo.AT_BEGIN);
}
/**
* Synchronize variables at end of tag file
*/
public void syncEndTagFile() {
copyTagToPageScope(VariableInfo.AT_BEGIN);
copyTagToPageScope(VariableInfo.AT_END);
restoreNestedVariables();
}
/**
* Copies the variables of the given scope from the virtual page scope of
* this JSP context wrapper to the page scope of the invoking JSP context.
*
* @param scope
* variable scope (one of NESTED, AT_BEGIN, or AT_END)
*/
private void copyTagToPageScope(int scope) {
Iterator<String> iter = null;
switch (scope) {
case VariableInfo.NESTED:
if (nestedVars != null) {
iter = nestedVars.iterator();
}
break;
case VariableInfo.AT_BEGIN:
if (atBeginVars != null) {
iter = atBeginVars.iterator();
}
break;
case VariableInfo.AT_END:
if (atEndVars != null) {
iter = atEndVars.iterator();
}
break;
}
while ((iter != null) && iter.hasNext()) {
String varName = iter.next();
Object obj = getAttribute(varName);
varName = findAlias(varName);
if (obj != null) {
invokingJspCtxt.setAttribute(varName, obj);
} else {
invokingJspCtxt.removeAttribute(varName, PAGE_SCOPE);
}
}
}
/**
* Saves the values of any NESTED variables that are present in the invoking
* JSP context, so they can later be restored.
*/
private void saveNestedVariables() {
if (nestedVars != null) {
for (String varName : nestedVars) {
varName = findAlias(varName);
Object obj = invokingJspCtxt.getAttribute(varName);
if (obj != null) {
originalNestedVars.put(varName, obj);
}
}
}
}
/**
* Restores the values of any NESTED variables in the invoking JSP context.
*/
private void restoreNestedVariables() {
if (nestedVars != null) {
for (String varName : nestedVars) {
varName = findAlias(varName);
Object obj = originalNestedVars.get(varName);
if (obj != null) {
invokingJspCtxt.setAttribute(varName, obj);
} else {
invokingJspCtxt.removeAttribute(varName, PAGE_SCOPE);
}
}
}
}
/**
* Checks to see if the given variable name is used as an alias, and if so,
* returns the variable name for which it is used as an alias.
*
* @param varName
* The variable name to check
* @return The variable name for which varName is used as an alias, or
* varName if it is not being used as an alias
*/
private String findAlias(String varName) {
if (aliases == null)
return varName;
String alias = aliases.get(varName);
if (alias == null) {
return varName;
}
return alias;
}
@Override
public ELContext getELContext() {
if (elContext == null) {
elContext = new ELContextWrapper(rootJspCtxt.getELContext(), jspTag, this);
JspFactory factory = JspFactory.getDefaultFactory();
JspApplicationContext jspAppCtxt = factory.getJspApplicationContext(servletContext);
if (jspAppCtxt instanceof JspApplicationContextImpl) {
((JspApplicationContextImpl) jspAppCtxt).fireListeners(elContext);
}
}
return elContext;
}
static class ELContextWrapper extends ELContext {
private final ELContext wrapped;
private final JspTag jspTag;
private final PageContext pageContext;
private ImportHandler importHandler;
private ELContextWrapper(ELContext wrapped, JspTag jspTag, PageContext pageContext) {
this.wrapped = wrapped;
this.jspTag = jspTag;
this.pageContext = pageContext;
}
ELContext getWrappedELContext() {
return wrapped;
}
@Override
public void setPropertyResolved(boolean resolved) {
wrapped.setPropertyResolved(resolved);
}
@Override
public void setPropertyResolved(Object base, Object property) {
wrapped.setPropertyResolved(base, property);
}
@Override
public boolean isPropertyResolved() {
return wrapped.isPropertyResolved();
}
@Override
public void putContext(@SuppressWarnings("rawtypes") Class key, Object contextObject) {
wrapped.putContext(key, contextObject);
}
@Override
public Object getContext(@SuppressWarnings("rawtypes") Class key) {
if (key == JspContext.class) {
return pageContext;
}
return wrapped.getContext(key);
}
@Override
public ImportHandler getImportHandler() {
if (importHandler == null) {
importHandler = new ImportHandler();
if (jspTag instanceof JspSourceImports) {
Set<String> packageImports = ((JspSourceImports) jspTag).getPackageImports();
if (packageImports != null) {
for (String packageImport : packageImports) {
importHandler.importPackage(packageImport);
}
}
Set<String> classImports = ((JspSourceImports) jspTag).getClassImports();
if (classImports != null) {
for (String classImport : classImports) {
importHandler.importClass(classImport);
}
}
}
}
return importHandler;
}
@Override
public Locale getLocale() {
return wrapped.getLocale();
}
@Override
public void setLocale(Locale locale) {
wrapped.setLocale(locale);
}
@Override
public void addEvaluationListener(EvaluationListener listener) {
wrapped.addEvaluationListener(listener);
}
@Override
public List<EvaluationListener> getEvaluationListeners() {
return wrapped.getEvaluationListeners();
}
@Override
public void notifyBeforeEvaluation(String expression) {
wrapped.notifyBeforeEvaluation(expression);
}
@Override
public void notifyAfterEvaluation(String expression) {
wrapped.notifyAfterEvaluation(expression);
}
@Override
public void notifyPropertyResolved(Object base, Object property) {
wrapped.notifyPropertyResolved(base, property);
}
@Override
public boolean isLambdaArgument(String name) {
return wrapped.isLambdaArgument(name);
}
@Override
public Object getLambdaArgument(String name) {
return wrapped.getLambdaArgument(name);
}
@Override
public void enterLambdaScope(Map<String, Object> arguments) {
wrapped.enterLambdaScope(arguments);
}
@Override
public void exitLambdaScope() {
wrapped.exitLambdaScope();
}
@Override
public Object convertToType(Object obj, Class<?> type) {
return wrapped.convertToType(obj, type);
}
@Override
public ELResolver getELResolver() {
return wrapped.getELResolver();
}
@Override
public FunctionMapper getFunctionMapper() {
return wrapped.getFunctionMapper();
}
@Override
public VariableMapper getVariableMapper() {
return wrapped.getVariableMapper();
}
}
}

View File

@@ -0,0 +1,220 @@
/*
* 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.jasper.runtime;
import java.io.IOException;
import java.security.AccessController;
import java.security.PrivilegedAction;
import javax.servlet.Servlet;
import javax.servlet.ServletContext;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.jsp.JspApplicationContext;
import javax.servlet.jsp.JspEngineInfo;
import javax.servlet.jsp.JspFactory;
import javax.servlet.jsp.PageContext;
import org.apache.jasper.Constants;
/**
* Implementation of JspFactory.
*
* @author Anil K. Vijendran
*/
public class JspFactoryImpl extends JspFactory {
private static final String SPEC_VERSION = "2.3";
private static final boolean USE_POOL =
Boolean.parseBoolean(System.getProperty("org.apache.jasper.runtime.JspFactoryImpl.USE_POOL", "true"));
private static final int POOL_SIZE =
Integer.parseInt(System.getProperty("org.apache.jasper.runtime.JspFactoryImpl.POOL_SIZE", "8"));
private final ThreadLocal<PageContextPool> localPool = new ThreadLocal<>();
@Override
public PageContext getPageContext(Servlet servlet, ServletRequest request,
ServletResponse response, String errorPageURL, boolean needsSession,
int bufferSize, boolean autoflush) {
if( Constants.IS_SECURITY_ENABLED ) {
PrivilegedGetPageContext dp = new PrivilegedGetPageContext(
this, servlet, request, response, errorPageURL,
needsSession, bufferSize, autoflush);
return AccessController.doPrivileged(dp);
} else {
return internalGetPageContext(servlet, request, response,
errorPageURL, needsSession,
bufferSize, autoflush);
}
}
@Override
public void releasePageContext(PageContext pc) {
if( pc == null )
return;
if( Constants.IS_SECURITY_ENABLED ) {
PrivilegedReleasePageContext dp = new PrivilegedReleasePageContext(
this,pc);
AccessController.doPrivileged(dp);
} else {
internalReleasePageContext(pc);
}
}
@Override
public JspEngineInfo getEngineInfo() {
return new JspEngineInfo() {
@Override
public String getSpecificationVersion() {
return SPEC_VERSION;
}
};
}
private PageContext internalGetPageContext(Servlet servlet, ServletRequest request,
ServletResponse response, String errorPageURL, boolean needsSession,
int bufferSize, boolean autoflush) {
PageContext pc;
if (USE_POOL) {
PageContextPool pool = localPool.get();
if (pool == null) {
pool = new PageContextPool();
localPool.set(pool);
}
pc = pool.get();
if (pc == null) {
pc = new PageContextImpl();
}
} else {
pc = new PageContextImpl();
}
try {
pc.initialize(servlet, request, response, errorPageURL,
needsSession, bufferSize, autoflush);
} catch (IOException ioe) {
// Implementation never throws IOE but can't change the signature
// since it is part of the JSP API
}
return pc;
}
private void internalReleasePageContext(PageContext pc) {
pc.release();
if (USE_POOL && (pc instanceof PageContextImpl)) {
localPool.get().put(pc);
}
}
private static class PrivilegedGetPageContext
implements PrivilegedAction<PageContext> {
private JspFactoryImpl factory;
private Servlet servlet;
private ServletRequest request;
private ServletResponse response;
private String errorPageURL;
private boolean needsSession;
private int bufferSize;
private boolean autoflush;
PrivilegedGetPageContext(JspFactoryImpl factory, Servlet servlet,
ServletRequest request, ServletResponse response, String errorPageURL,
boolean needsSession, int bufferSize, boolean autoflush) {
this.factory = factory;
this.servlet = servlet;
this.request = request;
this.response = response;
this.errorPageURL = errorPageURL;
this.needsSession = needsSession;
this.bufferSize = bufferSize;
this.autoflush = autoflush;
}
@Override
public PageContext run() {
return factory.internalGetPageContext(servlet, request, response,
errorPageURL, needsSession, bufferSize, autoflush);
}
}
private static class PrivilegedReleasePageContext
implements PrivilegedAction<Void> {
private JspFactoryImpl factory;
private PageContext pageContext;
PrivilegedReleasePageContext(JspFactoryImpl factory,
PageContext pageContext) {
this.factory = factory;
this.pageContext = pageContext;
}
@Override
public Void run() {
factory.internalReleasePageContext(pageContext);
return null;
}
}
private static final class PageContextPool {
private final PageContext[] pool;
private int current = -1;
public PageContextPool() {
this.pool = new PageContext[POOL_SIZE];
}
public void put(PageContext o) {
if (current < (POOL_SIZE - 1)) {
current++;
pool[current] = o;
}
}
public PageContext get() {
PageContext item = null;
if (current >= 0) {
item = pool[current];
current--;
}
return item;
}
}
@Override
public JspApplicationContext getJspApplicationContext(
final ServletContext context) {
if (Constants.IS_SECURITY_ENABLED) {
return AccessController.doPrivileged(
new PrivilegedAction<JspApplicationContext>() {
@Override
public JspApplicationContext run() {
return JspApplicationContextImpl.getInstance(context);
}
});
} else {
return JspApplicationContextImpl.getInstance(context);
}
}
}

View File

@@ -0,0 +1,65 @@
/*
* 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.jasper.runtime;
import javax.servlet.jsp.JspContext;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.JspFragment;
import javax.servlet.jsp.tagext.JspTag;
/**
* Helper class from which all Jsp Fragment helper classes extend.
* This class allows for the emulation of numerous fragments within
* a single class, which in turn reduces the load on the class loader
* since there are potentially many JspFragments in a single page.
* <p>
* The class also provides various utility methods for JspFragment
* implementations.
*
* @author Mark Roth
*/
public abstract class JspFragmentHelper extends JspFragment {
protected final int discriminator;
protected final JspContext jspContext;
protected final PageContext _jspx_page_context;
protected final JspTag parentTag;
public JspFragmentHelper( int discriminator, JspContext jspContext,
JspTag parentTag )
{
this.discriminator = discriminator;
this.jspContext = jspContext;
if(jspContext instanceof PageContext) {
_jspx_page_context = (PageContext)jspContext;
} else {
_jspx_page_context = null;
}
this.parentTag = parentTag;
}
@Override
public JspContext getJspContext() {
return this.jspContext;
}
public JspTag getParentTag() {
return this.parentTag;
}
}

View File

@@ -0,0 +1,983 @@
/*
* 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.jasper.runtime;
import java.beans.PropertyEditor;
import java.beans.PropertyEditorManager;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.lang.reflect.Method;
import java.util.Enumeration;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.BodyContent;
import javax.servlet.jsp.tagext.BodyTag;
import javax.servlet.jsp.tagext.Tag;
import org.apache.jasper.JasperException;
import org.apache.jasper.compiler.Localizer;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
import org.apache.tomcat.InstanceManager;
/**
* Bunch of util methods that are used by code generated for useBean,
* getProperty and setProperty.
*
* The __begin, __end stuff is there so that the JSP engine can
* actually parse this file and inline them if people don't want
* runtime dependencies on this class. However, I'm not sure if that
* works so well right now. It got forgotten at some point. -akv
*
* @author Mandar Raje
* @author Shawn Bayern
*/
public class JspRuntimeLibrary {
/**
* Returns the value of the javax.servlet.error.exception request
* attribute value, if present, otherwise the value of the
* javax.servlet.jsp.jspException request attribute value.
*
* This method is called at the beginning of the generated servlet code
* for a JSP error page, when the "exception" implicit scripting language
* variable is initialized.
* @param request The Servlet request
* @return the throwable in the error attribute if any
*/
public static Throwable getThrowable(ServletRequest request) {
Throwable error = (Throwable) request.getAttribute(
RequestDispatcher.ERROR_EXCEPTION);
if (error == null) {
error = (Throwable) request.getAttribute(PageContext.EXCEPTION);
if (error != null) {
/*
* The only place that sets JSP_EXCEPTION is
* PageContextImpl.handlePageException(). It really should set
* SERVLET_EXCEPTION, but that would interfere with the
* ErrorReportValve. Therefore, if JSP_EXCEPTION is set, we
* need to set SERVLET_EXCEPTION.
*/
request.setAttribute(RequestDispatcher.ERROR_EXCEPTION, error);
}
}
return error;
}
public static boolean coerceToBoolean(String s) {
if (s == null || s.length() == 0)
return false;
else
return Boolean.parseBoolean(s);
}
public static byte coerceToByte(String s) {
if (s == null || s.length() == 0)
return (byte) 0;
else
return Byte.parseByte(s);
}
public static char coerceToChar(String s) {
if (s == null || s.length() == 0) {
return (char) 0;
} else {
return s.charAt(0);
}
}
public static double coerceToDouble(String s) {
if (s == null || s.length() == 0)
return 0;
else
return Double.parseDouble(s);
}
public static float coerceToFloat(String s) {
if (s == null || s.length() == 0)
return 0;
else
return Float.parseFloat(s);
}
public static int coerceToInt(String s) {
if (s == null || s.length() == 0)
return 0;
else
return Integer.parseInt(s);
}
public static short coerceToShort(String s) {
if (s == null || s.length() == 0)
return (short) 0;
else
return Short.parseShort(s);
}
public static long coerceToLong(String s) {
if (s == null || s.length() == 0)
return 0;
else
return Long.parseLong(s);
}
public static Object coerce(String s, Class<?> target) {
boolean isNullOrEmpty = (s == null || s.length() == 0);
if (target == Boolean.class) {
if (isNullOrEmpty) {
s = "false";
}
return Boolean.valueOf(s);
} else if (target == Byte.class) {
if (isNullOrEmpty)
return Byte.valueOf((byte) 0);
else
return Byte.valueOf(s);
} else if (target == Character.class) {
if (isNullOrEmpty)
return Character.valueOf((char) 0);
else {
@SuppressWarnings("null")
Character result = Character.valueOf(s.charAt(0));
return result;
}
} else if (target == Double.class) {
if (isNullOrEmpty)
return Double.valueOf(0);
else
return Double.valueOf(s);
} else if (target == Float.class) {
if (isNullOrEmpty)
return Float.valueOf(0);
else
return Float.valueOf(s);
} else if (target == Integer.class) {
if (isNullOrEmpty)
return Integer.valueOf(0);
else
return Integer.valueOf(s);
} else if (target == Short.class) {
if (isNullOrEmpty)
return Short.valueOf((short) 0);
else
return Short.valueOf(s);
} else if (target == Long.class) {
if (isNullOrEmpty)
return Long.valueOf(0);
else
return Long.valueOf(s);
} else {
return null;
}
}
// __begin convertMethod
public static Object convert(String propertyName, String s, Class<?> t,
Class<?> propertyEditorClass)
throws JasperException
{
try {
if (s == null) {
if (t.equals(Boolean.class) || t.equals(Boolean.TYPE))
s = "false";
else
return null;
}
if (propertyEditorClass != null) {
return getValueFromBeanInfoPropertyEditor(
t, propertyName, s, propertyEditorClass);
} else if ( t.equals(Boolean.class) || t.equals(Boolean.TYPE) ) {
if (s.equalsIgnoreCase("on") || s.equalsIgnoreCase("true"))
s = "true";
else
s = "false";
return Boolean.valueOf(s);
} else if ( t.equals(Byte.class) || t.equals(Byte.TYPE) ) {
return Byte.valueOf(s);
} else if (t.equals(Character.class) || t.equals(Character.TYPE)) {
return s.length() > 0 ? Character.valueOf(s.charAt(0)) : null;
} else if ( t.equals(Short.class) || t.equals(Short.TYPE) ) {
return Short.valueOf(s);
} else if ( t.equals(Integer.class) || t.equals(Integer.TYPE) ) {
return Integer.valueOf(s);
} else if ( t.equals(Float.class) || t.equals(Float.TYPE) ) {
return Float.valueOf(s);
} else if ( t.equals(Long.class) || t.equals(Long.TYPE) ) {
return Long.valueOf(s);
} else if ( t.equals(Double.class) || t.equals(Double.TYPE) ) {
return Double.valueOf(s);
} else if ( t.equals(String.class) ) {
return s;
} else if ( t.equals(java.io.File.class) ) {
return new java.io.File(s);
} else if (t.getName().equals("java.lang.Object")) {
return new Object[] {s};
} else {
return getValueFromPropertyEditorManager(
t, propertyName, s);
}
} catch (Exception ex) {
throw new JasperException(ex);
}
}
// __end convertMethod
// __begin introspectMethod
public static void introspect(Object bean, ServletRequest request)
throws JasperException
{
Enumeration<String> e = request.getParameterNames();
while ( e.hasMoreElements() ) {
String name = e.nextElement();
String value = request.getParameter(name);
introspecthelper(bean, name, value, request, name, true);
}
}
// __end introspectMethod
// __begin introspecthelperMethod
public static void introspecthelper(Object bean, String prop,
String value, ServletRequest request,
String param, boolean ignoreMethodNF)
throws JasperException {
Method method = null;
Class<?> type = null;
Class<?> propertyEditorClass = null;
try {
java.beans.BeanInfo info
= java.beans.Introspector.getBeanInfo(bean.getClass());
if ( info != null ) {
java.beans.PropertyDescriptor pd[]
= info.getPropertyDescriptors();
for (int i = 0 ; i < pd.length ; i++) {
if ( pd[i].getName().equals(prop) ) {
method = pd[i].getWriteMethod();
type = pd[i].getPropertyType();
propertyEditorClass = pd[i].getPropertyEditorClass();
break;
}
}
}
if (method != null && type != null) {
if (type.isArray()) {
if (request == null) {
throw new JasperException(
Localizer.getMessage("jsp.error.beans.setproperty.noindexset"));
}
Class<?> t = type.getComponentType();
String[] values = request.getParameterValues(param);
//XXX Please check.
if(values == null) return;
if(t.equals(String.class)) {
method.invoke(bean, new Object[] { values });
} else {
createTypedArray (prop, bean, method, values, t,
propertyEditorClass);
}
} else {
if(value == null || (param != null && value.equals(""))) return;
Object oval = convert(prop, value, type, propertyEditorClass);
if ( oval != null )
method.invoke(bean, new Object[] { oval });
}
}
} catch (Exception ex) {
Throwable thr = ExceptionUtils.unwrapInvocationTargetException(ex);
ExceptionUtils.handleThrowable(thr);
throw new JasperException(ex);
}
if (!ignoreMethodNF && (method == null)) {
if (type == null) {
throw new JasperException(
Localizer.getMessage("jsp.error.beans.noproperty",
prop,
bean.getClass().getName()));
} else {
throw new JasperException(
Localizer.getMessage("jsp.error.beans.nomethod.setproperty",
prop,
type.getName(),
bean.getClass().getName()));
}
}
}
// __end introspecthelperMethod
//-------------------------------------------------------------------
// functions to convert builtin Java data types to string.
//-------------------------------------------------------------------
// __begin toStringMethod
public static String toString(Object o) {
return String.valueOf(o);
}
public static String toString(byte b) {
return Byte.toString(b);
}
public static String toString(boolean b) {
return Boolean.toString(b);
}
public static String toString(short s) {
return Short.toString(s);
}
public static String toString(int i) {
return Integer.toString(i);
}
public static String toString(float f) {
return Float.toString(f);
}
public static String toString(long l) {
return Long.toString(l);
}
public static String toString(double d) {
return Double.toString(d);
}
public static String toString(char c) {
return Character.toString(c);
}
// __end toStringMethod
/**
* Create a typed array.
* This is a special case where params are passed through
* the request and the property is indexed.
* @param propertyName The property name
* @param bean The bean
* @param method The method
* @param values Array values
* @param t The class
* @param propertyEditorClass The editor for the property
* @throws JasperException An error occurred
*/
public static void createTypedArray(String propertyName,
Object bean,
Method method,
String[] values,
Class<?> t,
Class<?> propertyEditorClass)
throws JasperException {
try {
if (propertyEditorClass != null) {
Object[] tmpval = new Integer[values.length];
for (int i=0; i<values.length; i++) {
tmpval[i] = getValueFromBeanInfoPropertyEditor(
t, propertyName, values[i], propertyEditorClass);
}
method.invoke (bean, new Object[] {tmpval});
} else if (t.equals(Integer.class)) {
Integer []tmpval = new Integer[values.length];
for (int i = 0 ; i < values.length; i++)
tmpval[i] = Integer.valueOf(values[i]);
method.invoke (bean, new Object[] {tmpval});
} else if (t.equals(Byte.class)) {
Byte[] tmpval = new Byte[values.length];
for (int i = 0 ; i < values.length; i++)
tmpval[i] = Byte.valueOf(values[i]);
method.invoke (bean, new Object[] {tmpval});
} else if (t.equals(Boolean.class)) {
Boolean[] tmpval = new Boolean[values.length];
for (int i = 0 ; i < values.length; i++)
tmpval[i] = Boolean.valueOf(values[i]);
method.invoke (bean, new Object[] {tmpval});
} else if (t.equals(Short.class)) {
Short[] tmpval = new Short[values.length];
for (int i = 0 ; i < values.length; i++)
tmpval[i] = Short.valueOf(values[i]);
method.invoke (bean, new Object[] {tmpval});
} else if (t.equals(Long.class)) {
Long[] tmpval = new Long[values.length];
for (int i = 0 ; i < values.length; i++)
tmpval[i] = Long.valueOf(values[i]);
method.invoke (bean, new Object[] {tmpval});
} else if (t.equals(Double.class)) {
Double[] tmpval = new Double[values.length];
for (int i = 0 ; i < values.length; i++)
tmpval[i] = Double.valueOf(values[i]);
method.invoke (bean, new Object[] {tmpval});
} else if (t.equals(Float.class)) {
Float[] tmpval = new Float[values.length];
for (int i = 0 ; i < values.length; i++)
tmpval[i] = Float.valueOf(values[i]);
method.invoke (bean, new Object[] {tmpval});
} else if (t.equals(Character.class)) {
Character[] tmpval = new Character[values.length];
for (int i = 0 ; i < values.length; i++)
tmpval[i] = Character.valueOf(values[i].charAt(0));
method.invoke (bean, new Object[] {tmpval});
} else if (t.equals(int.class)) {
int []tmpval = new int[values.length];
for (int i = 0 ; i < values.length; i++)
tmpval[i] = Integer.parseInt (values[i]);
method.invoke (bean, new Object[] {tmpval});
} else if (t.equals(byte.class)) {
byte[] tmpval = new byte[values.length];
for (int i = 0 ; i < values.length; i++)
tmpval[i] = Byte.parseByte (values[i]);
method.invoke (bean, new Object[] {tmpval});
} else if (t.equals(boolean.class)) {
boolean[] tmpval = new boolean[values.length];
for (int i = 0 ; i < values.length; i++)
tmpval[i] = Boolean.parseBoolean(values[i]);
method.invoke (bean, new Object[] {tmpval});
} else if (t.equals(short.class)) {
short[] tmpval = new short[values.length];
for (int i = 0 ; i < values.length; i++)
tmpval[i] = Short.parseShort (values[i]);
method.invoke (bean, new Object[] {tmpval});
} else if (t.equals(long.class)) {
long[] tmpval = new long[values.length];
for (int i = 0 ; i < values.length; i++)
tmpval[i] = Long.parseLong (values[i]);
method.invoke (bean, new Object[] {tmpval});
} else if (t.equals(double.class)) {
double[] tmpval = new double[values.length];
for (int i = 0 ; i < values.length; i++)
tmpval[i] = Double.parseDouble(values[i]);
method.invoke (bean, new Object[] {tmpval});
} else if (t.equals(float.class)) {
float[] tmpval = new float[values.length];
for (int i = 0 ; i < values.length; i++)
tmpval[i] = Float.parseFloat(values[i]);
method.invoke (bean, new Object[] {tmpval});
} else if (t.equals(char.class)) {
char[] tmpval = new char[values.length];
for (int i = 0 ; i < values.length; i++)
tmpval[i] = values[i].charAt(0);
method.invoke (bean, new Object[] {tmpval});
} else {
Object[] tmpval = new Integer[values.length];
for (int i=0; i<values.length; i++) {
tmpval[i] =
getValueFromPropertyEditorManager(
t, propertyName, values[i]);
}
method.invoke (bean, new Object[] {tmpval});
}
} catch (RuntimeException | ReflectiveOperationException ex) {
Throwable thr = ExceptionUtils.unwrapInvocationTargetException(ex);
ExceptionUtils.handleThrowable(thr);
throw new JasperException ("error in invoking method", ex);
}
}
/**
* Escape special shell characters.
* @param unescString The string to shell-escape
* @return The escaped shell string.
*/
public static String escapeQueryString(String unescString) {
if (unescString == null) {
return null;
}
StringBuilder escStringBuilder = new StringBuilder();
String shellSpChars = "&;`'\"|*?~<>^()[]{}$\\\n";
for (int index = 0; index < unescString.length(); index++) {
char nextChar = unescString.charAt(index);
if (shellSpChars.indexOf(nextChar) != -1) {
escStringBuilder.append('\\');
}
escStringBuilder.append(nextChar);
}
return escStringBuilder.toString();
}
// __begin lookupReadMethodMethod
public static Object handleGetProperty(Object o, String prop)
throws JasperException {
if (o == null) {
throw new JasperException(
Localizer.getMessage("jsp.error.beans.nullbean"));
}
Object value = null;
try {
Method method = getReadMethod(o.getClass(), prop);
value = method.invoke(o, (Object[]) null);
} catch (Exception ex) {
Throwable thr = ExceptionUtils.unwrapInvocationTargetException(ex);
ExceptionUtils.handleThrowable(thr);
throw new JasperException (ex);
}
return value;
}
// __end lookupReadMethodMethod
// handles <jsp:setProperty> with EL expression for 'value' attribute
public static void handleSetPropertyExpression(Object bean,
String prop, String expression, PageContext pageContext,
ProtectedFunctionMapper functionMapper )
throws JasperException
{
try {
Method method = getWriteMethod(bean.getClass(), prop);
method.invoke(bean, new Object[] {
PageContextImpl.proprietaryEvaluate(
expression,
method.getParameterTypes()[0],
pageContext,
functionMapper)
});
} catch (Exception ex) {
Throwable thr = ExceptionUtils.unwrapInvocationTargetException(ex);
ExceptionUtils.handleThrowable(thr);
throw new JasperException(ex);
}
}
public static void handleSetProperty(Object bean, String prop,
Object value)
throws JasperException
{
try {
Method method = getWriteMethod(bean.getClass(), prop);
method.invoke(bean, new Object[] { value });
} catch (Exception ex) {
Throwable thr = ExceptionUtils.unwrapInvocationTargetException(ex);
ExceptionUtils.handleThrowable(thr);
throw new JasperException(ex);
}
}
public static void handleSetProperty(Object bean, String prop,
int value)
throws JasperException
{
try {
Method method = getWriteMethod(bean.getClass(), prop);
method.invoke(bean, new Object[] { Integer.valueOf(value) });
} catch (Exception ex) {
Throwable thr = ExceptionUtils.unwrapInvocationTargetException(ex);
ExceptionUtils.handleThrowable(thr);
throw new JasperException(ex);
}
}
public static void handleSetProperty(Object bean, String prop,
short value)
throws JasperException
{
try {
Method method = getWriteMethod(bean.getClass(), prop);
method.invoke(bean, new Object[] { Short.valueOf(value) });
} catch (Exception ex) {
Throwable thr = ExceptionUtils.unwrapInvocationTargetException(ex);
ExceptionUtils.handleThrowable(thr);
throw new JasperException(ex);
}
}
public static void handleSetProperty(Object bean, String prop,
long value)
throws JasperException
{
try {
Method method = getWriteMethod(bean.getClass(), prop);
method.invoke(bean, new Object[] { Long.valueOf(value) });
} catch (Exception ex) {
Throwable thr = ExceptionUtils.unwrapInvocationTargetException(ex);
ExceptionUtils.handleThrowable(thr);
throw new JasperException(ex);
}
}
public static void handleSetProperty(Object bean, String prop,
double value)
throws JasperException
{
try {
Method method = getWriteMethod(bean.getClass(), prop);
method.invoke(bean, new Object[] { Double.valueOf(value) });
} catch (Exception ex) {
Throwable thr = ExceptionUtils.unwrapInvocationTargetException(ex);
ExceptionUtils.handleThrowable(thr);
throw new JasperException(ex);
}
}
public static void handleSetProperty(Object bean, String prop,
float value)
throws JasperException
{
try {
Method method = getWriteMethod(bean.getClass(), prop);
method.invoke(bean, new Object[] { Float.valueOf(value) });
} catch (Exception ex) {
Throwable thr = ExceptionUtils.unwrapInvocationTargetException(ex);
ExceptionUtils.handleThrowable(thr);
throw new JasperException(ex);
}
}
public static void handleSetProperty(Object bean, String prop,
char value)
throws JasperException
{
try {
Method method = getWriteMethod(bean.getClass(), prop);
method.invoke(bean, new Object[] { Character.valueOf(value) });
} catch (Exception ex) {
Throwable thr = ExceptionUtils.unwrapInvocationTargetException(ex);
ExceptionUtils.handleThrowable(thr);
throw new JasperException(ex);
}
}
public static void handleSetProperty(Object bean, String prop,
byte value)
throws JasperException
{
try {
Method method = getWriteMethod(bean.getClass(), prop);
method.invoke(bean, new Object[] { Byte.valueOf(value) });
} catch (Exception ex) {
Throwable thr = ExceptionUtils.unwrapInvocationTargetException(ex);
ExceptionUtils.handleThrowable(thr);
throw new JasperException(ex);
}
}
public static void handleSetProperty(Object bean, String prop,
boolean value)
throws JasperException
{
try {
Method method = getWriteMethod(bean.getClass(), prop);
method.invoke(bean, new Object[] { Boolean.valueOf(value) });
} catch (Exception ex) {
Throwable thr = ExceptionUtils.unwrapInvocationTargetException(ex);
ExceptionUtils.handleThrowable(thr);
throw new JasperException(ex);
}
}
public static Method getWriteMethod(Class<?> beanClass, String prop)
throws JasperException {
Method method = null;
Class<?> type = null;
try {
java.beans.BeanInfo info = java.beans.Introspector.getBeanInfo(beanClass);
java.beans.PropertyDescriptor pd[] = info.getPropertyDescriptors();
for (int i = 0 ; i < pd.length ; i++) {
if ( pd[i].getName().equals(prop) ) {
method = pd[i].getWriteMethod();
type = pd[i].getPropertyType();
break;
}
}
} catch (Exception ex) {
throw new JasperException (ex);
}
if (method == null) {
if (type == null) {
throw new JasperException(Localizer.getMessage(
"jsp.error.beans.noproperty", prop, beanClass.getName()));
} else {
throw new JasperException(Localizer.getMessage(
"jsp.error.beans.nomethod.setproperty",
prop, type.getName(), beanClass.getName()));
}
}
return method;
}
public static Method getReadMethod(Class<?> beanClass, String prop)
throws JasperException {
Method method = null;
Class<?> type = null;
try {
java.beans.BeanInfo info = java.beans.Introspector.getBeanInfo(beanClass);
java.beans.PropertyDescriptor pd[] = info.getPropertyDescriptors();
for (int i = 0 ; i < pd.length ; i++) {
if (pd[i].getName().equals(prop)) {
method = pd[i].getReadMethod();
type = pd[i].getPropertyType();
break;
}
}
} catch (Exception ex) {
throw new JasperException (ex);
}
if (method == null) {
if (type == null) {
throw new JasperException(Localizer.getMessage(
"jsp.error.beans.noproperty", prop, beanClass.getName()));
} else {
throw new JasperException(Localizer.getMessage(
"jsp.error.beans.nomethod", prop, beanClass.getName()));
}
}
return method;
}
//*********************************************************************
// PropertyEditor Support
public static Object getValueFromBeanInfoPropertyEditor(
Class<?> attrClass, String attrName, String attrValue,
Class<?> propertyEditorClass)
throws JasperException
{
try {
PropertyEditor pe = (PropertyEditor)propertyEditorClass.getConstructor().newInstance();
pe.setAsText(attrValue);
return pe.getValue();
} catch (Exception ex) {
throw new JasperException(
Localizer.getMessage("jsp.error.beans.property.conversion",
attrValue, attrClass.getName(), attrName,
ex.getMessage()));
}
}
public static Object getValueFromPropertyEditorManager(
Class<?> attrClass, String attrName, String attrValue)
throws JasperException
{
try {
PropertyEditor propEditor =
PropertyEditorManager.findEditor(attrClass);
if (propEditor != null) {
propEditor.setAsText(attrValue);
return propEditor.getValue();
} else {
throw new IllegalArgumentException(
Localizer.getMessage("jsp.error.beans.propertyeditor.notregistered"));
}
} catch (IllegalArgumentException ex) {
throw new JasperException(
Localizer.getMessage("jsp.error.beans.property.conversion",
attrValue, attrClass.getName(), attrName,
ex.getMessage()));
}
}
// ************************************************************************
// General Purpose Runtime Methods
// ************************************************************************
/**
* Convert a possibly relative resource path into a context-relative
* resource path that starts with a '/'.
*
* @param request The servlet request we are processing
* @param relativePath The possibly relative resource path
* @return an absolute path
*/
public static String getContextRelativePath(ServletRequest request,
String relativePath) {
if (relativePath.startsWith("/"))
return relativePath;
if (!(request instanceof HttpServletRequest))
return relativePath;
HttpServletRequest hrequest = (HttpServletRequest) request;
String uri = (String) request.getAttribute(
RequestDispatcher.INCLUDE_SERVLET_PATH);
if (uri != null) {
String pathInfo = (String)
request.getAttribute(RequestDispatcher.INCLUDE_PATH_INFO);
if (pathInfo == null) {
if (uri.lastIndexOf('/') >= 0)
uri = uri.substring(0, uri.lastIndexOf('/'));
}
}
else {
uri = hrequest.getServletPath();
if (uri.lastIndexOf('/') >= 0)
uri = uri.substring(0, uri.lastIndexOf('/'));
}
return uri + '/' + relativePath;
}
/**
* Perform a RequestDispatcher.include() operation, with optional flushing
* of the response beforehand.
*
* @param request The servlet request we are processing
* @param response The servlet response we are processing
* @param relativePath The relative path of the resource to be included
* @param out The Writer to whom we are currently writing
* @param flush Should we flush before the include is processed?
*
* @exception IOException if thrown by the included servlet
* @exception ServletException if thrown by the included servlet
*/
public static void include(ServletRequest request,
ServletResponse response,
String relativePath,
JspWriter out,
boolean flush)
throws IOException, ServletException {
if (flush && !(out instanceof BodyContent))
out.flush();
// FIXME - It is tempting to use request.getRequestDispatcher() to
// resolve a relative path directly, but Catalina currently does not
// take into account whether the caller is inside a RequestDispatcher
// include or not. Whether Catalina *should* take that into account
// is a spec issue currently under review. In the mean time,
// replicate Jasper's previous behavior
String resourcePath = getContextRelativePath(request, relativePath);
RequestDispatcher rd = request.getRequestDispatcher(resourcePath);
rd.include(request,
new ServletResponseWrapperInclude(response, out));
}
/**
* URL encodes a string, based on the supplied character encoding.
* This performs the same function as java.next.URLEncode.encode
* in J2SDK1.4, and should be removed if the only platform supported
* is 1.4 or higher.
* @param s The String to be URL encoded.
* @param enc The character encoding
* @return The URL encoded String
*/
public static String URLEncode(String s, String enc) {
if (s == null) {
return "null";
}
if (enc == null) {
enc = "ISO-8859-1"; // The default request encoding
}
StringBuilder out = new StringBuilder(s.length());
ByteArrayOutputStream buf = new ByteArrayOutputStream();
OutputStreamWriter writer = null;
try {
writer = new OutputStreamWriter(buf, enc);
} catch (java.io.UnsupportedEncodingException ex) {
// Use the default encoding?
writer = new OutputStreamWriter(buf);
}
for (int i = 0; i < s.length(); i++) {
int c = s.charAt(i);
if (c == ' ') {
out.append('+');
} else if (isSafeChar(c)) {
out.append((char)c);
} else {
// convert to external encoding before hex conversion
try {
writer.write(c);
writer.flush();
} catch(IOException e) {
buf.reset();
continue;
}
byte[] ba = buf.toByteArray();
for (int j = 0; j < ba.length; j++) {
out.append('%');
// Converting each byte in the buffer
out.append(Character.forDigit((ba[j]>>4) & 0xf, 16));
out.append(Character.forDigit(ba[j] & 0xf, 16));
}
buf.reset();
}
}
return out.toString();
}
private static boolean isSafeChar(int c) {
if (c >= 'a' && c <= 'z') {
return true;
}
if (c >= 'A' && c <= 'Z') {
return true;
}
if (c >= '0' && c <= '9') {
return true;
}
if (c == '-' || c == '_' || c == '.' || c == '!' ||
c == '~' || c == '*' || c == '\'' || c == '(' || c == ')') {
return true;
}
return false;
}
public static JspWriter startBufferedBody(PageContext pageContext, BodyTag tag)
throws JspException {
BodyContent out = pageContext.pushBody();
tag.setBodyContent(out);
tag.doInitBody();
return out;
}
public static void releaseTag(Tag tag, InstanceManager instanceManager, boolean reused) {
// Caller ensures pool is non-null if reuse is true
if (!reused) {
releaseTag(tag, instanceManager);
}
}
protected static void releaseTag(Tag tag, InstanceManager instanceManager) {
try {
tag.release();
} catch (Throwable t) {
ExceptionUtils.handleThrowable(t);
Log log = LogFactory.getLog(JspRuntimeLibrary.class);
log.warn(Localizer.getMessage("jsp.warning.tagRelease", tag.getClass().getName()), t);
}
try {
instanceManager.destroyInstance(tag);
} catch (Exception e) {
Throwable t = ExceptionUtils.unwrapInvocationTargetException(e);
ExceptionUtils.handleThrowable(t);
Log log = LogFactory.getLog(JspRuntimeLibrary.class);
log.warn(Localizer.getMessage("jsp.warning.tagPreDestroy", tag.getClass().getName()), t);
}
}
}

View File

@@ -0,0 +1,40 @@
/*
* 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.jasper.runtime;
import java.util.Map;
/**
* Interface for tracking the source files dependencies, for the purpose
* of compiling out of date pages. This is used for
* 1) files that are included by page directives
* 2) files that are included by include-prelude and include-coda in jsp:config
* 3) files that are tag files and referenced
* 4) TLDs referenced
*/
public interface JspSourceDependent {
/**
* Returns a map of file names and last modified time where the current page
* has a source dependency on the file.
* @return the map of dependent resources
*/
public Map<String,Long> getDependants();
}

View File

@@ -0,0 +1,30 @@
/*
* 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.jasper.runtime;
import java.util.Set;
/**
* The EL engine needs access to the imports used in the JSP page to configure
* the ELContext. The imports are available at compile time but the ELContext
* is created lazily per page. This interface exposes the imports at runtime so
* that they may be added to the ELContext when it is created.
*/
public interface JspSourceImports {
Set<String> getPackageImports();
Set<String> getClassImports();
}

View File

@@ -0,0 +1,597 @@
/*
* 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.jasper.runtime;
import java.io.IOException;
import java.io.Writer;
import java.security.AccessController;
import java.security.PrivilegedAction;
import javax.servlet.ServletResponse;
import javax.servlet.jsp.JspWriter;
import org.apache.jasper.Constants;
import org.apache.jasper.compiler.Localizer;
import org.apache.jasper.security.SecurityUtil;
/**
* Write text to a character-output stream, buffering characters so as
* to provide for the efficient writing of single characters, arrays,
* and strings.
*
* Provide support for discarding for the output that has been
* buffered.
*
* This needs revisiting when the buffering problems in the JSP spec
* are fixed -akv
*
* @author Anil K. Vijendran
*/
public class JspWriterImpl extends JspWriter {
private Writer out;
private ServletResponse response;
private char cb[];
private int nextChar;
private boolean flushed = false;
private boolean closed = false;
public JspWriterImpl() {
super( Constants.DEFAULT_BUFFER_SIZE, true );
}
/**
* Create a new buffered character-output stream that uses an output
* buffer of the given size.
*
* @param response A Servlet Response
* @param sz Output-buffer size, a positive integer
* @param autoFlush <code>true</code> to automatically flush on buffer
* full, <code>false</code> to throw an overflow exception in that case
* @exception IllegalArgumentException If sz is &lt;= 0
*/
public JspWriterImpl(ServletResponse response, int sz,
boolean autoFlush) {
super(sz, autoFlush);
if (sz < 0)
throw new IllegalArgumentException("Buffer size <= 0");
this.response = response;
cb = sz == 0 ? null : new char[sz];
nextChar = 0;
}
void init( ServletResponse response, int sz, boolean autoFlush ) {
this.response= response;
if( sz > 0 && ( cb == null || sz > cb.length ) )
cb=new char[sz];
nextChar = 0;
this.autoFlush=autoFlush;
this.bufferSize=sz;
}
/**
* Package-level access
*/
void recycle() {
flushed = false;
closed = false;
out = null;
nextChar = 0;
response = null;
}
/**
* Flush the output buffer to the underlying character stream, without
* flushing the stream itself. This method is non-private only so that it
* may be invoked by PrintStream.
* @throws IOException Error writing buffered data
*/
protected final void flushBuffer() throws IOException {
if (bufferSize == 0)
return;
flushed = true;
ensureOpen();
if (nextChar == 0)
return;
initOut();
out.write(cb, 0, nextChar);
nextChar = 0;
}
private void initOut() throws IOException {
if (out == null) {
out = response.getWriter();
}
}
private String getLocalizeMessage(final String message){
if (SecurityUtil.isPackageProtectionEnabled()){
return AccessController.doPrivileged(new PrivilegedAction<String>(){
@Override
public String run(){
return Localizer.getMessage(message);
}
});
} else {
return Localizer.getMessage(message);
}
}
/**
* Discard the output buffer.
*/
@Override
public final void clear() throws IOException {
if ((bufferSize == 0) && (out != null))
// clear() is illegal after any unbuffered output (JSP.5.5)
throw new IllegalStateException(
getLocalizeMessage("jsp.error.ise_on_clear"));
if (flushed)
throw new IOException(
getLocalizeMessage("jsp.error.attempt_to_clear_flushed_buffer"));
ensureOpen();
nextChar = 0;
}
@Override
public void clearBuffer() throws IOException {
if (bufferSize == 0)
throw new IllegalStateException(
getLocalizeMessage("jsp.error.ise_on_clear"));
ensureOpen();
nextChar = 0;
}
private final void bufferOverflow() throws IOException {
throw new IOException(getLocalizeMessage("jsp.error.overflow"));
}
/**
* Flush the stream.
*
*/
@Override
public void flush() throws IOException {
flushBuffer();
if (out != null) {
out.flush();
}
}
/**
* Close the stream.
*
*/
@Override
public void close() throws IOException {
if (response == null || closed)
// multiple calls to close is OK
return;
flush();
if (out != null)
out.close();
out = null;
closed = true;
}
/**
* @return the number of bytes unused in the buffer
*/
@Override
public int getRemaining() {
return bufferSize - nextChar;
}
/** check to make sure that the stream has not been closed */
private void ensureOpen() throws IOException {
if (response == null || closed)
throw new IOException("Stream closed");
}
/**
* Write a single character.
*/
@Override
public void write(int c) throws IOException {
ensureOpen();
if (bufferSize == 0) {
initOut();
out.write(c);
}
else {
if (nextChar >= bufferSize)
if (autoFlush)
flushBuffer();
else
bufferOverflow();
cb[nextChar++] = (char) c;
}
}
/**
* Our own little min method, to avoid loading java.lang.Math if we've run
* out of file descriptors and we're trying to print a stack trace.
*/
private static int min(int a, int b) {
if (a < b) return a;
return b;
}
/**
* Write a portion of an array of characters.
*
* <p> Ordinarily this method stores characters from the given array into
* this stream's buffer, flushing the buffer to the underlying stream as
* needed. If the requested length is at least as large as the buffer,
* however, then this method will flush the buffer and write the characters
* directly to the underlying stream. Thus redundant
* <code>DiscardableBufferedWriter</code>s will not copy data unnecessarily.
*
* @param cbuf A character array
* @param off Offset from which to start reading characters
* @param len Number of characters to write
*/
@Override
public void write(char cbuf[], int off, int len)
throws IOException
{
ensureOpen();
if (bufferSize == 0) {
initOut();
out.write(cbuf, off, len);
return;
}
if ((off < 0) || (off > cbuf.length) || (len < 0) ||
((off + len) > cbuf.length) || ((off + len) < 0)) {
throw new IndexOutOfBoundsException();
} else if (len == 0) {
return;
}
if (len >= bufferSize) {
/* If the request length exceeds the size of the output buffer,
flush the buffer and then write the data directly. In this
way buffered streams will cascade harmlessly. */
if (autoFlush)
flushBuffer();
else
bufferOverflow();
initOut();
out.write(cbuf, off, len);
return;
}
int b = off, t = off + len;
while (b < t) {
int d = min(bufferSize - nextChar, t - b);
System.arraycopy(cbuf, b, cb, nextChar, d);
b += d;
nextChar += d;
if (nextChar >= bufferSize)
if (autoFlush)
flushBuffer();
else
bufferOverflow();
}
}
/**
* Write an array of characters. This method cannot be inherited from the
* Writer class because it must suppress I/O exceptions.
*/
@Override
public void write(char buf[]) throws IOException {
write(buf, 0, buf.length);
}
/**
* Write a portion of a String.
*
* @param s String to be written
* @param off Offset from which to start reading characters
* @param len Number of characters to be written
*/
@Override
public void write(String s, int off, int len) throws IOException {
ensureOpen();
if (bufferSize == 0) {
initOut();
out.write(s, off, len);
return;
}
int b = off, t = off + len;
while (b < t) {
int d = min(bufferSize - nextChar, t - b);
s.getChars(b, b + d, cb, nextChar);
b += d;
nextChar += d;
if (nextChar >= bufferSize)
if (autoFlush)
flushBuffer();
else
bufferOverflow();
}
}
/**
* Write a line separator. The line separator string is defined by the
* system property <code>line.separator</code>, and is not necessarily a
* single newline ('\n') character.
*
* @exception IOException If an I/O error occurs
*/
@Override
public void newLine() throws IOException {
write(System.lineSeparator());
}
/* Methods that do not terminate lines */
/**
* Print a boolean value. The string produced by <code>{@link
* java.lang.String#valueOf(boolean)}</code> is translated into bytes
* according to the platform's default character encoding, and these bytes
* are written in exactly the manner of the <code>{@link
* #write(int)}</code> method.
*
* @param b The <code>boolean</code> to be printed
*/
@Override
public void print(boolean b) throws IOException {
write(b ? "true" : "false");
}
/**
* Print a character. The character is translated into one or more bytes
* according to the platform's default character encoding, and these bytes
* are written in exactly the manner of the <code>{@link
* #write(int)}</code> method.
*
* @param c The <code>char</code> to be printed
*/
@Override
public void print(char c) throws IOException {
write(String.valueOf(c));
}
/**
* Print an integer. The string produced by <code>{@link
* java.lang.String#valueOf(int)}</code> is translated into bytes according
* to the platform's default character encoding, and these bytes are
* written in exactly the manner of the <code>{@link #write(int)}</code>
* method.
*
* @param i The <code>int</code> to be printed
*/
@Override
public void print(int i) throws IOException {
write(String.valueOf(i));
}
/**
* Print a long integer. The string produced by <code>{@link
* java.lang.String#valueOf(long)}</code> is translated into bytes
* according to the platform's default character encoding, and these bytes
* are written in exactly the manner of the <code>{@link #write(int)}</code>
* method.
*
* @param l The <code>long</code> to be printed
*/
@Override
public void print(long l) throws IOException {
write(String.valueOf(l));
}
/**
* Print a floating-point number. The string produced by <code>{@link
* java.lang.String#valueOf(float)}</code> is translated into bytes
* according to the platform's default character encoding, and these bytes
* are written in exactly the manner of the <code>{@link #write(int)}</code>
* method.
*
* @param f The <code>float</code> to be printed
*/
@Override
public void print(float f) throws IOException {
write(String.valueOf(f));
}
/**
* Print a double-precision floating-point number. The string produced by
* <code>{@link java.lang.String#valueOf(double)}</code> is translated into
* bytes according to the platform's default character encoding, and these
* bytes are written in exactly the manner of the <code>{@link
* #write(int)}</code> method.
*
* @param d The <code>double</code> to be printed
*/
@Override
public void print(double d) throws IOException {
write(String.valueOf(d));
}
/**
* Print an array of characters. The characters are converted into bytes
* according to the platform's default character encoding, and these bytes
* are written in exactly the manner of the <code>{@link #write(int)}</code>
* method.
*
* @param s The array of chars to be printed
*
* @throws NullPointerException If <code>s</code> is <code>null</code>
*/
@Override
public void print(char s[]) throws IOException {
write(s);
}
/**
* Print a string. If the argument is <code>null</code> then the string
* <code>"null"</code> is printed. Otherwise, the string's characters are
* converted into bytes according to the platform's default character
* encoding, and these bytes are written in exactly the manner of the
* <code>{@link #write(int)}</code> method.
*
* @param s The <code>String</code> to be printed
*/
@Override
public void print(String s) throws IOException {
if (s == null) {
s = "null";
}
write(s);
}
/**
* Print an object. The string produced by the <code>{@link
* java.lang.String#valueOf(Object)}</code> method is translated into bytes
* according to the platform's default character encoding, and these bytes
* are written in exactly the manner of the <code>{@link #write(int)}</code>
* method.
*
* @param obj The <code>Object</code> to be printed
*/
@Override
public void print(Object obj) throws IOException {
write(String.valueOf(obj));
}
/* Methods that do terminate lines */
/**
* Terminate the current line by writing the line separator string. The
* line separator string is defined by the system property
* <code>line.separator</code>, and is not necessarily a single newline
* character (<code>'\n'</code>).
*
* Need to change this from PrintWriter because the default
* println() writes to the sink directly instead of through the
* write method...
*/
@Override
public void println() throws IOException {
newLine();
}
/**
* Print a boolean value and then terminate the line. This method behaves
* as though it invokes <code>{@link #print(boolean)}</code> and then
* <code>{@link #println()}</code>.
*/
@Override
public void println(boolean x) throws IOException {
print(x);
println();
}
/**
* Print a character and then terminate the line. This method behaves as
* though it invokes <code>{@link #print(char)}</code> and then <code>{@link
* #println()}</code>.
*/
@Override
public void println(char x) throws IOException {
print(x);
println();
}
/**
* Print an integer and then terminate the line. This method behaves as
* though it invokes <code>{@link #print(int)}</code> and then <code>{@link
* #println()}</code>.
*/
@Override
public void println(int x) throws IOException {
print(x);
println();
}
/**
* Print a long integer and then terminate the line. This method behaves
* as though it invokes <code>{@link #print(long)}</code> and then
* <code>{@link #println()}</code>.
*/
@Override
public void println(long x) throws IOException {
print(x);
println();
}
/**
* Print a floating-point number and then terminate the line. This method
* behaves as though it invokes <code>{@link #print(float)}</code> and then
* <code>{@link #println()}</code>.
*/
@Override
public void println(float x) throws IOException {
print(x);
println();
}
/**
* Print a double-precision floating-point number and then terminate the
* line. This method behaves as though it invokes <code>{@link
* #print(double)}</code> and then <code>{@link #println()}</code>.
*/
@Override
public void println(double x) throws IOException {
print(x);
println();
}
/**
* Print an array of characters and then terminate the line. This method
* behaves as though it invokes <code>{@link #print(char[])}</code> and then
* <code>{@link #println()}</code>.
*/
@Override
public void println(char x[]) throws IOException {
print(x);
println();
}
/**
* Print a String and then terminate the line. This method behaves as
* though it invokes <code>{@link #print(String)}</code> and then
* <code>{@link #println()}</code>.
*/
@Override
public void println(String x) throws IOException {
print(x);
println();
}
/**
* Print an Object and then terminate the line. This method behaves as
* though it invokes <code>{@link #print(Object)}</code> and then
* <code>{@link #println()}</code>.
*/
@Override
public void println(Object x) throws IOException {
print(x);
println();
}
}

View File

@@ -0,0 +1,969 @@
/*
* 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.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.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Set;
import javax.el.ELContext;
import javax.el.ELException;
import javax.el.ExpressionFactory;
import javax.el.ImportHandler;
import javax.el.ValueExpression;
import javax.servlet.RequestDispatcher;
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.tagext.BodyContent;
import org.apache.jasper.Constants;
import org.apache.jasper.compiler.Localizer;
import org.apache.jasper.el.ELContextImpl;
import org.apache.jasper.runtime.JspContextWrapper.ELContextWrapper;
import org.apache.jasper.security.SecurityUtil;
/**
* 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 final 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<>(16);
this.depth = -1;
}
@Override
public 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 (bufferSize == JspWriter.DEFAULT_BUFFER) {
bufferSize = Constants.DEFAULT_BUFFER_SIZE;
}
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(
RequestDispatcher.INCLUDE_SERVLET_PATH) != null;
}
@Override
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();
for (BodyContentImpl body: outs) {
body.recycle();
}
}
}
@Override
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<Object>() {
@Override
public Object run() {
return doGetAttribute(name);
}
});
} else {
return doGetAttribute(name);
}
}
private Object doGetAttribute(String name) {
return attributes.get(name);
}
@Override
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<Object>() {
@Override
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");
}
}
@Override
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<Void>() {
@Override
public Void 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);
}
}
@Override
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<Void>() {
@Override
public Void 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);
}
}
@Override
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<Void>() {
@Override
public Void 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");
}
}
@Override
public int getAttributesScope(final String name) {
if (name == null) {
throw new NullPointerException(Localizer
.getMessage("jsp.error.attribute.null_name"));
}
if (SecurityUtil.isPackageProtectionEnabled()) {
return (AccessController
.doPrivileged(new PrivilegedAction<Integer>() {
@Override
public Integer run() {
return Integer.valueOf(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;
}
@Override
public Object findAttribute(final String name) {
if (SecurityUtil.isPackageProtectionEnabled()) {
return AccessController.doPrivileged(
new PrivilegedAction<Object>() {
@Override
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);
}
@Override
public Enumeration<String> getAttributeNamesInScope(final int scope) {
if (SecurityUtil.isPackageProtectionEnabled()) {
return AccessController.doPrivileged(
new PrivilegedAction<Enumeration<String>>() {
@Override
public Enumeration<String> run() {
return doGetAttributeNamesInScope(scope);
}
});
} else {
return doGetAttributeNamesInScope(scope);
}
}
private Enumeration<String> doGetAttributeNamesInScope(int scope) {
switch (scope) {
case PAGE_SCOPE:
return Collections.enumeration(attributes.keySet());
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");
}
}
@Override
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<Void>() {
@Override
public Void 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);
}
@Override
public JspWriter getOut() {
return out;
}
@Override
public HttpSession getSession() {
return session;
}
@Override
public ServletConfig getServletConfig() {
return config;
}
@Override
public ServletContext getServletContext() {
return config.getServletContext();
}
@Override
public ServletRequest getRequest() {
return request;
}
@Override
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.
*/
@Override
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;
}
@Override
public Object getPage() {
return servlet;
}
private final String getAbsolutePathRelativeToContext(String relativeUrlPath) {
String path = relativeUrlPath;
if (!path.startsWith("/")) {
String uri = (String) request.getAttribute(
RequestDispatcher.INCLUDE_SERVLET_PATH);
if (uri == null)
uri = ((HttpServletRequest) request).getServletPath();
String baseURI = uri.substring(0, uri.lastIndexOf('/'));
path = baseURI + '/' + path;
}
return path;
}
@Override
public void include(String relativeUrlPath) throws ServletException,
IOException {
JspRuntimeLibrary
.include(request, response, relativeUrlPath, out, true);
}
@Override
public void include(final String relativeUrlPath, final boolean flush)
throws ServletException, IOException {
if (SecurityUtil.isPackageProtectionEnabled()) {
try {
AccessController.doPrivileged(
new PrivilegedExceptionAction<Void>() {
@Override
public Void 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);
}
@Override
@Deprecated
public javax.servlet.jsp.el.VariableResolver getVariableResolver() {
return new org.apache.jasper.el.VariableResolverImpl(
this.getELContext());
}
@Override
public void forward(final String relativeUrlPath) throws ServletException,
IOException {
if (SecurityUtil.isPackageProtectionEnabled()) {
try {
AccessController.doPrivileged(
new PrivilegedExceptionAction<Void>() {
@Override
public Void 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();
baseOut.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(
RequestDispatcher.INCLUDE_SERVLET_PATH);
if (includeUri != null)
request.removeAttribute(RequestDispatcher.INCLUDE_SERVLET_PATH);
try {
context.getRequestDispatcher(path).forward(request, response);
} finally {
if (includeUri != null)
request.setAttribute(RequestDispatcher.INCLUDE_SERVLET_PATH,
includeUri);
}
}
@Override
public BodyContent pushBody() {
return (BodyContent) pushBody(null);
}
@Override
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];
}
@Override
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.
*/
@Override
@Deprecated
public javax.servlet.jsp.el.ExpressionEvaluator getExpressionEvaluator() {
return new org.apache.jasper.el.ExpressionEvaluatorImpl(
this.applicationContext.getExpressionFactory());
}
@Override
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);
}
@Override
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<Void>() {
@Override
public Void 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);
}
}
@SuppressWarnings("deprecation") // Still jave to support old JSP EL
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(PageContext.EXCEPTION, t);
request.setAttribute(RequestDispatcher.ERROR_STATUS_CODE,
Integer.valueOf(HttpServletResponse.SC_INTERNAL_SERVER_ERROR));
request.setAttribute(RequestDispatcher.ERROR_REQUEST_URI,
((HttpServletRequest) request).getRequestURI());
request.setAttribute(RequestDispatcher.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(RequestDispatcher.ERROR_EXCEPTION);
// t==null means the attribute was not set.
if ((newException != null) && (newException == t)) {
request.removeAttribute(RequestDispatcher.ERROR_EXCEPTION);
}
// now clear the error code - to prevent double handling.
request.removeAttribute(RequestDispatcher.ERROR_STATUS_CODE);
request.removeAttribute(RequestDispatcher.ERROR_REQUEST_URI);
request.removeAttribute(RequestDispatcher.ERROR_SERVLET_NAME);
request.removeAttribute(PageContext.EXCEPTION);
} 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 || t instanceof ELException ||
t instanceof javax.servlet.jsp.el.ELException) {
rootCause =t.getCause();
}
if (rootCause != null) {
throw new ServletException(t.getClass().getName() + ": "
+ t.getMessage(), rootCause);
}
throw new ServletException(t);
}
}
/**
* 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
* @throws ELException If an error occurs during the evaluation
*/
public static Object proprietaryEvaluate(final String expression,
final Class<?> expectedType, final PageContext pageContext,
final ProtectedFunctionMapper functionMap)
throws ELException {
final ExpressionFactory exprFactory = jspf.getJspApplicationContext(pageContext.getServletContext()).getExpressionFactory();
ELContext ctx = pageContext.getELContext();
ELContextImpl ctxImpl;
if (ctx instanceof ELContextWrapper) {
ctxImpl = (ELContextImpl) ((ELContextWrapper) ctx).getWrappedELContext();
} else {
ctxImpl = (ELContextImpl) ctx;
}
ctxImpl.setFunctionMapper(functionMap);
ValueExpression ve = exprFactory.createValueExpression(ctx, expression, expectedType);
return ve.getValue(ctx);
}
@Override
public ELContext getELContext() {
if (elContext == null) {
elContext = applicationContext.createELContext(this);
if (servlet instanceof JspSourceImports) {
ImportHandler ih = elContext.getImportHandler();
Set<String> packageImports = ((JspSourceImports) servlet).getPackageImports();
if (packageImports != null) {
for (String packageImport : packageImports) {
ih.importPackage(packageImport);
}
}
Set<String> classImports = ((JspSourceImports) servlet).getClassImports();
if (classImports != null) {
for (String classImport : classImports) {
ih.importClass(classImport);
}
}
}
}
return this.elContext;
}
}

View File

@@ -0,0 +1,153 @@
/*
* 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.jasper.runtime;
import java.lang.reflect.Method;
import java.util.HashMap;
import javax.servlet.jsp.el.FunctionMapper;
/**
* 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
*/
@SuppressWarnings("deprecation") // Have to support old JSP EL API
public final class ProtectedFunctionMapper extends javax.el.FunctionMapper
implements FunctionMapper {
/**
* Maps "prefix:name" to java.lang.Method objects.
*/
private HashMap<String,Method> 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.
*
* @return A new protected function mapper.
*/
public static ProtectedFunctionMapper getInstance() {
ProtectedFunctionMapper funcMapper = new ProtectedFunctionMapper();
funcMapper.fnmap = new 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) {
// Skip if null values were passed in. They indicate a function
// added via a lambda or ImportHandler; nether of which need to be
// placed in the Map.
if (fnQName == null) {
return;
}
java.lang.reflect.Method method;
try {
method = c.getMethod(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.
* @return the mapped function
*/
public static ProtectedFunctionMapper getMapForFunction(String fnQName,
final Class<?> c, final String methodName, final Class<?>[] args) {
java.lang.reflect.Method method = null;
ProtectedFunctionMapper funcMapper = new ProtectedFunctionMapper();
// Skip if null values were passed in. They indicate a function
// added via a lambda or ImportHandler; nether of which need to be
// placed in the Map.
if (fnQName != null) {
try {
method = c.getMethod(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.
*/
@Override
public Method resolveFunction(String prefix, String localName) {
if (this.fnmap != null) {
return this.fnmap.get(prefix + ":" + localName);
}
return theMethod;
}
}

View File

@@ -0,0 +1,79 @@
/*
* 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.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 final PrintWriter printWriter;
private final 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.
*/
@Override
public PrintWriter getWriter() throws IOException {
return printWriter;
}
@Override
public ServletOutputStream getOutputStream() throws IOException {
throw new IllegalStateException();
}
/**
* Clears the output buffer of the JspWriter associated with the including
* page.
*/
@Override
public void resetBuffer() {
try {
jspWriter.clearBuffer();
} catch (IOException ioe) {
}
}
}

View File

@@ -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.jasper.runtime;
import javax.servlet.ServletConfig;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.Tag;
import org.apache.jasper.Constants;
import org.apache.tomcat.InstanceManager;
/**
* Pool of tag handlers that can be reused.
*
* @author Jan Luehe
*/
public class TagHandlerPool {
private Tag[] handlers;
public static final String OPTION_TAGPOOL = "tagpoolClassName";
public static final String OPTION_MAXSIZE = "tagpoolMaxSize";
// index of next available tag handler
private int current;
protected InstanceManager instanceManager = 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.getConstructor().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;
instanceManager = InstanceManagerFactory.getInstanceManager(config);
}
/**
* 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 .
}
/**
* 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<? extends Tag> handlerClass) throws JspException {
Tag handler;
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 {
if (Constants.USE_INSTANCE_MANAGER_FOR_TAGS) {
return (Tag) instanceManager.newInstance(
handlerClass.getName(), handlerClass.getClassLoader());
} else {
Tag instance = handlerClass.getConstructor().newInstance();
instanceManager.newInstance(instance);
return instance;
}
} catch (Exception e) {
Throwable t = ExceptionUtils.unwrapInvocationTargetException(e);
ExceptionUtils.handleThrowable(t);
throw new JspException(e.getMessage(), t);
}
}
/**
* 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
JspRuntimeLibrary.releaseTag(handler, instanceManager);
}
/**
* 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--) {
JspRuntimeLibrary.releaseTag(handlers[i], instanceManager);
}
}
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;
}
}