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

changeset 34
824d4042c857
parent 33
fd8c40ff78c3
child 36
0f4f8f255c32
equal deleted inserted replaced
33:fd8c40ff78c3 34:824d4042c857
1 /* 1 /*
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3 * 3 *
4 * Copyright 2018 Mike Becker. All rights reserved. 4 * Copyright 2018 Mike Becker. All rights reserved.
5 * 5 *
6 * Redistribution and use in source and binary forms, with or without 6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met: 7 * modification, are permitted provided that the following conditions are met:
8 * 8 *
9 * 1. Redistributions of source code must retain the above copyright 9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer. 10 * notice, this list of conditions and the following disclaimer.
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
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.dao.CoreDAOFactory;
32 import de.uapcore.lightpit.dao.ModuleDao;
33 import de.uapcore.lightpit.entities.Module; 31 import de.uapcore.lightpit.entities.Module;
34 import org.slf4j.Logger; 32 import org.slf4j.Logger;
35 import org.slf4j.LoggerFactory; 33 import org.slf4j.LoggerFactory;
36 34
37 import javax.servlet.Registration; 35 import javax.servlet.Registration;
48 /** 46 /**
49 * Scans registered servlets for LightPIT modules. 47 * Scans registered servlets for LightPIT modules.
50 */ 48 */
51 @WebListener 49 @WebListener
52 public final class ModuleManager implements ServletContextListener { 50 public final class ModuleManager implements ServletContextListener {
53 51
54 private static final Logger LOG = LoggerFactory.getLogger(ModuleManager.class); 52 private static final Logger LOG = LoggerFactory.getLogger(ModuleManager.class);
55 53
56 /** 54 /**
57 * The attribute name in the servlet context under which an instance of this class can be found. 55 * The attribute name in the servlet context under which an instance of this class can be found.
58 */ 56 */
59 public static final String SC_ATTR_NAME = ModuleManager.class.getName(); 57 public static final String SC_ATTR_NAME = ModuleManager.class.getName();
60 private ServletContext sc; 58 private ServletContext sc;
61 59
62 /** 60 /**
63 * Maps class names to module information. 61 * Maps class names to module information.
64 */ 62 */
65 private final Map<String, LightPITModule> registeredModules = new HashMap<>(); 63 private final Map<String, LightPITModule> registeredModules = new HashMap<>();
66 64
67 /** 65 /**
68 * This flag is true, when synchronization is needed. 66 * This flag is true, when synchronization is needed.
69 */ 67 */
70 private final AtomicBoolean dirty = new AtomicBoolean(true); 68 private final AtomicBoolean dirty = new AtomicBoolean(true);
71 69
72 @Override 70 @Override
73 public void contextInitialized(ServletContextEvent sce) { 71 public void contextInitialized(ServletContextEvent sce) {
74 sc = sce.getServletContext(); 72 sc = sce.getServletContext();
75 reloadAll(); 73 reloadAll();
76 sc.setAttribute(SC_ATTR_NAME, this); 74 sc.setAttribute(SC_ATTR_NAME, this);
79 77
80 @Override 78 @Override
81 public void contextDestroyed(ServletContextEvent sce) { 79 public void contextDestroyed(ServletContextEvent sce) {
82 unloadAll(); 80 unloadAll();
83 } 81 }
84 82
85 private Optional<LightPITModule> getModuleInfo(Registration reg) { 83 private Optional<LightPITModule> getModuleInfo(Registration reg) {
86 try { 84 try {
87 final Class<?> scclass = Class.forName(reg.getClassName()); 85 final Class<?> scclass = Class.forName(reg.getClassName());
88 86
89 final boolean lpservlet = AbstractLightPITServlet.class.isAssignableFrom(scclass); 87 final boolean lpservlet = AbstractLightPITServlet.class.isAssignableFrom(scclass);
90 final boolean lpmodule = scclass.isAnnotationPresent(LightPITModule.class); 88 final boolean lpmodule = scclass.isAnnotationPresent(LightPITModule.class);
91 89
92 if (lpservlet && !lpmodule) { 90 if (lpservlet && !lpmodule) {
93 LOG.warn( 91 LOG.warn(
94 "{} is a LightPIT Servlet but is missing the module annotation.", 92 "{} is a LightPIT Servlet but is missing the module annotation.",
95 reg.getClassName() 93 reg.getClassName()
96 ); 94 );
97 } else if (!lpservlet && lpmodule) { 95 } else if (!lpservlet && lpmodule) {
98 LOG.warn( 96 LOG.warn(
99 "{} is annotated as a LightPIT Module but does not extend {}.", 97 "{} is annotated as a LightPIT Module but does not extend {}.",
100 reg.getClassName(), 98 reg.getClassName(),
101 AbstractLightPITServlet.class.getSimpleName() 99 AbstractLightPITServlet.class.getSimpleName()
102 ); 100 );
103 } 101 }
104 102
105 if (lpservlet && lpmodule) { 103 if (lpservlet && lpmodule) {
106 final LightPITModule moduleInfo = scclass.getAnnotation(LightPITModule.class); 104 final LightPITModule moduleInfo = scclass.getAnnotation(LightPITModule.class);
107 return Optional.of(moduleInfo); 105 return Optional.of(moduleInfo);
108 } else { 106 } else {
109 return Optional.empty(); 107 return Optional.empty();
113 "Servlet registration refers to class {} which cannot be found by the class loader (Reason: {})", 111 "Servlet registration refers to class {} which cannot be found by the class loader (Reason: {})",
114 reg.getClassName(), 112 reg.getClassName(),
115 ex.getMessage() 113 ex.getMessage()
116 ); 114 );
117 return Optional.empty(); 115 return Optional.empty();
118 } 116 }
119 } 117 }
120 118
121 private void handleServletRegistration(String name, Registration reg) { 119 private void handleServletRegistration(String name, Registration reg) {
122 final Optional<LightPITModule> moduleInfo = getModuleInfo(reg); 120 final Optional<LightPITModule> moduleInfo = getModuleInfo(reg);
123 if (moduleInfo.isPresent()) { 121 if (moduleInfo.isPresent()) {
124 registeredModules.put(reg.getClassName(), moduleInfo.get()); 122 registeredModules.put(reg.getClassName(), moduleInfo.get());
125 LOG.info("Module detected: {}", name); 123 LOG.info("Module detected: {}", name);
126 } else { 124 } else {
127 LOG.debug("Servlet {} is no module, skipping.", name); 125 LOG.debug("Servlet {} is no module, skipping.", name);
128 } 126 }
129 } 127 }
130 128
131 /** 129 /**
132 * Scans for modules and reloads them all. 130 * Scans for modules and reloads them all.
133 */ 131 */
134 public void reloadAll() { 132 public void reloadAll() {
135 registeredModules.clear(); 133 registeredModules.clear();
136 sc.getServletRegistrations().forEach(this::handleServletRegistration); 134 sc.getServletRegistrations().forEach(this::handleServletRegistration);
137 135
138 // TODO: implement dependency resolver 136 // TODO: implement dependency resolver
139 137
140 dirty.set(true); 138 dirty.set(true);
141 LOG.info("Modules loaded."); 139 LOG.info("Modules loaded.");
142 } 140 }
143 141
144 /** 142 /**
155 */ 153 */
156 public void syncWithDatabase(DatabaseFacade db) { 154 public void syncWithDatabase(DatabaseFacade db) {
157 if (dirty.compareAndSet(true, false)) { 155 if (dirty.compareAndSet(true, false)) {
158 if (db.getDataSource().isPresent()) { 156 if (db.getDataSource().isPresent()) {
159 try (Connection conn = db.getDataSource().get().getConnection()) { 157 try (Connection conn = db.getDataSource().get().getConnection()) {
160 final ModuleDao moduleDao = CoreDAOFactory.getModuleDao(db.getSQLDialect()); 158 db.getDataAccessObjects()
161 moduleDao.syncRegisteredModuleClasses(conn, registeredModules.entrySet()); 159 .getModuleDao()
160 .syncRegisteredModuleClasses(conn, registeredModules.entrySet());
162 } catch (SQLException ex) { 161 } catch (SQLException ex) {
163 LOG.error("Unexpected SQL Exception", ex); 162 LOG.error("Unexpected SQL Exception", ex);
164 } 163 }
165 } else { 164 } else {
166 LOG.error("No datasource present. Cannot sync module information with database."); 165 LOG.error("No datasource present. Cannot sync module information with database.");
167 } 166 }
168 } else { 167 } else {
169 LOG.trace("Module information clean - no synchronization required."); 168 LOG.trace("Module information clean - no synchronization required.");
170 } 169 }
171 } 170 }
172 171
173 /** 172 /**
174 * Unloads all found modules. 173 * Unloads all found modules.
175 */ 174 */
176 public void unloadAll() { 175 public void unloadAll() {
177 registeredModules.clear(); 176 registeredModules.clear();
178 LOG.info("All modules unloaded."); 177 LOG.info("All modules unloaded.");
179 } 178 }
180 179
181 /** 180 /**
182 * Returns the main menu. 181 * Returns the main menu.
183 * 182 *
184 * @param db the interface to the database 183 * @param db the interface to the database
185 * @return a list of menus belonging to the main menu 184 * @return a list of menus belonging to the main menu
186 */ 185 */
187 public List<Menu> getMainMenu(DatabaseFacade db) { 186 public List<Menu> getMainMenu(DatabaseFacade db) {
188 // TODO: user specific menu 187 // TODO: user specific menu
189 188
190 if (db.getDataSource().isPresent()) { 189 if (db.getDataSource().isPresent()) {
191 try (Connection conn = db.getDataSource().get().getConnection()) { 190 try (Connection conn = db.getDataSource().get().getConnection()) {
192 final ModuleDao dao = CoreDAOFactory.getModuleDao(db.getSQLDialect()); 191 final List<Module> modules = db.getDataAccessObjects().getModuleDao().list(conn);
193 final List<Module> modules = dao.listAll(conn);
194 192
195 return modules 193 return modules
196 .stream() 194 .stream()
197 .filter(Module::isVisible) 195 .filter(Module::isVisible)
198 .sorted(new Module.PriorityComparator()) 196 .sorted(new Module.PriorityComparator())
209 } 207 }
210 } else { 208 } else {
211 return Collections.emptyList(); 209 return Collections.emptyList();
212 } 210 }
213 } 211 }
214 212
215 /** 213 /**
216 * Returns an unmodifiable map of all registered modules. 214 * Returns an unmodifiable map of all registered modules.
217 * 215 * <p>
218 * The key is the classname of the module. 216 * The key is the classname of the module.
219 * 217 *
220 * @return the map of registered modules 218 * @return the map of registered modules
221 */ 219 */
222 public Map<String, LightPITModule> getRegisteredModules() { 220 public Map<String, LightPITModule> getRegisteredModules() {
223 return Collections.unmodifiableMap(registeredModules); 221 return Collections.unmodifiableMap(registeredModules);
224 } 222 }

mercurial