1 /* |
1 /* |
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. |
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. |
3 * |
3 * |
4 * Copyright 2018 Mike Becker. All rights reserved. |
4 * Copyright 2018 Mike Becker. All rights reserved. |
5 * |
5 * |
6 * Redistribution and use in source and binary forms, with or without |
6 * Redistribution and use in source and binary forms, with or without |
7 * modification, are permitted provided that the following conditions are met: |
7 * modification, are permitted provided that the following conditions are met: |
8 * |
8 * |
9 * 1. Redistributions of source code must retain the above copyright |
9 * 1. Redistributions of source code must retain the above copyright |
10 * notice, this list of conditions and the following disclaimer. |
10 * notice, this list of conditions and the following disclaimer. |
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
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 |
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
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 |
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
26 * POSSIBILITY OF SUCH DAMAGE. |
26 * POSSIBILITY OF SUCH DAMAGE. |
27 * |
27 * |
28 */ |
28 */ |
29 package de.uapcore.lightpit; |
29 package de.uapcore.lightpit; |
30 |
30 |
|
31 import de.uapcore.lightpit.dao.DataAccessObjects; |
|
32 import de.uapcore.lightpit.dao.postgres.PGDataAccessObjects; |
31 import org.slf4j.Logger; |
33 import org.slf4j.Logger; |
32 import org.slf4j.LoggerFactory; |
34 import org.slf4j.LoggerFactory; |
33 |
35 |
34 import javax.naming.Context; |
36 import javax.naming.Context; |
35 import javax.naming.InitialContext; |
37 import javax.naming.InitialContext; |
55 /** |
57 /** |
56 * Timeout in seconds for the validation test. |
58 * Timeout in seconds for the validation test. |
57 */ |
59 */ |
58 private static final int DB_TEST_TIMEOUT = 10; |
60 private static final int DB_TEST_TIMEOUT = 10; |
59 |
61 |
|
62 /** |
|
63 * Specifies the database dialect. |
|
64 */ |
60 public enum Dialect { |
65 public enum Dialect { |
61 Postgres |
66 Postgres |
62 } |
67 } |
63 |
68 |
64 /** |
69 /** |
65 * The database dialect to use. |
70 * The database dialect to use. |
66 * <p> |
71 * <p> |
67 * May be override by context parameter. |
72 * May be overridden by context parameter. |
68 * |
73 * |
69 * @see Constants#CTX_ATTR_DB_DIALECT |
74 * @see Constants#CTX_ATTR_DB_DIALECT |
70 */ |
75 */ |
71 private Dialect dialect = Dialect.Postgres; |
76 private Dialect dialect = Dialect.Postgres; |
72 |
77 |
73 /** |
78 /** |
74 * The default schema to test against when validating the connection. |
79 * The default schema to test against when validating the connection. |
75 * |
80 * <p> |
76 * May be overridden by context parameter. |
81 * May be overridden by context parameter. |
77 * |
82 * |
78 * @see Constants#CTX_ATTR_DB_SCHEMA |
83 * @see Constants#CTX_ATTR_DB_SCHEMA |
79 */ |
84 */ |
80 private static final String DB_DEFAULT_SCHEMA = "lightpit"; |
85 private static final String DB_DEFAULT_SCHEMA = "lightpit"; |
81 |
86 |
82 /** |
87 /** |
83 * The attribute name in the Servlet context under which an instance of this class can be found. |
88 * The attribute name in the Servlet context under which an instance of this class can be found. |
84 */ |
89 */ |
85 public static final String SC_ATTR_NAME = DatabaseFacade.class.getName(); |
90 public static final String SC_ATTR_NAME = DatabaseFacade.class.getName(); |
86 |
91 |
87 private static final String DS_JNDI_NAME = "jdbc/lightpit/app"; |
92 private static final String DS_JNDI_NAME = "jdbc/lightpit/app"; |
88 private DataSource dataSource; |
93 private DataSource dataSource; |
89 |
94 private DataAccessObjects dataAccessObjects; |
|
95 |
90 /** |
96 /** |
91 * Returns the data source. |
97 * Returns the data source. |
92 * |
98 * <p> |
93 * The Optional returned should never be empty. However, if something goes |
99 * The Optional returned should never be empty. However, if something goes |
94 * wrong during initialization, the data source might be absent. |
100 * wrong during initialization, the data source might be absent. |
95 * Hence, users of this data source are forced to check the existence. |
101 * Hence, users of this data source are forced to check the existence. |
96 * |
102 * |
97 * @return a data source |
103 * @return a data source |
98 */ |
104 */ |
99 public Optional<DataSource> getDataSource() { |
105 public Optional<DataSource> getDataSource() { |
100 // TODO: this should not be an optional, if an empty optional is actually an exception |
106 // TODO: this should not be an optional, if an empty optional is actually an exception |
101 return Optional.ofNullable(dataSource); |
107 return Optional.ofNullable(dataSource); |
102 } |
108 } |
103 |
109 |
|
110 /** |
|
111 * Returns the data access objects. |
|
112 * |
|
113 * @return an interface to obtain the data access objects |
|
114 */ |
|
115 public DataAccessObjects getDataAccessObjects() { |
|
116 return dataAccessObjects; |
|
117 } |
|
118 |
104 public Dialect getSQLDialect() { |
119 public Dialect getSQLDialect() { |
105 return dialect; |
120 return dialect; |
106 } |
121 } |
107 |
122 |
108 private static void checkConnection(DataSource ds, String testSchema) { |
123 private static void checkConnection(DataSource ds, String testSchema) { |
136 } |
151 } |
137 |
152 |
138 @Override |
153 @Override |
139 public void contextInitialized(ServletContextEvent sce) { |
154 public void contextInitialized(ServletContextEvent sce) { |
140 ServletContext sc = sce.getServletContext(); |
155 ServletContext sc = sce.getServletContext(); |
141 |
156 |
142 dataSource = null; |
157 dataSource = null; |
143 |
158 |
144 final String contextName = Optional |
159 final String contextName = Optional |
145 .ofNullable(sc.getInitParameter(Constants.CTX_ATTR_JNDI_CONTEXT)) |
160 .ofNullable(sc.getInitParameter(Constants.CTX_ATTR_JNDI_CONTEXT)) |
146 .orElse("java:comp/env"); |
161 .orElse("java:comp/env"); |
147 final String dbSchema = Optional |
162 final String dbSchema = Optional |
148 .ofNullable(sc.getInitParameter(Constants.CTX_ATTR_DB_SCHEMA)) |
163 .ofNullable(sc.getInitParameter(Constants.CTX_ATTR_DB_SCHEMA)) |
154 } catch (IllegalArgumentException ex) { |
169 } catch (IllegalArgumentException ex) { |
155 LOG.error("Unknown or unsupported database dialect {}. Defaulting to {}.", dbDialect, dialect); |
170 LOG.error("Unknown or unsupported database dialect {}. Defaulting to {}.", dbDialect, dialect); |
156 } |
171 } |
157 } |
172 } |
158 |
173 |
|
174 dataAccessObjects = createDataAccessObjects(dialect); |
|
175 |
159 try { |
176 try { |
160 LOG.debug("Trying to access JNDI context {}...", contextName); |
177 LOG.debug("Trying to access JNDI context {}...", contextName); |
161 Context initialCtx = new InitialContext(); |
178 Context initialCtx = new InitialContext(); |
162 Context ctx = (Context) initialCtx.lookup(contextName); |
179 Context ctx = (Context) initialCtx.lookup(contextName); |
163 |
180 |
167 checkConnection(dataSource, dbSchema); |
184 checkConnection(dataSource, dbSchema); |
168 } |
185 } |
169 } catch (NamingException | ClassCastException ex) { |
186 } catch (NamingException | ClassCastException ex) { |
170 LOG.error("Cannot access JNDI resources.", ex); |
187 LOG.error("Cannot access JNDI resources.", ex); |
171 } |
188 } |
172 |
189 |
173 sc.setAttribute(SC_ATTR_NAME, this); |
190 sc.setAttribute(SC_ATTR_NAME, this); |
174 LOG.info("Database facade injected into ServletContext."); |
191 LOG.info("Database facade injected into ServletContext."); |
|
192 } |
|
193 |
|
194 private static DataAccessObjects createDataAccessObjects(Dialect dialect) { |
|
195 switch (dialect) { |
|
196 case Postgres: |
|
197 return new PGDataAccessObjects(); |
|
198 default: |
|
199 throw new AssertionError("Non-exhaustive switch - this is a bug."); |
|
200 } |
175 } |
201 } |
176 |
202 |
177 @Override |
203 @Override |
178 public void contextDestroyed(ServletContextEvent sce) { |
204 public void contextDestroyed(ServletContextEvent sce) { |
179 dataSource = null; |
205 dataSource = null; |
180 } |
206 } |
181 } |
207 } |