diff --git a/hbase-http/pom.xml b/hbase-http/pom.xml
index 667b3f5..0bc20db 100644
--- a/hbase-http/pom.xml
+++ b/hbase-http/pom.xml
@@ -203,6 +203,22 @@
org.eclipse.jetty
+ jetty-plus
+
+
+ org.eclipse.jetty
+ apache-jsp
+
+
+ org.eclipse.jetty
+ apache-jstl
+
+
+ org.eclipse.jetty
+ jetty-servlet
+
+
+ org.eclipse.jetty
jetty-server
diff --git a/hbase-http/src/main/java/org/apache/hadoop/hbase/http/HttpServer.java b/hbase-http/src/main/java/org/apache/hadoop/hbase/http/HttpServer.java
index af72ab8..575c276 100644
--- a/hbase-http/src/main/java/org/apache/hadoop/hbase/http/HttpServer.java
+++ b/hbase-http/src/main/java/org/apache/hadoop/hbase/http/HttpServer.java
@@ -27,6 +27,7 @@ import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
@@ -58,9 +59,13 @@ import org.apache.hadoop.security.UserGroupInformation;
import org.apache.hadoop.security.authentication.server.AuthenticationFilter;
import org.apache.hadoop.security.authorize.AccessControlList;
import org.apache.hadoop.util.Shell;
+import org.apache.tomcat.InstanceManager;
+import org.apache.tomcat.SimpleInstanceManager;
import org.apache.yetus.audience.InterfaceAudience;
import org.apache.yetus.audience.InterfaceStability;
+import org.eclipse.jetty.apache.jsp.JettyJasperInitializer;
import org.eclipse.jetty.http.HttpVersion;
+import org.eclipse.jetty.plus.annotation.ContainerInitializer;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.HttpConnectionFactory;
@@ -651,6 +656,9 @@ public class HttpServer implements FilterContainer {
addNoCacheFilter(webAppContext);
defaultContexts.put(logContext, true);
}
+ webAppContext.setAttribute("org.eclipse.jetty.containerInitializers" , Arrays
+ .asList (new ContainerInitializer(new JettyJasperInitializer(), null)));
+ webAppContext.setAttribute(InstanceManager.class.getName(), new SimpleInstanceManager());
// set up the context for "/static/*"
ServletContextHandler staticContext = new ServletContextHandler(parent, "/static");
staticContext.setResourceBase(appDir + "/static");
@@ -1071,8 +1079,11 @@ public class HttpServer implements FilterContainer {
try {
// clear & stop webAppContext attributes to avoid memory leaks.
- webAppContext.clearAttributes();
webAppContext.stop();
+ // stop first then clear up attributes. Otherwise, there may be a race
+ //condition when destroy JspServlet
+ webAppContext.clearAttributes();
+
} catch (Exception e) {
LOG.error("Error while stopping web app context for webapp "
+ webAppContext.getDisplayName(), e);
diff --git a/hbase-http/src/test/java/org/apache/hadoop/hbase/http/TestHttpServerDynamicallyCompileJsp.java b/hbase-http/src/test/java/org/apache/hadoop/hbase/http/TestHttpServerDynamicallyCompileJsp.java
new file mode 100644
index 0000000..1d51c26
--- /dev/null
+++ b/hbase-http/src/test/java/org/apache/hadoop/hbase/http/TestHttpServerDynamicallyCompileJsp.java
@@ -0,0 +1,76 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hadoop.hbase.http;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.hbase.HBaseClassTestRule;
+import org.apache.hadoop.hbase.testclassification.MiscTests;
+import org.apache.hadoop.hbase.testclassification.SmallTests;
+import org.apache.hadoop.net.NetUtils;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.net.URL;
+
+@Category({MiscTests.class, SmallTests.class})
+public class TestHttpServerDynamicallyCompileJsp extends HttpServerFunctionalTest {
+ @ClassRule
+ public static final HBaseClassTestRule CLASS_RULE =
+ HBaseClassTestRule.forClass(TestHttpServerDynamicallyCompileJsp.class);
+
+ private static final Logger LOG = LoggerFactory
+ .getLogger(TestHttpServerDynamicallyCompileJsp.class);
+ private static HttpServer server;
+ private static URL baseUrl;
+ // jetty 9.4.x needs this many threads to start, even in the small.
+ static final int MAX_THREADS = 16;
+ static final String JSP_NAME = "testDynamicallyCompile.jsp";
+
+ @BeforeClass
+ public static void setup() throws Exception {
+ Configuration conf = new Configuration();
+ conf.setInt(HttpServer.HTTP_MAX_THREADS, MAX_THREADS);
+ server = createTestServer(conf);
+ server.start();
+ baseUrl = getServerURL(server);
+ LOG.info("HTTP server started: "+ baseUrl);
+ }
+
+ @Test
+ public void testCompileJspDynamically() throws Exception {
+ String serverURL = "http://" +
+ NetUtils.getHostPortString(server.getConnectorAddress(0)) +
+ "/" + JSP_NAME;
+ LOG.info("url:" + serverURL);
+ Assert.assertEquals(readOutput(new URL(serverURL)).trim(), "hello world");
+ }
+
+ @AfterClass
+ public static void cleanup() throws Exception {
+ LOG.info("shutting down");
+ server.stop();
+ }
+
+}
diff --git a/hbase-http/src/test/resources/webapps/test/testDynamicallyCompile.jsp b/hbase-http/src/test/resources/webapps/test/testDynamicallyCompile.jsp
new file mode 100644
index 0000000..03366eb
--- /dev/null
+++ b/hbase-http/src/test/resources/webapps/test/testDynamicallyCompile.jsp
@@ -0,0 +1,22 @@
+<%!
+ /*
+ * 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.
+ */
+%>
+<%
+out.println("hello world");
+%>
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 4e1797b..05a59e4 100755
--- a/pom.xml
+++ b/pom.xml
@@ -2000,6 +2000,21 @@
org.eclipse.jetty
+ jetty-plus
+ ${jetty.version}
+
+
+ org.eclipse.jetty
+ apache-jsp
+ ${jetty.version}
+
+
+ org.eclipse.jetty
+ apache-jstl
+ ${jetty.version}
+
+
+ org.eclipse.jetty
jetty-server
${jetty.version}