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 java.io.IOException; |
31 import org.slf4j.Logger; |
32 import java.lang.reflect.Method; |
32 import org.slf4j.LoggerFactory; |
33 import java.lang.reflect.Modifier; |
33 |
34 import java.util.Arrays; |
|
35 import java.util.HashMap; |
|
36 import java.util.List; |
|
37 import java.util.Locale; |
|
38 import java.util.Map; |
|
39 import java.util.Optional; |
|
40 import javax.servlet.ServletException; |
34 import javax.servlet.ServletException; |
41 import javax.servlet.http.HttpServlet; |
35 import javax.servlet.http.HttpServlet; |
42 import javax.servlet.http.HttpServletRequest; |
36 import javax.servlet.http.HttpServletRequest; |
43 import javax.servlet.http.HttpServletResponse; |
37 import javax.servlet.http.HttpServletResponse; |
44 import javax.servlet.http.HttpSession; |
38 import javax.servlet.http.HttpSession; |
45 import org.slf4j.Logger; |
39 import java.io.IOException; |
46 import org.slf4j.LoggerFactory; |
40 import java.lang.reflect.Method; |
|
41 import java.lang.reflect.Modifier; |
|
42 import java.util.*; |
47 |
43 |
48 /** |
44 /** |
49 * A special implementation of a HTTPServlet which is focused on implementing |
45 * A special implementation of a HTTPServlet which is focused on implementing |
50 * the necessary functionality for {@link LightPITModule}s. |
46 * the necessary functionality for {@link LightPITModule}s. |
51 */ |
47 */ |
52 public abstract class AbstractLightPITServlet extends HttpServlet { |
48 public abstract class AbstractLightPITServlet extends HttpServlet { |
53 |
49 |
54 private static final Logger LOG = LoggerFactory.getLogger(AbstractLightPITServlet.class); |
50 private static final Logger LOG = LoggerFactory.getLogger(AbstractLightPITServlet.class); |
55 |
51 |
56 private static final String HTML_FULL_DISPATCHER = Functions.jspPath("html_full"); |
52 private static final String HTML_FULL_DISPATCHER = Functions.jspPath("html_full"); |
57 |
53 |
58 /** |
54 /** |
59 * Store a reference to the annotation for quicker access. |
55 * Store a reference to the annotation for quicker access. |
60 */ |
56 */ |
61 private Optional<LightPITModule> moduleInfo = Optional.empty(); |
57 private LightPITModule moduleInfo = null; |
62 |
58 |
63 /** |
59 /** |
64 * The EL proxy is necessary, because the EL resolver cannot handle annotation properties. |
60 * The EL proxy is necessary, because the EL resolver cannot handle annotation properties. |
65 */ |
61 */ |
66 private Optional<LightPITModule.ELProxy> moduleInfoELProxy = Optional.empty(); |
62 private LightPITModule.ELProxy moduleInfoELProxy = null; |
67 |
63 |
68 |
64 |
69 @FunctionalInterface |
65 @FunctionalInterface |
70 private static interface HandlerMethod { |
66 private interface HandlerMethod { |
71 ResponseType apply(HttpServletRequest t, HttpServletResponse u) throws IOException, ServletException; |
67 ResponseType apply(HttpServletRequest t, HttpServletResponse u) throws IOException; |
72 } |
68 } |
73 |
69 |
74 /** |
70 /** |
75 * Invocation mapping gathered from the {@link RequestMapping} annotations. |
71 * Invocation mapping gathered from the {@link RequestMapping} annotations. |
76 * |
72 * |
82 */ |
78 */ |
83 private final Map<HttpMethod, Map<String, HandlerMethod>> mappings = new HashMap<>(); |
79 private final Map<HttpMethod, Map<String, HandlerMethod>> mappings = new HashMap<>(); |
84 |
80 |
85 /** |
81 /** |
86 * Gives implementing modules access to the {@link ModuleManager}. |
82 * Gives implementing modules access to the {@link ModuleManager}. |
|
83 * |
87 * @return the module manager |
84 * @return the module manager |
88 */ |
85 */ |
89 protected final ModuleManager getModuleManager() { |
86 protected final ModuleManager getModuleManager() { |
90 return (ModuleManager) getServletContext().getAttribute(ModuleManager.SC_ATTR_NAME); |
87 return (ModuleManager) getServletContext().getAttribute(ModuleManager.SC_ATTR_NAME); |
91 } |
88 } |
92 |
89 |
|
90 public final LightPITModule getModuleInfo() { |
|
91 return moduleInfo; |
|
92 } |
|
93 |
93 /** |
94 /** |
94 * Gives implementing modules access to the {@link DatabaseFacade}. |
95 * Gives implementing modules access to the {@link DatabaseFacade}. |
|
96 * |
95 * @return the database facade |
97 * @return the database facade |
96 */ |
98 */ |
97 protected final DatabaseFacade getDatabaseFacade() { |
99 protected final DatabaseFacade getDatabaseFacade() { |
98 return (DatabaseFacade) getServletContext().getAttribute(DatabaseFacade.SC_ATTR_NAME); |
100 return (DatabaseFacade) getServletContext().getAttribute(DatabaseFacade.SC_ATTR_NAME); |
99 } |
101 } |
100 |
102 |
101 private ResponseType invokeMapping(Method method, HttpServletRequest req, HttpServletResponse resp) |
103 private ResponseType invokeMapping(Method method, HttpServletRequest req, HttpServletResponse resp) throws IOException { |
102 throws IOException, ServletException { |
|
103 try { |
104 try { |
104 LOG.trace("invoke {}#{}", method.getDeclaringClass().getName(), method.getName()); |
105 LOG.trace("invoke {}#{}", method.getDeclaringClass().getName(), method.getName()); |
105 return (ResponseType) method.invoke(this, req, resp); |
106 return (ResponseType) method.invoke(this, req, resp); |
106 } catch (ReflectiveOperationException | ClassCastException ex) { |
107 } catch (ReflectiveOperationException | ClassCastException ex) { |
107 LOG.error(String.format("invocation of method %s failed", method.getName()), ex); |
108 LOG.error(String.format("invocation of method %s failed", method.getName()), ex); |
110 } |
111 } |
111 } |
112 } |
112 |
113 |
113 @Override |
114 @Override |
114 public void init() throws ServletException { |
115 public void init() throws ServletException { |
115 moduleInfo = Optional.ofNullable(this.getClass().getAnnotation(LightPITModule.class)); |
116 moduleInfo = this.getClass().getAnnotation(LightPITModule.class); |
116 moduleInfoELProxy = moduleInfo.map(LightPITModule.ELProxy::convert); |
117 moduleInfoELProxy = moduleInfo == null ? null : LightPITModule.ELProxy.convert(moduleInfo); |
117 |
118 |
118 if (moduleInfo.isPresent()) { |
119 if (moduleInfo != null) { |
119 scanForRequestMappings(); |
120 scanForRequestMappings(); |
120 } |
121 } |
121 |
122 |
122 LOG.trace("{} initialized", getServletName()); |
123 LOG.trace("{} initialized", getServletName()); |
123 } |
124 } |
124 |
125 |
125 private void scanForRequestMappings() { |
126 private void scanForRequestMappings() { |
126 try { |
127 try { |
268 } |
269 } |
269 |
270 |
270 // set some internal request attributes |
271 // set some internal request attributes |
271 req.setAttribute(Constants.REQ_ATTR_PATH, Functions.fullPath(req)); |
272 req.setAttribute(Constants.REQ_ATTR_PATH, Functions.fullPath(req)); |
272 req.setAttribute(Constants.REQ_ATTR_MODULE_CLASSNAME, this.getClass().getName()); |
273 req.setAttribute(Constants.REQ_ATTR_MODULE_CLASSNAME, this.getClass().getName()); |
273 moduleInfoELProxy.ifPresent((proxy) -> req.setAttribute(Constants.REQ_ATTR_MODULE_INFO, proxy)); |
274 Optional.ofNullable(moduleInfoELProxy).ifPresent((proxy) -> req.setAttribute(Constants.REQ_ATTR_MODULE_INFO, proxy)); |
274 |
275 |
275 |
276 |
276 // call the handler, if available, or send an HTTP 404 error |
277 // call the handler, if available, or send an HTTP 404 error |
277 Optional<HandlerMethod> mapping = findMapping(method, req); |
278 Optional<HandlerMethod> mapping = findMapping(method, req); |
278 if (mapping.isPresent()) { |
279 if (mapping.isPresent()) { |