bloat removal 3/3 - LightPITModule annotation and ModuleManager

Sat, 23 May 2020 14:13:09 +0200

author
Mike Becker <universe@uap-core.de>
date
Sat, 23 May 2020 14:13:09 +0200
changeset 79
f64255a88d66
parent 78
bb4c52bf3439
child 80
27a25f32048e

bloat removal 3/3 - LightPITModule annotation and ModuleManager

src/main/java/de/uapcore/lightpit/AbstractLightPITServlet.java file | annotate | diff | comparison | revisions
src/main/java/de/uapcore/lightpit/LightPITModule.java file | annotate | diff | comparison | revisions
src/main/java/de/uapcore/lightpit/MenuEntry.java file | annotate | diff | comparison | revisions
src/main/java/de/uapcore/lightpit/ModuleManager.java file | annotate | diff | comparison | revisions
src/main/java/de/uapcore/lightpit/modules/ErrorModule.java file | annotate | diff | comparison | revisions
src/main/java/de/uapcore/lightpit/modules/LanguageModule.java file | annotate | diff | comparison | revisions
src/main/java/de/uapcore/lightpit/modules/ProjectsModule.java file | annotate | diff | comparison | revisions
src/main/java/de/uapcore/lightpit/modules/UsersModule.java file | annotate | diff | comparison | revisions
src/main/resources/localization/language.properties file | annotate | diff | comparison | revisions
src/main/resources/localization/language_de.properties file | annotate | diff | comparison | revisions
src/main/resources/localization/lightpit.properties file | annotate | diff | comparison | revisions
src/main/resources/localization/lightpit_de.properties file | annotate | diff | comparison | revisions
src/main/resources/localization/projects.properties file | annotate | diff | comparison | revisions
src/main/resources/localization/projects_de.properties file | annotate | diff | comparison | revisions
src/main/resources/localization/users.properties file | annotate | diff | comparison | revisions
src/main/resources/localization/users_de.properties file | annotate | diff | comparison | revisions
src/main/webapp/index.jsp file | annotate | diff | comparison | revisions
--- a/src/main/java/de/uapcore/lightpit/AbstractLightPITServlet.java	Sat May 23 13:52:04 2020 +0200
+++ b/src/main/java/de/uapcore/lightpit/AbstractLightPITServlet.java	Sat May 23 14:13:09 2020 +0200
@@ -50,7 +50,7 @@
 
 /**
  * A special implementation of a HTTPServlet which is focused on implementing
- * the necessary functionality for {@link LightPITModule}s.
+ * the necessary functionality for LightPIT pages.
  */
 public abstract class AbstractLightPITServlet extends HttpServlet {
 
@@ -90,15 +90,6 @@
     private final Map<HttpMethod, Map<String, Method>> mappings = new HashMap<>();
 
     /**
-     * Gives implementing modules access to the {@link ModuleManager}.
-     *
-     * @return the module manager
-     */
-    protected final ModuleManager getModuleManager() {
-        return (ModuleManager) getServletContext().getAttribute(ModuleManager.SC_ATTR_NAME);
-    }
-
-    /**
      * Returns the name of the resource bundle associated with this servlet.
      * @return the resource bundle base name
      */
@@ -332,7 +323,12 @@
     private void forwardToFullView(HttpServletRequest req, HttpServletResponse resp)
             throws IOException, ServletException {
 
-        final var mainMenu = new ArrayList<MenuEntry>(getModuleManager().getMainMenu());
+        final String lightpitBundle = "localization.lightpit";
+        final var mainMenu = List.of(
+                new MenuEntry(new ResourceKey(lightpitBundle, "menu.projects"), "projects/"),
+                new MenuEntry(new ResourceKey(lightpitBundle, "menu.users"), "teams/"),
+                new MenuEntry(new ResourceKey(lightpitBundle, "menu.languages"), "language/")
+        );
         for (var entry : mainMenu) {
             if (Functions.fullPath(req).startsWith("/" + entry.getPathName())) {
                 entry.setActive(true);
--- a/src/main/java/de/uapcore/lightpit/LightPITModule.java	Sat May 23 13:52:04 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,101 +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;
-
-import javax.servlet.annotation.WebServlet;
-import java.lang.annotation.*;
-
-
-/**
- * Contains information about a LightPIT module.
- * <p>
- * This annotation is typically used to annotate the {@link WebServlet} which
- * implements the module's functionality.
- */
-@Documented
-@Retention(RetentionPolicy.RUNTIME)
-@Target(ElementType.TYPE)
-public @interface LightPITModule {
-    /**
-     * Base name of the module specific resource bundle.
-     *
-     * @return a base name suitable for the JSTL tag 'setBundle'.
-     */
-    String bundleBaseName();
-
-    /**
-     * The path for this module, which will also be used for the menu entry.
-     * <p>
-     * This path must adhere to the URL pattern of the Servlet but must not
-     * contain any starting or trailing slashes.
-     *
-     * @return the relative module path
-     */
-    String modulePath();
-
-    /**
-     * If set to <code>true</code>, this module is always loaded, but never
-     * visible in the menu or the Web UI module manager.
-     *
-     * @return true, if this is a system module
-     */
-    boolean systemModule() default false;
-
-    /**
-     * Optionally specifies a default priority for this module.
-     * The priority is used to order the menu entries.
-     *
-     * @return an integer priority
-     */
-    int defaultPriority() default 1000;
-
-    /**
-     * Class representing the annotation.
-     * This is necessary, because the EL resolver cannot deal with
-     * annotation objects.
-     * <p>
-     * Note, that only the properties which are interesting for the JSP pages
-     * are proxied by this object.
-     */
-    class ELProxy {
-        private final String bundleBaseName, modulePath;
-
-        public ELProxy(LightPITModule annotation) {
-            bundleBaseName = annotation.bundleBaseName();
-            modulePath = annotation.modulePath();
-        }
-
-        public String getBundleBaseName() {
-            return bundleBaseName;
-        }
-        public String getModulePath() {
-            return modulePath;
-        }
-    }
-}
--- a/src/main/java/de/uapcore/lightpit/MenuEntry.java	Sat May 23 13:52:04 2020 +0200
+++ b/src/main/java/de/uapcore/lightpit/MenuEntry.java	Sat May 23 14:13:09 2020 +0200
@@ -28,16 +28,7 @@
  */
 package de.uapcore.lightpit;
 
-import java.util.Objects;
-
-/**
- * Maps a resource key for the menu label to the path name for the underlying
- * site.
- * <p>
- * Objects of this class are internally instantiated by the
- * {@link ModuleManager}.
- */
-public class MenuEntry implements Comparable<MenuEntry> {
+public class MenuEntry {
 
     /**
      * Resource key for the menu label.
@@ -55,27 +46,20 @@
     private final String pathName;
 
     /**
-     * Sequence number to determine the ordering of the menu.
-     */
-    private final int sequence;
-
-    /**
      * True if this menu entry is active.
      */
     private boolean active = false;
 
-    public MenuEntry(ResourceKey resourceKey, String pathName, int sequence) {
+    public MenuEntry(ResourceKey resourceKey, String pathName) {
         this.text = null;
         this.resourceKey = resourceKey;
         this.pathName = pathName;
-        this.sequence = sequence;
     }
 
-    public MenuEntry(String text, String pathName, int sequence) {
+    public MenuEntry(String text, String pathName) {
         this.text = text;
         this.resourceKey = null;
         this.pathName = pathName;
-        this.sequence = sequence;
     }
 
     public ResourceKey getResourceKey() {
@@ -90,10 +74,6 @@
         return pathName;
     }
 
-    public int getSequence() {
-        return sequence;
-    }
-
     public boolean isActive() {
         return this.active;
     }
@@ -102,22 +82,4 @@
         this.active = true;
     }
 
-    @Override
-    public boolean equals(Object o) {
-        if (this == o) return true;
-        if (o == null || getClass() != o.getClass()) return false;
-        MenuEntry menuEntry = (MenuEntry) o;
-        return resourceKey.equals(menuEntry.resourceKey) &&
-                pathName.equals(menuEntry.pathName);
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hash(resourceKey, pathName);
-    }
-
-    @Override
-    public int compareTo(MenuEntry menuEntry) {
-        return Integer.compare(this.sequence, menuEntry.sequence);
-    }
 }
--- a/src/main/java/de/uapcore/lightpit/ModuleManager.java	Sat May 23 13:52:04 2020 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,172 +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;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import javax.servlet.Registration;
-import javax.servlet.ServletContext;
-import javax.servlet.ServletContextEvent;
-import javax.servlet.ServletContextListener;
-import javax.servlet.annotation.WebListener;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Optional;
-
-/**
- * Scans registered servlets for LightPIT modules.
- */
-@WebListener
-public final class ModuleManager implements ServletContextListener {
-
-    private static final Logger LOG = LoggerFactory.getLogger(ModuleManager.class);
-
-    /**
-     * The attribute name in the servlet context under which an instance of this class can be found.
-     */
-    public static final String SC_ATTR_NAME = ModuleManager.class.getName();
-    private ServletContext sc;
-
-    /**
-     * Maps class names to module information.
-     */
-    private final List<LightPITModule> registeredModules = new ArrayList<>();
-
-    /**
-     * Contains the menu entries for the loaded modules.
-     */
-    private final List<MenuEntry> mainMenu = new ArrayList<>();
-
-    @Override
-    public void contextInitialized(ServletContextEvent sce) {
-        sc = sce.getServletContext();
-        reloadAll();
-        sc.setAttribute(SC_ATTR_NAME, this);
-        LOG.info("Module manager injected into ServletContext.");
-    }
-
-    @Override
-    public void contextDestroyed(ServletContextEvent sce) {
-        unloadAll();
-    }
-
-    private Optional<LightPITModule> getModuleInfo(Registration reg) {
-        try {
-            final Class<?> scclass = Class.forName(reg.getClassName());
-
-            final boolean lpservlet = AbstractLightPITServlet.class.isAssignableFrom(scclass);
-            final boolean lpmodule = scclass.isAnnotationPresent(LightPITModule.class);
-
-            if (lpservlet && !lpmodule) {
-                LOG.warn(
-                        "{} is a LightPIT Servlet but is missing the module annotation.",
-                        reg.getClassName()
-                );
-            } else if (!lpservlet && lpmodule) {
-                LOG.warn(
-                        "{} is annotated as a LightPIT Module but does not extend {}.",
-                        reg.getClassName(),
-                        AbstractLightPITServlet.class.getSimpleName()
-                );
-            }
-
-            if (lpservlet && lpmodule) {
-                final LightPITModule moduleInfo = scclass.getAnnotation(LightPITModule.class);
-                return Optional.of(moduleInfo);
-            } else {
-                return Optional.empty();
-            }
-        } catch (ClassNotFoundException ex) {
-            LOG.error(
-                    "Servlet registration refers to class {} which cannot be found by the class loader (Reason: {})",
-                    reg.getClassName(),
-                    ex.getMessage()
-            );
-            return Optional.empty();
-        }
-    }
-
-    private void handleServletRegistration(String name, Registration reg) {
-        final Optional<LightPITModule> moduleInfo = getModuleInfo(reg);
-        if (moduleInfo.isPresent()) {
-            registeredModules.add(moduleInfo.get());
-            LOG.info("Module detected: {}", name);
-        } else {
-            LOG.debug("Servlet {} is no module, skipping.", name);
-        }
-    }
-
-    /**
-     * Scans for modules and reloads them all.
-     */
-    public void reloadAll() {
-        registeredModules.clear();
-        sc.getServletRegistrations().forEach(this::handleServletRegistration);
-        createMainMenu();
-
-        LOG.info("Modules loaded.");
-    }
-
-    /**
-     * Unloads all found modules.
-     */
-    public void unloadAll() {
-        registeredModules.clear();
-        LOG.info("All modules unloaded.");
-    }
-
-    /**
-     * Populates the main menu based on the registered modules.
-     */
-    private void createMainMenu() {
-        mainMenu.clear();
-        registeredModules
-                .stream()
-                .filter(mod -> !mod.systemModule())
-                .map(mod -> new MenuEntry(
-                        new ResourceKey(
-                                mod.bundleBaseName(),
-                                "menuLabel"),
-                        mod.modulePath() + "/",
-                        mod.defaultPriority()))
-                .sorted()
-                .forEachOrdered(mainMenu::add);
-    }
-
-    /**
-     * Returns the main menu.
-     *
-     * @return a list of menu items
-     */
-    public List<MenuEntry> getMainMenu() {
-        return Collections.unmodifiableList(mainMenu);
-    }
-}
--- a/src/main/java/de/uapcore/lightpit/modules/ErrorModule.java	Sat May 23 13:52:04 2020 +0200
+++ b/src/main/java/de/uapcore/lightpit/modules/ErrorModule.java	Sat May 23 14:13:09 2020 +0200
@@ -28,21 +28,16 @@
  */
 package de.uapcore.lightpit.modules;
 
-import de.uapcore.lightpit.*;
+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;
 import java.util.Optional;
 
-/**
- * Entry point for the application.
- */
-@LightPITModule(
-        bundleBaseName = "localization.error",
-        modulePath = "error",
-        systemModule = true
-)
 @WebServlet(
         name = "ErrorModule",
         urlPatterns = "/error/*"
--- a/src/main/java/de/uapcore/lightpit/modules/LanguageModule.java	Sat May 23 13:52:04 2020 +0200
+++ b/src/main/java/de/uapcore/lightpit/modules/LanguageModule.java	Sat May 23 14:13:09 2020 +0200
@@ -38,12 +38,6 @@
 import javax.servlet.http.HttpServletResponse;
 import java.util.*;
 
-
-@LightPITModule(
-        bundleBaseName = "localization.language",
-        modulePath = "language",
-        defaultPriority = 20000
-)
 @WebServlet(
         name = "LanguageModule",
         urlPatterns = "/language/*"
--- a/src/main/java/de/uapcore/lightpit/modules/ProjectsModule.java	Sat May 23 13:52:04 2020 +0200
+++ b/src/main/java/de/uapcore/lightpit/modules/ProjectsModule.java	Sat May 23 14:13:09 2020 +0200
@@ -49,11 +49,6 @@
 
 import static de.uapcore.lightpit.Functions.fqn;
 
-@LightPITModule(
-        bundleBaseName = "localization.projects",
-        modulePath = "projects",
-        defaultPriority = 20
-)
 @WebServlet(
         name = "ProjectsModule",
         urlPatterns = "/projects/*"
@@ -149,18 +144,18 @@
         MenuEntry entry;
 
         final var breadcrumbs = new ArrayList<MenuEntry>();
-        entry = new MenuEntry(new ResourceKey("localization.projects", "menuLabel"),
-                "projects/", 0);
+        entry = new MenuEntry(new ResourceKey("localization.lightpit", "menu.projects"),
+                "projects/");
         breadcrumbs.add(entry);
         if (level == 0) entry.setActive(true);
 
         if (sessionSelection.project != null) {
             if (sessionSelection.project.getId() < 0) {
                 entry = new MenuEntry(new ResourceKey("localization.projects", "button.create"),
-                        "projects/edit", 1);
+                        "projects/edit");
             } else {
                 entry = new MenuEntry(sessionSelection.project.getName(),
-                        "projects/view?pid=" + sessionSelection.project.getId(), 1);
+                        "projects/view?pid=" + sessionSelection.project.getId());
             }
             if (level == 1) entry.setActive(true);
             breadcrumbs.add(entry);
@@ -169,11 +164,11 @@
         if (sessionSelection.version != null) {
             if (sessionSelection.version.getId() < 0) {
                 entry = new MenuEntry(new ResourceKey("localization.projects", "button.version.create"),
-                        "projects/versions/edit", 2);
+                        "projects/versions/edit");
             } else {
                 entry = new MenuEntry(sessionSelection.version.getName(),
                         // TODO: change link to issue overview for that version
-                        "projects/versions/edit?id=" + sessionSelection.version.getId(), 2);
+                        "projects/versions/edit?id=" + sessionSelection.version.getId());
             }
             if (level == 2) entry.setActive(true);
             breadcrumbs.add(entry);
@@ -182,15 +177,15 @@
         if (sessionSelection.issue != null) {
             entry = new MenuEntry(new ResourceKey("localization.projects", "menu.issues"),
                     // TODO: change link to a separate issue view (maybe depending on the selected version)
-                    "projects/view?pid=" + sessionSelection.issue.getProject().getId(), 3);
+                    "projects/view?pid=" + sessionSelection.issue.getProject().getId());
             breadcrumbs.add(entry);
             if (sessionSelection.issue.getId() < 0) {
                 entry = new MenuEntry(new ResourceKey("localization.projects", "button.issue.create"),
-                        "projects/issues/edit", 2);
+                        "projects/issues/edit");
             } else {
                 entry = new MenuEntry("#" + sessionSelection.issue.getId(),
                         // TODO: maybe change link to a view rather than directly opening the editor
-                        "projects/issues/edit?id=" + sessionSelection.issue.getId(), 4);
+                        "projects/issues/edit?id=" + sessionSelection.issue.getId());
             }
             if (level == 3) entry.setActive(true);
             breadcrumbs.add(entry);
--- a/src/main/java/de/uapcore/lightpit/modules/UsersModule.java	Sat May 23 13:52:04 2020 +0200
+++ b/src/main/java/de/uapcore/lightpit/modules/UsersModule.java	Sat May 23 14:13:09 2020 +0200
@@ -40,11 +40,6 @@
 import java.sql.SQLException;
 import java.util.NoSuchElementException;
 
-@LightPITModule(
-        bundleBaseName = "localization.users",
-        modulePath = "teams",
-        defaultPriority = 100
-)
 @WebServlet(
         name = "UsersModule",
         urlPatterns = "/teams/*"
--- a/src/main/resources/localization/language.properties	Sat May 23 13:52:04 2020 +0200
+++ b/src/main/resources/localization/language.properties	Sat May 23 14:13:09 2020 +0200
@@ -22,7 +22,6 @@
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
 
 pageTitle=Language Selection
-menuLabel=Language
 
 submit = Switch language
 browserLanguage = Browser language
--- a/src/main/resources/localization/language_de.properties	Sat May 23 13:52:04 2020 +0200
+++ b/src/main/resources/localization/language_de.properties	Sat May 23 14:13:09 2020 +0200
@@ -22,7 +22,6 @@
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
 
 pageTitle=Sprachauswahl
-menuLabel = Sprache
 
 submit = Sprache ausw\u00e4hlen
 browserLanguage = Browsersprache
--- a/src/main/resources/localization/lightpit.properties	Sat May 23 13:52:04 2020 +0200
+++ b/src/main/resources/localization/lightpit.properties	Sat May 23 14:13:09 2020 +0200
@@ -21,10 +21,14 @@
 # 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.
 
-version=LightPIT - Version 0.1 (Snapshot) 
+version=LightPIT - Version 0.1 (Snapshot)
 
 button.okay=OK
 button.cancel=Cancel
 
 commit.success=Operation successful - you will be redirected in a second.
-commit.redirect-link=If redirection does not work, click the following link:
\ No newline at end of file
+commit.redirect-link=If redirection does not work, click the following link:
+
+menu.projects=Projects
+menu.users=Developer
+menu.languages=Language
--- a/src/main/resources/localization/lightpit_de.properties	Sat May 23 13:52:04 2020 +0200
+++ b/src/main/resources/localization/lightpit_de.properties	Sat May 23 14:13:09 2020 +0200
@@ -28,3 +28,7 @@
 
 commit.success=Operation erfolgreich - Sie werden jeden Moment weitergeleitet.
 commit.redirect-link=Falls die Weiterleitung nicht klappt, klicken Sie bitte hier:
+
+menu.projects=Projekte
+menu.users=Entwickler
+menu.languages=Sprache
--- a/src/main/resources/localization/projects.properties	Sat May 23 13:52:04 2020 +0200
+++ b/src/main/resources/localization/projects.properties	Sat May 23 14:13:09 2020 +0200
@@ -22,7 +22,6 @@
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 pageTitle=Project Tracking
-menuLabel=Projects
 
 button.create=New Project
 button.version.create=New Version
--- a/src/main/resources/localization/projects_de.properties	Sat May 23 13:52:04 2020 +0200
+++ b/src/main/resources/localization/projects_de.properties	Sat May 23 14:13:09 2020 +0200
@@ -22,7 +22,6 @@
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 pageTitle=Projektverwaltung
-menuLabel=Projekte
 
 button.create=Neues Projekt
 button.version.create=Neue Version
--- a/src/main/resources/localization/users.properties	Sat May 23 13:52:04 2020 +0200
+++ b/src/main/resources/localization/users.properties	Sat May 23 14:13:09 2020 +0200
@@ -22,7 +22,6 @@
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 pageTitle=User Management
-menuLabel=Developer
 
 button.create=Add Developer
 
--- a/src/main/resources/localization/users_de.properties	Sat May 23 13:52:04 2020 +0200
+++ b/src/main/resources/localization/users_de.properties	Sat May 23 14:13:09 2020 +0200
@@ -22,7 +22,6 @@
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 pageTitle=Benutzerverwaltung
-menuLabel=Entwickler
 
 button.create=Neuer Entwickler
 
--- a/src/main/webapp/index.jsp	Sat May 23 13:52:04 2020 +0200
+++ b/src/main/webapp/index.jsp	Sat May 23 14:13:09 2020 +0200
@@ -26,5 +26,5 @@
 --%>
 <%
     response.setStatus(response.SC_MOVED_TEMPORARILY);
-    response.setHeader("Location", "/projects/");
+    response.setHeader("Location", "projects/");
 %>

mercurial