Sat, 16 May 2020 15:45:06 +0200
fixes bug where displaying an error page for missing data source would also require that data source (error pages don't try to get database connections now)
also improves error pages in general
16 | 1 | /* |
2 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. | |
34
824d4042c857
cleanup and simplification of database access layer
Mike Becker <universe@uap-core.de>
parents:
33
diff
changeset
|
3 | * |
24 | 4 | * Copyright 2018 Mike Becker. All rights reserved. |
34
824d4042c857
cleanup and simplification of database access layer
Mike Becker <universe@uap-core.de>
parents:
33
diff
changeset
|
5 | * |
16 | 6 | * Redistribution and use in source and binary forms, with or without |
7 | * modification, are permitted provided that the following conditions are met: | |
8 | * | |
9 | * 1. Redistributions of source code must retain the above copyright | |
10 | * notice, this list of conditions and the following disclaimer. | |
11 | * | |
12 | * 2. Redistributions in binary form must reproduce the above copyright | |
13 | * notice, this list of conditions and the following disclaimer in the | |
14 | * documentation and/or other materials provided with the distribution. | |
15 | * | |
16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |
17 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
19 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE | |
20 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
21 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
22 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
23 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
24 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
25 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
26 | * POSSIBILITY OF SUCH DAMAGE. | |
34
824d4042c857
cleanup and simplification of database access layer
Mike Becker <universe@uap-core.de>
parents:
33
diff
changeset
|
27 | * |
16 | 28 | */ |
29 | package de.uapcore.lightpit; | |
30 | ||
33 | 31 | import org.slf4j.Logger; |
32 | import org.slf4j.LoggerFactory; | |
33 | ||
16 | 34 | import javax.naming.Context; |
35 | import javax.naming.InitialContext; | |
36 | import javax.naming.NamingException; | |
37 | import javax.servlet.ServletContext; | |
38 | import javax.servlet.ServletContextEvent; | |
39 | import javax.servlet.ServletContextListener; | |
40 | import javax.servlet.annotation.WebListener; | |
41 | import javax.sql.DataSource; | |
33 | 42 | import java.sql.Connection; |
43 | import java.sql.DatabaseMetaData; | |
44 | import java.sql.SQLException; | |
45 | import java.util.Optional; | |
16 | 46 | |
47 | /** | |
48 | * Provides access to different privilege layers within the database. | |
49 | */ | |
50 | @WebListener | |
51 | public final class DatabaseFacade implements ServletContextListener { | |
33 | 52 | |
16 | 53 | private static final Logger LOG = LoggerFactory.getLogger(DatabaseFacade.class); |
33 | 54 | |
16 | 55 | /** |
56 | * Timeout in seconds for the validation test. | |
57 | */ | |
58 | private static final int DB_TEST_TIMEOUT = 10; | |
33 | 59 | |
34
824d4042c857
cleanup and simplification of database access layer
Mike Becker <universe@uap-core.de>
parents:
33
diff
changeset
|
60 | /** |
824d4042c857
cleanup and simplification of database access layer
Mike Becker <universe@uap-core.de>
parents:
33
diff
changeset
|
61 | * Specifies the database dialect. |
824d4042c857
cleanup and simplification of database access layer
Mike Becker <universe@uap-core.de>
parents:
33
diff
changeset
|
62 | */ |
33 | 63 | public enum Dialect { |
64 | Postgres | |
19
1a0ac419f714
removes the privileged data source from the application and the ability to have a web UI for a setup
Mike Becker <universe@uap-core.de>
parents:
16
diff
changeset
|
65 | } |
33 | 66 | |
19
1a0ac419f714
removes the privileged data source from the application and the ability to have a web UI for a setup
Mike Becker <universe@uap-core.de>
parents:
16
diff
changeset
|
67 | /** |
1a0ac419f714
removes the privileged data source from the application and the ability to have a web UI for a setup
Mike Becker <universe@uap-core.de>
parents:
16
diff
changeset
|
68 | * The database dialect to use. |
33 | 69 | * <p> |
34
824d4042c857
cleanup and simplification of database access layer
Mike Becker <universe@uap-core.de>
parents:
33
diff
changeset
|
70 | * May be overridden by context parameter. |
33 | 71 | * |
19
1a0ac419f714
removes the privileged data source from the application and the ability to have a web UI for a setup
Mike Becker <universe@uap-core.de>
parents:
16
diff
changeset
|
72 | * @see Constants#CTX_ATTR_DB_DIALECT |
1a0ac419f714
removes the privileged data source from the application and the ability to have a web UI for a setup
Mike Becker <universe@uap-core.de>
parents:
16
diff
changeset
|
73 | */ |
1a0ac419f714
removes the privileged data source from the application and the ability to have a web UI for a setup
Mike Becker <universe@uap-core.de>
parents:
16
diff
changeset
|
74 | private Dialect dialect = Dialect.Postgres; |
34
824d4042c857
cleanup and simplification of database access layer
Mike Becker <universe@uap-core.de>
parents:
33
diff
changeset
|
75 | |
16 | 76 | /** |
77 | * The default schema to test against when validating the connection. | |
34
824d4042c857
cleanup and simplification of database access layer
Mike Becker <universe@uap-core.de>
parents:
33
diff
changeset
|
78 | * <p> |
16 | 79 | * May be overridden by context parameter. |
34
824d4042c857
cleanup and simplification of database access layer
Mike Becker <universe@uap-core.de>
parents:
33
diff
changeset
|
80 | * |
19
1a0ac419f714
removes the privileged data source from the application and the ability to have a web UI for a setup
Mike Becker <universe@uap-core.de>
parents:
16
diff
changeset
|
81 | * @see Constants#CTX_ATTR_DB_SCHEMA |
16 | 82 | */ |
83 | private static final String DB_DEFAULT_SCHEMA = "lightpit"; | |
34
824d4042c857
cleanup and simplification of database access layer
Mike Becker <universe@uap-core.de>
parents:
33
diff
changeset
|
84 | |
16 | 85 | /** |
19
1a0ac419f714
removes the privileged data source from the application and the ability to have a web UI for a setup
Mike Becker <universe@uap-core.de>
parents:
16
diff
changeset
|
86 | * The attribute name in the Servlet context under which an instance of this class can be found. |
16 | 87 | */ |
88 | public static final String SC_ATTR_NAME = DatabaseFacade.class.getName(); | |
33 | 89 | |
19
1a0ac419f714
removes the privileged data source from the application and the ability to have a web UI for a setup
Mike Becker <universe@uap-core.de>
parents:
16
diff
changeset
|
90 | private static final String DS_JNDI_NAME = "jdbc/lightpit/app"; |
33 | 91 | private DataSource dataSource; |
34
824d4042c857
cleanup and simplification of database access layer
Mike Becker <universe@uap-core.de>
parents:
33
diff
changeset
|
92 | |
16 | 93 | /** |
19
1a0ac419f714
removes the privileged data source from the application and the ability to have a web UI for a setup
Mike Becker <universe@uap-core.de>
parents:
16
diff
changeset
|
94 | * Returns the data source. |
34
824d4042c857
cleanup and simplification of database access layer
Mike Becker <universe@uap-core.de>
parents:
33
diff
changeset
|
95 | * |
19
1a0ac419f714
removes the privileged data source from the application and the ability to have a web UI for a setup
Mike Becker <universe@uap-core.de>
parents:
16
diff
changeset
|
96 | * @return a data source |
16 | 97 | */ |
38
cf85ef18f231
adds DAO for Project entity and save/update methods
Mike Becker <universe@uap-core.de>
parents:
34
diff
changeset
|
98 | public DataSource getDataSource() { |
cf85ef18f231
adds DAO for Project entity and save/update methods
Mike Becker <universe@uap-core.de>
parents:
34
diff
changeset
|
99 | return dataSource; |
34
824d4042c857
cleanup and simplification of database access layer
Mike Becker <universe@uap-core.de>
parents:
33
diff
changeset
|
100 | } |
824d4042c857
cleanup and simplification of database access layer
Mike Becker <universe@uap-core.de>
parents:
33
diff
changeset
|
101 | |
19
1a0ac419f714
removes the privileged data source from the application and the ability to have a web UI for a setup
Mike Becker <universe@uap-core.de>
parents:
16
diff
changeset
|
102 | public Dialect getSQLDialect() { |
1a0ac419f714
removes the privileged data source from the application and the ability to have a web UI for a setup
Mike Becker <universe@uap-core.de>
parents:
16
diff
changeset
|
103 | return dialect; |
16 | 104 | } |
33 | 105 | |
106 | private static void checkConnection(DataSource ds, String testSchema) { | |
16 | 107 | try (Connection conn = ds.getConnection()) { |
108 | if (!conn.isValid(DB_TEST_TIMEOUT)) { | |
109 | throw new SQLException("Validation check failed."); | |
110 | } | |
111 | if (conn.isReadOnly()) { | |
112 | throw new SQLException("Connection is read-only and thus unusable."); | |
113 | } | |
114 | if (!conn.getSchema().equals(testSchema)) { | |
115 | throw new SQLException(String.format("Connection is not configured to use the schema %s.", testSchema)); | |
116 | } | |
117 | DatabaseMetaData metaData = conn.getMetaData(); | |
118 | LOG.info("Connections as {} to {}/{} ready to go.", metaData.getUserName(), metaData.getURL(), conn.getSchema()); | |
119 | } catch (SQLException ex) { | |
33 | 120 | LOG.error("Checking database connection failed", ex); |
16 | 121 | } |
122 | } | |
33 | 123 | |
124 | private static DataSource retrieveDataSource(Context ctx) { | |
16 | 125 | DataSource ret = null; |
126 | try { | |
33 | 127 | ret = (DataSource) ctx.lookup(DS_JNDI_NAME); |
19
1a0ac419f714
removes the privileged data source from the application and the ability to have a web UI for a setup
Mike Becker <universe@uap-core.de>
parents:
16
diff
changeset
|
128 | LOG.info("Data source retrieved."); |
16 | 129 | } catch (NamingException ex) { |
19
1a0ac419f714
removes the privileged data source from the application and the ability to have a web UI for a setup
Mike Becker <universe@uap-core.de>
parents:
16
diff
changeset
|
130 | LOG.error("Data source {} not available.", DS_JNDI_NAME); |
16 | 131 | LOG.error("Reason for the missing data source: ", ex); |
132 | } | |
33 | 133 | return ret; |
16 | 134 | } |
135 | ||
136 | @Override | |
137 | public void contextInitialized(ServletContextEvent sce) { | |
33 | 138 | ServletContext sc = sce.getServletContext(); |
34
824d4042c857
cleanup and simplification of database access layer
Mike Becker <universe@uap-core.de>
parents:
33
diff
changeset
|
139 | |
19
1a0ac419f714
removes the privileged data source from the application and the ability to have a web UI for a setup
Mike Becker <universe@uap-core.de>
parents:
16
diff
changeset
|
140 | dataSource = null; |
34
824d4042c857
cleanup and simplification of database access layer
Mike Becker <universe@uap-core.de>
parents:
33
diff
changeset
|
141 | |
16 | 142 | final String dbSchema = Optional |
143 | .ofNullable(sc.getInitParameter(Constants.CTX_ATTR_DB_SCHEMA)) | |
144 | .orElse(DB_DEFAULT_SCHEMA); | |
19
1a0ac419f714
removes the privileged data source from the application and the ability to have a web UI for a setup
Mike Becker <universe@uap-core.de>
parents:
16
diff
changeset
|
145 | final String dbDialect = sc.getInitParameter(Constants.CTX_ATTR_DB_DIALECT); |
1a0ac419f714
removes the privileged data source from the application and the ability to have a web UI for a setup
Mike Becker <universe@uap-core.de>
parents:
16
diff
changeset
|
146 | if (dbDialect != null) { |
1a0ac419f714
removes the privileged data source from the application and the ability to have a web UI for a setup
Mike Becker <universe@uap-core.de>
parents:
16
diff
changeset
|
147 | try { |
1a0ac419f714
removes the privileged data source from the application and the ability to have a web UI for a setup
Mike Becker <universe@uap-core.de>
parents:
16
diff
changeset
|
148 | dialect = Dialect.valueOf(dbDialect); |
1a0ac419f714
removes the privileged data source from the application and the ability to have a web UI for a setup
Mike Becker <universe@uap-core.de>
parents:
16
diff
changeset
|
149 | } catch (IllegalArgumentException ex) { |
20
bd1a76c91d5b
module synchronization with database
Mike Becker <universe@uap-core.de>
parents:
19
diff
changeset
|
150 | LOG.error("Unknown or unsupported database dialect {}. Defaulting to {}.", dbDialect, dialect); |
19
1a0ac419f714
removes the privileged data source from the application and the ability to have a web UI for a setup
Mike Becker <universe@uap-core.de>
parents:
16
diff
changeset
|
151 | } |
1a0ac419f714
removes the privileged data source from the application and the ability to have a web UI for a setup
Mike Becker <universe@uap-core.de>
parents:
16
diff
changeset
|
152 | } |
16 | 153 | |
154 | try { | |
50
2a90d105edec
adds lookup-name to web.xml resource reference and removes custom JNDI context parameter
Mike Becker <universe@uap-core.de>
parents:
38
diff
changeset
|
155 | LOG.debug("Trying to access JNDI context ..."); |
16 | 156 | Context initialCtx = new InitialContext(); |
50
2a90d105edec
adds lookup-name to web.xml resource reference and removes custom JNDI context parameter
Mike Becker <universe@uap-core.de>
parents:
38
diff
changeset
|
157 | Context ctx = (Context) initialCtx.lookup("java:comp/env"); |
33 | 158 | |
19
1a0ac419f714
removes the privileged data source from the application and the ability to have a web UI for a setup
Mike Becker <universe@uap-core.de>
parents:
16
diff
changeset
|
159 | dataSource = retrieveDataSource(ctx); |
33 | 160 | |
161 | if (dataSource != null) { | |
162 | checkConnection(dataSource, dbSchema); | |
163 | } | |
16 | 164 | } catch (NamingException | ClassCastException ex) { |
165 | LOG.error("Cannot access JNDI resources.", ex); | |
166 | } | |
34
824d4042c857
cleanup and simplification of database access layer
Mike Becker <universe@uap-core.de>
parents:
33
diff
changeset
|
167 | |
16 | 168 | sc.setAttribute(SC_ATTR_NAME, this); |
169 | LOG.info("Database facade injected into ServletContext."); | |
170 | } | |
171 | ||
172 | @Override | |
173 | public void contextDestroyed(ServletContextEvent sce) { | |
19
1a0ac419f714
removes the privileged data source from the application and the ability to have a web UI for a setup
Mike Becker <universe@uap-core.de>
parents:
16
diff
changeset
|
174 | dataSource = null; |
34
824d4042c857
cleanup and simplification of database access layer
Mike Becker <universe@uap-core.de>
parents:
33
diff
changeset
|
175 | } |
16 | 176 | } |