Author: musachy Date: Thu Jul 30 19:23:24 2009 New Revision: 799418 URL: http://svn.apache.org/viewvc?rev=799418&view=rev Log: import jsp plugin
Added: struts/sandbox/trunk/struts2-jsp-plugin/ struts/sandbox/trunk/struts2-jsp-plugin/pom.xml struts/sandbox/trunk/struts2-jsp-plugin/src/ struts/sandbox/trunk/struts2-jsp-plugin/src/main/ struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/ struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/ struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/ struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts/ struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts/EmbeddedJSPResult.java struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts/JSPLoader.java struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts/JSPServletConfig.java struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts/ServletCache.java struts/sandbox/trunk/struts2-jsp-plugin/src/test/ struts/sandbox/trunk/struts2-jsp-plugin/src/test/java/ struts/sandbox/trunk/struts2-jsp-plugin/src/test/java/org/ struts/sandbox/trunk/struts2-jsp-plugin/src/test/java/org/apache/ struts/sandbox/trunk/struts2-jsp-plugin/src/test/java/org/apache/struts2/ struts/sandbox/trunk/struts2-jsp-plugin/src/test/java/org/apache/struts2/EmbeddedJSPResultTest.java struts/sandbox/trunk/struts2-jsp-plugin/src/test/resources/ struts/sandbox/trunk/struts2-jsp-plugin/src/test/resources/org/ struts/sandbox/trunk/struts2-jsp-plugin/src/test/resources/org/apache/ struts/sandbox/trunk/struts2-jsp-plugin/src/test/resources/org/apache/struts2/ struts/sandbox/trunk/struts2-jsp-plugin/src/test/resources/org/apache/struts2/includes0.jsp struts/sandbox/trunk/struts2-jsp-plugin/src/test/resources/org/apache/struts2/simple0.jsp Added: struts/sandbox/trunk/struts2-jsp-plugin/pom.xml URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-jsp-plugin/pom.xml?rev=799418&view=auto ============================================================================== --- struts/sandbox/trunk/struts2-jsp-plugin/pom.xml (added) +++ struts/sandbox/trunk/struts2-jsp-plugin/pom.xml Thu Jul 30 19:23:24 2009 @@ -0,0 +1,56 @@ +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + <modelVersion>4.0.0</modelVersion> + <groupId>struts2-jsp-plugin</groupId> + <artifactId>struts2-jsp-plugin</artifactId> + <packaging>jar</packaging> + <version>1.0</version> + <name>struts2-jsp-plugin</name> + <url>http://maven.apache.org</url> + <dependencies> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <version>3.8.1</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.springframework</groupId> + <artifactId>spring-test</artifactId> + <version>2.5.6</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.springframework</groupId> + <artifactId>spring-core</artifactId> + <version>2.5.6</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>commons-io</groupId> + <artifactId>commons-io</artifactId> + <version>1.3.2</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.apache.struts</groupId> + <artifactId>struts2-core</artifactId> + <version>2.1.8-SNAPSHOT</version> + </dependency> + <dependency> + <groupId>com.opensymphony</groupId> + <artifactId>xwork-core</artifactId> + <version>2.1.5-SNAPSHOT</version> + </dependency> + <dependency> + <groupId>tomcat</groupId> + <artifactId>jasper-compiler</artifactId> + <version>5.5.23</version> + </dependency> + <dependency> + <groupId>tomcat</groupId> + <artifactId>jasper-runtime</artifactId> + <version>5.5.23</version> + </dependency> + </dependencies> +</project> Added: struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts/EmbeddedJSPResult.java URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts/EmbeddedJSPResult.java?rev=799418&view=auto ============================================================================== --- struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts/EmbeddedJSPResult.java (added) +++ struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts/EmbeddedJSPResult.java Thu Jul 30 19:23:24 2009 @@ -0,0 +1,47 @@ +package org.apache.struts; + +import org.apache.struts2.dispatcher.StrutsResultSupport; +import org.apache.struts2.ServletActionContext; +import org.apache.commons.lang.xwork.StringUtils; +import org.apache.jasper.JspC; +import org.apache.jasper.JasperException; +import org.apache.tools.ant.Project; +import org.apache.tools.ant.BuildListener; +import org.apache.tools.ant.BuildEvent; +import com.opensymphony.xwork2.ActionInvocation; +import com.opensymphony.xwork2.util.ClassLoaderUtil; +import com.opensymphony.xwork2.util.logging.Logger; +import com.opensymphony.xwork2.util.logging.LoggerFactory; + +import javax.servlet.jsp.JspPage; +import javax.servlet.jsp.HttpJspPage; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.ServletException; +import javax.servlet.Servlet; +import javax.servlet.ServletConfig; +import javax.servlet.ServletContext; +import java.io.*; +import java.nio.channels.Channels; +import java.nio.channels.ReadableByteChannel; +import java.nio.channels.FileChannel; +import java.nio.ByteBuffer; +import java.net.URLClassLoader; +import java.net.URL; +import java.net.MalformedURLException; +import java.util.concurrent.ConcurrentHashMap; + + +public class EmbeddedJSPResult extends StrutsResultSupport { + private static final Logger LOG = LoggerFactory.getLogger(EmbeddedJSPResult.class); + + //maps from jsp path -> pagelet + private static final ServletCache servletCache = new ServletCache(ServletActionContext.getServletContext()); + + protected void doExecute(String finalLocation, ActionInvocation invocation) throws Exception { + Servlet servlet = servletCache.get(finalLocation); + HttpJspPage page = (HttpJspPage) servlet; + page.jspInit(); + page._jspService(ServletActionContext.getRequest(), ServletActionContext.getResponse()); + } +} Added: struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts/JSPLoader.java URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts/JSPLoader.java?rev=799418&view=auto ============================================================================== --- struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts/JSPLoader.java (added) +++ struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts/JSPLoader.java Thu Jul 30 19:23:24 2009 @@ -0,0 +1,192 @@ +/* + * $Id$ + * + * 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.struts; + +import com.opensymphony.xwork2.util.logging.Logger; +import com.opensymphony.xwork2.util.logging.LoggerFactory; +import com.opensymphony.xwork2.util.ClassLoaderUtil; + +import javax.servlet.Servlet; +import javax.servlet.ServletContext; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.jsp.HttpJspPage; +import java.io.*; +import java.net.URLClassLoader; +import java.net.URL; +import java.net.MalformedURLException; +import java.nio.channels.ReadableByteChannel; +import java.nio.channels.Channels; +import java.nio.channels.FileChannel; +import java.nio.ByteBuffer; + +import org.apache.commons.lang.xwork.StringUtils; +import org.apache.commons.io.FileUtils; +import org.apache.jasper.JasperException; +import org.apache.jasper.JspC; +import org.apache.tools.ant.Project; +import org.apache.tools.ant.BuildEvent; +import org.apache.tools.ant.BuildListener; + +/** + * Uses jasper to extract a JSP from the classpath to a file and compile it + */ +public class JSPLoader implements BuildListener { + private static final Logger LOG = LoggerFactory.getLogger(JSPLoader.class); + public static final File JSP_DIR = new File(System.getProperty("java.io.tmpdir"), "struts_jsps"); + + private static ClassLoader classLoader; + private static final String DEFAULT_NAMESPACE = "org.apache.jsp"; + private static final String DEFAULT_PATH = "org/apache/jsp"; + + static { + try { + classLoader = new URLClassLoader(new URL[]{JSP_DIR.toURI().toURL()}); + } catch (MalformedURLException e) { + //this is kinda dumb + throw new RuntimeException(e); + } + } + + public Servlet load(String location, ServletContext servletContext) throws Exception { + File jspFile = extractFile(location); + File classFile = compileJSP(jspFile); + Class clazz = loadClass(classFile); + return createServlet(clazz, servletContext); + } + + /** + * Creates and inits a servlet + */ + private Servlet createServlet(Class clazz, ServletContext servletContext) throws IllegalAccessException, InstantiationException, ServletException { + Servlet servlet = (Servlet) clazz.newInstance(); + JSPServletConfig config = new JSPServletConfig(servletContext); + servlet.init(config); + + return servlet; + } + + private Class loadClass(File file) throws ClassNotFoundException { + StringBuilder sb = new StringBuilder(DEFAULT_NAMESPACE); + sb.append("."); + sb.append(StringUtils.substringBefore(file.getName(), ".")); + return classLoader.loadClass(sb.toString()); + } + + private File compileJSP(File file) throws JasperException { + //ant setup + Project project = new Project(); + project.addBuildListener(this); + + File parentFile = file.getParentFile(); + String parentPath = parentFile.getAbsolutePath(); + + JspC jspC = new JspC(); + jspC.setProject(project); + jspC.setOutputDir(parentPath); + jspC.setCompile(true); + jspC.setJspFiles(file.getName()); + jspC.setUriroot(parentPath); + jspC.execute(); + + String classFileName = file.getName().replace(".jsp", "_jsp.class"); + return new File(parentFile, DEFAULT_PATH + "/" + classFileName); + } + + /** + * Looks up a file with path finalLocation from the classpath and extracts it to a temporal file + */ + public File extractFile(String finalLocation) throws IOException { + InputStream inputStream = ClassLoaderUtil.getResourceAsStream(finalLocation, EmbeddedJSPResult.class); + + if (inputStream == null) + throw new FileNotFoundException("Unable to find file [" + + finalLocation + + "] in the classpath"); + + FileOutputStream jspOutputStream = null; + + try { + ReadableByteChannel readableByteChannel = Channels.newChannel(inputStream); + + //file name and path + String[] splitted = finalLocation.split("\\.|/"); + String path = StringUtils.substringBeforeLast(finalLocation, "/"); + String fileName = StringUtils.substringAfterLast(finalLocation, "/"); + + + //create output dir + if (!JSP_DIR.exists()) + JSP_DIR.mkdirs(); + + //temp file + File jspFile = new File(JSP_DIR, fileName); + + //output channel + jspOutputStream = new FileOutputStream(jspFile); + FileChannel outChannel = jspOutputStream.getChannel(); + + ByteBuffer buffer = ByteBuffer.allocate(1024); + + //copy + while (true) { + int read = readableByteChannel.read(buffer); + + if (read == -1) + break; + + buffer.flip(); + outChannel.write(buffer); + buffer.clear(); + } + + return jspFile; + } finally { + if (inputStream != null) + inputStream.close(); + if (jspOutputStream != null) + jspOutputStream.close(); + } + } + + public void buildStarted(BuildEvent buildEvent) { + } + + public void buildFinished(BuildEvent buildEvent) { + } + + public void targetStarted(BuildEvent buildEvent) { + } + + public void targetFinished(BuildEvent buildEvent) { + } + + public void taskStarted(BuildEvent buildEvent) { + } + + public void taskFinished(BuildEvent buildEvent) { + } + + public void messageLogged(BuildEvent buildEvent) { + LOG.debug(buildEvent.getMessage()); + } +} Added: struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts/JSPServletConfig.java URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts/JSPServletConfig.java?rev=799418&view=auto ============================================================================== --- struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts/JSPServletConfig.java (added) +++ struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts/JSPServletConfig.java Thu Jul 30 19:23:24 2009 @@ -0,0 +1,52 @@ +/* + * $Id$ + * + * 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.struts; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletContext; +import java.util.Enumeration; +import java.util.Collections; + +public class JSPServletConfig implements ServletConfig { + private final Enumeration EMPTY_ENUMERATION = Collections.enumeration(Collections.EMPTY_LIST); + + private ServletContext servletContext; + + public JSPServletConfig(ServletContext servletContext) { + this.servletContext = servletContext; + } + + public String getInitParameter(String name) { + return null; + } + + public Enumeration getInitParameterNames() { + return EMPTY_ENUMERATION; + } + + public ServletContext getServletContext() { + return servletContext; + } + + public String getServletName() { + return null; + } +} Added: struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts/ServletCache.java URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts/ServletCache.java?rev=799418&view=auto ============================================================================== --- struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts/ServletCache.java (added) +++ struts/sandbox/trunk/struts2-jsp-plugin/src/main/java/org/apache/struts/ServletCache.java Thu Jul 30 19:23:24 2009 @@ -0,0 +1,78 @@ +/* + * $Id$ + * + * 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.struts; + +import javax.servlet.Servlet; +import javax.servlet.ServletContext; +import java.util.concurrent.*; + +/** + * Caches servlet instances by jsp location + */ +public class ServletCache { + private final ConcurrentMap<String, Future<Servlet>> cache + = new ConcurrentHashMap<String, Future<Servlet>>(); + + private final JSPLoader jspLoader = new JSPLoader(); + + private final ServletContext servletContext; + + public ServletCache(ServletContext servletContext) { + this.servletContext = servletContext; + } + + public Servlet get(final String location) throws InterruptedException { + while (true) { + Future<Servlet> future = cache.get(location); + if (future == null) { + Callable<Servlet> loadJSPCallable = new Callable<Servlet>() { + public Servlet call() throws Exception { + return jspLoader.load(location, servletContext); + } + }; + FutureTask<Servlet> futureTask = new FutureTask<Servlet>(loadJSPCallable); + future = cache.putIfAbsent(location, futureTask); + if (future == null) { + future = futureTask; + futureTask.run(); + } + } + try { + return future.get(); + } catch (CancellationException e) { + cache.remove(location, future); + } catch (ExecutionException e) { + throw launderThrowable(e.getCause()); + } + } + } + + public static RuntimeException launderThrowable(Throwable t) { + if (t instanceof RuntimeException) + return (RuntimeException) t; + else if (t instanceof Error) + throw (Error) t; + else + throw new IllegalStateException("Not unchecked", t); + } + +} + Added: struts/sandbox/trunk/struts2-jsp-plugin/src/test/java/org/apache/struts2/EmbeddedJSPResultTest.java URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-jsp-plugin/src/test/java/org/apache/struts2/EmbeddedJSPResultTest.java?rev=799418&view=auto ============================================================================== --- struts/sandbox/trunk/struts2-jsp-plugin/src/test/java/org/apache/struts2/EmbeddedJSPResultTest.java (added) +++ struts/sandbox/trunk/struts2-jsp-plugin/src/test/java/org/apache/struts2/EmbeddedJSPResultTest.java Thu Jul 30 19:23:24 2009 @@ -0,0 +1,44 @@ +package org.apache.struts2; + +import junit.framework.TestCase; +import org.apache.commons.io.FileUtils; +import org.apache.struts.EmbeddedJSPResult; +import org.apache.struts.JSPLoader; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.mock.web.MockServletContext; +import com.opensymphony.xwork2.ActionContext; + +import java.util.HashMap; + +public class EmbeddedJSPResultTest extends TestCase { + + + public void testSimple() throws Exception { + //mock objects + MockHttpServletRequest request = new MockHttpServletRequest(); + MockHttpServletResponse response = new MockHttpServletResponse(); + MockServletContext context = new MockServletContext(); + + ActionContext actionContext = new ActionContext(new HashMap<String, Object>()); + ActionContext.setContext(actionContext); + ServletActionContext.setRequest(request); + ServletActionContext.setResponse(response); + ServletActionContext.setServletContext(context); + + EmbeddedJSPResult result = new EmbeddedJSPResult(); + + result.setLocation("org/apache/struts2/simple0.jsp"); + result.execute(null); + + assertEquals("hello", response.getContentAsString()); + } + + + @Override + protected void setUp() throws Exception { + super.setUp(); + if (JSPLoader.JSP_DIR.exists()) + FileUtils.forceDelete(JSPLoader.JSP_DIR); + } +} Added: struts/sandbox/trunk/struts2-jsp-plugin/src/test/resources/org/apache/struts2/includes0.jsp URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-jsp-plugin/src/test/resources/org/apache/struts2/includes0.jsp?rev=799418&view=auto ============================================================================== --- struts/sandbox/trunk/struts2-jsp-plugin/src/test/resources/org/apache/struts2/includes0.jsp (added) +++ struts/sandbox/trunk/struts2-jsp-plugin/src/test/resources/org/apache/struts2/includes0.jsp Thu Jul 30 19:23:24 2009 @@ -0,0 +1,2 @@ +<jsp:include page="simple0.jsp" /> +Test \ No newline at end of file Added: struts/sandbox/trunk/struts2-jsp-plugin/src/test/resources/org/apache/struts2/simple0.jsp URL: http://svn.apache.org/viewvc/struts/sandbox/trunk/struts2-jsp-plugin/src/test/resources/org/apache/struts2/simple0.jsp?rev=799418&view=auto ============================================================================== --- struts/sandbox/trunk/struts2-jsp-plugin/src/test/resources/org/apache/struts2/simple0.jsp (added) +++ struts/sandbox/trunk/struts2-jsp-plugin/src/test/resources/org/apache/struts2/simple0.jsp Thu Jul 30 19:23:24 2009 @@ -0,0 +1 @@ +hello \ No newline at end of file