Mon, 09 Aug 2021 15:50:37 +0200
#105 fixes wrong font for form controls
universe@151 | 1 | /* |
universe@180 | 2 | * Copyright 2021 Mike Becker. All rights reserved. |
universe@151 | 3 | * |
universe@151 | 4 | * Redistribution and use in source and binary forms, with or without |
universe@151 | 5 | * modification, are permitted provided that the following conditions are met: |
universe@151 | 6 | * |
universe@151 | 7 | * 1. Redistributions of source code must retain the above copyright |
universe@151 | 8 | * notice, this list of conditions and the following disclaimer. |
universe@151 | 9 | * |
universe@151 | 10 | * 2. Redistributions in binary form must reproduce the above copyright |
universe@151 | 11 | * notice, this list of conditions and the following disclaimer in the |
universe@151 | 12 | * documentation and/or other materials provided with the distribution. |
universe@151 | 13 | * |
universe@151 | 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
universe@151 | 15 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
universe@151 | 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
universe@151 | 17 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE |
universe@151 | 18 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
universe@151 | 19 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
universe@151 | 20 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
universe@151 | 21 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
universe@151 | 22 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
universe@151 | 23 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
universe@151 | 24 | */ |
universe@151 | 25 | |
universe@151 | 26 | package de.uapcore.lightpit |
universe@151 | 27 | |
universe@151 | 28 | import java.sql.SQLException |
universe@151 | 29 | import javax.naming.Context |
universe@151 | 30 | import javax.naming.InitialContext |
universe@151 | 31 | import javax.naming.NamingException |
universe@151 | 32 | import javax.servlet.ServletContextEvent |
universe@151 | 33 | import javax.servlet.ServletContextListener |
universe@151 | 34 | import javax.servlet.annotation.WebListener |
universe@151 | 35 | import javax.sql.DataSource |
universe@151 | 36 | |
universe@151 | 37 | /** |
universe@151 | 38 | * Provides access to the database. |
universe@151 | 39 | */ |
universe@151 | 40 | @WebListener |
universe@151 | 41 | class DataSourceProvider : ServletContextListener, LoggingTrait { |
universe@151 | 42 | |
universe@158 | 43 | enum class Dialect { |
universe@158 | 44 | Postgres |
universe@158 | 45 | } |
universe@158 | 46 | |
universe@151 | 47 | /** |
universe@151 | 48 | * The database dialect to use. |
universe@151 | 49 | * May be overridden by context parameter. |
universe@151 | 50 | * |
universe@151 | 51 | * @see Constants.CTX_ATTR_DB_DIALECT |
universe@151 | 52 | */ |
universe@158 | 53 | var dialect = Dialect.Postgres; private set |
universe@151 | 54 | |
universe@151 | 55 | /** |
universe@151 | 56 | * The data source, if available. |
universe@151 | 57 | */ |
universe@151 | 58 | var dataSource: DataSource? = null |
universe@151 | 59 | |
universe@151 | 60 | companion object { |
universe@151 | 61 | /** |
universe@151 | 62 | * The attribute name in the Servlet context under which an instance of this class can be found. |
universe@151 | 63 | */ |
universe@184 | 64 | const val SC_ATTR_NAME = "lightpit.service.DataSourceProvider" |
universe@151 | 65 | |
universe@151 | 66 | /** |
universe@151 | 67 | * Timeout in seconds for the validation test. |
universe@151 | 68 | */ |
universe@184 | 69 | private const val DB_TEST_TIMEOUT = 10 |
universe@151 | 70 | |
universe@151 | 71 | /** |
universe@151 | 72 | * The default schema to test against when validating the connection. |
universe@151 | 73 | * May be overridden by context parameter. |
universe@151 | 74 | * |
universe@151 | 75 | * @see Constants.CTX_ATTR_DB_SCHEMA |
universe@151 | 76 | */ |
universe@184 | 77 | private const val DB_DEFAULT_SCHEMA = "lightpit" |
universe@151 | 78 | |
universe@151 | 79 | /** |
universe@151 | 80 | * The JNDI resource name for the data source. |
universe@151 | 81 | */ |
universe@184 | 82 | private const val DS_JNDI_NAME = "jdbc/lightpit/app" |
universe@151 | 83 | } |
universe@151 | 84 | |
universe@151 | 85 | private fun checkConnection(ds: DataSource, testSchema: String) { |
universe@151 | 86 | try { |
universe@151 | 87 | ds.connection.use { conn -> |
universe@151 | 88 | if (!conn.isValid(DB_TEST_TIMEOUT)) { |
universe@151 | 89 | throw SQLException("Validation check failed.") |
universe@151 | 90 | } |
universe@151 | 91 | if (conn.isReadOnly) { |
universe@151 | 92 | throw SQLException("Connection is read-only and thus unusable.") |
universe@151 | 93 | } |
universe@151 | 94 | if (conn.schema != testSchema) { |
universe@151 | 95 | throw SQLException( |
universe@151 | 96 | String.format( |
universe@151 | 97 | "Connection is not configured to use the schema %s.", |
universe@151 | 98 | testSchema |
universe@151 | 99 | ) |
universe@151 | 100 | ) |
universe@151 | 101 | } |
universe@151 | 102 | val metaData = conn.metaData |
universe@151 | 103 | logger().info( |
universe@151 | 104 | "Connections as {} to {}/{} ready to go.", |
universe@151 | 105 | metaData.userName, |
universe@151 | 106 | metaData.url, |
universe@151 | 107 | conn.schema |
universe@151 | 108 | ) |
universe@151 | 109 | } |
universe@151 | 110 | } catch (ex: SQLException) { |
universe@151 | 111 | logger().error("Checking database connection failed", ex) |
universe@151 | 112 | } |
universe@151 | 113 | } |
universe@151 | 114 | |
universe@151 | 115 | private fun retrieveDataSource(ctx: Context): DataSource? { |
universe@151 | 116 | return try { |
universe@151 | 117 | val ret = ctx.lookup(DS_JNDI_NAME) as DataSource |
universe@151 | 118 | logger().info("Data source retrieved.") |
universe@151 | 119 | ret |
universe@151 | 120 | } catch (ex: NamingException) { |
universe@151 | 121 | logger().error("Data source {} not available.", DS_JNDI_NAME) |
universe@151 | 122 | logger().error("Reason for the missing data source: ", ex) |
universe@151 | 123 | null |
universe@151 | 124 | } |
universe@151 | 125 | } |
universe@151 | 126 | |
universe@151 | 127 | override fun contextInitialized(sce: ServletContextEvent?) { |
universe@151 | 128 | val sc = sce!!.servletContext |
universe@151 | 129 | |
universe@151 | 130 | val dbSchema = sc.getInitParameter(Constants.CTX_ATTR_DB_SCHEMA) ?: DB_DEFAULT_SCHEMA |
universe@167 | 131 | sc.getInitParameter(Constants.CTX_ATTR_DB_DIALECT)?.let { dbDialect -> |
universe@151 | 132 | try { |
universe@158 | 133 | dialect = Dialect.valueOf(dbDialect) |
universe@151 | 134 | } catch (ex: IllegalArgumentException) { |
universe@151 | 135 | logger().error( |
universe@151 | 136 | "Unknown or unsupported database dialect {}. Defaulting to {}.", |
universe@151 | 137 | dbDialect, |
universe@151 | 138 | dialect |
universe@151 | 139 | ) |
universe@151 | 140 | } |
universe@151 | 141 | } |
universe@151 | 142 | |
universe@151 | 143 | dataSource = try { |
universe@151 | 144 | logger().debug("Trying to access JNDI context ...") |
universe@151 | 145 | val initialCtx: Context = InitialContext() |
universe@151 | 146 | val ctx = initialCtx.lookup("java:comp/env") as Context |
universe@151 | 147 | retrieveDataSource(ctx) |
universe@151 | 148 | } catch (ex: NamingException) { |
universe@151 | 149 | logger().error("Cannot access JNDI resources.", ex) |
universe@151 | 150 | null |
universe@151 | 151 | } catch (ex: ClassCastException) { |
universe@151 | 152 | logger().error("Cannot access JNDI resources.", ex) |
universe@151 | 153 | null |
universe@151 | 154 | } |
universe@151 | 155 | |
universe@151 | 156 | dataSource?.let { checkConnection(it, dbSchema) } |
universe@151 | 157 | |
universe@151 | 158 | sc.setAttribute(SC_ATTR_NAME, this) |
universe@151 | 159 | logger().info("Database facade injected into ServletContext.") |
universe@151 | 160 | } |
universe@151 | 161 | |
universe@151 | 162 | override fun contextDestroyed(sce: ServletContextEvent?) { |
universe@151 | 163 | dataSource = null |
universe@151 | 164 | } |
universe@151 | 165 | } |