Add support for JSPs in DevMode; this also enables annotations scanning.
Bug: #9292
Bug-Link: https://github.com/gwtproject/gwt/issues/9292
Change-Id: Ibd8704a74292088857f344a25a073ba03771696c
diff --git a/dev/build.xml b/dev/build.xml
index 1d8bf84..a864a2b 100755
--- a/dev/build.xml
+++ b/dev/build.xml
@@ -75,12 +75,13 @@
<include name="jsr305/jsr305.jar"/>
<include name="protobuf/protobuf-2.5.0/protobuf-java-rebased-2.5.0.jar"/>
<!-- dependencies needed for JSP support in DevMode: BEGIN -->
- <include name="tomcat/commons-el-1.0.jar"/>
- <include name="tomcat/jasper-compiler-1.0.jar"/>
- <include name="tomcat/jasper-runtime-1.0.jar"/>
- <include name="tomcat/jsp-api-2.0.jar"/>
+ <include name="jetty/jetty-9.2.14.v20151106/mortbay-apache-jsp-8.0.9.M3.jar"/>
+ <include name="jetty/jetty-9.2.14.v20151106/mortbay-apache-el-8.0.9.M3.jar"/>
+ <include name="jetty/jetty-9.2.14.v20151106/jetty-apache-jsp-9.2.14.v20151106.jar"/>
<!-- dependencies needed for JSP support in DevMode: END -->
<include name="tomcat/tomcat-servlet-api-8.0.28.jar"/>
+ <include name="tomcat/tomcat-websocket-api-8.0.28.jar"/>
+ <include name="tomcat/tomcat-annotations-api-8.0.28.jar"/>
<include name="apache/commons/commons-collections-3.2.2.jar"/>
<!-- htmlunit dependencies not already included: BEGIN -->
<include name="apache/http/httpclient-4.5.1.jar"/>
@@ -111,6 +112,10 @@
</targetfiles>
<sequential>
<gwt.jar destfile="${alldeps.jar}" duplicate="preserve">
+ <service type="javax.servlet.ServletContainerInitializer">
+ <provider classname="org.eclipse.jetty.websocket.jsr356.server.deploy.WebSocketServerContainerInitializer"/>
+ <provider classname="org.eclipse.jetty.apache.jsp.JettyJasperInitializer"/>
+ </service>
<zipfileset src="${gwt.tools.lib}/objectweb/asm-5.0.3/lib/asm-all-5.0.3.jar"/>
<zipfileset src="${gwt.tools.lib}/apache/tapestry-util-text-4.0.2.jar"/>
<zipfileset src="${gwt.tools.lib}/apache/ant-1.6.5.jar"/>
@@ -130,12 +135,13 @@
<zipfileset
src="${gwt.tools.lib}/protobuf/protobuf-2.5.0/protobuf-java-rebased-2.5.0.jar"/>
<!-- dependencies needed for JSP support in DevMode: BEGIN -->
- <zipfileset src="${gwt.tools.lib}/tomcat/commons-el-1.0.jar"/>
- <zipfileset src="${gwt.tools.lib}/tomcat/jasper-compiler-1.0.jar"/>
- <zipfileset src="${gwt.tools.lib}/tomcat/jasper-runtime-1.0.jar"/>
- <zipfileset src="${gwt.tools.lib}/tomcat/jsp-api-2.0.jar"/>
+ <zipfileset src="${gwt.tools.lib}/jetty/jetty-9.2.14.v20151106/mortbay-apache-jsp-8.0.9.M3.jar"/>
+ <zipfileset src="${gwt.tools.lib}/jetty/jetty-9.2.14.v20151106/mortbay-apache-el-8.0.9.M3.jar"/>
+ <zipfileset src="${gwt.tools.lib}/jetty/jetty-9.2.14.v20151106/jetty-apache-jsp-9.2.14.v20151106.jar"/>
<!-- dependencies needed for JSP support in DevMode: END -->
<zipfileset src="${gwt.tools.lib}/tomcat/tomcat-servlet-api-8.0.28.jar"/>
+ <zipfileset src="${gwt.tools.lib}/tomcat/tomcat-websocket-api-8.0.28.jar"/>
+ <zipfileset src="${gwt.tools.lib}/tomcat/tomcat-annotations-api-8.0.28.jar"/>
<zipfileset
src="${gwt.tools.lib}/apache/commons/commons-collections-3.2.2.jar"/>
<!-- htmlunit dependencies not already included: BEGIN -->
diff --git a/dev/core/src/com/google/gwt/dev/shell/jetty/JettyLauncher.java b/dev/core/src/com/google/gwt/dev/shell/jetty/JettyLauncher.java
index 5a7b37c..317159c 100644
--- a/dev/core/src/com/google/gwt/dev/shell/jetty/JettyLauncher.java
+++ b/dev/core/src/com/google/gwt/dev/shell/jetty/JettyLauncher.java
@@ -21,9 +21,9 @@
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.dev.util.InstalledHelpInfo;
import com.google.gwt.dev.util.Util;
+import com.google.gwt.thirdparty.guava.common.collect.Iterators;
+import com.google.gwt.thirdparty.guava.common.collect.Lists;
-import org.apache.tools.ant.taskdefs.Javac;
-import org.eclipse.jdt.core.JDTCompilerAdapter;
import org.eclipse.jetty.http.HttpField;
import org.eclipse.jetty.http.HttpFields;
import org.eclipse.jetty.server.HttpConfiguration;
@@ -41,6 +41,7 @@
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.eclipse.jetty.webapp.ClasspathPattern;
+import org.eclipse.jetty.webapp.Configuration;
import org.eclipse.jetty.webapp.WebAppClassLoader;
import org.eclipse.jetty.webapp.WebAppContext;
@@ -51,6 +52,10 @@
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.List;
import javax.imageio.ImageIO;
import javax.xml.parsers.DocumentBuilderFactory;
@@ -62,23 +67,6 @@
public class JettyLauncher extends ServletContainerLauncher {
/**
- * Ant compiler adapter for Eclipse Java compiler, but with default
- * target and source compatibility set to Java 6.
- */
- public static final class JDTCompiler16 extends JDTCompilerAdapter {
- @Override
- public void setJavac(Javac attributes) {
- if (attributes.getTarget() == null) {
- attributes.setTarget("1.6");
- }
- if (attributes.getSource() == null) {
- attributes.setSource("1.6");
- }
- super.setJavac(attributes);
- }
- }
-
- /**
* Log jetty requests/responses to TreeLogger.
*/
public static class JettyRequestLogger extends AbstractLifeCycle implements
@@ -363,13 +351,17 @@
private final ClasspathPattern systemClassesFromWebappFirst = new ClasspathPattern(new String[] {
"-javax.servlet.",
+ "-javax.el.",
"javax.",
});
private final ClasspathPattern allowedFromSystemClassLoader = new ClasspathPattern(new String[] {
"org.eclipse.jetty.",
+ "javax.websocket.",
// Jasper
"org.apache.jasper.",
- "org.apache.commons.logging.",
+ "org.apache.juli.logging.",
+ "org.apache.tomcat.",
+ "org.apache.el.",
// Xerces
"org.apache.xerces.",
"javax.xml.", // Used by Jetty for jetty-web.xml parsing
@@ -380,6 +372,18 @@
}
@Override
+ public Enumeration<URL> getResources(String name) throws IOException {
+ // Logic copied from Jetty's WebAppClassLoader
+ List<URL> fromParent = isServerClass(name)
+ ? Collections.<URL>emptyList()
+ : Lists.newArrayList(Iterators.forEnumeration(systemClassLoader.getResources(name)));
+ Iterator<URL> fromWebapp = isSystemClass(name) && !fromParent.isEmpty()
+ ? Collections.<URL>emptyIterator()
+ : Iterators.forEnumeration(findResources(name));
+ return Iterators.asEnumeration(Iterators.concat(fromWebapp, fromParent.iterator()));
+ }
+
+ @Override
public URL findResource(String name) {
// Specifically for META-INF/services/javax.xml.parsers.SAXParserFactory
String checkName = name;
@@ -390,7 +394,7 @@
// For a system path, load from the outside world.
// Note: bootstrap has already been searched, so javax. classes should be
- // tried from the webapp first (except for javax.servlet).
+ // tried from the webapp first (except for javax.servlet and javax.el).
URL found;
if (isSystemClass(checkName) && !systemClassesFromWebappFirst.match(checkName)) {
found = systemClassLoader.getResource(name);
@@ -413,12 +417,8 @@
// Special-case Jetty/Jasper/etc. resources
if (allowedFromSystemClassLoader.match(checkName) ||
- // Jasper uses Log4j (via Commons Logging), which will try
- // to load those.
- // We have a log4j.properties in user/test and don't want
- // to add gwt-user when using a "Developer SDK" in Eclipse.
- "log4j.xml".equals(name) ||
- "log4j.properties".equals(name)) {
+ // Jetty-plus reads jndi.properties
+ "jndi.properties".equals(name)) {
return found;
}
@@ -460,6 +460,12 @@
return null;
}
+ // Special-case JDBCUnloader; it should always be loaded in the webapp classloader
+ if (JDBCUnloader.class.getName().equals(name)) {
+ byte[] jdbcUnloader = Util.readURLAsBytes(found);
+ return defineClass(name, jdbcUnloader, 0, jdbcUnloader.length);
+ }
+
// Those classes are allowed to be loaded right from the systemClassLoader
// Note: Jetty classes here are not "server classes", handled above.
if (allowedFromSystemClassLoader.match(name)) {
@@ -574,16 +580,6 @@
*/
private static final String PROPERTY_NOWARN_WEBAPP_CLASSPATH = "gwt.nowarn.webapp.classpath";
- static {
- /*
- * Make JDT the default Ant compiler so that JSP compilation just works
- * out-of-the-box. If we don't set this, it's very, very difficult to make
- * JSP compilation work.
- */
- String antJavaC = System.getProperty("build.compiler", JDTCompiler16.class.getName());
- System.setProperty("build.compiler", antJavaC);
- }
-
/**
* Setup a connector for the bind address/port.
*
@@ -735,8 +731,28 @@
setupConnector(connector, bindAddress, port);
server.addConnector(connector);
+ Configuration.ClassList cl = Configuration.ClassList.setServerDefault(server);
+ try {
+ // from jetty-plus.xml
+ Thread.currentThread().getContextClassLoader().loadClass("org.eclipse.jetty.plus.webapp.PlusConfiguration");
+ cl.addAfter("org.eclipse.jetty.webapp.FragmentConfiguration",
+ "org.eclipse.jetty.plus.webapp.EnvConfiguration",
+ "org.eclipse.jetty.plus.webapp.PlusConfiguration");
+ } catch (ClassNotFoundException cnfe) {
+ logger.log(TreeLogger.Type.DEBUG, "jetty-plus isn't on the classpath, JNDI won't work. This might also affect annotations scanning and JSP.");
+ }
+ try {
+ // from jetty-annotations.xml
+ Thread.currentThread().getContextClassLoader()
+ .loadClass("org.eclipse.jetty.annotations.AnnotationConfiguration");
+ cl.addBefore("org.eclipse.jetty.webapp.JettyWebXmlConfiguration",
+ "org.eclipse.jetty.annotations.AnnotationConfiguration");
+ } catch (ClassNotFoundException cnfe) {
+ logger.log(TreeLogger.Type.DEBUG, "jetty-annotations isn't on the classpath, annotation scanning won't work. This might also affect annotations scanning.");
+ }
+
// Create a new web app in the war directory.
- WebAppContext wac = createWebAppContext(logger, appRootDir);
+ WebAppContext wac = createWebAppContext(logger, appRootDir);
RequestLogHandler logHandler = new RequestLogHandler();
logHandler.setRequestLog(new JettyRequestLogger(logger, getBaseLogLevel()));
@@ -766,7 +782,18 @@
}
protected WebAppContext createWebAppContext(TreeLogger logger, File appRootDir) {
- return new WebAppContextWithReload(logger, appRootDir.getAbsolutePath(), "/");
+ WebAppContext context = new WebAppContextWithReload(logger, appRootDir.getAbsolutePath(), "/");
+ context.setConfigurationClasses(new String[] {
+ "org.eclipse.jetty.webapp.WebInfConfiguration",
+ "org.eclipse.jetty.webapp.WebXmlConfiguration",
+ "org.eclipse.jetty.webapp.MetaInfConfiguration",
+ "org.eclipse.jetty.webapp.FragmentConfiguration",
+ "org.eclipse.jetty.plus.webapp.EnvConfiguration",
+ "org.eclipse.jetty.plus.webapp.PlusConfiguration",
+ "org.eclipse.jetty.annotations.AnnotationConfiguration",
+ "org.eclipse.jetty.webapp.JettyWebXmlConfiguration"
+ });
+ return context;
}
protected ServerConnector getConnector(Server server, TreeLogger logger) {
diff --git a/eclipse/dev/.classpath b/eclipse/dev/.classpath
index 85c02a6..14118db 100644
--- a/eclipse/dev/.classpath
+++ b/eclipse/dev/.classpath
@@ -15,10 +15,9 @@
<classpathentry kind="var" path="GWT_TOOLS/lib/tomcat/ant-launcher-1.6.5.jar"/>
<classpathentry kind="var" path="GWT_TOOLS/lib/tomcat/catalina-1.0.jar"/>
<classpathentry kind="var" path="GWT_TOOLS/lib/tomcat/catalina-optional-1.0.jar"/>
- <classpathentry kind="var" path="GWT_TOOLS/lib/tomcat/commons-el-1.0.jar"/>
- <classpathentry kind="var" path="GWT_TOOLS/lib/tomcat/jasper-compiler-1.0.jar"/>
- <classpathentry kind="var" path="GWT_TOOLS/lib/tomcat/jasper-runtime-1.0.jar"/>
- <classpathentry kind="var" path="GWT_TOOLS/lib/tomcat/jsp-api-2.0.jar"/>
+ <classpathentry kind="var" path="GWT_TOOLS/lib/jetty/jetty-9.2.14.v20151106/mortbay-apache-jsp-8.0.9.M3.jar"/>
+ <classpathentry kind="var" path="GWT_TOOLS/lib/jetty/jetty-9.2.14.v20151106/mortbay-apache-el-8.0.9.M3.jar"/>
+ <classpathentry kind="var" path="GWT_TOOLS/lib/jetty/jetty-9.2.14.v20151106/jetty-apache-jsp-9.2.14.v20151106.jar"/>
<classpathentry kind="var" path="GWT_TOOLS/lib/htmlunit/htmlunit-2.19/htmlunit-2.19.jar"/>
<classpathentry kind="var" path="GWT_TOOLS/lib/htmlunit/htmlunit-2.19/htmlunit-core-js-2.15.jar"/>
<classpathentry kind="var" path="GWT_TOOLS/lib/protobuf/protobuf-2.5.0/protobuf-java-rebased-2.5.0.jar"/>
@@ -29,6 +28,8 @@
<classpathentry kind="var" path="GWT_TOOLS/lib/json/android-sdk-19.1/json-android-rebased.jar"/>
<classpathentry kind="var" path="GWT_TOOLS/lib/apache/commons/commons-collections-3.2.2.jar"/>
<classpathentry exported="true" kind="var" path="GWT_TOOLS/lib/tomcat/tomcat-servlet-api-8.0.28.jar"/>
+ <classpathentry exported="true" kind="var" path="GWT_TOOLS/lib/tomcat/tomcat-websocket-api-8.0.28.jar"/>
+ <classpathentry exported="true" kind="var" path="GWT_TOOLS/lib/tomcat/tomcat-annotations-api-8.0.28.jar"/>
<classpathentry kind="var" path="GWT_TOOLS/lib/colt/colt-1.2.jar" sourcepath="/GWT_TOOLS/lib/colt/colt-1.2-src.jar"/>
<classpathentry kind="output" path="bin"/>
</classpath>
diff --git a/user/test/com/google/gwt/dev/shell/jetty/JettyLauncherSuite.java b/user/test/com/google/gwt/dev/shell/jetty/JettyLauncherSuite.java
new file mode 100644
index 0000000..aebca32
--- /dev/null
+++ b/user/test/com/google/gwt/dev/shell/jetty/JettyLauncherSuite.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * 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 com.google.gwt.dev.shell.jetty;
+
+import com.google.gwt.dev.shell.jetty.client.JspTest;
+import com.google.gwt.junit.tools.GWTTestSuite;
+
+import junit.framework.Test;
+
+/**
+ * All JettyLauncher tests that use GWTTestCase.
+ */
+public class JettyLauncherSuite {
+ public static Test suite() {
+ GWTTestSuite suite = new GWTTestSuite("All JettyLauncher tests");
+
+ suite.addTestSuite(JspTest.class);
+
+ return suite;
+ }
+}
diff --git a/user/test/com/google/gwt/dev/shell/jetty/Jsp.gwt.xml b/user/test/com/google/gwt/dev/shell/jetty/Jsp.gwt.xml
new file mode 100644
index 0000000..684596f
--- /dev/null
+++ b/user/test/com/google/gwt/dev/shell/jetty/Jsp.gwt.xml
@@ -0,0 +1,17 @@
+<!-- -->
+<!-- Copyright 2016 Google Inc. -->
+<!-- Licensed under the Apache License, Version 2.0 (the "License"); you -->
+<!-- may not use this file except in compliance with the License. You may -->
+<!-- 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. License for the specific language governing permissions and -->
+<!-- limitations under the License. -->
+
+<module>
+ <inherits name="com.google.gwt.http.HTTP" />
+</module>
diff --git a/user/test/com/google/gwt/dev/shell/jetty/client/JspTest.java b/user/test/com/google/gwt/dev/shell/jetty/client/JspTest.java
new file mode 100644
index 0000000..d6d0027
--- /dev/null
+++ b/user/test/com/google/gwt/dev/shell/jetty/client/JspTest.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * 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 com.google.gwt.dev.shell.jetty.client;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.http.client.Request;
+import com.google.gwt.http.client.RequestBuilder;
+import com.google.gwt.http.client.RequestCallback;
+import com.google.gwt.http.client.Response;
+import com.google.gwt.junit.client.GWTTestCase;
+
+/**
+ * Checks that JSPs are supported in JettyLauncher (through JUnitShell)
+ */
+public class JspTest extends GWTTestCase {
+ @Override
+ public String getModuleName() {
+ return "com.google.gwt.dev.shell.jetty.Jsp";
+ }
+
+ public void testJsp() throws Exception {
+ delayTestFinish(5000);
+ new RequestBuilder(RequestBuilder.GET, GWT.getModuleBaseForStaticFiles() + "java7.jsp")
+ .sendRequest("", new RequestCallback() {
+ @Override
+ public void onResponseReceived(Request request, Response response) {
+ assertEquals(200, response.getStatusCode());
+ assertEquals("OK", response.getText().trim());
+ finishTest();
+ }
+
+ @Override
+ public void onError(Request request, Throwable exception) {
+ fail();
+ }
+ });
+ }
+}
diff --git a/user/test/com/google/gwt/dev/shell/jetty/public/java7.jsp b/user/test/com/google/gwt/dev/shell/jetty/public/java7.jsp
new file mode 100644
index 0000000..dbc65d3
--- /dev/null
+++ b/user/test/com/google/gwt/dev/shell/jetty/public/java7.jsp
@@ -0,0 +1,11 @@
+<%@page language="java" contentType="text/plain; charset=UTF-8" session="false" %>
+<%
+// Use a switch-on-string to check whether the page compiles as Java 7
+switch (request.getMethod()) {
+case "GET":
+ out.print("OK");
+ break;
+default:
+ out.print(request.getMethod());
+}
+%>