26 * POSSIBILITY OF SUCH DAMAGE. |
26 * POSSIBILITY OF SUCH DAMAGE. |
27 * |
27 * |
28 */ |
28 */ |
29 package de.uapcore.lightpit; |
29 package de.uapcore.lightpit; |
30 |
30 |
|
31 import de.uapcore.lightpit.entities.CoreDAOFactory; |
|
32 import de.uapcore.lightpit.entities.ModuleDao; |
31 import java.sql.Connection; |
33 import java.sql.Connection; |
32 import java.sql.PreparedStatement; |
|
33 import java.sql.ResultSet; |
|
34 import java.sql.SQLException; |
34 import java.sql.SQLException; |
35 import java.util.ArrayList; |
35 import java.util.Collection; |
36 import java.util.Collections; |
36 import java.util.Collections; |
37 import java.util.HashMap; |
37 import java.util.HashMap; |
38 import java.util.List; |
38 import java.util.List; |
39 import java.util.Map; |
39 import java.util.Map; |
40 import java.util.Map.Entry; |
40 import java.util.Map.Entry; |
41 import java.util.Optional; |
41 import java.util.Optional; |
42 import java.util.concurrent.CopyOnWriteArrayList; |
42 import java.util.concurrent.CopyOnWriteArrayList; |
43 import java.util.concurrent.atomic.AtomicBoolean; |
43 import java.util.concurrent.atomic.AtomicBoolean; |
|
44 import java.util.stream.Collectors; |
44 import javax.servlet.Registration; |
45 import javax.servlet.Registration; |
45 import javax.servlet.ServletContext; |
46 import javax.servlet.ServletContext; |
46 import javax.servlet.ServletContextEvent; |
47 import javax.servlet.ServletContextEvent; |
47 import javax.servlet.ServletContextListener; |
48 import javax.servlet.ServletContextListener; |
48 import javax.servlet.annotation.WebListener; |
49 import javax.servlet.annotation.WebListener; |
64 private ServletContext sc; |
65 private ServletContext sc; |
65 |
66 |
66 /** |
67 /** |
67 * This flag is true, when synchronization is needed. |
68 * This flag is true, when synchronization is needed. |
68 */ |
69 */ |
69 private AtomicBoolean dirty = new AtomicBoolean(true); |
70 private final AtomicBoolean dirty = new AtomicBoolean(true); |
70 |
71 |
71 private final CopyOnWriteArrayList<Menu> mainMenu = new CopyOnWriteArrayList<>(); |
72 private final CopyOnWriteArrayList<Menu> mainMenu = new CopyOnWriteArrayList<>(); |
72 private final List<Menu> immutableMainMenu = Collections.unmodifiableList(mainMenu); |
73 private final List<Menu> immutableMainMenu = Collections.unmodifiableList(mainMenu); |
73 |
74 |
74 /** |
75 /** |
138 |
139 |
139 /** |
140 /** |
140 * Scans for modules and reloads them all. |
141 * Scans for modules and reloads them all. |
141 */ |
142 */ |
142 public void reloadAll() { |
143 public void reloadAll() { |
|
144 registeredModules.clear(); |
143 sc.getServletRegistrations().forEach(this::handleServletRegistration); |
145 sc.getServletRegistrations().forEach(this::handleServletRegistration); |
144 |
146 |
145 // TODO: implement dependency resolver |
147 // TODO: implement dependency resolver |
146 |
148 |
|
149 dirty.set(true); |
147 LOG.info("Modules loaded."); |
150 LOG.info("Modules loaded."); |
148 } |
151 } |
149 |
152 |
150 /** |
153 /** |
151 * Synchronizes module information with the database. |
154 * Synchronizes module information with the database. |
154 */ |
157 */ |
155 public void syncWithDatabase(DatabaseFacade db) { |
158 public void syncWithDatabase(DatabaseFacade db) { |
156 if (dirty.compareAndSet(true, false)) { |
159 if (dirty.compareAndSet(true, false)) { |
157 if (db.getDataSource().isPresent()) { |
160 if (db.getDataSource().isPresent()) { |
158 try (Connection conn = db.getDataSource().get().getConnection()) { |
161 try (Connection conn = db.getDataSource().get().getConnection()) { |
159 PreparedStatement |
162 final ModuleDao moduleDao = CoreDAOFactory.getModuleDao(db.getSQLDialect()); |
160 check = conn.prepareStatement("SELECT visible FROM lpitcore_module WHERE classname = ?"), |
|
161 insert = conn.prepareStatement("INSERT INTO lpitcore_module (classname, visible) VALUES (?, ?)"); |
|
162 insert.setBoolean(2, true); |
|
163 // update/delete not required, we do this in the module management UI |
|
164 |
163 |
165 final List<Menu> updatedMenu = new ArrayList<>(); |
164 final List<Entry<String, LightPITModule>> visibleModules = |
|
165 moduleDao.syncRegisteredModuleClasses(conn, registeredModules.entrySet()); |
166 |
166 |
167 for (Entry<String, LightPITModule> mod : registeredModules.entrySet()) { |
167 final List<Menu> updatedMenu = visibleModules |
168 if (mod.getValue().systemModule()) continue; |
168 .stream() |
169 |
169 .collect(Collectors.mapping( |
170 check.setString(1, mod.getKey()); |
170 (mod) -> new Menu( |
171 try (ResultSet r = check.executeQuery()) { |
171 mod.getKey(), |
172 final boolean addToMenu; |
172 new ResourceKey(mod.getValue().bundleBaseName(), mod.getValue().menuKey()), |
173 if (r.next()) { |
173 mod.getValue().modulePath()), |
174 addToMenu = r.getBoolean(1); |
174 Collectors.toList()) |
175 } else { |
175 ); |
176 insert.setString(1, mod.getKey()); |
|
177 insert.executeUpdate(); |
|
178 addToMenu = !mod.getValue().menuKey().isEmpty(); |
|
179 } |
|
180 if (addToMenu) { |
|
181 updatedMenu.add(new Menu( |
|
182 mod.getKey(), |
|
183 new ResourceKey(mod.getValue().bundleBaseName(), mod.getValue().menuKey()), |
|
184 mod.getValue().modulePath() |
|
185 )); |
|
186 } |
|
187 } |
|
188 } |
|
189 |
176 |
190 mainMenu.removeIf((e) -> !updatedMenu.contains(e)); |
177 mainMenu.removeIf((e) -> !updatedMenu.contains(e)); |
191 mainMenu.addAllAbsent(updatedMenu); |
178 mainMenu.addAllAbsent(updatedMenu); |
192 } catch (SQLException ex) { |
179 } catch (SQLException ex) { |
193 LOG.error("Unexpected SQL Exception", ex); |
180 LOG.error("Unexpected SQL Exception", ex); |
203 /** |
190 /** |
204 * Unloads all found modules. |
191 * Unloads all found modules. |
205 */ |
192 */ |
206 public void unloadAll() { |
193 public void unloadAll() { |
207 mainMenu.clear(); |
194 mainMenu.clear(); |
|
195 registeredModules.clear(); |
208 LOG.info("All modules unloaded."); |
196 LOG.info("All modules unloaded."); |
209 } |
197 } |
210 |
198 |
211 /** |
199 /** |
212 * Returns the main menu. |
200 * Returns the main menu. |
213 * @return a list of menus belonging to the main menu |
201 * @return a list of menus belonging to the main menu |
214 */ |
202 */ |
215 public List<Menu> getMainMenu() { |
203 public List<Menu> getMainMenu() { |
216 return immutableMainMenu; |
204 return immutableMainMenu; |
217 } |
205 } |
|
206 |
|
207 /** |
|
208 * Returns an unmodifiable map of all registered modules. |
|
209 * |
|
210 * The key is the classname of the module. |
|
211 * |
|
212 * @return the map of registered modules |
|
213 */ |
|
214 public Map<String, LightPITModule> getRegisteredModules() { |
|
215 return Collections.unmodifiableMap(registeredModules); |
|
216 } |
218 } |
217 } |