--- a/src/java/de/uapcore/lightpit/ModuleManager.java Sat Mar 31 18:11:09 2018 +0200 +++ b/src/java/de/uapcore/lightpit/ModuleManager.java Sat Mar 31 19:35:04 2018 +0200 @@ -28,11 +28,19 @@ */ package de.uapcore.lightpit; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; import java.util.List; -import java.util.Objects; +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 javax.servlet.Registration; import javax.servlet.ServletContext; import javax.servlet.ServletContextEvent; @@ -55,9 +63,19 @@ public static final String SC_ATTR_NAME = ModuleManager.class.getName(); private ServletContext sc; - private final List<Menu> mainMenu = new ArrayList<>(); + /** + * This flag is true, when synchronization is needed. + */ + private 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(); @@ -108,24 +126,10 @@ } } - private void addModuleToMenu(String moduleClassName, LightPITModule moduleInfo) { - final Menu menu = new Menu( - moduleClassName, - new ResourceKey(moduleInfo.bundleBaseName(), moduleInfo.menuKey()), - moduleInfo.modulePath() - ); - mainMenu.add(menu); - } - private void handleServletRegistration(String name, Registration reg) { final Optional<LightPITModule> moduleInfo = getModuleInfo(reg); - if (moduleInfo.isPresent()) { - // TODO: implement dependency resolver - - if (!moduleInfo.get().menuKey().isEmpty()) { - addModuleToMenu(reg.getClassName(), moduleInfo.get()); - } - + if (moduleInfo.isPresent()) { + registeredModules.put(reg.getClassName(), moduleInfo.get()); LOG.info("Module detected: {}", name); } else { LOG.debug("Servlet {} is no module, skipping.", name); @@ -137,10 +141,66 @@ */ public void reloadAll() { sc.getServletRegistrations().forEach(this::handleServletRegistration); + + // TODO: implement dependency resolver + LOG.info("Modules loaded."); } /** + * Synchronizes module information with the database. + * + * @param db interface to the database + */ + public void syncWithDatabase(DatabaseFacade db) { + if (dirty.compareAndSet(true, false)) { + if (db.getDataSource().isPresent()) { + try (Connection conn = db.getDataSource().get().getConnection()) { + PreparedStatement + check = conn.prepareStatement("SELECT visible FROM lpitcore_module WHERE classname = ?"), + insert = conn.prepareStatement("INSERT INTO lpitcore_module (classname, visible) VALUES (?, ?)"); + insert.setBoolean(2, true); + // update/delete not required, we do this in the module management UI + + final List<Menu> updatedMenu = new ArrayList<>(); + + for (Entry<String, LightPITModule> mod : registeredModules.entrySet()) { + if (mod.getValue().systemModule()) continue; + + check.setString(1, mod.getKey()); + try (ResultSet r = check.executeQuery()) { + final boolean addToMenu; + if (r.next()) { + addToMenu = r.getBoolean(1); + } else { + insert.setString(1, mod.getKey()); + insert.executeUpdate(); + addToMenu = !mod.getValue().menuKey().isEmpty(); + } + if (addToMenu) { + updatedMenu.add(new Menu( + mod.getKey(), + new ResourceKey(mod.getValue().bundleBaseName(), mod.getValue().menuKey()), + mod.getValue().modulePath() + )); + } + } + } + + mainMenu.removeIf((e) -> !updatedMenu.contains(e)); + mainMenu.addAllAbsent(updatedMenu); + } catch (SQLException ex) { + LOG.error("Unexpected SQL Exception", ex); + } + } else { + LOG.warn("No datasource present. Cannot sync module information with database."); + } + } else { + LOG.debug("Module information clean - no synchronization required."); + } + } + + /** * Unloads all found modules. */ public void unloadAll() {