1.1 --- a/src/main/java/de/uapcore/lightpit/DatabaseFacade.java Fri Oct 23 20:34:57 2020 +0200 1.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 1.3 @@ -1,176 +0,0 @@ 1.4 -/* 1.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 1.6 - * 1.7 - * Copyright 2018 Mike Becker. All rights reserved. 1.8 - * 1.9 - * Redistribution and use in source and binary forms, with or without 1.10 - * modification, are permitted provided that the following conditions are met: 1.11 - * 1.12 - * 1. Redistributions of source code must retain the above copyright 1.13 - * notice, this list of conditions and the following disclaimer. 1.14 - * 1.15 - * 2. Redistributions in binary form must reproduce the above copyright 1.16 - * notice, this list of conditions and the following disclaimer in the 1.17 - * documentation and/or other materials provided with the distribution. 1.18 - * 1.19 - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 1.20 - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1.21 - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1.22 - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 1.23 - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 1.24 - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 1.25 - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 1.26 - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 1.27 - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 1.28 - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 1.29 - * POSSIBILITY OF SUCH DAMAGE. 1.30 - * 1.31 - */ 1.32 -package de.uapcore.lightpit; 1.33 - 1.34 -import org.slf4j.Logger; 1.35 -import org.slf4j.LoggerFactory; 1.36 - 1.37 -import javax.naming.Context; 1.38 -import javax.naming.InitialContext; 1.39 -import javax.naming.NamingException; 1.40 -import javax.servlet.ServletContext; 1.41 -import javax.servlet.ServletContextEvent; 1.42 -import javax.servlet.ServletContextListener; 1.43 -import javax.servlet.annotation.WebListener; 1.44 -import javax.sql.DataSource; 1.45 -import java.sql.Connection; 1.46 -import java.sql.DatabaseMetaData; 1.47 -import java.sql.SQLException; 1.48 -import java.util.Optional; 1.49 - 1.50 -/** 1.51 - * Provides access to different privilege layers within the database. 1.52 - */ 1.53 -@WebListener 1.54 -public final class DatabaseFacade implements ServletContextListener { 1.55 - 1.56 - private static final Logger LOG = LoggerFactory.getLogger(DatabaseFacade.class); 1.57 - 1.58 - /** 1.59 - * Timeout in seconds for the validation test. 1.60 - */ 1.61 - private static final int DB_TEST_TIMEOUT = 10; 1.62 - 1.63 - /** 1.64 - * Specifies the database dialect. 1.65 - */ 1.66 - public enum Dialect { 1.67 - Postgres 1.68 - } 1.69 - 1.70 - /** 1.71 - * The database dialect to use. 1.72 - * <p> 1.73 - * May be overridden by context parameter. 1.74 - * 1.75 - * @see Constants#CTX_ATTR_DB_DIALECT 1.76 - */ 1.77 - private Dialect dialect = Dialect.Postgres; 1.78 - 1.79 - /** 1.80 - * The default schema to test against when validating the connection. 1.81 - * <p> 1.82 - * May be overridden by context parameter. 1.83 - * 1.84 - * @see Constants#CTX_ATTR_DB_SCHEMA 1.85 - */ 1.86 - private static final String DB_DEFAULT_SCHEMA = "lightpit"; 1.87 - 1.88 - /** 1.89 - * The attribute name in the Servlet context under which an instance of this class can be found. 1.90 - */ 1.91 - public static final String SC_ATTR_NAME = DatabaseFacade.class.getName(); 1.92 - 1.93 - private static final String DS_JNDI_NAME = "jdbc/lightpit/app"; 1.94 - private DataSource dataSource; 1.95 - 1.96 - /** 1.97 - * Returns the data source. 1.98 - * 1.99 - * @return a data source 1.100 - */ 1.101 - public DataSource getDataSource() { 1.102 - return dataSource; 1.103 - } 1.104 - 1.105 - public Dialect getSQLDialect() { 1.106 - return dialect; 1.107 - } 1.108 - 1.109 - private static void checkConnection(DataSource ds, String testSchema) { 1.110 - try (Connection conn = ds.getConnection()) { 1.111 - if (!conn.isValid(DB_TEST_TIMEOUT)) { 1.112 - throw new SQLException("Validation check failed."); 1.113 - } 1.114 - if (conn.isReadOnly()) { 1.115 - throw new SQLException("Connection is read-only and thus unusable."); 1.116 - } 1.117 - if (!conn.getSchema().equals(testSchema)) { 1.118 - throw new SQLException(String.format("Connection is not configured to use the schema %s.", testSchema)); 1.119 - } 1.120 - DatabaseMetaData metaData = conn.getMetaData(); 1.121 - LOG.info("Connections as {} to {}/{} ready to go.", metaData.getUserName(), metaData.getURL(), conn.getSchema()); 1.122 - } catch (SQLException ex) { 1.123 - LOG.error("Checking database connection failed", ex); 1.124 - } 1.125 - } 1.126 - 1.127 - private static DataSource retrieveDataSource(Context ctx) { 1.128 - DataSource ret = null; 1.129 - try { 1.130 - ret = (DataSource) ctx.lookup(DS_JNDI_NAME); 1.131 - LOG.info("Data source retrieved."); 1.132 - } catch (NamingException ex) { 1.133 - LOG.error("Data source {} not available.", DS_JNDI_NAME); 1.134 - LOG.error("Reason for the missing data source: ", ex); 1.135 - } 1.136 - return ret; 1.137 - } 1.138 - 1.139 - @Override 1.140 - public void contextInitialized(ServletContextEvent sce) { 1.141 - ServletContext sc = sce.getServletContext(); 1.142 - 1.143 - dataSource = null; 1.144 - 1.145 - final String dbSchema = Optional 1.146 - .ofNullable(sc.getInitParameter(Constants.CTX_ATTR_DB_SCHEMA)) 1.147 - .orElse(DB_DEFAULT_SCHEMA); 1.148 - final String dbDialect = sc.getInitParameter(Constants.CTX_ATTR_DB_DIALECT); 1.149 - if (dbDialect != null) { 1.150 - try { 1.151 - dialect = Dialect.valueOf(dbDialect); 1.152 - } catch (IllegalArgumentException ex) { 1.153 - LOG.error("Unknown or unsupported database dialect {}. Defaulting to {}.", dbDialect, dialect); 1.154 - } 1.155 - } 1.156 - 1.157 - try { 1.158 - LOG.debug("Trying to access JNDI context ..."); 1.159 - Context initialCtx = new InitialContext(); 1.160 - Context ctx = (Context) initialCtx.lookup("java:comp/env"); 1.161 - 1.162 - dataSource = retrieveDataSource(ctx); 1.163 - 1.164 - if (dataSource != null) { 1.165 - checkConnection(dataSource, dbSchema); 1.166 - } 1.167 - } catch (NamingException | ClassCastException ex) { 1.168 - LOG.error("Cannot access JNDI resources.", ex); 1.169 - } 1.170 - 1.171 - sc.setAttribute(SC_ATTR_NAME, this); 1.172 - LOG.info("Database facade injected into ServletContext."); 1.173 - } 1.174 - 1.175 - @Override 1.176 - public void contextDestroyed(ServletContextEvent sce) { 1.177 - dataSource = null; 1.178 - } 1.179 -}