Sun, 17 Dec 2017 01:45:28 +0100
implements simple request mapper
--- a/src/java/de/uapcore/lightpit/AbstractLightPITServlet.java Sat Dec 16 20:19:28 2017 +0100 +++ b/src/java/de/uapcore/lightpit/AbstractLightPITServlet.java Sun Dec 17 01:45:28 2017 +0100 @@ -29,6 +29,12 @@ package de.uapcore.lightpit; import java.io.IOException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import java.util.function.BiConsumer; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; @@ -43,9 +49,23 @@ public abstract class AbstractLightPITServlet extends HttpServlet { private static final Logger LOG = LoggerFactory.getLogger(AbstractLightPITServlet.class); + + /** + * Store a reference to the annotation for quicker access. + */ + private Optional<LightPITModule> moduleInfo = Optional.empty(); + /** + * The EL proxy is necessary, because the EL resolver cannot handle annotation properties. + */ + private Optional<LightPITModule.ELProxy> moduleInfoELProxy = Optional.empty(); /** + * Invocation mapping gathered from the {@link RequestMapping} annotations. + */ + private final Map<HttpMethod, Map<String, BiConsumer<HttpServletRequest, HttpServletResponse>>> mappings = new HashMap<>(); + + /** * Gives implementing modules access to the {@link ModuleManager}. * @return the module manager */ @@ -53,25 +73,114 @@ return (ModuleManager) getServletContext().getAttribute(ModuleManager.SC_ATTR_NAME); } - private void addPathInformation(HttpServletRequest req) { - final String path = req.getServletPath()+"/"+req.getPathInfo(); - req.setAttribute(Constants.REQ_ATTR_PATH, path); + private void invokeMapping(Method method, HttpServletRequest req, HttpServletResponse resp) { + try { + LOG.debug("invoke {}", method.getName()); + method.invoke(this, req, resp); + } catch (ReflectiveOperationException ex) { + LOG.error(String.format("invocation of method %s failed", method.getName()), ex); + } + } + + @Override + public void init() throws ServletException { + moduleInfo = Optional.ofNullable(this.getClass().getAnnotation(LightPITModule.class)); + moduleInfoELProxy = moduleInfo.map(LightPITModule.ELProxy::convert); + + if (moduleInfo.isPresent()) { + Method[] methods = getClass().getDeclaredMethods(); + for (Method method : methods) { + Optional<RequestMapping> mapping = Optional.ofNullable(method.getAnnotation(RequestMapping.class)); + if (mapping.isPresent()) { + if (!Modifier.isPublic(method.getModifiers())) { + LOG.warn("{} is annotated with {} but is not public", + method.getName(), RequestMapping.class.getSimpleName() + ); + continue; + } + if (Modifier.isAbstract(method.getModifiers())) { + LOG.warn("{} is annotated with {} but is abstract", + method.getName(), RequestMapping.class.getSimpleName() + ); + continue; + } + + Class<?>[] params = method.getParameterTypes(); + if (params.length == 2 + && HttpServletRequest.class.isAssignableFrom(params[0]) + && HttpServletResponse.class.isAssignableFrom(params[1])) { + + if (mappings.computeIfAbsent(mapping.get().method(), k -> new HashMap<>()). + putIfAbsent(mapping.get().requestPath(), + (req, resp) -> invokeMapping(method, req, resp)) != null) { + LOG.warn("{} {} has multiple mappings", + mapping.get().method(), + mapping.get().requestPath() + ); + } + + LOG.info("{} {} maps to {}", + mapping.get().method(), + mapping.get().requestPath(), + method.getName() + ); + } else { + LOG.warn("{} is annotated with {} but has the wrong signature - (HttpServletRequest,HttpServletResponse) required", + method.getName(), RequestMapping.class.getSimpleName() + ); + } + } + } + } + + LOG.trace("{} initialized", getServletName()); + } + + @Override + public void destroy() { + mappings.clear(); + LOG.trace("{} destroyed", getServletName()); + } + + + /** + * Sets several requests attributes, that can be used by the JSP. + * + * @param req the servlet request object + * @see Constants#REQ_ATTR_PATH + * @see Constants#REQ_ATTR_MODULE_CLASSNAME + * @see Constants#REQ_ATTR_MODULE_INFO + */ + private void setGenericRequestAttributes(HttpServletRequest req) { + req.setAttribute(Constants.REQ_ATTR_PATH, Functions.fullPath(req)); + + req.setAttribute(Constants.REQ_ATTR_MODULE_CLASSNAME, this.getClass().getName()); + + moduleInfoELProxy.ifPresent((proxy) -> req.setAttribute(Constants.REQ_ATTR_MODULE_INFO, proxy)); } private void forwardToFullView(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException { - addPathInformation(req); - - final ModuleManager mm = getModuleManager(); - req.setAttribute(Constants.REQ_ATTR_MENU, mm.getMainMenu()); - + setGenericRequestAttributes(req); + req.setAttribute(Constants.REQ_ATTR_MENU, getModuleManager().getMainMenu()); req.getRequestDispatcher(Functions.jspPath("full.jsp")).forward(req, resp); } + private Optional<BiConsumer<HttpServletRequest, HttpServletResponse>> findMapping(HttpMethod method, HttpServletRequest req) { + return Optional.ofNullable(mappings.get(method)).map( + (rm) -> rm.get(Optional.ofNullable(req.getPathInfo()).orElse("")) + ); + } + @Override protected final void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + + findMapping(HttpMethod.GET, req).ifPresent((consumer) -> consumer.accept(req, resp)); + + // TODO: let the invoked handler decide (signature must be changed from a BiConsumer to a BiFunction) + // TODO: we should call a default handler, if no specific mapping could be found forwardToFullView(req, resp); } @@ -79,6 +188,8 @@ protected final void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + findMapping(HttpMethod.POST, req).ifPresent((consumer) -> consumer.accept(req, resp)); + forwardToFullView(req, resp); } }
--- a/src/java/de/uapcore/lightpit/Constants.java Sat Dec 16 20:19:28 2017 +0100 +++ b/src/java/de/uapcore/lightpit/Constants.java Sun Dec 17 01:45:28 2017 +0100 @@ -28,16 +28,33 @@ */ package de.uapcore.lightpit; -import static de.uapcore.lightpit.Functions.fullyQualifiedName; +import static de.uapcore.lightpit.Functions.fqn; /** * Contains all constants used by the this application. */ public final class Constants { - public static final String JSP_PATH_PREFIX = "/WEB-INF/view/"; + public static final String JSP_PATH_PREFIX = "/WEB-INF/jsp/"; + + /** + * 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"); - public static final String REQ_ATTR_MENU = fullyQualifiedName(AbstractLightPITServlet.class, "mainMenu"); - public static final String REQ_ATTR_PATH = fullyQualifiedName(AbstractLightPITServlet.class, "path"); + /** + * 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"); + + /** + * Key for the request attribute containing the menu list. + */ + public static final String REQ_ATTR_MENU = fqn(AbstractLightPITServlet.class, "mainMenu"); + + /** + * 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"); /** * This class is not instantiatable.
--- a/src/java/de/uapcore/lightpit/Functions.java Sat Dec 16 20:19:28 2017 +0100 +++ b/src/java/de/uapcore/lightpit/Functions.java Sun Dec 17 01:45:28 2017 +0100 @@ -28,6 +28,8 @@ */ package de.uapcore.lightpit; +import java.util.Optional; +import javax.servlet.http.HttpServletRequest; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -42,12 +44,27 @@ return Constants.JSP_PATH_PREFIX + filename; } - public static String fullyQualifiedName(String base, String name) { + public static String fqn(String base, String name) { return base+"."+name; } - public static String fullyQualifiedName(Class clazz, String name) { - return fullyQualifiedName(clazz.getName(), name); + public static String fqn(Class clazz, String name) { + return fqn(clazz.getName(), name); + } + + public static String fullPath(LightPITModule module, RequestMapping mapping) { + StringBuilder sb = new StringBuilder(); + sb.append(module.modulePath()); + sb.append('/'); + if (!mapping.requestPath().isEmpty()) { + sb.append(mapping.requestPath().isEmpty()); + sb.append('/'); + } + return sb.toString(); + } + + public static String fullPath(HttpServletRequest req) { + return req.getServletPath() + Optional.ofNullable(req.getPathInfo()).orElse(""); } /** @@ -60,15 +77,15 @@ * @return the module path */ public static String modulePathOf(Class<? extends AbstractLightPITServlet> clazz) { - LightPITModule moduleInfo = clazz.getAnnotation(LightPITModule.class); - if (moduleInfo == null) { + Optional<LightPITModule> moduleInfo = Optional.ofNullable(clazz.getAnnotation(LightPITModule.class)); + if (moduleInfo.isPresent()) { + return moduleInfo.get().modulePath(); + } else { LOG.warn( "{} is a LightPIT Servlet but is missing the module annotation.", clazz.getName() ); return "/error/404.html"; - } else { - return moduleInfo.modulePath(); } }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/java/de/uapcore/lightpit/HttpMethod.java Sun Dec 17 01:45:28 2017 +0100 @@ -0,0 +1,34 @@ +/* + * 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; + + +public enum HttpMethod { + GET, POST, PUT, DELETE, TRACE, HEAD, OPTIONS +}
--- a/src/java/de/uapcore/lightpit/LightPITModule.java Sat Dec 16 20:19:28 2017 +0100 +++ b/src/java/de/uapcore/lightpit/LightPITModule.java Sun Dec 17 01:45:28 2017 +0100 @@ -71,7 +71,60 @@ /** * Returns the properties key for the menu label. - * @return the properties key relative to the base name + * @return the properties key */ String menuKey() default "menuLabel"; + + /** + * Returns the properties key for the page title. + * + * By default this is the same as the menu label. + * + * @return the properties key + */ + String titleKey() default "menuLabel"; + + /** + * Class representing the annotation. + * This is necessary, because the EL resolver cannot deal with + * annotation objects. + * + * Note, that only the properties which are interesting for the JSP pages + * are proxied by this object. + */ + public static class ELProxy { + private final String bundleBaseName, modulePath, menuKey, titleKey; + + public static ELProxy convert(LightPITModule annotation) { + return new ELProxy( + annotation.bundleBaseName(), + annotation.modulePath(), + annotation.menuKey(), + annotation.titleKey() + ); + } + + private ELProxy(String bundleBaseName, String modulePath, String menuKey, String titleKey) { + this.bundleBaseName = bundleBaseName; + this.modulePath = modulePath; + this.menuKey = menuKey; + this.titleKey = titleKey; + } + + public String getBundleBaseName() { + return bundleBaseName; + } + + public String getMenuKey() { + return menuKey; + } + + public String getModulePath() { + return modulePath; + } + + public String getTitleKey() { + return titleKey; + } + } }
--- a/src/java/de/uapcore/lightpit/Menu.java Sat Dec 16 20:19:28 2017 +0100 +++ b/src/java/de/uapcore/lightpit/Menu.java Sun Dec 17 01:45:28 2017 +0100 @@ -44,12 +44,27 @@ private final List<MenuEntry> entries = new ArrayList<>(); private final List<MenuEntry> immutableEntries = Collections.unmodifiableList(entries); + /** + * Class name of the module for which this menu is built. + */ + private String moduleClassName; + + public Menu() { super(); } - public Menu(ResourceKey resourceKey, String pathName) { + public Menu(String moduleClassName, ResourceKey resourceKey, String pathName) { super(resourceKey, pathName); + this.moduleClassName = moduleClassName; + } + + public void setModuleClassName(String moduleClassName) { + this.moduleClassName = moduleClassName; + } + + public String getModuleClassName() { + return moduleClassName; } /**
--- a/src/java/de/uapcore/lightpit/MenuEntry.java Sat Dec 16 20:19:28 2017 +0100 +++ b/src/java/de/uapcore/lightpit/MenuEntry.java Sun Dec 17 01:45:28 2017 +0100 @@ -37,7 +37,14 @@ */ public class MenuEntry { + /** + * Resource key for the menu label. + */ private ResourceKey resourceKey; + + /** + * Path name of the module, linked by this menu entry. + */ private String pathName; public MenuEntry() { @@ -48,38 +55,18 @@ this.pathName = pathName; } - /** - * Sets the resource key, which is used to look up the menu label. - * - * @param resourceKey the key for the resource bundle - */ public void setResourceKey(ResourceKey resourceKey) { this.resourceKey = resourceKey; } - /** - * Retrieves the resource key. - * - * @return the key for the resource bundle - */ public ResourceKey getResourceKey() { return resourceKey; } - /** - * Sets the path name of the web page accessed via this menu entry. - * - * @param pathName path name relative to the context path - */ public void setPathName(String pathName) { this.pathName = pathName; } - /** - * Retrieves the path name of the web page accessed via this menu entry. - * - * @return path name relative to the context path - */ public String getPathName() { return pathName; }
--- a/src/java/de/uapcore/lightpit/ModuleManager.java Sat Dec 16 20:19:28 2017 +0100 +++ b/src/java/de/uapcore/lightpit/ModuleManager.java Sun Dec 17 01:45:28 2017 +0100 @@ -107,8 +107,9 @@ } } - private void addModuleToMenu(LightPITModule moduleInfo) { + private void addModuleToMenu(String moduleClassName, LightPITModule moduleInfo) { final Menu menu = new Menu( + moduleClassName, new ResourceKey(moduleInfo.bundleBaseName(), moduleInfo.menuKey()), moduleInfo.modulePath() ); @@ -118,7 +119,9 @@ private void handleServletRegistration(String name, Registration reg) { final Optional<LightPITModule> moduleInfo = getModuleInfo(reg); if (moduleInfo.isPresent()) { - addModuleToMenu(moduleInfo.get()); + + // TODO: remove this call and add the module to some dependency resolver, first + addModuleToMenu(reg.getClassName(), moduleInfo.get()); LOG.info("Module detected: {}", name); } else {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/java/de/uapcore/lightpit/RequestMapping.java Sun Dec 17 01:45:28 2017 +0100 @@ -0,0 +1,76 @@ +/* + * 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; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + + +/** + * Maps requests to methods. + * + * This annotation is used to annotate methods within classes which + * override {@link AbstractLightPITServlet}. + */ +@Documented +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface RequestMapping { + + /** + * Specifies the HTTP method. + * + * @return the HTTP method handled by the annotated Java method + */ + HttpMethod method(); + + /** + * Specifies the request path relative to the module path. + * + * 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. + * + * @return the request path the annotated method should handle + */ + String requestPath() default ""; + + /** + * Returns the properties key for the (sub) menu label. + * + * This should only be used for {@link HttpMethod#GET} requests. + * + * @return the properties key + */ + String menuKey() default ""; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/java/de/uapcore/lightpit/modules/LanguageModule.java Sun Dec 17 01:45:28 2017 +0100 @@ -0,0 +1,54 @@ +/* + * 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 javax.servlet.annotation.WebServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import de.uapcore.lightpit.RequestMapping; + + +@LightPITModule( + bundleBaseName = "de.uapcore.lightpit.resources.localization.language", + modulePath = "language" +) +@WebServlet( + name = "LanguageModule", + urlPatterns = "/language/*" +) +public final class LanguageModule extends AbstractLightPITServlet { + + @RequestMapping(method = HttpMethod.GET) + public void handle(HttpServletRequest req, HttpServletResponse resp) { + + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/java/de/uapcore/lightpit/resources/localization/language.properties Sun Dec 17 01:45:28 2017 +0100 @@ -0,0 +1,24 @@ +# 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. + +menuLabel = Languages
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/java/de/uapcore/lightpit/resources/localization/language_de.properties Sun Dec 17 01:45:28 2017 +0100 @@ -0,0 +1,24 @@ +# 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. + +menuLabel = Sprache
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/WEB-INF/jsp/full.jsp Sun Dec 17 01:45:28 2017 +0100 @@ -0,0 +1,78 @@ +<%-- +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 contentType="text/html" pageEncoding="UTF-8" trimDirectiveWhitespaces="true" %> +<%@page import="de.uapcore.lightpit.Constants" %> +<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> +<%@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 main menu --%> +<c:set scope="page" var="mainMenu" value="${requestScope[Constants.REQ_ATTR_MENU]}"/> + +<%-- Define an alias for the module info --%> +<c:set scope="page" var="moduleInfo" value="${requestScope[Constants.REQ_ATTR_MODULE_INFO]}"/> + +<!DOCTYPE html> +<html> + <head> + <base href="${pageContext.request.scheme}://${pageContext.request.serverName}:${pageContext.request.serverPort}${pageContext.request.contextPath}/"> + <title>LightPIT - + <fmt:bundle basename="${moduleInfo.bundleBaseName}"> + <fmt:message key="${moduleInfo.titleKey}" /> + </fmt:bundle> + </title> + <meta charset="UTF-8"> + <link rel="stylesheet" href="lightpit.css" type="text/css"> + </head> + <body> + <div id="mainMenu"> + <c:forEach var="menu" items="${mainMenu}"> + <div class="menuEntry" + <c:if test="${requestScope[Constants.REQ_ATTR_MODULE_CLASSNAME] eq menu.moduleClassName}"> + data-active + </c:if> + > + <a href="${menu.pathName}"> + <fmt:bundle basename="${menu.resourceKey.bundle}"> + <fmt:message key="${menu.resourceKey.key}" /> + </fmt:bundle> + </a> + </div> + </c:forEach> + + </div> + <div id="subMenu"> + + </div> + <div id="content-area"> + <%-- Resource keys should be rooted in the specific bundle for this module. --%> + <fmt:bundle basename="${moduleInfo.bundleBaseName}"> + TODO: load fragment + </fmt:bundle> + </div> + </body> +</html>
--- a/web/WEB-INF/view/full.jsp Sat Dec 16 20:19:28 2017 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,69 +0,0 @@ -<%-- -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 contentType="text/html" pageEncoding="UTF-8" trimDirectiveWhitespaces="true" %> -<%@page import="de.uapcore.lightpit.Constants" %> -<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> -<%@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 main menu --%> -<c:set scope="page" var="mainMenu" value="${requestScope[Constants.REQ_ATTR_MENU]}"/> - -<!DOCTYPE html> -<html> - <head> - <base href="${pageContext.request.scheme}://${pageContext.request.serverName}:${pageContext.request.serverPort}${pageContext.request.contextPath}/"> - <title>LightPIT - TODO: current menu</title> - <meta charset="UTF-8"> - <link rel="stylesheet" href="lightpit.css" type="text/css"> - </head> - <body> - - <div id="mainMenu"> - <c:forEach var="menuEntry" items="${mainMenu}"> - <div class="menuEntry" - <c:if test="${fn:contains(requestScope[Constants.REQ_ATTR_PATH], menuEntry.pathName)}"> - data-active - </c:if> - > - <a href="${menuEntry.pathName}"> - <fmt:bundle basename="${menuEntry.resourceKey.bundle}"> - <fmt:message key="${menuEntry.resourceKey.key}" /> - </fmt:bundle> - </a> - </div> - </c:forEach> - - </div> - <div id="subMenu"> - - </div> - <div id="content-area"> - TODO: content fragment - </div> - </body> -</html>
--- a/web/lightpit.css Sat Dec 16 20:19:28 2017 +0100 +++ b/web/lightpit.css Sun Dec 17 01:45:28 2017 +0100 @@ -43,7 +43,7 @@ } a { - color: #3030f8; + color: #3060f8; text-decoration: none; } @@ -60,7 +60,7 @@ #subMenu { background: #f7f7ff; - border-image: linear-gradient(to right, #606060, rgba(60,60,60,.1)); + border-image: linear-gradient(to right, #606060, rgba(60,60,60,.25)); border-image-slice: 1; border-top-style: solid; border-top-width: 1pt;