You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@submarine.apache.org by li...@apache.org on 2020/03/17 11:21:13 UTC

[submarine] branch master updated: SUBMARINE-422. Fix refreshing page returns 404 error

This is an automated email from the ASF dual-hosted git repository.

liuxun pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/submarine.git


The following commit(s) were added to refs/heads/master by this push:
     new 068ff93  SUBMARINE-422. Fix refreshing page returns 404 error
068ff93 is described below

commit 068ff93e9a03912cc3b04b5ae7548dd53ec1f4b0
Author: Xun Liu <li...@apache.org>
AuthorDate: Tue Mar 17 17:33:43 2020 +0800

    SUBMARINE-422. Fix refreshing page returns 404 error
    
    ### What is this PR for?
    Because the workbench is developed using angular, the adjustment of angular WEB pages is completely controlled by the front end, so when you manually refresh a specific page in the browser, the browser will send the request for this page to the back-end service, but the back-end service only In response to API requests, it will cause the front end to display 404.
    
    The solution is to find that not all API requests directly return the content of the index page,
    so that the front end will automatically perform correct page routing processing.
    
    ### What type of PR is it?
    [Bug Fix | Improvement]
    
    ### Todos
    * [ ] - Task
    
    ### What is the Jira issue?
    * https://issues.apache.org/jira/browse/SUBMARINE-422
    
    ### How should this be tested?
    * https://travis-ci.org/github/liuxunorg/submarine/builds/663406363
    
    ### Screenshots (if appropriate)
    
    ### Questions:
    * Does the licenses files need update? No
    * Is there breaking changes for older versions? No
    * Does this needs documentation? No
    
    Author: Xun Liu <li...@apache.org>
    
    Closes #232 from liuxunorg/SUBMARINE-422 and squashes the following commits:
    
    f098039 [Xun Liu] Safe close InputStreamReader.
    4f44976 [Xun Liu] SUBMARINE-422. Fix refreshing page returns 404 error
---
 .travis.yml                                        | 95 ++++++++++++++++++---
 .../apache/submarine/server/SubmarineServer.java   | 96 +++++++++++++++++++---
 .../server/AbstractSubmarineServerTest.java        |  4 +-
 .../submarine/server/SubmarineServerTest.java      | 63 ++++++++++++++
 .../org/apache/submarine/AbstractSubmarineIT.java  |  4 +-
 .../workbench-web-ng/src/WEB-INF/web.xml           |  3 +-
 6 files changed, 233 insertions(+), 32 deletions(-)

diff --git a/.travis.yml b/.travis.yml
index 4178401..c23635c 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -107,7 +107,12 @@ matrix:
         chrome: stable
         firefox: latest
       # Because submarine on k8s uses port 80, it needs to be set `-Durl=http://127.0.0.1`
-      env: PROFILE="-Phadoop-2.9" BUILD_FLAG="clean package install -DskipTests" TEST_FLAG="verify -DskipRat -am -Durl=http://127.0.0.1" MODULES="" TEST_MODULES="-pl ${EXCLUDE_SERVER},${EXCLUDE_COMMONS},${EXCLUDE_CLIENT},org.apache.submarine:submarine-test-k8s" TEST_PROJECTS=""
+      env:
+        - PROFILE="-Phadoop-2.9"
+        - BUILD_FLAG="clean package install -DskipTests" TEST_FLAG="verify -DskipRat -am -Durl=http://127.0.0.1"
+        - MODULES=""
+        - TEST_MODULES="-pl ${EXCLUDE_SERVER},${EXCLUDE_COMMONS},${EXCLUDE_CLIENT},org.apache.submarine:submarine-test-k8s"
+        - TEST_PROJECTS=""
 
     - name: Test submarine test-e2e
       language: java
@@ -116,61 +121,120 @@ matrix:
       addons:
         chrome: stable
         firefox: latest
-      env: PROFILE="-Phadoop-2.9" BUILD_FLAG="clean package install -DskipTests" TEST_FLAG="verify -DskipRat -am" TEST_MODULES="-pl org.apache.submarine:submarine-test-e2e" TEST_PROJECTS=""
+      env:
+        - PROFILE="-Phadoop-2.9"
+        - BUILD_FLAG="clean package install -DskipTests"
+        - TEST_FLAG="verify -DskipRat -am"
+        - TEST_MODULES="-pl org.apache.submarine:submarine-test-e2e"
+        - TEST_PROJECTS=""
 
     - name: Test submarine commons-cluster
       language: java
       jdk: openjdk8
       dist: xenial
-      env: PROFILE="-Phadoop-2.9" BUILD_FLAG="clean package install -DskipTests" TEST_FLAG="test -DskipRat -am" MODULES="-pl ${EXCLUDE_COMMONS},${EXCLUDE_SUBMITTER},${EXCLUDE_WORKBENCH},${EXCLUDE_INTERPRETER},${EXCLUDE_CLIENT},${EXCLUDE_CLOUD},${EXCLUDE_SERVER},${EXCLUDE_ALL},${EXCLUDE_DIST},${EXCLUDE_TEST}" TEST_MODULES="-pl org.apache.submarine:submarine-commons-cluster" TEST_PROJECTS=""
+      env:
+        - PROFILE="-Phadoop-2.9"
+        - BUILD_FLAG="clean package install -DskipTests"
+        - TEST_FLAG="test -DskipRat -am"
+        - MODULES="-pl ${EXCLUDE_COMMONS},${EXCLUDE_SUBMITTER},${EXCLUDE_WORKBENCH},${EXCLUDE_INTERPRETER},${EXCLUDE_CLIENT},${EXCLUDE_CLOUD},${EXCLUDE_SERVER},${EXCLUDE_ALL},${EXCLUDE_DIST},${EXCLUDE_TEST}"
+        - TEST_MODULES="-pl org.apache.submarine:submarine-commons-cluster"
+        - TEST_PROJECTS=""
 
     - name: Test submarine commons-metastore
       language: java
       jdk: openjdk8
       dist: xenial
-      env: PROFILE="-Phadoop-2.9" BUILD_FLAG="clean package install -DskipTests" TEST_FLAG="test -DskipRat -am" MODULES="-pl ${EXCLUDE_COMMONS},${EXCLUDE_SUBMITTER},${EXCLUDE_WORKBENCH},${EXCLUDE_INTERPRETER},${EXCLUDE_CLIENT},${EXCLUDE_CLOUD},${EXCLUDE_SERVER},${EXCLUDE_ALL},${EXCLUDE_DIST},${EXCLUDE_TEST}" TEST_MODULES="-pl org.apache.submarine:submarine-commons-metastore" TEST_PROJECTS=""
+      env:
+        - PROFILE="-Phadoop-2.9"
+        - BUILD_FLAG="clean package install -DskipTests"
+        - TEST_FLAG="test -DskipRat -am"
+        - MODULES="-pl ${EXCLUDE_COMMONS},${EXCLUDE_SUBMITTER},${EXCLUDE_WORKBENCH},${EXCLUDE_INTERPRETER},${EXCLUDE_CLIENT},${EXCLUDE_CLOUD},${EXCLUDE_SERVER},${EXCLUDE_ALL},${EXCLUDE_DIST},${EXCLUDE_TEST}"
+        - TEST_MODULES="-pl org.apache.submarine:submarine-commons-metastore"
+        - TEST_PROJECTS=""
 
     - name: Test submarine commons-rpc
       language: java
       jdk: openjdk8
       dist: xenial
-      env: PROFILE="-Phadoop-2.9" BUILD_FLAG="clean package install -DskipTests" TEST_FLAG="test -DskipRat -am" MODULES="-pl ${EXCLUDE_COMMONS},${EXCLUDE_SUBMITTER},${EXCLUDE_WORKBENCH},${EXCLUDE_INTERPRETER},${EXCLUDE_CLIENT},${EXCLUDE_CLOUD},${EXCLUDE_SERVER},${EXCLUDE_ALL},${EXCLUDE_DIST},${EXCLUDE_TEST}" TEST_MODULES="-pl org.apache.submarine:submarine-commons-rpc" TEST_PROJECTS=""
+      env:
+        - PROFILE="-Phadoop-2.9"
+        - BUILD_FLAG="clean package install -DskipTests"
+        - TEST_FLAG="test -DskipRat -am"
+        - MODULES="-pl ${EXCLUDE_COMMONS},${EXCLUDE_SUBMITTER},${EXCLUDE_WORKBENCH},${EXCLUDE_INTERPRETER},${EXCLUDE_CLIENT},${EXCLUDE_CLOUD},${EXCLUDE_SERVER},${EXCLUDE_ALL},${EXCLUDE_DIST},${EXCLUDE_TEST}"
+        - TEST_MODULES="-pl org.apache.submarine:submarine-commons-rpc"
+        - TEST_PROJECTS=""
 
     - name: Test submarine commons-runtime
       language: java
       jdk: openjdk8
       dist: xenial
-      env: PROFILE="-Phadoop-2.9" BUILD_FLAG="clean package install -DskipTests" TEST_FLAG="test -DskipRat -am" MODULES="-pl ${EXCLUDE_COMMONS},${EXCLUDE_SUBMITTER},${EXCLUDE_WORKBENCH},${EXCLUDE_INTERPRETER},${EXCLUDE_CLIENT},${EXCLUDE_CLOUD},${EXCLUDE_SERVER},${EXCLUDE_ALL},${EXCLUDE_DIST},${EXCLUDE_TEST}" TEST_MODULES="-pl org.apache.submarine:submarine-commons-runtime" TEST_PROJECTS=""
+      env:
+        - PROFILE="-Phadoop-2.9"
+        - BUILD_FLAG="clean package install -DskipTests"
+        - TEST_FLAG="test -DskipRat -am"
+        - MODULES="-pl ${EXCLUDE_COMMONS},${EXCLUDE_SUBMITTER},${EXCLUDE_WORKBENCH},${EXCLUDE_INTERPRETER},${EXCLUDE_CLIENT},${EXCLUDE_CLOUD},${EXCLUDE_SERVER},${EXCLUDE_ALL},${EXCLUDE_DIST},${EXCLUDE_TEST}"
+        - TEST_MODULES="-pl org.apache.submarine:submarine-commons-runtime"
+        - TEST_PROJECTS=""
 
     - name: Test submarine server
       language: java
       jdk: openjdk8
       dist: xenial
-      env: PROFILE="-Phadoop-2.9" BUILD_FLAG="clean package install -DskipTests" TEST_FLAG="test -DskipRat -am" MODULES="-pl ${EXCLUDE_SUBMITTER_K8S},${EXCLUDE_WORKBENCH},${EXCLUDE_INTERPRETER},${EXCLUDE_CLOUD},${EXCLUDE_ALL},${EXCLUDE_DIST},${EXCLUDE_TEST}" TEST_MODULES="-pl ${EXCLUDE_COMMONS},org.apache.submarine:submarine-server-core" TEST_PROJECTS=""
+      env:
+        - PROFILE="-Phadoop-2.9"
+        - BUILD_FLAG="clean package install -DskipTests"
+        - TEST_FLAG="test -DskipRat -am"
+        - MODULES="-pl ${EXCLUDE_SUBMITTER_K8S},${EXCLUDE_WORKBENCH},${EXCLUDE_INTERPRETER},${EXCLUDE_CLOUD},${EXCLUDE_ALL},${EXCLUDE_DIST},${EXCLUDE_TEST}"
+        - TEST_MODULES="-pl ${EXCLUDE_COMMONS},org.apache.submarine:submarine-server-core"
+        - TEST_PROJECTS=""
 
     - name: Test submarine submitter on hadoop-2.9 (default)
       language: java
       jdk: openjdk8
       dist: xenial
-      env: PROFILE="-Phadoop-2.9" BUILD_FLAG="clean package install -DskipTests -DskipRat" TEST_FLAG="test -DskipRat -am" MODULES="-pl ${EXCLUDE_SUBMITTER_K8S},${EXCLUDE_WORKBENCH},${EXCLUDE_INTERPRETER},${EXCLUDE_CLOUD},${EXCLUDE_DIST}" TEST_MODULES="-pl ${EXCLUDE_SUBMITTER_K8S},${EXCLUDE_WORKBENCH},${EXCLUDE_INTERPRETER},${EXCLUDE_CLOUD},${EXCLUDE_COMMONS},${EXCLUDE_DIST},${EXCLUDE_TEST},${EXCLUDE_ALL},${EXCLUDE_SERVER}" TEST_PROJECTS=""
+      env:
+        - PROFILE="-Phadoop-2.9"
+        - BUILD_FLAG="clean package install -DskipTests -DskipRat"
+        - TEST_FLAG="test -DskipRat -am"
+        - MODULES="-pl ${EXCLUDE_SUBMITTER_K8S},${EXCLUDE_WORKBENCH},${EXCLUDE_INTERPRETER},${EXCLUDE_CLOUD},${EXCLUDE_DIST}"
+        - TEST_MODULES="-pl ${EXCLUDE_SUBMITTER_K8S},${EXCLUDE_WORKBENCH},${EXCLUDE_INTERPRETER},${EXCLUDE_CLOUD},${EXCLUDE_COMMONS},${EXCLUDE_DIST},${EXCLUDE_TEST},${EXCLUDE_ALL},${EXCLUDE_SERVER},${EXCLUDE_SPARK_SECURTITY}"
+        - TEST_PROJECTS=""
 
     - name: Test submarine submitter on hadoop-2.10
       language: java
       jdk: openjdk8
       dist: xenial
-      env: PROFILE="-Phadoop-2.10" BUILD_FLAG="clean package install -DskipTests -DskipRat" TEST_FLAG="test -DskipRat -am" MODULES="-pl ${EXCLUDE_SUBMITTER_K8S},${EXCLUDE_WORKBENCH},${EXCLUDE_INTERPRETER},${EXCLUDE_CLOUD},${EXCLUDE_DIST}" TEST_MODULES="-pl ${EXCLUDE_SUBMITTER_K8S},${EXCLUDE_WORKBENCH},${EXCLUDE_INTERPRETER},${EXCLUDE_CLOUD},${EXCLUDE_COMMONS},${EXCLUDE_DIST},${EXCLUDE_TEST},${EXCLUDE_ALL},${EXCLUDE_SERVER}" TEST_PROJECTS=""
+      env:
+        - PROFILE="-Phadoop-2.10"
+        - BUILD_FLAG="clean package install -DskipTests -DskipRat"
+        - TEST_FLAG="test -DskipRat -am"
+        - MODULES="-pl ${EXCLUDE_SUBMITTER_K8S},${EXCLUDE_WORKBENCH},${EXCLUDE_INTERPRETER},${EXCLUDE_CLOUD},${EXCLUDE_DIST}"
+        - TEST_MODULES="-pl ${EXCLUDE_SUBMITTER_K8S},${EXCLUDE_WORKBENCH},${EXCLUDE_INTERPRETER},${EXCLUDE_CLOUD},${EXCLUDE_COMMONS},${EXCLUDE_DIST},${EXCLUDE_TEST},${EXCLUDE_ALL},${EXCLUDE_SERVER},${EXCLUDE_SPARK_SECURTITY}"
+        - TEST_PROJECTS=""
 
     - name: Test submarine submitter on hadoop-3.1
       language: java
       jdk: openjdk8
       dist: xenial
-      env: PROFILE="-Phadoop-3.1" BUILD_FLAG="clean package install -DskipTests -DskipRat" TEST_FLAG="test -DskipRat -am" MODULES="-pl ${EXCLUDE_SUBMITTER_K8S},${EXCLUDE_WORKBENCH},${EXCLUDE_INTERPRETER},${EXCLUDE_CLOUD},${EXCLUDE_DIST}" TEST_MODULES="-pl ${EXCLUDE_SUBMITTER_K8S},${EXCLUDE_WORKBENCH},${EXCLUDE_INTERPRETER},${EXCLUDE_CLOUD},${EXCLUDE_COMMONS},${EXCLUDE_DIST},${EXCLUDE_TEST},${EXCLUDE_ALL},${EXCLUDE_SERVER},${EXCLUDE_SPARK_SECURTITY}" TEST_PROJECTS=""
+      env:
+        - PROFILE="-Phadoop-3.1"
+        - BUILD_FLAG="clean package install -DskipTests -DskipRat"
+        - TEST_FLAG="test -DskipRat -am"
+        - MODULES="-pl ${EXCLUDE_SUBMITTER_K8S},${EXCLUDE_WORKBENCH},${EXCLUDE_INTERPRETER},${EXCLUDE_CLOUD},${EXCLUDE_DIST}"
+        - TEST_MODULES="-pl ${EXCLUDE_SUBMITTER_K8S},${EXCLUDE_WORKBENCH},${EXCLUDE_INTERPRETER},${EXCLUDE_CLOUD},${EXCLUDE_COMMONS},${EXCLUDE_DIST},${EXCLUDE_TEST},${EXCLUDE_ALL},${EXCLUDE_SERVER},${EXCLUDE_SPARK_SECURTITY}"
+        - TEST_PROJECTS=""
 
     - name: Test submarine submitter on hadoop-3.2
       language: java
       jdk: openjdk8
       dist: xenial
-      env: PROFILE="-Phadoop-3.2" BUILD_FLAG="clean package install -DskipTests -DskipRat" TEST_FLAG="test -DskipRat -am" MODULES="-pl ${EXCLUDE_SUBMITTER_K8S},${EXCLUDE_WORKBENCH},${EXCLUDE_INTERPRETER},${EXCLUDE_CLOUD},${EXCLUDE_DIST}" TEST_MODULES="-pl ${EXCLUDE_SUBMITTER_K8S},${EXCLUDE_WORKBENCH},${EXCLUDE_INTERPRETER},${EXCLUDE_CLOUD},${EXCLUDE_COMMONS},${EXCLUDE_DIST},${EXCLUDE_TEST},${EXCLUDE_ALL},${EXCLUDE_SERVER},${EXCLUDE_SPARK_SECURTITY}" TEST_PROJECTS=""
+      env:
+        - PROFILE="-Phadoop-3.2"
+        - BUILD_FLAG="clean package install -DskipTests -DskipRat"
+        - TEST_FLAG="test -DskipRat -am"
+        - MODULES="-pl ${EXCLUDE_SUBMITTER_K8S},${EXCLUDE_WORKBENCH},${EXCLUDE_INTERPRETER},${EXCLUDE_CLOUD},${EXCLUDE_DIST}"
+        - TEST_MODULES="-pl ${EXCLUDE_SUBMITTER_K8S},${EXCLUDE_WORKBENCH},${EXCLUDE_INTERPRETER},${EXCLUDE_CLOUD},${EXCLUDE_COMMONS},${EXCLUDE_DIST},${EXCLUDE_TEST},${EXCLUDE_ALL},${EXCLUDE_SERVER},${EXCLUDE_SPARK_SECURTITY}"
+        - TEST_PROJECTS=""
 
     - name: Test submarine submitter on Kubernetes
       dist: xenial
@@ -204,7 +268,7 @@ matrix:
     #  jdk: "openjdk8"
     #  dist: xenial
     #  env: PYTHON="3" PROFILE="-Phadoop-2.9" BUILD_FLAG="clean package install -DskipTests" TEST_FLAG="test -DskipRat -am" MODULES="-pl ${EXCLUDE_SUBMITTER_K8S},${EXCLUDE_SUBMARINE},${EXCLUDE_WORKBENCH}" TEST_MODULES="-pl $(echo ${EXCLUDE_INTERPRETER} | sed 's/!//g')" TEST_PROJECTS=""
-    
+
     - name: Test submarine workbench-web VUE
       language: node_js
       node_js:
@@ -234,7 +298,12 @@ matrix:
         - npm run test -- --no-watch --no-progress --browsers=FirefoxHeadless
         - npm run webdriver
         - npm run e2e -- --protractor-config=e2e/protractor-ci.conf.js
-      env: BUILD_FLAG="clean package -DskipTests" TEST_FLAG="test -DskipRat -am" MODULES="-pl org.apache.submarine:submarine-workbench-web-ng" TEST_MODULES="-pl org.apache.submarine:submarine-workbench-web-ng" TEST_PROJECTS=""
+      env:
+        - BUILD_FLAG="clean package -DskipTests"
+        - TEST_FLAG="test -DskipRat -am"
+        - MODULES="-pl org.apache.submarine:submarine-workbench-web-ng"
+        - TEST_MODULES="-pl org.apache.submarine:submarine-workbench-web-ng"
+        - TEST_PROJECTS=""
 
     - name: Test submarine spark security with spark 2.3 and ranger 1.0
       language: scala
diff --git a/submarine-server/server-core/src/main/java/org/apache/submarine/server/SubmarineServer.java b/submarine-server/server-core/src/main/java/org/apache/submarine/server/SubmarineServer.java
index 8ef560a..b6a0a0e 100644
--- a/submarine-server/server-core/src/main/java/org/apache/submarine/server/SubmarineServer.java
+++ b/submarine-server/server-core/src/main/java/org/apache/submarine/server/SubmarineServer.java
@@ -23,13 +23,14 @@ import org.apache.submarine.server.rpc.SubmarineRpcServer;
 import org.apache.submarine.server.workbench.websocket.NotebookServer;
 import org.apache.submarine.commons.cluster.ClusterServer;
 import org.eclipse.jetty.http.HttpVersion;
+import org.eclipse.jetty.server.Handler;
 import org.eclipse.jetty.server.HttpConfiguration;
 import org.eclipse.jetty.server.HttpConnectionFactory;
 import org.eclipse.jetty.server.SecureRequestCustomizer;
 import org.eclipse.jetty.server.Server;
 import org.eclipse.jetty.server.ServerConnector;
 import org.eclipse.jetty.server.SslConnectionFactory;
-import org.eclipse.jetty.server.handler.ContextHandlerCollection;
+import org.eclipse.jetty.server.handler.HandlerList;
 import org.eclipse.jetty.server.session.SessionHandler;
 import org.eclipse.jetty.servlet.DefaultServlet;
 import org.eclipse.jetty.servlet.ServletContextHandler;
@@ -52,8 +53,15 @@ import org.apache.submarine.commons.utils.SubmarineConfVars;
 
 import javax.inject.Inject;
 import javax.inject.Singleton;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.BufferedReader;
 import java.io.File;
+import java.io.FileInputStream;
 import java.io.IOException;
+import java.io.InputStreamReader;
 
 public class SubmarineServer extends ResourceConfig {
   private static final Logger LOG = LoggerFactory.getLogger(SubmarineServer.class);
@@ -63,7 +71,7 @@ public class SubmarineServer extends ResourceConfig {
   public static Server jettyWebServer;
   public static SubmarineRpcServer rpcServer;
   public static ServiceLocator sharedServiceLocator;
-
+  private static WebAppContext webApp;
   private static SubmarineConfiguration conf = SubmarineConfiguration.getInstance();
 
   public static long getServerTimeStamp() {
@@ -84,11 +92,10 @@ public class SubmarineServer extends ResourceConfig {
 
     jettyWebServer = setupJettyServer(conf);
 
-    ContextHandlerCollection contexts = new ContextHandlerCollection();
-    jettyWebServer.setHandler(contexts);
-
     // Web UI
-    final WebAppContext webApp = setupWebAppContext(contexts, conf);
+    HandlerList handlers = new HandlerList();
+    webApp = setupWebAppContext(handlers, conf);
+    jettyWebServer.setHandler(handlers);
 
     // Add
     sharedServiceLocator = ServiceLocatorFactory.getInstance().create("shared-locator");
@@ -127,7 +134,7 @@ public class SubmarineServer extends ResourceConfig {
   private static void startServer() throws InterruptedException {
     LOG.info("Starting submarine server");
     try {
-      jettyWebServer.start(); // Instantiates WorkbenchServer
+      jettyWebServer.start(); // Instantiates SubmarineServer
     } catch (Exception e) {
       LOG.error("Error while running jettyServer", e);
       System.exit(-1);
@@ -162,16 +169,15 @@ public class SubmarineServer extends ResourceConfig {
     webapp.addServlet(servletHolder, "/api/*");
   }
 
-  private static WebAppContext setupWebAppContext(ContextHandlerCollection contexts,
+  private static WebAppContext setupWebAppContext(HandlerList handlers,
       SubmarineConfiguration conf) {
     WebAppContext webApp = new WebAppContext();
     webApp.setContextPath("/");
     File warPath = new File(conf.getString(SubmarineConfVars.ConfVars.WORKBENCH_WEB_WAR));
-    LOG.info("workbench web war file path is {}.", 
+    LOG.info("workbench web war file path is {}.",
         conf.getString(SubmarineConfVars.ConfVars.WORKBENCH_WEB_WAR));
     if (warPath.isDirectory()) {
       // Development mode, read from FS
-      // webApp.setDescriptor(warPath+"/WEB-INF/web.xml");
       webApp.setResourceBase(warPath.getPath());
       webApp.setParentLoaderPriority(true);
     } else {
@@ -181,9 +187,16 @@ public class SubmarineServer extends ResourceConfig {
       warTempDirectory.mkdir();
       webApp.setTempDirectory(warTempDirectory);
     }
-    // Explicit bind to root
-    webApp.addServlet(new ServletHolder(new DefaultServlet()), "/*");
-    contexts.addHandler(webApp);
+
+    webApp.addServlet(new ServletHolder(new DefaultServlet()), "/");
+    // When requesting the workbench page, the content of index.html needs to be returned,
+    // otherwise a 404 error will be displayed
+    // NOTE: If you modify the workbench directory in the front-end URL,
+    // you need to modify the `/workbench/*` here.
+    webApp.addServlet(new ServletHolder(RefreshServlet.class), "/user/*");
+    webApp.addServlet(new ServletHolder(RefreshServlet.class), "/workbench/*");
+
+    handlers.setHandlers(new Handler[] { webApp });
 
     return webApp;
   }
@@ -280,4 +293,61 @@ public class SubmarineServer extends ResourceConfig {
     cf.getHttpConfiguration().setRequestHeaderSize(requestHeaderSize);
   }
 
+  // SUBMARINE-422. Fix refreshing page returns 404 error
+  // Because the workbench is developed using angular,
+  // the adjustment of angular WEB pages is completely controlled by the front end,
+  // so when you manually refresh a specific page in the browser,
+  // the browser will send the request for this page to the back-end service,
+  // but the back-end service only In response to API requests, it will cause the front end to display 404.
+  // The solution is to find that not all API requests directly return the content of the index page,
+  // so that the front end will automatically perform correct page routing processing.
+  public static class RefreshServlet extends HttpServlet {
+    private static final long serialVersionUID = 1L;
+
+    @Override
+    protected void doGet(HttpServletRequest request, HttpServletResponse response)
+      throws ServletException, IOException {
+      response.setContentType("text/html");
+      response.encodeRedirectURL("/");
+      response.setStatus(HttpServletResponse.SC_OK);
+
+      File warPath = new File(conf.getString(SubmarineConfVars.ConfVars.WORKBENCH_WEB_WAR));
+      File indexFile = null;
+      if (warPath.isDirectory()) {
+        // Development mode, read from FS
+        indexFile = new File(warPath.getAbsolutePath() + "/index.html");
+      } else {
+        // Product mode, read from war file
+        File warFile = webApp.getTempDirectory();
+        if (false == warFile.exists()) {
+          throw new ServletException("Can't found war directory!");
+        }
+        indexFile = new File(warFile.getAbsolutePath() + "/webapp/index.html");
+      }
+
+      InputStreamReader reader = null;
+      StringBuffer sbIndexBuf = new StringBuffer();
+      try {
+        if (indexFile.isFile() && indexFile.exists()) {
+          reader = new InputStreamReader(new FileInputStream(indexFile), "GBK");
+          BufferedReader bufferedReader = new BufferedReader(reader);
+          String lineTxt = null;
+
+          while ((lineTxt = bufferedReader.readLine()) != null) {
+            sbIndexBuf.append(lineTxt);
+          }
+          bufferedReader.close();
+        } else {
+          throw new Exception("Can't found index html!");
+        }
+      } catch (Exception e) {
+        LOG.error(e.getMessage(), e);
+        throw new ServletException("Can't found index html!");
+      } finally {
+        reader.close();
+      }
+
+      response.getWriter().print(sbIndexBuf.toString());
+    }
+  }
 }
diff --git a/submarine-server/server-core/src/test/java/org/apache/submarine/server/AbstractSubmarineServerTest.java b/submarine-server/server-core/src/test/java/org/apache/submarine/server/AbstractSubmarineServerTest.java
index 5741278..33ad4bb 100644
--- a/submarine-server/server-core/src/test/java/org/apache/submarine/server/AbstractSubmarineServerTest.java
+++ b/submarine-server/server-core/src/test/java/org/apache/submarine/server/AbstractSubmarineServerTest.java
@@ -101,14 +101,14 @@ public abstract class AbstractSubmarineServerTest {
       confDir.mkdirs();
 
       System.setProperty(SubmarineConfVars.ConfVars.WORKBENCH_WEB_WAR.getVarName(),
-          new File("../workbench-web/dist").getAbsolutePath());
+          new File("../../submarine-workbench/workbench-web-ng/dist/workbench-web-ng").getAbsolutePath());
       System.setProperty(SubmarineConfVars.ConfVars.SUBMARINE_CONF_DIR.getVarName(),
           confDir.getAbsolutePath());
 
       // some test profile does not build workbench-web.
       // to prevent submarine server starting up fail,
       // create workbench-web/dist directory
-      new File("../workbench-web/dist").mkdirs();
+      new File("../../submarine-workbench/workbench-web-ng/dist/workbench-web-ng").mkdirs();
 
       LOG.info("Staring test Submarine server up...");
 
diff --git a/submarine-server/server-core/src/test/java/org/apache/submarine/server/SubmarineServerTest.java b/submarine-server/server-core/src/test/java/org/apache/submarine/server/SubmarineServerTest.java
new file mode 100644
index 0000000..fa7f5cf
--- /dev/null
+++ b/submarine-server/server-core/src/test/java/org/apache/submarine/server/SubmarineServerTest.java
@@ -0,0 +1,63 @@
+/*
+ * 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.submarine.server;
+
+import org.apache.commons.httpclient.methods.GetMethod;
+import org.apache.submarine.server.rest.JobManagerRestApiTest;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.util.ArrayList;
+
+import static org.junit.Assert.assertFalse;
+
+public class SubmarineServerTest extends AbstractSubmarineServerTest {
+  private static final Logger LOG = LoggerFactory.getLogger(JobManagerRestApiTest.class);
+
+  @BeforeClass
+  public static void init() throws Exception {
+    AbstractSubmarineServerTest.startUp(SubmarineServerTest.class.getSimpleName());
+  }
+
+  @AfterClass
+  public static void destroy() throws Exception {
+    AbstractSubmarineServerTest.shutDown();
+  }
+
+  @Test
+  // SUBMARINE-422. Fix refreshing page returns 404 error
+  public void testRefreshingURL() throws IOException {
+    ArrayList<String> arrUrls = new ArrayList();
+    arrUrls.add("/user/login");
+    arrUrls.add("/workbench/manager/user");
+
+    for (int i = 0; i < arrUrls.size(); i++) {
+      GetMethod response = httpGet(arrUrls.get(i));
+      LOG.info(response.toString());
+
+      String requestBody = response.getResponseBodyAsString();
+      LOG.info(requestBody);
+      assertFalse(requestBody.contains("Error 404 Not Found"));
+    }
+  }
+}
diff --git a/submarine-test/test-e2e/src/test/java/org/apache/submarine/AbstractSubmarineIT.java b/submarine-test/test-e2e/src/test/java/org/apache/submarine/AbstractSubmarineIT.java
index b7d26db..c04389a 100644
--- a/submarine-test/test-e2e/src/test/java/org/apache/submarine/AbstractSubmarineIT.java
+++ b/submarine-test/test-e2e/src/test/java/org/apache/submarine/AbstractSubmarineIT.java
@@ -209,7 +209,7 @@ abstract public class AbstractSubmarineIT {
     return "";
   }
 
-  // findTargetFile function will help you see some files in submarine-dist module directory
+  // listTargetDirFiles function will help you see some files in submarine-dist module directory
   public static void listTargetDirFiles(File dir, String targetDir) {
     LOG.info("dir:{}, targetDir:{}", dir.getName(), targetDir);
     File[] files = dir.listFiles();
@@ -218,7 +218,7 @@ abstract public class AbstractSubmarineIT {
         listTargetDirFiles(file, targetDir);
       } else {
         if (StringUtils.equals(dir.getName(), targetDir))
-          LOG.info("file : "+file.getName());
+          LOG.info("file : " + file.getName());
       }
     }
   }
diff --git a/submarine-workbench/workbench-web-ng/src/WEB-INF/web.xml b/submarine-workbench/workbench-web-ng/src/WEB-INF/web.xml
index 2374dec..c7b7a29 100644
--- a/submarine-workbench/workbench-web-ng/src/WEB-INF/web.xml
+++ b/submarine-workbench/workbench-web-ng/src/WEB-INF/web.xml
@@ -28,11 +28,10 @@
     <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
     <init-param>
       <param-name>jersey.config.server.provider.packages</param-name>
-      <param-value>org.apache.submarine.rest</param-value>
+      <param-value>org.apache.submarine.server.rest</param-value>
     </init-param>
     <load-on-startup>1</load-on-startup>
   </servlet>
-
   <context-param>
     <param-name>configuration</param-name>
     <param-value>deployment</param-value>


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@submarine.apache.org
For additional commands, e-mail: dev-help@submarine.apache.org