net.sf.jsptest.compiler.jsp20.JasperExecution Maven / Gradle / Ivy
/*
* Copyright 2007 Lasse Koskela.
*
* Licensed 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 net.sf.jsptest.compiler.jsp20;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.servlet.jsp.JspFactory;
import junit.framework.TestCase;
import net.sf.jsptest.compiler.JspCompilationInfo;
import net.sf.jsptest.compiler.jsp20.mock.MockHttpServletRequest;
import net.sf.jsptest.compiler.jsp20.mock.MockHttpServletResponse;
import net.sf.jsptest.compiler.jsp20.mock.MockHttpSession;
import net.sf.jsptest.compiler.jsp20.mock.MockJspFactory;
import net.sf.jsptest.compiler.jsp20.mock.MockJspWriter;
import net.sf.jsptest.compiler.jsp20.mock.MockPageContext;
import net.sf.jsptest.compiler.jsp20.mock.MockServletConfig;
import net.sf.jsptest.compiler.jsp20.mock.MockServletContext;
import net.sf.jsptest.utils.CustomClassLoader;
import net.sf.jsptest.utils.IO;
/**
* The JasperTestCase provides a facility for rendering JavaServer Pages outside a real
* Servlet/JSP container.
*
* It uses the JasperCompiler to compile JSP files and invokes the compiled Servlet class
* using a custom ClassLoader, providing access to a WebResponse object
* representing the rendered output by pointing HttpUnit to a temporary file on the local file
* system.
*
* @author Lasse Koskela
* @author Meinert Schwartau (scwar32)
*/
public abstract class JasperExecution extends TestCase {
private static Map mockTaglibs = new HashMap();
private static JasperCompiler compiler = new JasperCompiler();
private MockPageContext pageContext;
private File responseFile;
protected Map sessionAttributes;
protected Map requestAttributes;
public JasperExecution() {
this.sessionAttributes = new HashMap();
this.requestAttributes = new HashMap();
mockTaglibs.clear();
responseFile = null;
}
/**
* Returns a handle to the rendered output written into a temporary file.
*/
protected File getRenderedResponse() {
return responseFile;
}
/**
* Returns the root directory relative to which all request paths will be resolved. This root
* directory is the one which contains your "WEB-INF". By default, it is the current working
* directory. Override this method to point JspTest to your web root.
*/
protected String getWebRoot() {
return ".";
}
/**
* Returns the directory where generated .class file(s) should be written. Unless overridden by
* subclasses, the default is "$HOME/.jsptest/compiled" plus a unique subdirectory derived from
* the current working directory.
*/
protected String getClassOutputBaseDir() {
File home = new File(System.getProperty("user.home"));
File jspClassDir = new File(home, ".jsptest/compiled/"
+ createUniqueIdentifierForWorkspace());
jspClassDir.mkdirs();
return jspClassDir.getAbsolutePath();
}
private String createUniqueIdentifierForWorkspace() {
return "workspace-" + new File(".").getAbsolutePath().hashCode();
}
/**
* Simulate a HTTP GET request to the given path and return the rendered page.
*
* @param path
* The resource path to query.
* @throws Exception
*/
protected void get(String path) throws Exception {
request(path, "GET");
}
/**
* Simulate a HTTP POST request to the given path and return the rendered page.
*
* @param path
* The resource path to query.
* @throws Exception
*/
protected void post(String path) throws Exception {
request(path, "POST");
}
/**
* Overriding the request() method in JspTestCase in order to perform the
* necessary compilation before starting the container.
*
* @param path
* The path to the JSP file.
* @param httpMethod
* The HTTP request method (GET, POST).
*/
protected void request(String path, String httpMethod) throws Exception {
require(path.startsWith("/"), "JSP paths must start with a slash ('/')");
Class jspClass = compileToClass(path);
responseFile = File.createTempFile("jsptest-response", ".txt");
invokeServlet(httpMethod, jspClass);
}
private void require(boolean condition, String message) {
if (!condition) {
throw new IllegalArgumentException(message);
}
}
protected void invokeServlet(String httpMethod, Class jspClass) throws InstantiationException,
IllegalAccessException, ServletException, IOException {
ServletContext servletContext = new MockServletContext();
ServletConfig servletConfig = new MockServletConfig(servletContext);
MockHttpSession httpSession = new MockHttpSession();
httpSession.setAttributes(sessionAttributes);
MockHttpServletRequest request = new MockHttpServletRequest();
request.setSession(httpSession);
request.setMethod(httpMethod);
request.setAttributes(requestAttributes);
MockHttpServletResponse response = new MockHttpServletResponse(getRenderedResponse());
MockJspWriter jspWriter = configureJspFactory(servletContext, request, httpSession);
initializeAndInvokeJsp(jspClass, servletConfig, request, response);
writeOutputToTempFile(jspWriter.getContents());
}
protected MockJspWriter configureJspFactory(ServletContext httpContext,
HttpServletRequest httpRequest, HttpSession httpSession) {
pageContext = new MockPageContext();
pageContext.setRequest(httpRequest);
pageContext.setServletContext(httpContext);
pageContext.setSession(httpSession);
MockJspWriter jspWriter = new MockJspWriter();
pageContext.setJspWriter(jspWriter);
JspFactory.setDefaultFactory(new MockJspFactory(pageContext));
return jspWriter;
}
protected void initializeAndInvokeJsp(Class jspClass, ServletConfig servletConfig,
HttpServletRequest request, HttpServletResponse response)
throws InstantiationException, IllegalAccessException, ServletException, IOException {
HttpServlet servlet = (HttpServlet) jspClass.newInstance();
servlet.init(servletConfig);
servlet.service(request, response);
if (pageContext.getException() != null) {
throw new RuntimeException(pageContext.getException());
}
}
private Class compileToClass(String path) throws Exception, ClassNotFoundException {
JspCompilationInfo compilation = getCompiler().compile(path, mockTaglibs);
return loadJspClass(compilation.getClassName());
}
private JasperCompiler getCompiler() {
compiler.setWebRoot(getWebRoot());
compiler.setClassOutputBaseDir(getClassOutputBaseDir());
return compiler;
}
private Class loadJspClass(String jspClassName) throws ClassNotFoundException {
ClassLoader cl = new CustomClassLoader(getClassOutputBaseDir());
return cl.loadClass(jspClassName);
}
protected File writeOutputToTempFile(String output) throws IOException {
File temp = File.createTempFile("generated_html_", ".html");
IO.write(output, temp);
return temp;
}
protected void substituteTaglib(String namespace, Class klass) {
mockTaglibs.put(namespace, klass);
}
}