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

ahuber pushed a commit to branch spring6
in repository https://gitbox.apache.org/repos/asf/isis.git


The following commit(s) were added to refs/heads/spring6 by this push:
     new 2490c1e00c ISIS-3275: adopt H2 Console for jakarta
2490c1e00c is described below

commit 2490c1e00caa615297723706e3f4a8eefa39a023
Author: Andi Huber <[email protected]>
AuthorDate: Mon Dec 5 11:00:25 2022 +0100

    ISIS-3275: adopt H2 Console for jakarta
---
 .../h2console/ui/webmodule/H2WebServerWrapper.java |  63 ++-----
 .../h2console/ui/webmodule/WebModuleH2Console.java |  32 ++--
 .../org/h2/server/web/H2WebServletForJakarta.java  | 205 +++++++++++++++++++++
 3 files changed, 234 insertions(+), 66 deletions(-)

diff --git 
a/testing/h2console/ui/src/main/java/org/apache/causeway/testing/h2console/ui/webmodule/H2WebServerWrapper.java
 
b/testing/h2console/ui/src/main/java/org/apache/causeway/testing/h2console/ui/webmodule/H2WebServerWrapper.java
index 1b3e6b37c0..c4011690bb 100644
--- 
a/testing/h2console/ui/src/main/java/org/apache/causeway/testing/h2console/ui/webmodule/H2WebServerWrapper.java
+++ 
b/testing/h2console/ui/src/main/java/org/apache/causeway/testing/h2console/ui/webmodule/H2WebServerWrapper.java
@@ -18,9 +18,14 @@
  */
 package org.apache.causeway.testing.h2console.ui.webmodule;
 
+import java.util.function.Consumer;
+
 import org.h2.server.web.ConnectionInfo;
-//import org.h2.server.web.WebServer;
-//import org.h2.server.web.WebServlet;
+import org.h2.server.web.H2WebServletForJakarta;
+import org.h2.server.web.WebServer;
+
+import lombok.NonNull;
+import lombok.SneakyThrows;
 
 /**
  * Provides programmatic access to otherwise protected H2 {@link WebServer} 
configuration.
@@ -49,72 +54,34 @@ public interface H2WebServerWrapper {
 
     // -- UTILITY
 
-  //TODO[ISIS-3275] H2WebServlet (com.h2database:h2) does not support jakarta 
API
-    /*
-
     @SneakyThrows
     static void withH2WebServerWrapperDo(
-            final @NonNull WebServlet webServlet,
+            final @NonNull H2WebServletForJakarta webServlet,
             final @NonNull Consumer<H2WebServerWrapper> onConfiguration) {
-        try {
-            val serverWrapper = H2WebServerWrapper.wrap(webServlet);
-            onConfiguration.accept(serverWrapper);
-        } catch (Throwable cause) {
-            // if for any reason wrapping fails, we fail hard to harden 
against potential security issues
-            throw _Exceptions.unrecoverable(cause, "Unable to customize 
settings for H2 console");
-        }
-    }
 
-    // -- HELPER
+        onConfiguration.accept(new H2WebServerWrapper() {
 
-    @SneakyThrows
-    private static H2WebServerWrapper wrap(final @NonNull WebServlet 
webServlet) {
-        return new H2WebServerWrapper() {
-
-            final WebServer webServer = (WebServer) _Reflect.getFieldOn(
-                    WebServlet.class.getDeclaredField("server"),
-                    webServlet);
-
-            @SneakyThrows
             @Override
-            public void setConnectionInfo(final ConnectionInfo connectionInfo) 
{
-                val updateSettingMethod = 
WebServer.class.getDeclaredMethod("updateSetting",
-                        ConnectionInfo.class);
-                _Reflect.invokeMethodOn(updateSettingMethod, webServer, 
connectionInfo);
+            public void setConnectionInfo(ConnectionInfo connectionInfo) {
+                webServlet.setConnectionInfo(connectionInfo);
             }
 
-            @SneakyThrows
             @Override
             public void setAllowOthers(boolean b) {
-                val method = 
WebServer.class.getDeclaredMethod("setAllowOthers",
-                        boolean.class);
-                _Reflect.invokeMethodOn(method, webServer, b);
-
-                // just so we verify reflection works
-                _Assert.assertEquals(b, getAllowOthers());
+                webServlet.setAllowOthers(b);
             }
 
-            @SneakyThrows
             @Override
             public boolean getAllowOthers() {
-                val method = 
WebServer.class.getDeclaredMethod("getAllowOthers",
-                        _Constants.emptyClasses);
-                return (boolean)_Reflect.invokeMethodOn(method, webServer,
-                        _Constants.emptyObjects)
-                        .getValue().get();
+                return webServlet.getAllowOthers();
             }
 
-            @SneakyThrows
             @Override
             public void setAdminPassword(String password) {
-                val method = 
WebServer.class.getDeclaredMethod("setAdminPassword",
-                        String.class);
-                _Reflect.invokeMethodOn(method, webServer, password);
+                webServlet.setAdminPassword(password);
             }
 
-        };
-
+        });
     }
-*/
 
 }
diff --git 
a/testing/h2console/ui/src/main/java/org/apache/causeway/testing/h2console/ui/webmodule/WebModuleH2Console.java
 
b/testing/h2console/ui/src/main/java/org/apache/causeway/testing/h2console/ui/webmodule/WebModuleH2Console.java
index 96072c076a..d372aa8b0f 100644
--- 
a/testing/h2console/ui/src/main/java/org/apache/causeway/testing/h2console/ui/webmodule/WebModuleH2Console.java
+++ 
b/testing/h2console/ui/src/main/java/org/apache/causeway/testing/h2console/ui/webmodule/WebModuleH2Console.java
@@ -18,25 +18,33 @@
  */
 package org.apache.causeway.testing.h2console.ui.webmodule;
 
+import jakarta.inject.Inject;
+import jakarta.inject.Named;
+import jakarta.servlet.ServletContext;
+import jakarta.servlet.ServletContextListener;
+import jakarta.servlet.ServletException;
+
+import org.h2.server.web.ConnectionInfo;
+import org.h2.server.web.H2WebServletForJakarta;
 import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
 import org.springframework.stereotype.Service;
 
 import org.apache.causeway.applib.annotation.PriorityPrecedence;
 import org.apache.causeway.applib.services.inject.ServiceInjector;
 import org.apache.causeway.applib.value.LocalResourcePath;
 import org.apache.causeway.commons.collections.Can;
+import org.apache.causeway.commons.internal.base._Strings;
+import org.apache.causeway.core.config.CausewayConfiguration;
 import 
org.apache.causeway.core.config.datasources.DataSourceIntrospectionService;
 import 
org.apache.causeway.core.config.datasources.DataSourceIntrospectionService.DataSourceInfo;
 import org.apache.causeway.core.config.environment.CausewaySystemEnvironment;
+import 
org.apache.causeway.core.security.authentication.standard.RandomCodeGenerator;
 import org.apache.causeway.core.webapp.modules.WebModuleAbstract;
 import org.apache.causeway.core.webapp.modules.WebModuleContext;
 
-import jakarta.inject.Inject;
-import jakarta.inject.Named;
-import jakarta.servlet.ServletContext;
-import jakarta.servlet.ServletContextListener;
-import jakarta.servlet.ServletException;
 import lombok.Getter;
+import lombok.val;
 import lombok.extern.log4j.Log4j2;
 
 /**
@@ -83,10 +91,6 @@ public class WebModuleH2Console extends WebModuleAbstract {
     @Override
     public Can<ServletContextListener> init(final ServletContext ctx) throws 
ServletException {
 
-        /*
-
-            //TODO[ISIS-3275] H2WebServlet (com.h2database:h2) does not 
support jakarta API
-
         registerServlet(ctx, SERVLET_NAME, H2WebServlet.class)
             .ifPresent(servletReg -> {
                 servletReg.addMapping(CONSOLE_PATH + "/*");
@@ -97,8 +101,6 @@ public class WebModuleH2Console extends WebModuleAbstract {
 
             });
 
-            */
-
         return Can.empty(); // registers no listeners
     }
 
@@ -109,9 +111,7 @@ public class WebModuleH2Console extends WebModuleAbstract {
 
     // -- WRAPPER AROUND H2'S SERVLET
 
-  //TODO[ISIS-3275] H2WebServlet (com.h2database:h2) does not support jakarta 
API
-    /*
-    public static class H2WebServlet extends WebServlet {
+    public static class H2WebServlet extends H2WebServletForJakarta {
 
         private static final long serialVersionUID = 1L;
 
@@ -165,7 +165,6 @@ public class WebModuleH2Console extends WebModuleAbstract {
         }
 
     }
-    */
 
     // -- HELPER
 
@@ -181,10 +180,7 @@ public class WebModuleH2Console extends WebModuleAbstract {
         .anyMatch(jdbcUrl->{
             if(jdbcUrl.contains(":h2:mem:")) {
                 log.info("found h2 in-memory data-source: {}", jdbcUrl);
-                //TODO[ISIS-3275] H2WebServlet (com.h2database:h2) does not 
support jakarta API
-                /*
                 H2WebServlet.configure(jdbcUrl);
-                */
                 return true;
             }
             return false;
diff --git 
a/testing/h2console/ui/src/main/java/org/h2/server/web/H2WebServletForJakarta.java
 
b/testing/h2console/ui/src/main/java/org/h2/server/web/H2WebServletForJakarta.java
new file mode 100644
index 0000000000..f7feeeb9b5
--- /dev/null
+++ 
b/testing/h2console/ui/src/main/java/org/h2/server/web/H2WebServletForJakarta.java
@@ -0,0 +1,205 @@
+/*
+ *  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.h2.server.web;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.Properties;
+
+import jakarta.servlet.ServletConfig;
+import jakarta.servlet.ServletOutputStream;
+import jakarta.servlet.http.HttpServlet;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+
+import org.h2.util.NetworkConnectionInfo;
+
+/**
+ * Adopted from {@link WebServlet} for Apache Causeway 3+.
+ * <p>
+ * Eventually replace with original WebServlet, once it supports Jakarta 
name-spaces.
+ * @see WebServlet
+ */
+public class H2WebServletForJakarta extends HttpServlet {
+
+    private static final long serialVersionUID = 1L;
+    private transient WebServer server;
+
+    // -- MODIFICATIONS (OPEN UP API)
+
+    public void setConnectionInfo(final ConnectionInfo connectionInfo) {
+        server.updateSetting(connectionInfo);
+    }
+
+    public void setAllowOthers(final boolean b) {
+        server.setAllowOthers(b);
+    }
+
+    public boolean getAllowOthers() {
+        return server.getAllowOthers();
+    }
+
+    public void setAdminPassword(final String password) {
+        server.setAdminPassword(password);
+    }
+
+    // --
+
+    @Override
+    public void init() {
+        ServletConfig config = getServletConfig();
+        Enumeration<?> en = config.getInitParameterNames();
+        ArrayList<String> list = new ArrayList<>();
+        while (en.hasMoreElements()) {
+            String name = en.nextElement().toString();
+            String value = config.getInitParameter(name);
+            if (!name.startsWith("-")) {
+                name = "-" + name;
+            }
+            list.add(name);
+            if (value.length() > 0) {
+                list.add(value);
+            }
+        }
+        String[] args = list.toArray(new String[0]);
+        server = new WebServer();
+        server.setAllowChunked(false);
+        server.init(args);
+    }
+
+    @Override
+    public void destroy() {
+        server.stop();
+    }
+
+    private boolean allow(final HttpServletRequest req) {
+        if (server.getAllowOthers()) {
+            return true;
+        }
+        String addr = req.getRemoteAddr();
+        try {
+            InetAddress address = InetAddress.getByName(addr);
+            return address.isLoopbackAddress();
+        } catch (UnknownHostException | NoClassDefFoundError e) {
+            // Google App Engine does not allow java.net.InetAddress
+            return false;
+        }
+
+    }
+
+    private String getAllowedFile(final HttpServletRequest req, final String 
requestedFile) {
+        if (!allow(req)) {
+            return "notAllowed.jsp";
+        }
+        if (requestedFile.length() == 0) {
+            return "index.do";
+        }
+        return requestedFile;
+    }
+
+    @Override
+    public void doGet(final HttpServletRequest req, final HttpServletResponse 
resp)
+            throws IOException {
+        req.setCharacterEncoding("utf-8");
+        String file = req.getPathInfo();
+        if (file == null) {
+            resp.sendRedirect(req.getRequestURI() + "/");
+            return;
+        } else if (file.startsWith("/")) {
+            file = file.substring(1);
+        }
+        file = getAllowedFile(req, file);
+
+        // extract the request attributes
+        Properties attributes = new Properties();
+        Enumeration<?> en = req.getAttributeNames();
+        while (en.hasMoreElements()) {
+            String name = en.nextElement().toString();
+            String value = req.getAttribute(name).toString();
+            attributes.put(name, value);
+        }
+        en = req.getParameterNames();
+        while (en.hasMoreElements()) {
+            String name = en.nextElement().toString();
+            String value = req.getParameter(name);
+            attributes.put(name, value);
+        }
+
+        WebSession session = null;
+        String sessionId = attributes.getProperty("jsessionid");
+        if (sessionId != null) {
+            session = server.getSession(sessionId);
+        }
+        WebApp app = new WebApp(server);
+        app.setSession(session, attributes);
+        String ifModifiedSince = req.getHeader("if-modified-since");
+
+        String scheme = req.getScheme();
+        StringBuilder builder = new 
StringBuilder(scheme).append("://").append(req.getServerName());
+        int serverPort = req.getServerPort();
+        if (!(serverPort == 80 && scheme.equals("http") || serverPort == 443 
&& scheme.equals("https"))) {
+            builder.append(':').append(serverPort);
+        }
+        String path = builder.append(req.getContextPath()).toString();
+        file = app.processRequest(file, new NetworkConnectionInfo(path, 
req.getRemoteAddr(), req.getRemotePort()));
+        session = app.getSession();
+
+        String mimeType = app.getMimeType();
+        boolean cache = app.getCache();
+
+        if (cache && server.getStartDateTime().equals(ifModifiedSince)) {
+            resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
+            return;
+        }
+        byte[] bytes = server.getFile(file);
+        if (bytes == null) {
+            resp.sendError(HttpServletResponse.SC_NOT_FOUND);
+            bytes = ("File not found: " + 
file).getBytes(StandardCharsets.UTF_8);
+        } else {
+            if (session != null && file.endsWith(".jsp")) {
+                String page = new String(bytes, StandardCharsets.UTF_8);
+                page = PageParser.parse(page, session.map);
+                bytes = page.getBytes(StandardCharsets.UTF_8);
+            }
+            resp.setContentType(mimeType);
+            if (!cache) {
+                resp.setHeader("Cache-Control", "no-cache");
+            } else {
+                resp.setHeader("Cache-Control", "max-age=10");
+                resp.setHeader("Last-Modified", server.getStartDateTime());
+            }
+        }
+        if (bytes != null) {
+            ServletOutputStream out = resp.getOutputStream();
+            out.write(bytes);
+        }
+    }
+
+    @Override
+    public void doPost(final HttpServletRequest req, final HttpServletResponse 
resp)
+            throws IOException {
+        doGet(req, resp);
+    }
+
+}
+

Reply via email to