Sun, 31 Dec 2017 17:43:39 +0100
user friendly error pages for codes 404, 403 and 500
--- a/src/java/de/uapcore/lightpit/AbstractLightPITServlet.java Sat Dec 30 20:41:55 2017 +0100 +++ b/src/java/de/uapcore/lightpit/AbstractLightPITServlet.java Sun Dec 31 17:43:39 2017 +0100 @@ -73,6 +73,12 @@ /** * Invocation mapping gathered from the {@link RequestMapping} annotations. + * + * Paths in this map must always start with a leading slash, although + * the specification in the annotation must not start with a leading slash. + * + * The reason for this is the different handling of empty paths in + * {@link HttpServletRequest#getPathInfo()}. */ private final Map<HttpMethod, Map<String, HandlerMethod>> mappings = new HashMap<>(); @@ -145,9 +151,11 @@ if (params.length == 2 && HttpServletRequest.class.isAssignableFrom(params[0]) && HttpServletResponse.class.isAssignableFrom(params[1])) { + + final String requestPath = "/"+mapping.get().requestPath(); if (mappings.computeIfAbsent(mapping.get().method(), k -> new HashMap<>()). - putIfAbsent(mapping.get().requestPath(), + putIfAbsent(requestPath, (req, resp) -> invokeMapping(method, req, resp)) != null) { LOG.warn("{} {} has multiple mappings", mapping.get().method(), @@ -157,7 +165,7 @@ LOG.info("{} {} maps to {}", mapping.get().method(), - mapping.get().requestPath(), + requestPath, method.getName() ); } else { @@ -219,7 +227,7 @@ private Optional<HandlerMethod> findMapping(HttpMethod method, HttpServletRequest req) { return Optional.ofNullable(mappings.get(method)).map( - (rm) -> rm.get(Optional.ofNullable(req.getPathInfo()).orElse("")) + (rm) -> rm.get(Optional.ofNullable(req.getPathInfo()).orElse("/")) ); }
--- a/src/java/de/uapcore/lightpit/LightPITModule.java Sat Dec 30 20:41:55 2017 +0100 +++ b/src/java/de/uapcore/lightpit/LightPITModule.java Sun Dec 31 17:43:39 2017 +0100 @@ -71,6 +71,10 @@ /** * Returns the properties key for the menu label. + * + * Set this string to empty string, if the module should be hidden from + * the menu. + * * @return the properties key */ String menuKey() default "menuLabel";
--- a/src/java/de/uapcore/lightpit/ModuleManager.java Sat Dec 30 20:41:55 2017 +0100 +++ b/src/java/de/uapcore/lightpit/ModuleManager.java Sun Dec 31 17:43:39 2017 +0100 @@ -31,6 +31,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Objects; import java.util.Optional; import javax.servlet.Registration; import javax.servlet.ServletContext; @@ -118,10 +119,12 @@ private void handleServletRegistration(String name, Registration reg) { final Optional<LightPITModule> moduleInfo = getModuleInfo(reg); - if (moduleInfo.isPresent()) { + if (moduleInfo.isPresent()) { + // TODO: implement dependency resolver - // TODO: remove this call and add the module to some dependency resolver, first - addModuleToMenu(reg.getClassName(), moduleInfo.get()); + if (!moduleInfo.get().menuKey().isEmpty()) { + addModuleToMenu(reg.getClassName(), moduleInfo.get()); + } LOG.info("Module detected: {}", name); } else {
--- a/src/java/de/uapcore/lightpit/RequestMapping.java Sat Dec 30 20:41:55 2017 +0100 +++ b/src/java/de/uapcore/lightpit/RequestMapping.java Sun Dec 31 17:43:39 2017 +0100 @@ -59,7 +59,7 @@ * If a menu key is specified, this is also the path, which is linked * by the menu entry. * - * The path must be specified <em>without</em> a trailing slash. + * The path must be specified <em>without</em> leading and trailing slash. * * @return the request path the annotated method should handle */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/java/de/uapcore/lightpit/modules/ErrorModule.java Sun Dec 31 17:43:39 2017 +0100 @@ -0,0 +1,80 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2017 Mike Becker. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ +package de.uapcore.lightpit.modules; + +import de.uapcore.lightpit.LightPITModule; +import de.uapcore.lightpit.AbstractLightPITServlet; +import de.uapcore.lightpit.HttpMethod; +import de.uapcore.lightpit.RequestMapping; +import de.uapcore.lightpit.ResponseType; +import javax.servlet.annotation.WebServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +/** + * Entry point for the application. + */ +@LightPITModule( + bundleBaseName = "de.uapcore.lightpit.resources.localization.error", + modulePath = "error", + menuKey = "", + titleKey = "title" +) +@WebServlet( + name = "ErrorModule", + urlPatterns = "/error/*" +) +public final class ErrorModule extends AbstractLightPITServlet { + + public static final String REQ_ATTR_ERROR_CODE = "errorCode"; + + private ResponseType handle(HttpServletRequest req, HttpServletResponse resp, int sc) { + + req.setAttribute(REQ_ATTR_ERROR_CODE, sc); + setStylesheet(req, "error"); + setDynamicFragment(req, "error"); + + return ResponseType.HTML_FULL; + } + + @RequestMapping(requestPath = "404", method = HttpMethod.GET) + public ResponseType handle404(HttpServletRequest req, HttpServletResponse resp) { + return handle(req, resp, 404); + } + + @RequestMapping(requestPath = "403", method = HttpMethod.GET) + public ResponseType handle403(HttpServletRequest req, HttpServletResponse resp) { + return handle(req, resp, 403); + } + + @RequestMapping(requestPath = "500", method = HttpMethod.GET) + public ResponseType handle500(HttpServletRequest req, HttpServletResponse resp) { + return handle(req, resp, 500); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/java/de/uapcore/lightpit/resources/localization/error.properties Sun Dec 31 17:43:39 2017 +0100 @@ -0,0 +1,35 @@ +# Copyright 2017 Mike Becker. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +title = Error + +h1 = The requested page cannot be displayed. +errorCode = Code + +errorMessage = Message +errorMessage.404 = Page not found +errorMessage.403 = Access denied +errorMessage.500 = Internal error + +errorTimestamp = Timestamp +errorExceptionText = Internal Exception
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/java/de/uapcore/lightpit/resources/localization/error_de.properties Sun Dec 31 17:43:39 2017 +0100 @@ -0,0 +1,35 @@ +# Copyright 2017 Mike Becker. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +title = Fehler + +h1 = Die angeforderte Seite kann nicht angezeigt werden. +errorCode = Fehlercode + +errorMessage = Nachricht +errorMessage.404 = Seite nicht gefunden +errorMessage.403 = Zugriff verboten +errorMessage.500 = Interner Fehler + +errorTimestamp = Zeitstempel +errorExceptionText = Interne Ausnahme
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/WEB-INF/dynamic_fragments/error.jsp Sun Dec 31 17:43:39 2017 +0100 @@ -0,0 +1,56 @@ +<%-- +DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + +Copyright 2017 Mike Becker. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--%> +<%@page pageEncoding="UTF-8" session="true" %> +<%@page import="de.uapcore.lightpit.modules.ErrorModule" %> +<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> +<%@taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %> + +<c:set scope="page" var="errorCode" value="${requestScope[ErrorModule.REQ_ATTR_ERROR_CODE]}"/> + +<div id="error-page"> + <h1><fmt:message key="h1"/></h1> + <table> + <tr> + <th><fmt:message key="errorCode" />:</th> + <td>${errorCode}</td> + </tr> + <tr> + <th><fmt:message key="errorMessage" />:</th> + <td><fmt:message key="errorMessage.${errorCode}" /></td> + </tr> + <tr> + <th><fmt:message key="errorTimestamp" />:</th> + <td><fmt:formatDate type="both" value="<%= new java.util.Date()%>"/></td> + </tr> + <c:if test="${not empty exception}"> + <tr> + <th><fmt:message key="errorExceptionText" />:</th> + <td>${exception.class.name} - ${exception.message}</td> + </tr> + </c:if> + </table> +</div>
--- a/web/WEB-INF/web.xml Sat Dec 30 20:41:55 2017 +0100 +++ b/web/WEB-INF/web.xml Sun Dec 31 17:43:39 2017 +0100 @@ -9,4 +9,16 @@ <param-name>available-languages</param-name> <param-value>en,de</param-value> </context-param> + <error-page> + <error-code>404</error-code> + <location>/error/404</location> + </error-page> + <error-page> + <error-code>403</error-code> + <location>/error/403</location> + </error-page> + <error-page> + <error-code>500</error-code> + <location>/error/500</location> + </error-page> </web-app>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/error.css Sun Dec 31 17:43:39 2017 +0100 @@ -0,0 +1,55 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2017 Mike Becker. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +#error-page h1 { + font-size: 1.5em; +} + +#error-page table { + width: 100%; + + border-top-style: solid; + border-top-width: 1pt; + border-top-color: #606060; + + border-bottom-style: solid; + border-bottom-width: 1pt; + border-bottom-color: #505050; + + border-collapse: separate; + border-spacing: .5em; +} + +#error-page table th { + text-align: right; +} + +#error-page table td { + width: 100%; +}