001// Generated by delombok at Fri Mar 22 16:21:46 GMT 2024
002/*
003 *  Licensed to the Apache Software Foundation (ASF) under one
004 *  or more contributor license agreements.  See the NOTICE file
005 *  distributed with this work for additional information
006 *  regarding copyright ownership.  The ASF licenses this file
007 *  to you under the Apache License, Version 2.0 (the
008 *  "License"); you may not use this file except in compliance
009 *  with the License.  You may obtain a copy of the License at
010 *
011 *        http://www.apache.org/licenses/LICENSE-2.0
012 *
013 *  Unless required by applicable law or agreed to in writing,
014 *  software distributed under the License is distributed on an
015 *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
016 *  KIND, either express or implied.  See the License for the
017 *  specific language governing permissions and limitations
018 *  under the License.
019 */
020package org.apache.causeway.testing.h2console.ui.webmodule;
021
022import javax.inject.Inject;
023import javax.inject.Named;
024import javax.servlet.ServletContext;
025import javax.servlet.ServletContextListener;
026import javax.servlet.ServletException;
027import org.h2.server.web.ConnectionInfo;
028import org.h2.server.web.WebServlet;
029import org.springframework.beans.factory.annotation.Qualifier;
030import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
031import org.springframework.stereotype.Service;
032import org.apache.causeway.applib.annotation.PriorityPrecedence;
033import org.apache.causeway.applib.services.inject.ServiceInjector;
034import org.apache.causeway.applib.value.LocalResourcePath;
035import org.apache.causeway.commons.collections.Can;
036import org.apache.causeway.commons.internal.base._Strings;
037import org.apache.causeway.core.config.CausewayConfiguration;
038import org.apache.causeway.core.config.datasources.DataSourceIntrospectionService;
039import org.apache.causeway.core.config.datasources.DataSourceIntrospectionService.DataSourceInfo;
040import org.apache.causeway.core.config.environment.CausewaySystemEnvironment;
041import org.apache.causeway.core.security.authentication.standard.RandomCodeGenerator;
042import org.apache.causeway.core.webapp.modules.WebModuleAbstract;
043import org.apache.causeway.core.webapp.modules.WebModuleContext;
044
045/**
046 * @since 2.0 {@index}
047 */
048@Service
049@Named("causeway.test.WebModuleH2Console")
050@javax.annotation.Priority(PriorityPrecedence.MIDPOINT)
051@Qualifier("H2Console")
052public class WebModuleH2Console extends WebModuleAbstract {
053    @java.lang.SuppressWarnings("all")
054    private static final org.apache.logging.log4j.Logger log = org.apache.logging.log4j.LogManager.getLogger(WebModuleH2Console.class);
055    private static final String SERVLET_NAME = "H2Console";
056    private static final String CONSOLE_PATH = "/db";
057    private final LocalResourcePath localResourcePathIfEnabled;
058    private final CausewaySystemEnvironment causewaySystemEnvironment;
059    private final boolean applicable;
060
061    @Inject
062    public WebModuleH2Console(final DataSourceIntrospectionService datasourceIntrospector, final CausewaySystemEnvironment causewaySystemEnvironment, final ServiceInjector serviceInjector) {
063        super(serviceInjector);
064        this.causewaySystemEnvironment = causewaySystemEnvironment;
065        this.applicable = isPrototyping() && isH2MemConnectionUsed(datasourceIntrospector);
066        this.localResourcePathIfEnabled = applicable ? new LocalResourcePath(CONSOLE_PATH) : null;
067    }
068
069    private final String name = "H2Console";
070
071    @Override
072    public Can<ServletContextListener> init(final ServletContext ctx) throws ServletException {
073        registerServlet(ctx, SERVLET_NAME, H2WebServlet.class).ifPresent(servletReg -> {
074            servletReg.addMapping(CONSOLE_PATH + "/*");
075        });
076        //[CAUSEWAY-3128] presence of "webAllowOthers" is a potential security risk
077        // setting this later based on configuration below ...
078        //servletReg.setInitParameter("webAllowOthers", "true");
079        return Can.empty(); // registers no listeners
080    }
081
082    @Override
083    public boolean isApplicable(final WebModuleContext ctx) {
084        return applicable;
085    }
086
087    // -- WRAPPER AROUND H2'S SERVLET
088    public static class H2WebServlet extends WebServlet {
089        private static final long serialVersionUID = 1L;
090        private static String jdbcUrl;
091        @Inject
092        private CausewayConfiguration causewayConfiguration;
093        @Inject
094        private RandomCodeGenerator randomCodeGenerator;
095
096        @Override
097        public void init() {
098            super.init();
099            if (_Strings.isEmpty(jdbcUrl)) {
100                return;
101            }
102            final org.springframework.boot.autoconfigure.jdbc.DataSourceProperties dataSourceProperties = new DataSourceProperties();
103            dataSourceProperties.setUsername("sa");
104            dataSourceProperties.setUrl(jdbcUrl);
105            final org.h2.server.web.ConnectionInfo connectionInfo = new ConnectionInfo(String.format("Generic Spring Datasource|%s|%s|%s", dataSourceProperties.determineDriverClassName(), dataSourceProperties.determineUrl(), dataSourceProperties.determineUsername()));
106            final org.apache.causeway.testing.h2console.ui.webmodule.WebModuleH2Console.H2WebServlet webServlet = this;
107            H2WebServerWrapper.withH2WebServerWrapperDo(webServlet, h2WebServerWrapper -> {
108                h2WebServerWrapper.setConnectionInfo(connectionInfo);
109                h2WebServerWrapper.setAllowOthers(isWebAllowRemoteAccess());
110                if (isGenerateRandomWebAdminPassword()) {
111                    final java.lang.String webAdminPass = randomCodeGenerator.generateRandomCode();
112                    log.info("webAdminPass: {}", webAdminPass);
113                    h2WebServerWrapper.setAdminPassword(webAdminPass);
114                }
115            });
116        }
117
118        public static void configure(final String jdbcUrl) {
119            H2WebServlet.jdbcUrl = jdbcUrl;
120        }
121
122        private boolean isWebAllowRemoteAccess() {
123            return causewayConfiguration.getPrototyping().getH2Console().isWebAllowRemoteAccess();
124        }
125
126        private boolean isGenerateRandomWebAdminPassword() {
127            return causewayConfiguration.getPrototyping().getH2Console().isGenerateRandomWebAdminPassword();
128        }
129    }
130
131    // -- HELPER
132    private boolean isPrototyping() {
133        return causewaySystemEnvironment.getDeploymentType().isPrototyping();
134    }
135
136    private boolean isH2MemConnectionUsed(final DataSourceIntrospectionService datasourceIntrospector) {
137        return datasourceIntrospector.getDataSourceInfos().stream().map(DataSourceInfo::getJdbcUrl).anyMatch(jdbcUrl -> {
138            if (jdbcUrl.contains(":h2:mem:")) {
139                log.info("found h2 in-memory data-source: {}", jdbcUrl);
140                H2WebServlet.configure(jdbcUrl);
141                return true;
142            }
143            return false;
144        });
145    }
146
147    @java.lang.SuppressWarnings("all")
148    public LocalResourcePath getLocalResourcePathIfEnabled() {
149        return this.localResourcePathIfEnabled;
150    }
151
152    @java.lang.SuppressWarnings("all")
153    public String getName() {
154        return this.name;
155    }
156}