removes caching of main menu

Sun, 08 Apr 2018 16:41:02 +0200

author
Mike Becker <universe@uap-core.de>
date
Sun, 08 Apr 2018 16:41:02 +0200
changeset 27
1f2a96efa69f
parent 26
65d5a0ca49ae
child 28
cfc3d11884ad

removes caching of main menu

src/java/de/uapcore/lightpit/AbstractLightPITServlet.java file | annotate | diff | comparison | revisions
src/java/de/uapcore/lightpit/ModuleManager.java file | annotate | diff | comparison | revisions
src/java/de/uapcore/lightpit/entities/ModuleDao.java file | annotate | diff | comparison | revisions
--- a/src/java/de/uapcore/lightpit/AbstractLightPITServlet.java	Sun Apr 08 15:34:11 2018 +0200
+++ b/src/java/de/uapcore/lightpit/AbstractLightPITServlet.java	Sun Apr 08 16:41:02 2018 +0200
@@ -222,7 +222,7 @@
     private void forwardToFullView(HttpServletRequest req, HttpServletResponse resp)
             throws IOException, ServletException {
         
-        req.setAttribute(Constants.REQ_ATTR_MENU, getModuleManager().getMainMenu());
+        req.setAttribute(Constants.REQ_ATTR_MENU, getModuleManager().getMainMenu(getDatabaseFacade()));
         req.getRequestDispatcher(HTML_FULL_DISPATCHER).forward(req, resp);
     }
     
@@ -249,7 +249,7 @@
     
     private void doProcess(HttpMethod method, HttpServletRequest req, HttpServletResponse resp)
             throws ServletException, IOException {
-        
+
         // Synchronize module information with database
         getModuleManager().syncWithDatabase(getDatabaseFacade());
         
--- a/src/java/de/uapcore/lightpit/ModuleManager.java	Sun Apr 08 15:34:11 2018 +0200
+++ b/src/java/de/uapcore/lightpit/ModuleManager.java	Sun Apr 08 16:41:02 2018 +0200
@@ -29,6 +29,7 @@
 package de.uapcore.lightpit;
 
 import de.uapcore.lightpit.entities.CoreDAOFactory;
+import de.uapcore.lightpit.entities.Module;
 import de.uapcore.lightpit.entities.ModuleDao;
 import java.sql.Connection;
 import java.sql.SQLException;
@@ -36,9 +37,7 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.Map.Entry;
 import java.util.Optional;
-import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.stream.Collectors;
 import javax.servlet.Registration;
@@ -64,18 +63,15 @@
     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);
     
-    private final CopyOnWriteArrayList<Menu> mainMenu = new CopyOnWriteArrayList<>();
-    private final List<Menu> immutableMainMenu = Collections.unmodifiableList(mainMenu);
-    
-    /**
-     * Maps class names to module information.
-     */
-    private final Map<String, LightPITModule> registeredModules = new HashMap<>();
-    
     @Override
     public void contextInitialized(ServletContextEvent sce) {
         sc = sce.getServletContext();
@@ -152,6 +148,13 @@
     /**
      * Synchronizes module information with the database.
      * 
+     * This must be called from the {@link AbstractLightPITServlet}.
+     * Admittedly the call will perform the synchronization once after reload
+     * and be a no-op, afterwards.
+     * However, we since the DatabaseFacade might be loaded after the module
+     * manager, we must defer the synchronization to the first request
+     * handled by the Servlet.
+     * 
      * @param db interface to the database
      */
     public void syncWithDatabase(DatabaseFacade db) {
@@ -159,27 +162,12 @@
             if (db.getDataSource().isPresent()) {
                 try (Connection conn = db.getDataSource().get().getConnection()) {
                     final ModuleDao moduleDao = CoreDAOFactory.getModuleDao(db.getSQLDialect());
-                    
-                    final List<Entry<String, LightPITModule>> visibleModules =
-                            moduleDao.syncRegisteredModuleClasses(conn, registeredModules.entrySet());
-                    
-                    final List<Menu> updatedMenu = visibleModules
-                            .stream()
-                            .collect(Collectors.mapping(
-                                    (mod) -> new Menu(
-                                            mod.getKey(),
-                                            new ResourceKey(mod.getValue().bundleBaseName(), mod.getValue().menuKey()),
-                                            mod.getValue().modulePath()),
-                                    Collectors.toList())
-                            );
-                    
-                    mainMenu.removeIf((e) -> !updatedMenu.contains(e));
-                    mainMenu.addAllAbsent(updatedMenu);
+                    moduleDao.syncRegisteredModuleClasses(conn, registeredModules.entrySet());
                 } catch (SQLException ex) {
                     LOG.error("Unexpected SQL Exception", ex);
                 }
             } else {
-                LOG.warn("No datasource present. Cannot sync module information with database.");
+                LOG.error("No datasource present. Cannot sync module information with database.");
             }
         } else {
             LOG.trace("Module information clean - no synchronization required.");
@@ -190,17 +178,44 @@
      * Unloads all found modules.
      */
     public void unloadAll() {
-        mainMenu.clear();
         registeredModules.clear();
         LOG.info("All modules unloaded.");
     }
 
     /**
      * 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() {
-        return immutableMainMenu;
+    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<Menu> menu = modules
+                    .stream()
+                    .filter((mod) -> mod.isVisible())
+                    .collect(Collectors.mapping(
+                            (mod) -> new Menu(
+                                    mod.getClassname(),
+                                    new ResourceKey(
+                                            registeredModules.get(mod.getClassname()).bundleBaseName(),
+                                            registeredModules.get(mod.getClassname()).menuKey()),
+                                    registeredModules.get(mod.getClassname()).modulePath()),
+                            Collectors.toList())
+                    );
+                return menu;
+            } catch (SQLException ex) {
+                LOG.error("Unexpected SQLException when loading the main menu", ex);
+                return Collections.emptyList();
+            }
+        } else {
+            return Collections.emptyList();
+        }
     }
     
     /**
--- a/src/java/de/uapcore/lightpit/entities/ModuleDao.java	Sun Apr 08 15:34:11 2018 +0200
+++ b/src/java/de/uapcore/lightpit/entities/ModuleDao.java	Sun Apr 08 16:41:02 2018 +0200
@@ -34,7 +34,6 @@
 import java.sql.ResultSet;
 import java.sql.SQLException;
 import java.sql.Statement;
-import java.util.AbstractMap;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
@@ -88,18 +87,16 @@
     }
     
     /**
-     * Synchronizes a set of registered module classes with the database and gives a list of visible modules in return.
+     * Synchronizes a set of registered module classes with the database.
      * 
      * 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 moduleSet the module set to synchronize
-     * @return a list of elements from the given set, which should be visible in the menu
      * @throws SQLException
      */
-    public final List<Map.Entry<String, LightPITModule>>
-            syncRegisteredModuleClasses(Connection conn, Set<Map.Entry<String, LightPITModule>> moduleSet) throws SQLException {
+    public final void syncRegisteredModuleClasses(Connection conn, Set<Map.Entry<String, LightPITModule>> moduleSet) throws SQLException {
                 
         PreparedStatement
                 check = moduleCheckStatement(conn),
@@ -107,30 +104,17 @@
         insert.setBoolean(2, true);
         // update/delete not required, we do this in the module management UI
 
-        final List<Map.Entry<String, LightPITModule>> visibleModules = new ArrayList<>();
+        for (Map.Entry<String, LightPITModule> modEntry : moduleSet) {
+            if (modEntry.getValue().systemModule()) continue;
 
-        for (Map.Entry<String, LightPITModule> mod : moduleSet) {
-            if (mod.getValue().systemModule()) continue;
-
-            check.setString(1, mod.getKey());
+            check.setString(1, modEntry.getKey());
             try (ResultSet r = check.executeQuery()) {
-                final boolean visible;
-                if (r.next()) {
-                    visible = r.getBoolean(1);
-                } else {
-                    insert.setString(1, mod.getKey());
+                if (!r.next()) {
+                    insert.setString(1, modEntry.getKey());
                     insert.executeUpdate();
-                    visible = !mod.getValue().menuKey().isEmpty();
-                }
-                if (visible) {
-                    visibleModules.add(new AbstractMap.SimpleEntry<>(
-                            mod.getKey(),
-                            mod.getValue()
-                    ));
                 }
             }
         }
-        return visibleModules;
     }
 
     /**
@@ -144,8 +128,7 @@
      */
     public List<Module> listAll(Connection conn) throws SQLException {
         List<Module> list = new ArrayList<>();
-        try (
-                Statement stmt = conn.createStatement();
+        try (Statement stmt = conn.createStatement();
                 ResultSet result = stmt.executeQuery("SELECT * FROM lpitcore_module")) {
             while (result.next()) {
                 final Module mod = new Module();

mercurial