Sun, 08 Apr 2018 16:41:02 +0200
removes caching of main menu
1.1 --- a/src/java/de/uapcore/lightpit/AbstractLightPITServlet.java Sun Apr 08 15:34:11 2018 +0200 1.2 +++ b/src/java/de/uapcore/lightpit/AbstractLightPITServlet.java Sun Apr 08 16:41:02 2018 +0200 1.3 @@ -222,7 +222,7 @@ 1.4 private void forwardToFullView(HttpServletRequest req, HttpServletResponse resp) 1.5 throws IOException, ServletException { 1.6 1.7 - req.setAttribute(Constants.REQ_ATTR_MENU, getModuleManager().getMainMenu()); 1.8 + req.setAttribute(Constants.REQ_ATTR_MENU, getModuleManager().getMainMenu(getDatabaseFacade())); 1.9 req.getRequestDispatcher(HTML_FULL_DISPATCHER).forward(req, resp); 1.10 } 1.11 1.12 @@ -249,7 +249,7 @@ 1.13 1.14 private void doProcess(HttpMethod method, HttpServletRequest req, HttpServletResponse resp) 1.15 throws ServletException, IOException { 1.16 - 1.17 + 1.18 // Synchronize module information with database 1.19 getModuleManager().syncWithDatabase(getDatabaseFacade()); 1.20
2.1 --- a/src/java/de/uapcore/lightpit/ModuleManager.java Sun Apr 08 15:34:11 2018 +0200 2.2 +++ b/src/java/de/uapcore/lightpit/ModuleManager.java Sun Apr 08 16:41:02 2018 +0200 2.3 @@ -29,6 +29,7 @@ 2.4 package de.uapcore.lightpit; 2.5 2.6 import de.uapcore.lightpit.entities.CoreDAOFactory; 2.7 +import de.uapcore.lightpit.entities.Module; 2.8 import de.uapcore.lightpit.entities.ModuleDao; 2.9 import java.sql.Connection; 2.10 import java.sql.SQLException; 2.11 @@ -36,9 +37,7 @@ 2.12 import java.util.HashMap; 2.13 import java.util.List; 2.14 import java.util.Map; 2.15 -import java.util.Map.Entry; 2.16 import java.util.Optional; 2.17 -import java.util.concurrent.CopyOnWriteArrayList; 2.18 import java.util.concurrent.atomic.AtomicBoolean; 2.19 import java.util.stream.Collectors; 2.20 import javax.servlet.Registration; 2.21 @@ -64,18 +63,15 @@ 2.22 private ServletContext sc; 2.23 2.24 /** 2.25 + * Maps class names to module information. 2.26 + */ 2.27 + private final Map<String, LightPITModule> registeredModules = new HashMap<>(); 2.28 + 2.29 + /** 2.30 * This flag is true, when synchronization is needed. 2.31 */ 2.32 private final AtomicBoolean dirty = new AtomicBoolean(true); 2.33 2.34 - private final CopyOnWriteArrayList<Menu> mainMenu = new CopyOnWriteArrayList<>(); 2.35 - private final List<Menu> immutableMainMenu = Collections.unmodifiableList(mainMenu); 2.36 - 2.37 - /** 2.38 - * Maps class names to module information. 2.39 - */ 2.40 - private final Map<String, LightPITModule> registeredModules = new HashMap<>(); 2.41 - 2.42 @Override 2.43 public void contextInitialized(ServletContextEvent sce) { 2.44 sc = sce.getServletContext(); 2.45 @@ -152,6 +148,13 @@ 2.46 /** 2.47 * Synchronizes module information with the database. 2.48 * 2.49 + * This must be called from the {@link AbstractLightPITServlet}. 2.50 + * Admittedly the call will perform the synchronization once after reload 2.51 + * and be a no-op, afterwards. 2.52 + * However, we since the DatabaseFacade might be loaded after the module 2.53 + * manager, we must defer the synchronization to the first request 2.54 + * handled by the Servlet. 2.55 + * 2.56 * @param db interface to the database 2.57 */ 2.58 public void syncWithDatabase(DatabaseFacade db) { 2.59 @@ -159,27 +162,12 @@ 2.60 if (db.getDataSource().isPresent()) { 2.61 try (Connection conn = db.getDataSource().get().getConnection()) { 2.62 final ModuleDao moduleDao = CoreDAOFactory.getModuleDao(db.getSQLDialect()); 2.63 - 2.64 - final List<Entry<String, LightPITModule>> visibleModules = 2.65 - moduleDao.syncRegisteredModuleClasses(conn, registeredModules.entrySet()); 2.66 - 2.67 - final List<Menu> updatedMenu = visibleModules 2.68 - .stream() 2.69 - .collect(Collectors.mapping( 2.70 - (mod) -> new Menu( 2.71 - mod.getKey(), 2.72 - new ResourceKey(mod.getValue().bundleBaseName(), mod.getValue().menuKey()), 2.73 - mod.getValue().modulePath()), 2.74 - Collectors.toList()) 2.75 - ); 2.76 - 2.77 - mainMenu.removeIf((e) -> !updatedMenu.contains(e)); 2.78 - mainMenu.addAllAbsent(updatedMenu); 2.79 + moduleDao.syncRegisteredModuleClasses(conn, registeredModules.entrySet()); 2.80 } catch (SQLException ex) { 2.81 LOG.error("Unexpected SQL Exception", ex); 2.82 } 2.83 } else { 2.84 - LOG.warn("No datasource present. Cannot sync module information with database."); 2.85 + LOG.error("No datasource present. Cannot sync module information with database."); 2.86 } 2.87 } else { 2.88 LOG.trace("Module information clean - no synchronization required."); 2.89 @@ -190,17 +178,44 @@ 2.90 * Unloads all found modules. 2.91 */ 2.92 public void unloadAll() { 2.93 - mainMenu.clear(); 2.94 registeredModules.clear(); 2.95 LOG.info("All modules unloaded."); 2.96 } 2.97 2.98 /** 2.99 * Returns the main menu. 2.100 + * 2.101 + * @param db the interface to the database 2.102 * @return a list of menus belonging to the main menu 2.103 */ 2.104 - public List<Menu> getMainMenu() { 2.105 - return immutableMainMenu; 2.106 + public List<Menu> getMainMenu(DatabaseFacade db) { 2.107 + // TODO: user specific menu 2.108 + 2.109 + if (db.getDataSource().isPresent()) { 2.110 + try (Connection conn = db.getDataSource().get().getConnection()) { 2.111 + final ModuleDao dao = CoreDAOFactory.getModuleDao(db.getSQLDialect()); 2.112 + final List<Module> modules = dao.listAll(conn); 2.113 + 2.114 + final List<Menu> menu = modules 2.115 + .stream() 2.116 + .filter((mod) -> mod.isVisible()) 2.117 + .collect(Collectors.mapping( 2.118 + (mod) -> new Menu( 2.119 + mod.getClassname(), 2.120 + new ResourceKey( 2.121 + registeredModules.get(mod.getClassname()).bundleBaseName(), 2.122 + registeredModules.get(mod.getClassname()).menuKey()), 2.123 + registeredModules.get(mod.getClassname()).modulePath()), 2.124 + Collectors.toList()) 2.125 + ); 2.126 + return menu; 2.127 + } catch (SQLException ex) { 2.128 + LOG.error("Unexpected SQLException when loading the main menu", ex); 2.129 + return Collections.emptyList(); 2.130 + } 2.131 + } else { 2.132 + return Collections.emptyList(); 2.133 + } 2.134 } 2.135 2.136 /**
3.1 --- a/src/java/de/uapcore/lightpit/entities/ModuleDao.java Sun Apr 08 15:34:11 2018 +0200 3.2 +++ b/src/java/de/uapcore/lightpit/entities/ModuleDao.java Sun Apr 08 16:41:02 2018 +0200 3.3 @@ -34,7 +34,6 @@ 3.4 import java.sql.ResultSet; 3.5 import java.sql.SQLException; 3.6 import java.sql.Statement; 3.7 -import java.util.AbstractMap; 3.8 import java.util.ArrayList; 3.9 import java.util.List; 3.10 import java.util.Map; 3.11 @@ -88,18 +87,16 @@ 3.12 } 3.13 3.14 /** 3.15 - * Synchronizes a set of registered module classes with the database and gives a list of visible modules in return. 3.16 + * Synchronizes a set of registered module classes with the database. 3.17 * 3.18 * Inserts module classes which are not known to the database and sets them to be visible by default. 3.19 * Module classes known to the database, which are not in the given set, are ignored. 3.20 * 3.21 * @param conn the connection to use 3.22 * @param moduleSet the module set to synchronize 3.23 - * @return a list of elements from the given set, which should be visible in the menu 3.24 * @throws SQLException 3.25 */ 3.26 - public final List<Map.Entry<String, LightPITModule>> 3.27 - syncRegisteredModuleClasses(Connection conn, Set<Map.Entry<String, LightPITModule>> moduleSet) throws SQLException { 3.28 + public final void syncRegisteredModuleClasses(Connection conn, Set<Map.Entry<String, LightPITModule>> moduleSet) throws SQLException { 3.29 3.30 PreparedStatement 3.31 check = moduleCheckStatement(conn), 3.32 @@ -107,30 +104,17 @@ 3.33 insert.setBoolean(2, true); 3.34 // update/delete not required, we do this in the module management UI 3.35 3.36 - final List<Map.Entry<String, LightPITModule>> visibleModules = new ArrayList<>(); 3.37 + for (Map.Entry<String, LightPITModule> modEntry : moduleSet) { 3.38 + if (modEntry.getValue().systemModule()) continue; 3.39 3.40 - for (Map.Entry<String, LightPITModule> mod : moduleSet) { 3.41 - if (mod.getValue().systemModule()) continue; 3.42 - 3.43 - check.setString(1, mod.getKey()); 3.44 + check.setString(1, modEntry.getKey()); 3.45 try (ResultSet r = check.executeQuery()) { 3.46 - final boolean visible; 3.47 - if (r.next()) { 3.48 - visible = r.getBoolean(1); 3.49 - } else { 3.50 - insert.setString(1, mod.getKey()); 3.51 + if (!r.next()) { 3.52 + insert.setString(1, modEntry.getKey()); 3.53 insert.executeUpdate(); 3.54 - visible = !mod.getValue().menuKey().isEmpty(); 3.55 - } 3.56 - if (visible) { 3.57 - visibleModules.add(new AbstractMap.SimpleEntry<>( 3.58 - mod.getKey(), 3.59 - mod.getValue() 3.60 - )); 3.61 } 3.62 } 3.63 } 3.64 - return visibleModules; 3.65 } 3.66 3.67 /** 3.68 @@ -144,8 +128,7 @@ 3.69 */ 3.70 public List<Module> listAll(Connection conn) throws SQLException { 3.71 List<Module> list = new ArrayList<>(); 3.72 - try ( 3.73 - Statement stmt = conn.createStatement(); 3.74 + try (Statement stmt = conn.createStatement(); 3.75 ResultSet result = stmt.executeQuery("SELECT * FROM lpitcore_module")) { 3.76 while (result.next()) { 3.77 final Module mod = new Module();