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);
+ }
+
+}
+