# HG changeset patch # User Mike Becker # Date 1589397023 -7200 # Node ID cc7f082c5ef3bb5aa540d3d9290a91bb7804097c # Parent 835dd169642a566999318176e03dc2f7e07eaab2 simplifies menu generation, adds submenus and removes VersionsModule (versions will be part of the ProjectsModule) diff -r 835dd169642a -r cc7f082c5ef3 src/main/java/de/uapcore/lightpit/AbstractLightPITServlet.java --- a/src/main/java/de/uapcore/lightpit/AbstractLightPITServlet.java Wed May 13 18:55:05 2020 +0200 +++ b/src/main/java/de/uapcore/lightpit/AbstractLightPITServlet.java Wed May 13 21:10:23 2020 +0200 @@ -71,6 +71,8 @@ */ private final Map> mappings = new HashMap<>(); + private final List subMenu = new ArrayList<>(); + /** * Gives implementing modules access to the {@link ModuleManager}. * @@ -174,6 +176,14 @@ ); } + final var menuKey = mapping.get().menuKey(); + if (!menuKey.isBlank()) { + subMenu.add(new MenuEntry( + new ResourceKey(moduleInfo.getBundleBaseName(), menuKey), + moduleInfo.getModulePath() + requestPath, + mapping.get().menuSequence())); + } + LOG.debug("{} {} maps to {}::{}", mapping.get().method(), requestPath, @@ -234,13 +244,16 @@ throws IOException, ServletException { req.setAttribute(Constants.REQ_ATTR_MENU, getModuleManager().getMainMenu()); + req.setAttribute(Constants.REQ_ATTR_SUB_MENU, subMenu); req.getRequestDispatcher(SITE_JSP).forward(req, resp); } + private String sanitizeRequestPath(HttpServletRequest req) { + return Optional.ofNullable(req.getPathInfo()).orElse("/"); + } + private Optional findMapping(HttpMethod method, HttpServletRequest req) { - return Optional.ofNullable(mappings.get(method)) - .map(rm -> rm.get(Optional.ofNullable(req.getPathInfo()).orElse("/")) - ); + return Optional.ofNullable(mappings.get(method)).map(rm -> rm.get(sanitizeRequestPath(req))); } private void forwardAsSpecified(ResponseType type, HttpServletRequest req, HttpServletResponse resp) @@ -275,7 +288,6 @@ // set some internal request attributes req.setAttribute(Constants.REQ_ATTR_PATH, Functions.fullPath(req)); - req.setAttribute(Constants.REQ_ATTR_MODULE_CLASSNAME, this.getClass().getName()); Optional.ofNullable(moduleInfo).ifPresent((proxy) -> req.setAttribute(Constants.REQ_ATTR_MODULE_INFO, proxy)); // obtain a connection and create the data access objects diff -r 835dd169642a -r cc7f082c5ef3 src/main/java/de/uapcore/lightpit/Constants.java --- a/src/main/java/de/uapcore/lightpit/Constants.java Wed May 13 18:55:05 2020 +0200 +++ b/src/main/java/de/uapcore/lightpit/Constants.java Wed May 13 21:10:23 2020 +0200 @@ -38,8 +38,6 @@ public final class Constants { public static final String JSP_PATH_PREFIX = "/WEB-INF/jsp/"; - public static final String JSPF_PATH_PREFIX = "/WEB-INF/jspf/"; - public static final String DYN_FRAGMENT_PATH_PREFIX = "/WEB-INF/dynamic_fragments/"; @@ -64,11 +62,6 @@ public static final String CTX_ATTR_DB_DIALECT = "db-dialect"; /** - * Key for the request attribute containing the class name of the currently dispatching module. - */ - public static final String REQ_ATTR_MODULE_CLASSNAME = fqn(AbstractLightPITServlet.class, "moduleClassname"); - - /** * Key for the request attribute containing the {@link LightPITModule} information of the currently dispatching module. */ public static final String REQ_ATTR_MODULE_INFO = fqn(AbstractLightPITServlet.class, "moduleInfo"); @@ -79,6 +72,11 @@ public static final String REQ_ATTR_MENU = fqn(AbstractLightPITServlet.class, "mainMenu"); /** + * Key for the request attribute containing the sub menu list. + */ + public static final String REQ_ATTR_SUB_MENU = fqn(AbstractLightPITServlet.class, "subMenu"); + + /** * Key for the request attribute containing the full path information (servlet path + path info). */ public static final String REQ_ATTR_PATH = fqn(AbstractLightPITServlet.class, "path"); diff -r 835dd169642a -r cc7f082c5ef3 src/main/java/de/uapcore/lightpit/Functions.java --- a/src/main/java/de/uapcore/lightpit/Functions.java Wed May 13 18:55:05 2020 +0200 +++ b/src/main/java/de/uapcore/lightpit/Functions.java Wed May 13 21:10:23 2020 +0200 @@ -54,10 +54,6 @@ return enforceExt(Constants.JSP_PATH_PREFIX + filename, ".jsp"); } - public static String jspfPath(String filename) { - return enforceExt(Constants.JSPF_PATH_PREFIX + filename, ".jspf"); - } - public static String dynFragmentPath(String filename) { return enforceExt(Constants.DYN_FRAGMENT_PATH_PREFIX + filename, ".jsp"); } diff -r 835dd169642a -r cc7f082c5ef3 src/main/java/de/uapcore/lightpit/MenuEntry.java --- a/src/main/java/de/uapcore/lightpit/MenuEntry.java Wed May 13 18:55:05 2020 +0200 +++ b/src/main/java/de/uapcore/lightpit/MenuEntry.java Wed May 13 21:10:23 2020 +0200 @@ -40,11 +40,6 @@ public class MenuEntry implements Comparable { /** - * Class name of the module for which this menu is built. - */ - private final String moduleClassName; - - /** * Resource key for the menu label. */ private final ResourceKey resourceKey; @@ -59,17 +54,12 @@ */ private final int sequence; - public MenuEntry(String moduleClassName, ResourceKey resourceKey, String pathName, int sequence) { - this.moduleClassName = moduleClassName; + public MenuEntry(ResourceKey resourceKey, String pathName, int sequence) { this.resourceKey = resourceKey; this.pathName = pathName; this.sequence = sequence; } - public String getModuleClassName() { - return moduleClassName; - } - public ResourceKey getResourceKey() { return resourceKey; } diff -r 835dd169642a -r cc7f082c5ef3 src/main/java/de/uapcore/lightpit/ModuleManager.java --- a/src/main/java/de/uapcore/lightpit/ModuleManager.java Wed May 13 18:55:05 2020 +0200 +++ b/src/main/java/de/uapcore/lightpit/ModuleManager.java Wed May 13 21:10:23 2020 +0200 @@ -36,7 +36,10 @@ import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; import javax.servlet.annotation.WebListener; -import java.util.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Optional; /** * Scans registered servlets for LightPIT modules. @@ -55,7 +58,7 @@ /** * Maps class names to module information. */ - private final Map registeredModules = new HashMap<>(); + private final List registeredModules = new ArrayList<>(); /** * Contains the menu entries for the loaded modules. @@ -114,7 +117,7 @@ private void handleServletRegistration(String name, Registration reg) { final Optional moduleInfo = getModuleInfo(reg); if (moduleInfo.isPresent()) { - registeredModules.put(reg.getClassName(), moduleInfo.get()); + registeredModules.add(moduleInfo.get()); LOG.info("Module detected: {}", name); } else { LOG.debug("Servlet {} is no module, skipping.", name); @@ -145,16 +148,15 @@ */ private void createMainMenu() { mainMenu.clear(); - registeredModules.entrySet() + registeredModules .stream() - .filter(mod -> !mod.getValue().systemModule()) + .filter(mod -> !mod.systemModule()) .map(mod -> new MenuEntry( - mod.getKey(), new ResourceKey( - mod.getValue().bundleBaseName(), - mod.getValue().menuKey()), - mod.getValue().modulePath(), - mod.getValue().defaultPriority())) + mod.bundleBaseName(), + mod.menuKey()), + mod.modulePath(), + mod.defaultPriority())) .sorted() .forEachOrdered(mainMenu::add); } diff -r 835dd169642a -r cc7f082c5ef3 src/main/java/de/uapcore/lightpit/RequestMapping.java --- a/src/main/java/de/uapcore/lightpit/RequestMapping.java Wed May 13 18:55:05 2020 +0200 +++ b/src/main/java/de/uapcore/lightpit/RequestMapping.java Wed May 13 21:10:23 2020 +0200 @@ -62,11 +62,19 @@ String requestPath() default ""; /** - * Returns the properties key for the (sub) menu label. + * Specifies the properties key for the sub menu label. + * An empty string (default) means that no sub menu entry shall be created. *

* This should only be used for {@link HttpMethod#GET} requests. * * @return the properties key */ String menuKey() default ""; + + /** + * May be changed to control the ordering of menu items. + * + * @return an integer to control the ordering + */ + int menuSequence() default 0; } diff -r 835dd169642a -r cc7f082c5ef3 src/main/java/de/uapcore/lightpit/modules/ErrorModule.java --- a/src/main/java/de/uapcore/lightpit/modules/ErrorModule.java Wed May 13 18:55:05 2020 +0200 +++ b/src/main/java/de/uapcore/lightpit/modules/ErrorModule.java Wed May 13 21:10:23 2020 +0200 @@ -59,17 +59,17 @@ return ResponseType.HTML; } - @RequestMapping(requestPath = "404", method = HttpMethod.GET) + @RequestMapping(requestPath = "404.html", method = HttpMethod.GET) public ResponseType handle404(HttpServletRequest req) { return handle(req, 404); } - @RequestMapping(requestPath = "403", method = HttpMethod.GET) + @RequestMapping(requestPath = "403.html", method = HttpMethod.GET) public ResponseType handle403(HttpServletRequest req) { return handle(req, 403); } - @RequestMapping(requestPath = "500", method = HttpMethod.GET) + @RequestMapping(requestPath = "500.html", method = HttpMethod.GET) public ResponseType handle500(HttpServletRequest req) { return handle(req, 500); } diff -r 835dd169642a -r cc7f082c5ef3 src/main/java/de/uapcore/lightpit/modules/ProjectsModule.java --- a/src/main/java/de/uapcore/lightpit/modules/ProjectsModule.java Wed May 13 18:55:05 2020 +0200 +++ b/src/main/java/de/uapcore/lightpit/modules/ProjectsModule.java Wed May 13 21:10:23 2020 +0200 @@ -47,7 +47,13 @@ public final class ProjectsModule extends AbstractLightPITServlet { @RequestMapping(method = HttpMethod.GET) - public ResponseType handle(HttpServletRequest req, DataAccessObjects dao) { + public ResponseType index(HttpServletRequest req, DataAccessObjects dao) { + + return ResponseType.HTML; + } + + @RequestMapping(method = HttpMethod.GET, requestPath = "versions", menuKey = "menu.versions") + public ResponseType versions(HttpServletRequest req, DataAccessObjects dao) { return ResponseType.HTML; } diff -r 835dd169642a -r cc7f082c5ef3 src/main/java/de/uapcore/lightpit/modules/VersionsModule.java --- a/src/main/java/de/uapcore/lightpit/modules/VersionsModule.java Wed May 13 18:55:05 2020 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,53 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 2018 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.*; -import de.uapcore.lightpit.dao.DataAccessObjects; - -import javax.servlet.annotation.WebServlet; -import javax.servlet.http.HttpServletRequest; - - -@LightPITModule( - bundleBaseName = "localization.versions", - modulePath = "versions", - defaultPriority = 50 -) -@WebServlet( - name = "VersionsModule", - urlPatterns = "/versions/*" -) -public final class VersionsModule extends AbstractLightPITServlet { - @RequestMapping(method = HttpMethod.GET) - public ResponseType handle(HttpServletRequest req, DataAccessObjects dao) { - - return ResponseType.HTML; - } -} diff -r 835dd169642a -r cc7f082c5ef3 src/main/resources/localization/projects.properties --- a/src/main/resources/localization/projects.properties Wed May 13 18:55:05 2020 +0200 +++ b/src/main/resources/localization/projects.properties Wed May 13 21:10:23 2020 +0200 @@ -23,3 +23,4 @@ name=Project Management description=Allows the configuration of projects. menuLabel=Projects +menu.versions=Versions diff -r 835dd169642a -r cc7f082c5ef3 src/main/resources/localization/projects_de.properties --- a/src/main/resources/localization/projects_de.properties Wed May 13 18:55:05 2020 +0200 +++ b/src/main/resources/localization/projects_de.properties Wed May 13 21:10:23 2020 +0200 @@ -23,3 +23,4 @@ name=Projektverwaltung description=Erlaubt die Konfiguration von Projekten. menuLabel=Projekte +menu.versions=Versionen \ No newline at end of file diff -r 835dd169642a -r cc7f082c5ef3 src/main/resources/localization/versions.properties --- a/src/main/resources/localization/versions.properties Wed May 13 18:55:05 2020 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,26 +0,0 @@ -# Copyright 2018 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. - -name = Version Management -description = Allows the configuration of versions and milestones within your project. -menuLabel = Versions diff -r 835dd169642a -r cc7f082c5ef3 src/main/resources/localization/versions_de.properties --- a/src/main/resources/localization/versions_de.properties Wed May 13 18:55:05 2020 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,26 +0,0 @@ -# Copyright 2018 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. - -name = Versionsverwaltung -description = Erlaubt die Konfiguration von Versionen und Meilensteinen im Projekt. -menuLabel = Versionen diff -r 835dd169642a -r cc7f082c5ef3 src/main/webapp/WEB-INF/jsp/site.jsp --- a/src/main/webapp/WEB-INF/jsp/site.jsp Wed May 13 18:55:05 2020 +0200 +++ b/src/main/webapp/WEB-INF/jsp/site.jsp Wed May 13 21:10:23 2020 +0200 @@ -30,9 +30,15 @@ <%@taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %> <%@taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %> +<%-- Define an alias for the request path --%> + + <%-- Define an alias for the main menu --%> +<%-- Define an alias for the sub menu --%> + + <%-- Define an alias for the fragment name --%> @@ -65,22 +71,16 @@

- + + +
diff -r 835dd169642a -r cc7f082c5ef3 src/main/webapp/WEB-INF/jspf/menu-entry.jspf --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/webapp/WEB-INF/jspf/menu-entry.jspf Wed May 13 21:10:23 2020 +0200 @@ -0,0 +1,38 @@ +<%-- +DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + +Copyright 2018 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. +--%> + \ No newline at end of file diff -r 835dd169642a -r cc7f082c5ef3 src/main/webapp/WEB-INF/web.xml --- a/src/main/webapp/WEB-INF/web.xml Wed May 13 18:55:05 2020 +0200 +++ b/src/main/webapp/WEB-INF/web.xml Wed May 13 21:10:23 2020 +0200 @@ -11,14 +11,14 @@ 404 - /error/404 + /error/404.html 403 - /error/403 + /error/403.html 500 - /error/500 + /error/500.html diff -r 835dd169642a -r cc7f082c5ef3 src/main/webapp/index.jsp --- a/src/main/webapp/index.jsp Wed May 13 18:55:05 2020 +0200 +++ b/src/main/webapp/index.jsp Wed May 13 21:10:23 2020 +0200 @@ -27,6 +27,6 @@ <%@page import="de.uapcore.lightpit.Functions" %> <%@page import="de.uapcore.lightpit.modules.HomeModule" %> <% -response.setStatus(response.SC_MOVED_TEMPORARILY); -response.setHeader("Location", "./"+Functions.modulePathOf(HomeModule.class)); + response.setStatus(response.SC_MOVED_TEMPORARILY); + response.setHeader("Location", Functions.modulePathOf(HomeModule.class)); %> diff -r 835dd169642a -r cc7f082c5ef3 src/main/webapp/lightpit.css --- a/src/main/webapp/lightpit.css Wed May 13 18:55:05 2020 +0200 +++ b/src/main/webapp/lightpit.css Wed May 13 21:10:23 2020 +0200 @@ -51,21 +51,22 @@ text-decoration: none; } -#mainMenu { +#mainMenu, #subMenu { width: 100%; display: flex; flex-flow: row wrap; - background: #f0f0f5; + border-image-source: linear-gradient(to right, #606060, rgba(60, 60, 60, .25)); + border-image-slice: 1; + border-bottom-style: solid; + border-bottom-width: 1pt; +} + +#mainMenu { + background: #e0e0e5; } #subMenu { background: #f7f7ff; - border-image-source: linear-gradient(to right, #606060, rgba(60, 60, 60, .25)); - border-image-slice: 1; - border-top-style: solid; - border-top-width: 1pt; - border-bottom-style: solid; - border-bottom-width: 1pt; } .menuEntry { @@ -76,7 +77,7 @@ } #mainMenu .menuEntry[data-active] { - background: #e0e0e5; + background: #d0d0d5; } #subMenu .menuEntry[data-active] {