cleanup and simplification of database access layer

Sat, 09 May 2020 17:01:29 +0200

author
Mike Becker <universe@uap-core.de>
date
Sat, 09 May 2020 17:01:29 +0200
changeset 34
824d4042c857
parent 33
fd8c40ff78c3
child 35
4fa33bfa8fb9

cleanup and simplification of database access layer

src/main/java/de/uapcore/lightpit/AbstractLightPITServlet.java file | annotate | diff | comparison | revisions
src/main/java/de/uapcore/lightpit/Constants.java file | annotate | diff | comparison | revisions
src/main/java/de/uapcore/lightpit/DatabaseFacade.java file | annotate | diff | comparison | revisions
src/main/java/de/uapcore/lightpit/Functions.java file | annotate | diff | comparison | revisions
src/main/java/de/uapcore/lightpit/HttpMethod.java file | annotate | diff | comparison | revisions
src/main/java/de/uapcore/lightpit/LightPITModule.java file | annotate | diff | comparison | revisions
src/main/java/de/uapcore/lightpit/Menu.java file | annotate | diff | comparison | revisions
src/main/java/de/uapcore/lightpit/MenuEntry.java file | annotate | diff | comparison | revisions
src/main/java/de/uapcore/lightpit/ModuleManager.java file | annotate | diff | comparison | revisions
src/main/java/de/uapcore/lightpit/RequestMapping.java file | annotate | diff | comparison | revisions
src/main/java/de/uapcore/lightpit/ResourceKey.java file | annotate | diff | comparison | revisions
src/main/java/de/uapcore/lightpit/ResponseType.java file | annotate | diff | comparison | revisions
src/main/java/de/uapcore/lightpit/dao/AbstractDao.java file | annotate | diff | comparison | revisions
src/main/java/de/uapcore/lightpit/dao/CoreDAOFactory.java file | annotate | diff | comparison | revisions
src/main/java/de/uapcore/lightpit/dao/DataAccessObjects.java file | annotate | diff | comparison | revisions
src/main/java/de/uapcore/lightpit/dao/GenericDao.java file | annotate | diff | comparison | revisions
src/main/java/de/uapcore/lightpit/dao/ModuleDao.java file | annotate | diff | comparison | revisions
src/main/java/de/uapcore/lightpit/dao/UserDao.java file | annotate | diff | comparison | revisions
src/main/java/de/uapcore/lightpit/dao/postgres/PGDataAccessObjects.java file | annotate | diff | comparison | revisions
src/main/java/de/uapcore/lightpit/dao/postgres/PGModuleDao.java file | annotate | diff | comparison | revisions
src/main/java/de/uapcore/lightpit/dao/postgres/PGUserDao.java file | annotate | diff | comparison | revisions
src/main/java/de/uapcore/lightpit/entities/Module.java file | annotate | diff | comparison | revisions
src/main/java/de/uapcore/lightpit/modules/ErrorModule.java file | annotate | diff | comparison | revisions
src/main/java/de/uapcore/lightpit/modules/HomeModule.java file | annotate | diff | comparison | revisions
src/main/java/de/uapcore/lightpit/modules/LanguageModule.java file | annotate | diff | comparison | revisions
src/main/java/de/uapcore/lightpit/modules/ModuleManagerModule.java file | annotate | diff | comparison | revisions
src/main/java/de/uapcore/lightpit/modules/VersionsModule.java file | annotate | diff | comparison | revisions
--- a/src/main/java/de/uapcore/lightpit/AbstractLightPITServlet.java	Sat May 09 15:19:21 2020 +0200
+++ b/src/main/java/de/uapcore/lightpit/AbstractLightPITServlet.java	Sat May 09 17:01:29 2020 +0200
@@ -1,8 +1,8 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
- * 
+ *
  * Copyright 2018 Mike Becker. All rights reserved.
- * 
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
  *
@@ -24,7 +24,7 @@
  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGE.
- * 
+ *
  */
 package de.uapcore.lightpit;
 
@@ -46,9 +46,9 @@
  * the necessary functionality for {@link LightPITModule}s.
  */
 public abstract class AbstractLightPITServlet extends HttpServlet {
-    
+
     private static final Logger LOG = LoggerFactory.getLogger(AbstractLightPITServlet.class);
-    
+
     private static final String HTML_FULL_DISPATCHER = Functions.jspPath("html_full");
 
     /**
@@ -66,14 +66,14 @@
     private interface HandlerMethod {
         ResponseType apply(HttpServletRequest t, HttpServletResponse u) throws IOException;
     }
-    
+
     /**
      * Invocation mapping gathered from the {@link RequestMapping} annotations.
-     * 
+     * <p>
      * Paths in this map must always start with a leading slash, although
      * the specification in the annotation must not start with a leading slash.
-     * 
-     * The reason for this is the different handling of empty paths in 
+     * <p>
+     * The reason for this is the different handling of empty paths in
      * {@link HttpServletRequest#getPathInfo()}.
      */
     private final Map<HttpMethod, Map<String, HandlerMethod>> mappings = new HashMap<>();
@@ -87,6 +87,11 @@
         return (ModuleManager) getServletContext().getAttribute(ModuleManager.SC_ATTR_NAME);
     }
 
+    /**
+     * Returns the annotated module information.
+     *
+     * @return the module annotation
+     */
     public final LightPITModule getModuleInfo() {
         return moduleInfo;
     }
@@ -152,8 +157,8 @@
                     if (params.length == 2
                             && HttpServletRequest.class.isAssignableFrom(params[0])
                             && HttpServletResponse.class.isAssignableFrom(params[1])) {
-                        
-                        final String requestPath = "/"+mapping.get().requestPath();
+
+                        final String requestPath = "/" + mapping.get().requestPath();
 
                         if (mappings.computeIfAbsent(mapping.get().method(), k -> new HashMap<>()).
                                 putIfAbsent(requestPath,
@@ -187,73 +192,72 @@
         mappings.clear();
         LOG.trace("{} destroyed", getServletName());
     }
-    
+
     /**
      * Sets the name of the dynamic fragment.
-     * 
+     * <p>
      * It is sufficient to specify the name without any extension. The extension
      * is added automatically if not specified.
-     * 
+     * <p>
      * The fragment must be located in the dynamic fragments folder.
-     * 
-     * @param req the servlet request object
+     *
+     * @param req          the servlet request object
      * @param fragmentName the name of the fragment
      * @see Constants#DYN_FRAGMENT_PATH_PREFIX
      */
     public void setDynamicFragment(HttpServletRequest req, String fragmentName) {
         req.setAttribute(Constants.REQ_ATTR_FRAGMENT, Functions.dynFragmentPath(fragmentName));
     }
-    
+
     /**
      * Specifies the name of an additional stylesheet used by the module.
-     * 
+     * <p>
      * Setting an additional stylesheet is optional, but quite common for HTML
      * output.
-     * 
+     * <p>
      * It is sufficient to specify the name without any extension. The extension
      * is added automatically if not specified.
-     * 
-     * @param req the servlet request object
+     *
+     * @param req        the servlet request object
      * @param stylesheet the name of the stylesheet
      */
     public void setStylesheet(HttpServletRequest req, String stylesheet) {
         req.setAttribute(Constants.REQ_ATTR_STYLESHEET, Functions.enforceExt(stylesheet, ".css"));
     }
-    
+
     private void forwardToFullView(HttpServletRequest req, HttpServletResponse resp)
             throws IOException, ServletException {
-        
+
         req.setAttribute(Constants.REQ_ATTR_MENU, getModuleManager().getMainMenu(getDatabaseFacade()));
         req.getRequestDispatcher(HTML_FULL_DISPATCHER).forward(req, resp);
     }
-    
+
     private Optional<HandlerMethod> findMapping(HttpMethod method, HttpServletRequest req) {
         return Optional.ofNullable(mappings.get(method)).map(
                 (rm) -> rm.get(Optional.ofNullable(req.getPathInfo()).orElse("/"))
         );
     }
-    
-    private void forwardAsSepcified(ResponseType type, HttpServletRequest req, HttpServletResponse resp)
+
+    private void forwardAsSpecified(ResponseType type, HttpServletRequest req, HttpServletResponse resp)
             throws ServletException, IOException {
         switch (type) {
-            case NONE: return;
+            case NONE:
+                return;
             case HTML_FULL:
                 forwardToFullView(req, resp);
                 return;
             // TODO: implement remaining response types
             default:
-                // this code should be unreachable
-                LOG.error("ResponseType switch is not exhaustive - this is a bug!");
-                throw new UnsupportedOperationException();
+                throw new AssertionError("ResponseType switch is not exhaustive - this is a bug!");
         }
     }
-    
+
     private void doProcess(HttpMethod method, HttpServletRequest req, HttpServletResponse resp)
             throws ServletException, IOException {
 
         // Synchronize module information with database
         getModuleManager().syncWithDatabase(getDatabaseFacade());
-        
+
         // choose the requested language as session language (if available) or fall back to english, otherwise
         HttpSession session = req.getSession();
         if (session.getAttribute(Constants.SESSION_ATTR_LANGUAGE) == null) {
@@ -261,28 +265,28 @@
             Optional<Locale> reqLocale = Optional.of(req.getLocale());
             Locale sessionLocale = reqLocale.filter((rl) -> availableLanguages.map((al) -> al.contains(rl.getLanguage())).orElse(false)).orElse(Locale.ENGLISH);
             session.setAttribute(Constants.SESSION_ATTR_LANGUAGE, sessionLocale);
-            LOG.debug("Settng language for new session {}: {}", session.getId(), sessionLocale.getDisplayLanguage());
+            LOG.debug("Setting language for new session {}: {}", session.getId(), sessionLocale.getDisplayLanguage());
         } else {
             Locale sessionLocale = (Locale) session.getAttribute(Constants.SESSION_ATTR_LANGUAGE);
             resp.setLocale(sessionLocale);
             LOG.trace("Continuing session {} with language {}", session.getId(), sessionLocale);
         }
-        
+
         // set some internal request attributes
         req.setAttribute(Constants.REQ_ATTR_PATH, Functions.fullPath(req));
         req.setAttribute(Constants.REQ_ATTR_MODULE_CLASSNAME, this.getClass().getName());
         Optional.ofNullable(moduleInfoELProxy).ifPresent((proxy) -> req.setAttribute(Constants.REQ_ATTR_MODULE_INFO, proxy));
-        
-        
+
+
         // call the handler, if available, or send an HTTP 404 error
         Optional<HandlerMethod> mapping = findMapping(method, req);
         if (mapping.isPresent()) {
-            forwardAsSepcified(mapping.get().apply(req, resp), req, resp);
+            forwardAsSpecified(mapping.get().apply(req, resp), req, resp);
         } else {
             resp.sendError(HttpServletResponse.SC_NOT_FOUND);
         }
     }
-    
+
     @Override
     protected final void doGet(HttpServletRequest req, HttpServletResponse resp)
             throws ServletException, IOException {
--- a/src/main/java/de/uapcore/lightpit/Constants.java	Sat May 09 15:19:21 2020 +0200
+++ b/src/main/java/de/uapcore/lightpit/Constants.java	Sat May 09 17:01:29 2020 +0200
@@ -1,8 +1,8 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
- * 
+ *
  * Copyright 2018 Mike Becker. All rights reserved.
- * 
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
  *
@@ -24,7 +24,7 @@
  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGE.
- * 
+ *
  */
 package de.uapcore.lightpit;
 
@@ -32,52 +32,52 @@
 
 /**
  * Contains all non-local scope constants used by the this application.
- * 
+ * <p>
  * Constants with (class) local scope are defined in their respective classes.
  */
 public final class Constants {
     public static final String JSP_PATH_PREFIX = "/WEB-INF/jsp/";
-    
+
     public static final String JSPF_PATH_PREFIX = "/WEB-INF/jspf/";
-    
+
     public static final String DYN_FRAGMENT_PATH_PREFIX = "/WEB-INF/dynamic_fragments/";
-    
-    
+
+
     /**
      * Name for the context parameter specifying the available languages.
      */
     public static final String CTX_ATTR_LANGUAGES = "available-languages";
-    
+
     /**
      * Name for the context parameter optionally specifying the JNDI context;
      */
     public static final String CTX_ATTR_JNDI_CONTEXT = "jndi-context";
-    
+
     /**
      * Name for the context parameter optionally specifying a database schema.
      */
     public static final String CTX_ATTR_DB_SCHEMA = "db-schema";
-    
+
     /**
      * Name for the context parameter optionally specifying a database dialect.
      */
     public static final String CTX_ATTR_DB_DIALECT = "db-dialect";
-    
+
     /**
      * Key for the request attribute containing the class name of the currently dispatching module.
      */
     public static final String REQ_ATTR_MODULE_CLASSNAME = fqn(AbstractLightPITServlet.class, "moduleClassname");
-    
+
     /**
      * Key for the request attribute containing the {@link LightPITModule} information of the currently dispatching module.
      */
     public static final String REQ_ATTR_MODULE_INFO = fqn(AbstractLightPITServlet.class, "moduleInfo");
-    
+
     /**
      * Key for the request attribute containing the menu list.
      */
     public static final String REQ_ATTR_MENU = fqn(AbstractLightPITServlet.class, "mainMenu");
-    
+
     /**
      * Key for the request attribute containing the full path information (servlet path + path info).
      */
@@ -85,22 +85,23 @@
 
     /**
      * Key for the name of the fragment which should be rendered.
-     */    
+     */
     public static final String REQ_ATTR_FRAGMENT = fqn(AbstractLightPITServlet.class, "fragment");
-    
+
     /**
      * Key for the name of the additional stylesheet used by a module.
-     */    
+     */
     public static final String REQ_ATTR_STYLESHEET = fqn(AbstractLightPITServlet.class, "extraCss");
-    
-    
+
+
     /**
      * Key for the current language selection within the session.
      */
     public static final String SESSION_ATTR_LANGUAGE = fqn(AbstractLightPITServlet.class, "language");
-    
+
     /**
      * This class is not instantiatable.
      */
-    private Constants() {}
+    private Constants() {
+    }
 }
--- a/src/main/java/de/uapcore/lightpit/DatabaseFacade.java	Sat May 09 15:19:21 2020 +0200
+++ b/src/main/java/de/uapcore/lightpit/DatabaseFacade.java	Sat May 09 17:01:29 2020 +0200
@@ -1,8 +1,8 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
- * 
+ *
  * Copyright 2018 Mike Becker. All rights reserved.
- * 
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
  *
@@ -24,10 +24,12 @@
  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGE.
- * 
+ *
  */
 package de.uapcore.lightpit;
 
+import de.uapcore.lightpit.dao.DataAccessObjects;
+import de.uapcore.lightpit.dao.postgres.PGDataAccessObjects;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -57,6 +59,9 @@
      */
     private static final int DB_TEST_TIMEOUT = 10;
 
+    /**
+     * Specifies the database dialect.
+     */
     public enum Dialect {
         Postgres
     }
@@ -64,21 +69,21 @@
     /**
      * The database dialect to use.
      * <p>
-     * May be override by context parameter.
+     * May be overridden by context parameter.
      *
      * @see Constants#CTX_ATTR_DB_DIALECT
      */
     private Dialect dialect = Dialect.Postgres;
-    
+
     /**
      * The default schema to test against when validating the connection.
-     * 
+     * <p>
      * May be overridden by context parameter.
-     * 
+     *
      * @see Constants#CTX_ATTR_DB_SCHEMA
      */
     private static final String DB_DEFAULT_SCHEMA = "lightpit";
-    
+
     /**
      * The attribute name in the Servlet context under which an instance of this class can be found.
      */
@@ -86,21 +91,31 @@
 
     private static final String DS_JNDI_NAME = "jdbc/lightpit/app";
     private DataSource dataSource;
-    
+    private DataAccessObjects dataAccessObjects;
+
     /**
      * Returns the data source.
-     * 
+     * <p>
      * The Optional returned should never be empty. However, if something goes
      * wrong during initialization, the data source might be absent.
      * Hence, users of this data source are forced to check the existence.
-     * 
+     *
      * @return a data source
      */
     public Optional<DataSource> getDataSource() {
         // TODO: this should not be an optional, if an empty optional is actually an exception
         return Optional.ofNullable(dataSource);
     }
-    
+
+    /**
+     * Returns the data access objects.
+     *
+     * @return an interface to obtain the data access objects
+     */
+    public DataAccessObjects getDataAccessObjects() {
+        return dataAccessObjects;
+    }
+
     public Dialect getSQLDialect() {
         return dialect;
     }
@@ -138,9 +153,9 @@
     @Override
     public void contextInitialized(ServletContextEvent sce) {
         ServletContext sc = sce.getServletContext();
-        
+
         dataSource = null;
-        
+
         final String contextName = Optional
                 .ofNullable(sc.getInitParameter(Constants.CTX_ATTR_JNDI_CONTEXT))
                 .orElse("java:comp/env");
@@ -156,6 +171,8 @@
             }
         }
 
+        dataAccessObjects = createDataAccessObjects(dialect);
+
         try {
             LOG.debug("Trying to access JNDI context {}...", contextName);
             Context initialCtx = new InitialContext();
@@ -169,13 +186,22 @@
         } catch (NamingException | ClassCastException ex) {
             LOG.error("Cannot access JNDI resources.", ex);
         }
-        
+
         sc.setAttribute(SC_ATTR_NAME, this);
         LOG.info("Database facade injected into ServletContext.");
     }
 
+    private static DataAccessObjects createDataAccessObjects(Dialect dialect) {
+        switch (dialect) {
+            case Postgres:
+                return new PGDataAccessObjects();
+            default:
+                throw new AssertionError("Non-exhaustive switch - this is a bug.");
+        }
+    }
+
     @Override
     public void contextDestroyed(ServletContextEvent sce) {
         dataSource = null;
-    }    
+    }
 }
--- a/src/main/java/de/uapcore/lightpit/Functions.java	Sat May 09 15:19:21 2020 +0200
+++ b/src/main/java/de/uapcore/lightpit/Functions.java	Sat May 09 17:01:29 2020 +0200
@@ -1,8 +1,8 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
- * 
+ *
  * Copyright 2018 Mike Becker. All rights reserved.
- * 
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
  *
@@ -24,7 +24,7 @@
  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGE.
- * 
+ *
  */
 package de.uapcore.lightpit;
 
@@ -39,13 +39,13 @@
  * Contains common static functions.
  */
 public final class Functions {
-    
+
     private static final Logger LOG = LoggerFactory.getLogger(Functions.class);
 
     public static Optional<String[]> availableLanguages(ServletContext ctx) {
         return Optional.ofNullable(ctx.getInitParameter(Constants.CTX_ATTR_LANGUAGES)).map((x) -> x.split("\\s*,\\s*"));
     }
-    
+
     public static String enforceExt(String filename, String ext) {
         return filename.endsWith(ext) ? filename : filename + ext;
     }
@@ -53,23 +53,23 @@
     public static String jspPath(String filename) {
         return enforceExt(Constants.JSP_PATH_PREFIX + filename, ".jsp");
     }
-    
+
     public static String jspfPath(String filename) {
         return enforceExt(Constants.JSPF_PATH_PREFIX + filename, ".jspf");
     }
-    
+
     public static String dynFragmentPath(String filename) {
         return enforceExt(Constants.DYN_FRAGMENT_PATH_PREFIX + filename, ".jsp");
     }
-    
+
     public static String fqn(String base, String name) {
-        return base+"."+name;
+        return base + "." + name;
     }
 
     public static String fqn(Class<?> clazz, String name) {
         return fqn(clazz.getName(), name);
     }
-    
+
     public static String fullPath(LightPITModule module, RequestMapping mapping) {
         StringBuilder sb = new StringBuilder();
         sb.append(module.modulePath());
@@ -80,17 +80,17 @@
         }
         return sb.toString();
     }
-    
+
     public static String fullPath(HttpServletRequest req) {
         return req.getServletPath() + Optional.ofNullable(req.getPathInfo()).orElse("");
     }
-    
+
     /**
      * Returns the module path of the given LightPIT Servlet module.
-     * 
+     * <p>
      * If you specify a malformed LightPIT servlet, which does not have a module
      * annotation, the path to the <code>/error/404.html</code> page is returned.
-     * 
+     *
      * @param clazz the servlet class
      * @return the module path
      */
@@ -106,9 +106,10 @@
             return "/error/404.html";
         }
     }
-    
+
     /**
      * This class is not instantiatable.
      */
-    private Functions() {}
+    private Functions() {
+    }
 }
--- a/src/main/java/de/uapcore/lightpit/HttpMethod.java	Sat May 09 15:19:21 2020 +0200
+++ b/src/main/java/de/uapcore/lightpit/HttpMethod.java	Sat May 09 17:01:29 2020 +0200
@@ -1,8 +1,8 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
- * 
+ *
  * Copyright 2018 Mike Becker. All rights reserved.
- * 
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
  *
@@ -24,7 +24,7 @@
  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGE.
- * 
+ *
  */
 package de.uapcore.lightpit;
 
--- a/src/main/java/de/uapcore/lightpit/LightPITModule.java	Sat May 09 15:19:21 2020 +0200
+++ b/src/main/java/de/uapcore/lightpit/LightPITModule.java	Sat May 09 17:01:29 2020 +0200
@@ -1,8 +1,8 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
- * 
+ *
  * Copyright 2018 Mike Becker. All rights reserved.
- * 
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
  *
@@ -24,7 +24,7 @@
  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGE.
- * 
+ *
  */
 package de.uapcore.lightpit;
 
@@ -34,7 +34,7 @@
 
 /**
  * Contains information about a LightPIT module.
- * 
+ * <p>
  * This annotation is typically used to annotate the {@link WebServlet} which
  * implements the module's functionality.
  */
@@ -44,57 +44,59 @@
 public @interface LightPITModule {
     /**
      * Base name of the module specific resource bundle.
+     *
      * @return a base name suitable for the JSTL tag 'setBundle'.
      */
     String bundleBaseName();
-    
+
     /**
      * An array of required modules, identified by the string representation of
      * their class names.
+     *
      * @return an array of class names of required modules
      */
     String[] requires() default {};
-    
+
     /**
      * The path for this module, which will also be used for the menu entry.
-     * 
+     * <p>
      * This path must adhere to the URL pattern of the Servlet but must not
      * contain any starting or trailing slashes.
-     * 
+     *
      * @return the relative module path
      */
     String modulePath();
-    
+
     /**
      * Returns the properties key for the module name.
-     * 
+     *
      * @return the properties key
      */
     String nameKey() default "name";
-    
+
     /**
      * Returns the properties key for the module description.
-     * 
+     *
      * @return the properties key
      */
     String descKey() default "description";
-    
-    
+
+
     /**
      * Returns the properties key for the menu label.
-     * 
+     * <p>
      * Set this string to empty string, if the module should be hidden from
      * the menu.
-     * 
+     *
      * @return the properties key
      */
     String menuKey() default "menuLabel";
-    
+
     /**
      * Returns the properties key for the page title.
-     * 
+     * <p>
      * By default this is the same as the menu label.
-     * 
+     *
      * @return the properties key
      */
     String titleKey() default "menuLabel";
@@ -169,6 +171,6 @@
         public String getDescKey() {
             return descKey;
         }
-        
+
     }
 }
--- a/src/main/java/de/uapcore/lightpit/Menu.java	Sat May 09 15:19:21 2020 +0200
+++ b/src/main/java/de/uapcore/lightpit/Menu.java	Sat May 09 17:01:29 2020 +0200
@@ -1,8 +1,8 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
- * 
+ *
  * Copyright 2018 Mike Becker. All rights reserved.
- * 
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
  *
@@ -24,7 +24,7 @@
  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGE.
- * 
+ *
  */
 package de.uapcore.lightpit;
 
@@ -35,30 +35,30 @@
 /**
  * Maps a resource key for the menu label to the path name for the underlying
  * site.
- * 
+ * <p>
  * Objects of this class are internally instantiated by the
  * {@link ModuleManager}.
  */
 public class Menu extends MenuEntry {
-    
+
     private final List<MenuEntry> entries = new ArrayList<>();
     private final List<MenuEntry> immutableEntries = Collections.unmodifiableList(entries);
-    
+
     /**
      * Class name of the module for which this menu is built.
      */
     private String moduleClassName;
-    
-    
+
+
     public Menu() {
         super();
     }
-    
+
     public Menu(String moduleClassName, ResourceKey resourceKey, String pathName) {
         super(resourceKey, pathName);
         this.moduleClassName = moduleClassName;
     }
-    
+
     public void setModuleClassName(String moduleClassName) {
         this.moduleClassName = moduleClassName;
     }
@@ -69,7 +69,7 @@
 
     /**
      * Sets a new list of menu entries for this menu.
-     * 
+     *
      * @param entries the list of new menu entries
      */
     public void setEntries(List<MenuEntry> entries) {
@@ -80,15 +80,16 @@
 
     /**
      * Retrieves an immutable list of menu entries for this menu.
-     * 
+     *
      * @return the list of menu entries
      */
     public List<MenuEntry> getEntries() {
         return immutableEntries;
     }
-    
+
     /**
      * Adds a new menu entry to this menu.
+     *
      * @param entry the menu entry to add
      */
     public void addMenuEntry(MenuEntry entry) {
--- a/src/main/java/de/uapcore/lightpit/MenuEntry.java	Sat May 09 15:19:21 2020 +0200
+++ b/src/main/java/de/uapcore/lightpit/MenuEntry.java	Sat May 09 17:01:29 2020 +0200
@@ -1,8 +1,8 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
- * 
+ *
  * Copyright 2018 Mike Becker. All rights reserved.
- * 
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
  *
@@ -24,24 +24,24 @@
  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGE.
- * 
+ *
  */
 package de.uapcore.lightpit;
 
 /**
  * Maps a resource key for the menu label to the path name for the underlying
  * site.
- * 
+ * <p>
  * Objects of this class are internally instantiated by the
  * {@link ModuleManager}.
  */
 public class MenuEntry {
-    
+
     /**
      * Resource key for the menu label.
      */
     private ResourceKey resourceKey;
-    
+
     /**
      * Path name of the module, linked by this menu entry.
      */
@@ -70,5 +70,5 @@
     public String getPathName() {
         return pathName;
     }
-    
+
 }
--- a/src/main/java/de/uapcore/lightpit/ModuleManager.java	Sat May 09 15:19:21 2020 +0200
+++ b/src/main/java/de/uapcore/lightpit/ModuleManager.java	Sat May 09 17:01:29 2020 +0200
@@ -1,8 +1,8 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
- * 
+ *
  * Copyright 2018 Mike Becker. All rights reserved.
- * 
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
  *
@@ -24,12 +24,10 @@
  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGE.
- * 
+ *
  */
 package de.uapcore.lightpit;
 
-import de.uapcore.lightpit.dao.CoreDAOFactory;
-import de.uapcore.lightpit.dao.ModuleDao;
 import de.uapcore.lightpit.entities.Module;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -50,25 +48,25 @@
  */
 @WebListener
 public final class ModuleManager implements ServletContextListener {
-    
+
     private static final Logger LOG = LoggerFactory.getLogger(ModuleManager.class);
-    
+
     /**
      * The attribute name in the servlet context under which an instance of this class can be found.
      */
     public static final String SC_ATTR_NAME = ModuleManager.class.getName();
     private ServletContext sc;
-    
+
     /**
      * Maps class names to module information.
      */
     private final Map<String, LightPITModule> registeredModules = new HashMap<>();
-    
+
     /**
      * This flag is true, when synchronization is needed.
      */
     private final AtomicBoolean dirty = new AtomicBoolean(true);
-    
+
     @Override
     public void contextInitialized(ServletContextEvent sce) {
         sc = sce.getServletContext();
@@ -81,27 +79,27 @@
     public void contextDestroyed(ServletContextEvent sce) {
         unloadAll();
     }
-    
+
     private Optional<LightPITModule> getModuleInfo(Registration reg) {
         try {
             final Class<?> scclass = Class.forName(reg.getClassName());
-            
+
             final boolean lpservlet = AbstractLightPITServlet.class.isAssignableFrom(scclass);
             final boolean lpmodule = scclass.isAnnotationPresent(LightPITModule.class);
-            
+
             if (lpservlet && !lpmodule) {
                 LOG.warn(
-                    "{} is a LightPIT Servlet but is missing the module annotation.",
-                    reg.getClassName()
+                        "{} is a LightPIT Servlet but is missing the module annotation.",
+                        reg.getClassName()
                 );
             } else if (!lpservlet && lpmodule) {
                 LOG.warn(
-                    "{} is annotated as a LightPIT Module but does not extend {}.",
-                    reg.getClassName(),
-                    AbstractLightPITServlet.class.getSimpleName()
+                        "{} is annotated as a LightPIT Module but does not extend {}.",
+                        reg.getClassName(),
+                        AbstractLightPITServlet.class.getSimpleName()
                 );
             }
-            
+
             if (lpservlet && lpmodule) {
                 final LightPITModule moduleInfo = scclass.getAnnotation(LightPITModule.class);
                 return Optional.of(moduleInfo);
@@ -115,28 +113,28 @@
                     ex.getMessage()
             );
             return Optional.empty();
-        }        
+        }
     }
-    
+
     private void handleServletRegistration(String name, Registration reg) {
         final Optional<LightPITModule> moduleInfo = getModuleInfo(reg);
         if (moduleInfo.isPresent()) {
-            registeredModules.put(reg.getClassName(), moduleInfo.get());            
+            registeredModules.put(reg.getClassName(), moduleInfo.get());
             LOG.info("Module detected: {}", name);
         } else {
             LOG.debug("Servlet {} is no module, skipping.", name);
         }
     }
-    
+
     /**
      * Scans for modules and reloads them all.
      */
     public void reloadAll() {
         registeredModules.clear();
         sc.getServletRegistrations().forEach(this::handleServletRegistration);
-        
+
         // TODO: implement dependency resolver
-        
+
         dirty.set(true);
         LOG.info("Modules loaded.");
     }
@@ -157,8 +155,9 @@
         if (dirty.compareAndSet(true, false)) {
             if (db.getDataSource().isPresent()) {
                 try (Connection conn = db.getDataSource().get().getConnection()) {
-                    final ModuleDao moduleDao = CoreDAOFactory.getModuleDao(db.getSQLDialect());
-                    moduleDao.syncRegisteredModuleClasses(conn, registeredModules.entrySet());
+                    db.getDataAccessObjects()
+                            .getModuleDao()
+                            .syncRegisteredModuleClasses(conn, registeredModules.entrySet());
                 } catch (SQLException ex) {
                     LOG.error("Unexpected SQL Exception", ex);
                 }
@@ -169,7 +168,7 @@
             LOG.trace("Module information clean - no synchronization required.");
         }
     }
-    
+
     /**
      * Unloads all found modules.
      */
@@ -180,17 +179,16 @@
 
     /**
      * Returns the main menu.
-     * 
+     *
      * @param db the interface to the database
      * @return a list of menus belonging to the main menu
      */
     public List<Menu> getMainMenu(DatabaseFacade db) {
         // TODO: user specific menu
-        
+
         if (db.getDataSource().isPresent()) {
             try (Connection conn = db.getDataSource().get().getConnection()) {
-                final ModuleDao dao = CoreDAOFactory.getModuleDao(db.getSQLDialect());
-                final List<Module> modules = dao.listAll(conn);
+                final List<Module> modules = db.getDataAccessObjects().getModuleDao().list(conn);
 
                 return modules
                         .stream()
@@ -211,12 +209,12 @@
             return Collections.emptyList();
         }
     }
-    
+
     /**
      * Returns an unmodifiable map of all registered modules.
-     * 
+     * <p>
      * The key is the classname of the module.
-     * 
+     *
      * @return the map of registered modules
      */
     public Map<String, LightPITModule> getRegisteredModules() {
--- a/src/main/java/de/uapcore/lightpit/RequestMapping.java	Sat May 09 15:19:21 2020 +0200
+++ b/src/main/java/de/uapcore/lightpit/RequestMapping.java	Sat May 09 17:01:29 2020 +0200
@@ -1,8 +1,8 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
- * 
+ *
  * Copyright 2018 Mike Becker. All rights reserved.
- * 
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
  *
@@ -24,20 +24,16 @@
  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGE.
- * 
+ *
  */
 package de.uapcore.lightpit;
 
-import java.lang.annotation.Documented;
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
+import java.lang.annotation.*;
 
 
 /**
  * Maps requests to methods.
- * 
+ * <p>
  * This annotation is used to annotate methods within classes which
  * override {@link AbstractLightPITServlet}.
  */
@@ -45,31 +41,31 @@
 @Retention(RetentionPolicy.RUNTIME)
 @Target(ElementType.METHOD)
 public @interface RequestMapping {
-    
+
     /**
      * Specifies the HTTP method.
-     * 
+     *
      * @return the HTTP method handled by the annotated Java method
      */
     HttpMethod method();
 
     /**
      * Specifies the request path relative to the module path.
-     * 
+     * <p>
      * If a menu key is specified, this is also the path, which is linked
      * by the menu entry.
-     * 
+     * <p>
      * The path must be specified <em>without</em> leading and trailing slash.
-     * 
+     *
      * @return the request path the annotated method should handle
      */
     String requestPath() default "";
-    
+
     /**
      * Returns the properties key for the (sub) menu label.
-     * 
+     * <p>
      * This should only be used for {@link HttpMethod#GET} requests.
-     * 
+     *
      * @return the properties key
      */
     String menuKey() default "";
--- a/src/main/java/de/uapcore/lightpit/ResourceKey.java	Sat May 09 15:19:21 2020 +0200
+++ b/src/main/java/de/uapcore/lightpit/ResourceKey.java	Sat May 09 17:01:29 2020 +0200
@@ -1,8 +1,8 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
- * 
+ *
  * Copyright 2018 Mike Becker. All rights reserved.
- * 
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
  *
@@ -24,7 +24,7 @@
  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGE.
- * 
+ *
  */
 package de.uapcore.lightpit;
 
@@ -34,9 +34,9 @@
 public final class ResourceKey {
     private String bundle;
     private String key;
-    
+
     public ResourceKey() {
-        
+
     }
 
     public ResourceKey(String bundle, String key) {
@@ -55,7 +55,7 @@
     public void setKey(String key) {
         this.key = key;
     }
-    
+
     public String getKey() {
         return key;
     }
--- a/src/main/java/de/uapcore/lightpit/ResponseType.java	Sat May 09 15:19:21 2020 +0200
+++ b/src/main/java/de/uapcore/lightpit/ResponseType.java	Sat May 09 17:01:29 2020 +0200
@@ -1,8 +1,8 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
- * 
+ *
  * Copyright 2018 Mike Becker. All rights reserved.
- * 
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
  *
@@ -24,7 +24,7 @@
  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGE.
- * 
+ *
  */
 package de.uapcore.lightpit;
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/de/uapcore/lightpit/dao/AbstractDao.java	Sat May 09 17:01:29 2020 +0200
@@ -0,0 +1,55 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2018 Mike Becker. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+package de.uapcore.lightpit.dao;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+
+public abstract class AbstractDao<T> implements GenericDao<T> {
+
+    protected abstract PreparedStatement listQuery(Connection connection) throws SQLException;
+
+    protected abstract T mapColumns(ResultSet result) throws SQLException;
+
+    @Override
+    public List<T> list(Connection conn) throws SQLException {
+        List<T> list = new ArrayList<>();
+        try (PreparedStatement stmt = listQuery(conn);
+             ResultSet result = stmt.executeQuery()) {
+            while (result.next()) {
+                list.add(mapColumns(result));
+            }
+        }
+        return list;
+    }
+}
--- a/src/main/java/de/uapcore/lightpit/dao/CoreDAOFactory.java	Sat May 09 15:19:21 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,49 +0,0 @@
-/*
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
- * 
- * Copyright 2018 Mike Becker. All rights reserved.
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- *   1. Redistributions of source code must retain the above copyright
- *      notice, this list of conditions and the following disclaimer.
- *
- *   2. Redistributions in binary form must reproduce the above copyright
- *      notice, this list of conditions and the following disclaimer in the
- *      documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- * 
- */
-package de.uapcore.lightpit.dao;
-
-import de.uapcore.lightpit.DatabaseFacade;
-
-public final class CoreDAOFactory {
-
-    private static final ModuleDao moduleDao = new ModuleDao();
-
-    private CoreDAOFactory() {
-    }
-
-    public static ModuleDao getModuleDao(DatabaseFacade.Dialect dialect) {
-        // TODO: this is idiotic, we would not change the dialect while the app is running
-        switch (dialect) {
-            case Postgres:
-                return moduleDao;
-            default:
-                throw new AssertionError("Switch was not exhaustive.");
-        }
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/de/uapcore/lightpit/dao/DataAccessObjects.java	Sat May 09 17:01:29 2020 +0200
@@ -0,0 +1,36 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2018 Mike Becker. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+package de.uapcore.lightpit.dao;
+
+public interface DataAccessObjects {
+
+    ModuleDao getModuleDao();
+
+    UserDao getUserDao();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/de/uapcore/lightpit/dao/GenericDao.java	Sat May 09 17:01:29 2020 +0200
@@ -0,0 +1,44 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2018 Mike Becker. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+package de.uapcore.lightpit.dao;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.util.List;
+
+public interface GenericDao<T> {
+    /**
+     * Returns a list of all entities.
+     *
+     * @param connection conn the connection to use
+     * @return a list of all objects
+     * @throws SQLException on any kind of SQL errors
+     */
+    List<T> list(Connection connection) throws SQLException;
+}
--- a/src/main/java/de/uapcore/lightpit/dao/ModuleDao.java	Sat May 09 15:19:21 2020 +0200
+++ b/src/main/java/de/uapcore/lightpit/dao/ModuleDao.java	Sat May 09 17:01:29 2020 +0200
@@ -1,8 +1,8 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
- * 
+ *
  * Copyright 2018 Mike Becker. All rights reserved.
- * 
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
  *
@@ -24,120 +24,29 @@
  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGE.
- * 
+ *
  */
 package de.uapcore.lightpit.dao;
 
 import de.uapcore.lightpit.LightPITModule;
 import de.uapcore.lightpit.entities.Module;
 
-import java.sql.*;
-import java.util.ArrayList;
-import java.util.List;
+import java.sql.Connection;
+import java.sql.SQLException;
 import java.util.Map;
 import java.util.Set;
 
-public class ModuleDao {
-
-    /**
-     * Maps database columns to POJO fields.
-     *
-     * @param result the database result set
-     * @param mod    the POJO
-     * @throws SQLException on any kind of SQL errors
-     */
-    protected void mapColumns(ResultSet result, Module mod) throws SQLException {
-        mod.setModID(result.getInt("modid"));
-        mod.setClassname(result.getString("classname"));
-        mod.setVisible(result.getBoolean("visible"));
-        mod.setPriority(result.getInt("priority"));
-    }
-
+public interface ModuleDao extends GenericDao<Module> {
 
     /**
-     * Must return a prepared statement for a single object query with the specified properties.
-     *
-     * <ul>
-     * <li>Parameter 1: classname</li>
-     * <li>Result field 1: visible</li>
-     * </ul>
-     *
-     * @param conn the connection to use
-     * @return the prepared statement
-     * @throws SQLException on any kind of SQL errors
-     */
-    protected PreparedStatement moduleCheckStatement(Connection conn) throws SQLException {
-        return conn.prepareStatement("SELECT visible FROM lpitcore_module WHERE classname = ?");
-    }
-
-    /**
-     * Must return a prepared statement for insertion with the specified properties.
-     *
-     * <ul>
-     * <li>Parameter 1: classname</li>
-     * <li>Parameter 2: visible</li>
-     * <li>Parameter 3: priority</li>
-     * </ul>
-     *
-     * @param conn the connection to use
-     * @return the prepared statement
-     * @throws SQLException on any kind of SQL errors
-     */
-    protected PreparedStatement moduleInsertStatement(Connection conn) throws SQLException {
-        return conn.prepareStatement("INSERT INTO lpitcore_module (classname, visible, priority) VALUES (?, ?, ?)");
-    }
-    
-    /**
      * Synchronizes a set of registered module classes with the database.
-     *
+     * <p>
      * Inserts module classes which are not known to the database and sets them to be visible by default.
      * Module classes known to the database, which are not in the given set, are ignored.
      *
-     * @param conn the connection to use
+     * @param conn      the connection to use
      * @param moduleSet the module set to synchronize
      * @throws SQLException on any kind of SQL errors
      */
-    public final void syncRegisteredModuleClasses(Connection conn, Set<Map.Entry<String, LightPITModule>> moduleSet) throws SQLException {
-                
-        PreparedStatement
-                check = moduleCheckStatement(conn),
-                insert = moduleInsertStatement(conn);
-        insert.setBoolean(2, true);
-        // update/delete not required, we do this in the module management UI
-
-        for (Map.Entry<String, LightPITModule> modEntry : moduleSet) {
-            if (modEntry.getValue().systemModule()) continue;
-
-            check.setString(1, modEntry.getKey());
-            try (ResultSet r = check.executeQuery()) {
-                if (!r.next()) {
-                    insert.setString(1, modEntry.getKey());
-                    insert.setInt(3, modEntry.getValue().defaultPriority());
-                    insert.executeUpdate();
-                }
-            }
-        }
-    }
-
-    /**
-     * Returns a list of all modules known by the database.
-     *
-     * Keep in mind, that system modules are never known to the database.
-     *
-     * @param conn the connection to use
-     * @return a list of all modules known by the database
-     * @throws SQLException on any kind of SQL errors
-     */
-    public List<Module> listAll(Connection conn) throws SQLException {
-        List<Module> list = new ArrayList<>();
-        try (Statement stmt = conn.createStatement();
-                ResultSet result = stmt.executeQuery("SELECT * FROM lpitcore_module")) {
-            while (result.next()) {
-                final Module mod = new Module();
-                mapColumns(result, mod);
-                list.add(mod);
-            }
-        }
-        return list;
-    }
+    void syncRegisteredModuleClasses(Connection conn, Set<Map.Entry<String, LightPITModule>> moduleSet) throws SQLException;
 }
--- a/src/main/java/de/uapcore/lightpit/dao/UserDao.java	Sat May 09 15:19:21 2020 +0200
+++ b/src/main/java/de/uapcore/lightpit/dao/UserDao.java	Sat May 09 17:01:29 2020 +0200
@@ -1,8 +1,8 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
- * 
+ *
  * Copyright 2018 Mike Becker. All rights reserved.
- * 
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
  *
@@ -30,50 +30,6 @@
 
 import de.uapcore.lightpit.entities.User;
 
-import java.sql.Connection;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.sql.Statement;
-import java.util.ArrayList;
-import java.util.List;
-
-public class UserDao {
-
-    /**
-     * Maps SQL columns to POJO fields.
-     *
-     * @param result the database result set
-     * @param user   the POJO
-     * @throws SQLException on any kind of SQL errors
-     */
-    protected void mapColumns(ResultSet result, User user) throws SQLException {
-        user.setUserID(result.getInt("userid"));
-        user.setUsername(result.getString("username"));
-        user.setGivenname(result.getString("givenname"));
-        user.setLastname(result.getString("lastname"));
-    }
+public interface UserDao extends GenericDao<User> {
 
-    /**
-     * Returns a list of all users ordered by their username.
-     * <p>
-     * Does not return reserved system users with negative user IDs.
-     *
-     * @param conn the connection to use
-     * @return a list of all users
-     * @throws SQLException on any kind of SQL errors
-     */
-    public List<User> listAll(Connection conn) throws SQLException {
-        List<User> list = new ArrayList<>();
-        try (
-                Statement stmt = conn.createStatement();
-                ResultSet result = stmt.executeQuery(
-                        "SELECT * FROM lpitcore_user WHERE userid >= 0 ORDER BY username")) {
-            while (result.next()) {
-                final User user = new User();
-                mapColumns(result, user);
-                list.add(user);
-            }
-        }
-        return list;
-    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/de/uapcore/lightpit/dao/postgres/PGDataAccessObjects.java	Sat May 09 17:01:29 2020 +0200
@@ -0,0 +1,49 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2018 Mike Becker. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+package de.uapcore.lightpit.dao.postgres;
+
+import de.uapcore.lightpit.dao.DataAccessObjects;
+import de.uapcore.lightpit.dao.ModuleDao;
+import de.uapcore.lightpit.dao.UserDao;
+
+public class PGDataAccessObjects implements DataAccessObjects {
+
+    private final ModuleDao moduleDao = new PGModuleDao();
+    private final UserDao userDao = new PGUserDao();
+
+    @Override
+    public ModuleDao getModuleDao() {
+        return moduleDao;
+    }
+
+    @Override
+    public UserDao getUserDao() {
+        return userDao;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/de/uapcore/lightpit/dao/postgres/PGModuleDao.java	Sat May 09 17:01:29 2020 +0200
@@ -0,0 +1,81 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2018 Mike Becker. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+package de.uapcore.lightpit.dao.postgres;
+
+import de.uapcore.lightpit.LightPITModule;
+import de.uapcore.lightpit.dao.AbstractDao;
+import de.uapcore.lightpit.dao.ModuleDao;
+import de.uapcore.lightpit.entities.Module;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.Map;
+import java.util.Set;
+
+public final class PGModuleDao extends AbstractDao<Module> implements ModuleDao {
+
+    @Override
+    protected PreparedStatement listQuery(Connection connection) throws SQLException {
+        return connection.prepareStatement("select * from lpitcore_module");
+    }
+
+    @Override
+    protected Module mapColumns(ResultSet result) throws SQLException {
+        final var mod = new Module();
+        mod.setModID(result.getInt("modid"));
+        mod.setClassname(result.getString("classname"));
+        mod.setVisible(result.getBoolean("visible"));
+        mod.setPriority(result.getInt("priority"));
+        return mod;
+    }
+
+    @Override
+    public void syncRegisteredModuleClasses(Connection conn, Set<Map.Entry<String, LightPITModule>> moduleSet) throws SQLException {
+
+        var check = conn.prepareStatement("select visible from lpitcore_module where classname = ?");
+        var insert = conn.prepareStatement("insert into lpitcore_module (classname, visible, priority) values (?, ?, ?)");
+        insert.setBoolean(2, true);
+        // update/delete not required, we do this in the module management UI
+
+        for (Map.Entry<String, LightPITModule> modEntry : moduleSet) {
+            if (modEntry.getValue().systemModule()) continue;
+
+            check.setString(1, modEntry.getKey());
+            try (ResultSet r = check.executeQuery()) {
+                if (!r.next()) {
+                    insert.setString(1, modEntry.getKey());
+                    insert.setInt(3, modEntry.getValue().defaultPriority());
+                    insert.executeUpdate();
+                }
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/de/uapcore/lightpit/dao/postgres/PGUserDao.java	Sat May 09 17:01:29 2020 +0200
@@ -0,0 +1,56 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2018 Mike Becker. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+package de.uapcore.lightpit.dao.postgres;
+
+import de.uapcore.lightpit.dao.AbstractDao;
+import de.uapcore.lightpit.dao.UserDao;
+import de.uapcore.lightpit.entities.User;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+public final class PGUserDao extends AbstractDao<User> implements UserDao {
+
+    @Override
+    protected User mapColumns(ResultSet result) throws SQLException {
+        final var user = new User();
+        user.setUserID(result.getInt("userid"));
+        user.setUsername(result.getString("username"));
+        user.setGivenname(result.getString("givenname"));
+        user.setLastname(result.getString("lastname"));
+        return user;
+    }
+
+    @Override
+    protected PreparedStatement listQuery(Connection conn) throws SQLException {
+        return conn.prepareStatement("select * from lpitcore_user where userid >= 0 order by username");
+    }
+}
--- a/src/main/java/de/uapcore/lightpit/entities/Module.java	Sat May 09 15:19:21 2020 +0200
+++ b/src/main/java/de/uapcore/lightpit/entities/Module.java	Sat May 09 17:01:29 2020 +0200
@@ -1,8 +1,8 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
- * 
+ *
  * Copyright 2018 Mike Becker. All rights reserved.
- * 
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
  *
--- a/src/main/java/de/uapcore/lightpit/modules/ErrorModule.java	Sat May 09 15:19:21 2020 +0200
+++ b/src/main/java/de/uapcore/lightpit/modules/ErrorModule.java	Sat May 09 17:01:29 2020 +0200
@@ -1,8 +1,8 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
- * 
+ *
  * Copyright 2018 Mike Becker. All rights reserved.
- * 
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
  *
@@ -24,15 +24,12 @@
  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGE.
- * 
+ *
  */
 package de.uapcore.lightpit.modules;
 
-import de.uapcore.lightpit.LightPITModule;
-import de.uapcore.lightpit.AbstractLightPITServlet;
-import de.uapcore.lightpit.HttpMethod;
-import de.uapcore.lightpit.RequestMapping;
-import de.uapcore.lightpit.ResponseType;
+import de.uapcore.lightpit.*;
+
 import javax.servlet.annotation.WebServlet;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
@@ -51,28 +48,28 @@
         urlPatterns = "/error/*"
 )
 public final class ErrorModule extends AbstractLightPITServlet {
-    
+
     public static final String REQ_ATTR_ERROR_CODE = "errorCode";
-    
+
     private ResponseType handle(HttpServletRequest req, HttpServletResponse resp, int sc) {
-        
+
         req.setAttribute(REQ_ATTR_ERROR_CODE, sc);
         setStylesheet(req, "error");
         setDynamicFragment(req, "error");
-        
+
         return ResponseType.HTML_FULL;
     }
-    
+
     @RequestMapping(requestPath = "404", method = HttpMethod.GET)
     public ResponseType handle404(HttpServletRequest req, HttpServletResponse resp) {
         return handle(req, resp, 404);
     }
-    
+
     @RequestMapping(requestPath = "403", method = HttpMethod.GET)
     public ResponseType handle403(HttpServletRequest req, HttpServletResponse resp) {
         return handle(req, resp, 403);
     }
-    
+
     @RequestMapping(requestPath = "500", method = HttpMethod.GET)
     public ResponseType handle500(HttpServletRequest req, HttpServletResponse resp) {
         return handle(req, resp, 500);
--- a/src/main/java/de/uapcore/lightpit/modules/HomeModule.java	Sat May 09 15:19:21 2020 +0200
+++ b/src/main/java/de/uapcore/lightpit/modules/HomeModule.java	Sat May 09 17:01:29 2020 +0200
@@ -1,8 +1,8 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
- * 
+ *
  * Copyright 2018 Mike Becker. All rights reserved.
- * 
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
  *
@@ -24,7 +24,7 @@
  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGE.
- * 
+ *
  */
 package de.uapcore.lightpit.modules;
 
@@ -47,10 +47,10 @@
         urlPatterns = "/home/*"
 )
 public final class HomeModule extends AbstractLightPITServlet {
-    
+
     @RequestMapping(method = HttpMethod.GET)
     public ResponseType handle(HttpServletRequest req, HttpServletResponse resp) {
-        
+
         return ResponseType.HTML_FULL;
     }
 }
--- a/src/main/java/de/uapcore/lightpit/modules/LanguageModule.java	Sat May 09 15:19:21 2020 +0200
+++ b/src/main/java/de/uapcore/lightpit/modules/LanguageModule.java	Sat May 09 17:01:29 2020 +0200
@@ -1,8 +1,8 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
- * 
+ *
  * Copyright 2018 Mike Becker. All rights reserved.
- * 
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
  *
@@ -24,7 +24,7 @@
  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGE.
- * 
+ *
  */
 package de.uapcore.lightpit.modules;
 
@@ -49,15 +49,15 @@
         urlPatterns = "/language/*"
 )
 public final class LanguageModule extends AbstractLightPITServlet {
-    
+
     private static final Logger LOG = LoggerFactory.getLogger(LanguageModule.class);
-    
+
     private final List<Locale> languages = new ArrayList<>();
 
     @Override
     public void init() throws ServletException {
         super.init();
-        
+
         Optional<String[]> langs = Functions.availableLanguages(getServletContext());
         if (langs.isPresent()) {
             for (String lang : langs.get()) {
@@ -71,7 +71,7 @@
                     LOG.warn("Specified lanaguge {} in context parameter cannot be mapped to an existing locale - skipping.", lang);
                 }
             }
-            
+
         } else {
             languages.add(Locale.ENGLISH);
             LOG.warn("Context parameter 'available-languges' not found. Only english will be available.");
@@ -83,28 +83,28 @@
         super.destroy();
         languages.clear();
     }
-    
+
     @RequestMapping(method = HttpMethod.GET)
     public ResponseType handle(HttpServletRequest req, HttpServletResponse resp) {
 
         req.setAttribute("languages", languages);
         req.setAttribute("browserLanguage", req.getLocale());
-        
+
         setStylesheet(req, "language");
         setDynamicFragment(req, "language");
         return ResponseType.HTML_FULL;
     }
-    
+
     @RequestMapping(method = HttpMethod.POST)
     public ResponseType switchLanguage(HttpServletRequest req, HttpServletResponse resp) {
-        
+
         Optional<Locale> chosenLanguage = Optional.ofNullable(req.getParameter("language"))
                 .map(Locale::forLanguageTag)
                 .filter((l) -> !l.getLanguage().isEmpty());
-        
+
         chosenLanguage.ifPresent((l) -> req.getSession().setAttribute(Constants.SESSION_ATTR_LANGUAGE, l));
         chosenLanguage.ifPresent(resp::setLocale);
-        
+
         return handle(req, resp);
     }
 }
--- a/src/main/java/de/uapcore/lightpit/modules/ModuleManagerModule.java	Sat May 09 15:19:21 2020 +0200
+++ b/src/main/java/de/uapcore/lightpit/modules/ModuleManagerModule.java	Sat May 09 17:01:29 2020 +0200
@@ -1,8 +1,8 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
- * 
+ *
  * Copyright 2018 Mike Becker. All rights reserved.
- * 
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
  *
@@ -24,13 +24,12 @@
  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGE.
- * 
+ *
  */
 package de.uapcore.lightpit.modules;
 
 import de.uapcore.lightpit.*;
 import de.uapcore.lightpit.LightPITModule.ELProxy;
-import de.uapcore.lightpit.dao.CoreDAOFactory;
 import de.uapcore.lightpit.entities.Module;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -59,25 +58,26 @@
         urlPatterns = "/modmgmt/*"
 )
 public final class ModuleManagerModule extends AbstractLightPITServlet {
-    
+
     private static final Logger LOG = LoggerFactory.getLogger(ModuleManagerModule.class);
-    
+
     private static final String REQ_ATTR_MODULES = "modules";
-    
-    
+
+
     @RequestMapping(method = HttpMethod.GET)
     public ResponseType handle(HttpServletRequest req, HttpServletResponse resp) throws IOException {
-        
-        Optional<DataSource> ds = getDatabaseFacade().getDataSource();
+
+        DatabaseFacade db = getDatabaseFacade();
+        Optional<DataSource> ds = db.getDataSource();
         if (ds.isPresent()) {
             try (Connection conn = ds.get().getConnection()) {
-                final List<Module> modules = CoreDAOFactory.getModuleDao(getDatabaseFacade().getSQLDialect()).listAll(conn);
-                
+                final List<Module> modules = db.getDataAccessObjects().getModuleDao().list(conn);
+
                 final Map<String, LightPITModule> registeredModules = getModuleManager().getRegisteredModules();
                 modules.forEach((mod) -> mod.setAnnotatedInfos(ELProxy.convert(registeredModules.get(mod.getClassname()))));
-                
+
                 req.setAttribute(REQ_ATTR_MODULES, modules);
-                setDynamicFragment(req, "modules");                
+                setDynamicFragment(req, "modules");
                 return ResponseType.HTML_FULL;
             } catch (SQLException ex) {
                 LOG.error("Unexpected SQL Exception", ex);
--- a/src/main/java/de/uapcore/lightpit/modules/VersionsModule.java	Sat May 09 15:19:21 2020 +0200
+++ b/src/main/java/de/uapcore/lightpit/modules/VersionsModule.java	Sat May 09 17:01:29 2020 +0200
@@ -1,8 +1,8 @@
 /*
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
- * 
+ *
  * Copyright 2018 Mike Becker. All rights reserved.
- * 
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
  *
@@ -24,15 +24,12 @@
  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGE.
- * 
+ *
  */
 package de.uapcore.lightpit.modules;
 
-import de.uapcore.lightpit.LightPITModule;
-import de.uapcore.lightpit.AbstractLightPITServlet;
-import de.uapcore.lightpit.HttpMethod;
-import de.uapcore.lightpit.RequestMapping;
-import de.uapcore.lightpit.ResponseType;
+import de.uapcore.lightpit.*;
+
 import javax.servlet.annotation.WebServlet;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
@@ -49,7 +46,7 @@
 public final class VersionsModule extends AbstractLightPITServlet {
     @RequestMapping(method = HttpMethod.GET)
     public ResponseType handle(HttpServletRequest req, HttpServletResponse resp) {
-        
+
         return ResponseType.HTML_FULL;
     }
 }

mercurial