src/java/de/uapcore/lightpit/ModuleManager.java

changeset 27
1f2a96efa69f
parent 24
8137ec335416
equal deleted inserted replaced
26:65d5a0ca49ae 27:1f2a96efa69f
27 * 27 *
28 */ 28 */
29 package de.uapcore.lightpit; 29 package de.uapcore.lightpit;
30 30
31 import de.uapcore.lightpit.entities.CoreDAOFactory; 31 import de.uapcore.lightpit.entities.CoreDAOFactory;
32 import de.uapcore.lightpit.entities.Module;
32 import de.uapcore.lightpit.entities.ModuleDao; 33 import de.uapcore.lightpit.entities.ModuleDao;
33 import java.sql.Connection; 34 import java.sql.Connection;
34 import java.sql.SQLException; 35 import java.sql.SQLException;
35 import java.util.Collections; 36 import java.util.Collections;
36 import java.util.HashMap; 37 import java.util.HashMap;
37 import java.util.List; 38 import java.util.List;
38 import java.util.Map; 39 import java.util.Map;
39 import java.util.Map.Entry;
40 import java.util.Optional; 40 import java.util.Optional;
41 import java.util.concurrent.CopyOnWriteArrayList;
42 import java.util.concurrent.atomic.AtomicBoolean; 41 import java.util.concurrent.atomic.AtomicBoolean;
43 import java.util.stream.Collectors; 42 import java.util.stream.Collectors;
44 import javax.servlet.Registration; 43 import javax.servlet.Registration;
45 import javax.servlet.ServletContext; 44 import javax.servlet.ServletContext;
46 import javax.servlet.ServletContextEvent; 45 import javax.servlet.ServletContextEvent;
62 */ 61 */
63 public static final String SC_ATTR_NAME = ModuleManager.class.getName(); 62 public static final String SC_ATTR_NAME = ModuleManager.class.getName();
64 private ServletContext sc; 63 private ServletContext sc;
65 64
66 /** 65 /**
66 * Maps class names to module information.
67 */
68 private final Map<String, LightPITModule> registeredModules = new HashMap<>();
69
70 /**
67 * This flag is true, when synchronization is needed. 71 * This flag is true, when synchronization is needed.
68 */ 72 */
69 private final AtomicBoolean dirty = new AtomicBoolean(true); 73 private final AtomicBoolean dirty = new AtomicBoolean(true);
70
71 private final CopyOnWriteArrayList<Menu> mainMenu = new CopyOnWriteArrayList<>();
72 private final List<Menu> immutableMainMenu = Collections.unmodifiableList(mainMenu);
73
74 /**
75 * Maps class names to module information.
76 */
77 private final Map<String, LightPITModule> registeredModules = new HashMap<>();
78 74
79 @Override 75 @Override
80 public void contextInitialized(ServletContextEvent sce) { 76 public void contextInitialized(ServletContextEvent sce) {
81 sc = sce.getServletContext(); 77 sc = sce.getServletContext();
82 reloadAll(); 78 reloadAll();
150 } 146 }
151 147
152 /** 148 /**
153 * Synchronizes module information with the database. 149 * Synchronizes module information with the database.
154 * 150 *
151 * This must be called from the {@link AbstractLightPITServlet}.
152 * Admittedly the call will perform the synchronization once after reload
153 * and be a no-op, afterwards.
154 * However, we since the DatabaseFacade might be loaded after the module
155 * manager, we must defer the synchronization to the first request
156 * handled by the Servlet.
157 *
155 * @param db interface to the database 158 * @param db interface to the database
156 */ 159 */
157 public void syncWithDatabase(DatabaseFacade db) { 160 public void syncWithDatabase(DatabaseFacade db) {
158 if (dirty.compareAndSet(true, false)) { 161 if (dirty.compareAndSet(true, false)) {
159 if (db.getDataSource().isPresent()) { 162 if (db.getDataSource().isPresent()) {
160 try (Connection conn = db.getDataSource().get().getConnection()) { 163 try (Connection conn = db.getDataSource().get().getConnection()) {
161 final ModuleDao moduleDao = CoreDAOFactory.getModuleDao(db.getSQLDialect()); 164 final ModuleDao moduleDao = CoreDAOFactory.getModuleDao(db.getSQLDialect());
162 165 moduleDao.syncRegisteredModuleClasses(conn, registeredModules.entrySet());
163 final List<Entry<String, LightPITModule>> visibleModules =
164 moduleDao.syncRegisteredModuleClasses(conn, registeredModules.entrySet());
165
166 final List<Menu> updatedMenu = visibleModules
167 .stream()
168 .collect(Collectors.mapping(
169 (mod) -> new Menu(
170 mod.getKey(),
171 new ResourceKey(mod.getValue().bundleBaseName(), mod.getValue().menuKey()),
172 mod.getValue().modulePath()),
173 Collectors.toList())
174 );
175
176 mainMenu.removeIf((e) -> !updatedMenu.contains(e));
177 mainMenu.addAllAbsent(updatedMenu);
178 } catch (SQLException ex) { 166 } catch (SQLException ex) {
179 LOG.error("Unexpected SQL Exception", ex); 167 LOG.error("Unexpected SQL Exception", ex);
180 } 168 }
181 } else { 169 } else {
182 LOG.warn("No datasource present. Cannot sync module information with database."); 170 LOG.error("No datasource present. Cannot sync module information with database.");
183 } 171 }
184 } else { 172 } else {
185 LOG.trace("Module information clean - no synchronization required."); 173 LOG.trace("Module information clean - no synchronization required.");
186 } 174 }
187 } 175 }
188 176
189 /** 177 /**
190 * Unloads all found modules. 178 * Unloads all found modules.
191 */ 179 */
192 public void unloadAll() { 180 public void unloadAll() {
193 mainMenu.clear();
194 registeredModules.clear(); 181 registeredModules.clear();
195 LOG.info("All modules unloaded."); 182 LOG.info("All modules unloaded.");
196 } 183 }
197 184
198 /** 185 /**
199 * Returns the main menu. 186 * Returns the main menu.
187 *
188 * @param db the interface to the database
200 * @return a list of menus belonging to the main menu 189 * @return a list of menus belonging to the main menu
201 */ 190 */
202 public List<Menu> getMainMenu() { 191 public List<Menu> getMainMenu(DatabaseFacade db) {
203 return immutableMainMenu; 192 // TODO: user specific menu
193
194 if (db.getDataSource().isPresent()) {
195 try (Connection conn = db.getDataSource().get().getConnection()) {
196 final ModuleDao dao = CoreDAOFactory.getModuleDao(db.getSQLDialect());
197 final List<Module> modules = dao.listAll(conn);
198
199 final List<Menu> menu = modules
200 .stream()
201 .filter((mod) -> mod.isVisible())
202 .collect(Collectors.mapping(
203 (mod) -> new Menu(
204 mod.getClassname(),
205 new ResourceKey(
206 registeredModules.get(mod.getClassname()).bundleBaseName(),
207 registeredModules.get(mod.getClassname()).menuKey()),
208 registeredModules.get(mod.getClassname()).modulePath()),
209 Collectors.toList())
210 );
211 return menu;
212 } catch (SQLException ex) {
213 LOG.error("Unexpected SQLException when loading the main menu", ex);
214 return Collections.emptyList();
215 }
216 } else {
217 return Collections.emptyList();
218 }
204 } 219 }
205 220
206 /** 221 /**
207 * Returns an unmodifiable map of all registered modules. 222 * Returns an unmodifiable map of all registered modules.
208 * 223 *

mercurial