converts to maven project

Sat, 09 May 2020 14:26:31 +0200

author
Mike Becker <universe@uap-core.de>
date
Sat, 09 May 2020 14:26:31 +0200
changeset 29
27a0fdd7bca7
parent 28
cfc3d11884ad
child 30
fb30f7b78f9b

converts to maven project

.hgignore file | annotate | diff | comparison | revisions
build.xml file | annotate | diff | comparison | revisions
nbproject/ant-deploy.xml file | annotate | diff | comparison | revisions
nbproject/build-impl.xml file | annotate | diff | comparison | revisions
nbproject/genfiles.properties file | annotate | diff | comparison | revisions
nbproject/project.properties file | annotate | diff | comparison | revisions
nbproject/project.xml file | annotate | diff | comparison | revisions
pom.xml file | annotate | diff | comparison | revisions
src/conf/MANIFEST.MF file | annotate | diff | comparison | revisions
src/java/de/uapcore/lightpit/AbstractLightPITServlet.java file | annotate | diff | comparison | revisions
src/java/de/uapcore/lightpit/Constants.java file | annotate | diff | comparison | revisions
src/java/de/uapcore/lightpit/DatabaseFacade.java file | annotate | diff | comparison | revisions
src/java/de/uapcore/lightpit/Functions.java file | annotate | diff | comparison | revisions
src/java/de/uapcore/lightpit/HttpMethod.java file | annotate | diff | comparison | revisions
src/java/de/uapcore/lightpit/LightPITModule.java file | annotate | diff | comparison | revisions
src/java/de/uapcore/lightpit/Menu.java file | annotate | diff | comparison | revisions
src/java/de/uapcore/lightpit/MenuEntry.java file | annotate | diff | comparison | revisions
src/java/de/uapcore/lightpit/ModuleManager.java file | annotate | diff | comparison | revisions
src/java/de/uapcore/lightpit/RequestMapping.java file | annotate | diff | comparison | revisions
src/java/de/uapcore/lightpit/ResourceKey.java file | annotate | diff | comparison | revisions
src/java/de/uapcore/lightpit/ResponseType.java file | annotate | diff | comparison | revisions
src/java/de/uapcore/lightpit/entities/CoreDAOFactory.java file | annotate | diff | comparison | revisions
src/java/de/uapcore/lightpit/entities/Module.java file | annotate | diff | comparison | revisions
src/java/de/uapcore/lightpit/entities/ModuleDao.java file | annotate | diff | comparison | revisions
src/java/de/uapcore/lightpit/entities/PostgresModuleDao.java file | annotate | diff | comparison | revisions
src/java/de/uapcore/lightpit/entities/User.java file | annotate | diff | comparison | revisions
src/java/de/uapcore/lightpit/entities/UserDao.java file | annotate | diff | comparison | revisions
src/java/de/uapcore/lightpit/modules/ErrorModule.java file | annotate | diff | comparison | revisions
src/java/de/uapcore/lightpit/modules/HomeModule.java file | annotate | diff | comparison | revisions
src/java/de/uapcore/lightpit/modules/LanguageModule.java file | annotate | diff | comparison | revisions
src/java/de/uapcore/lightpit/modules/ModuleManagerModule.java file | annotate | diff | comparison | revisions
src/java/de/uapcore/lightpit/modules/VersionsModule.java file | annotate | diff | comparison | revisions
src/java/de/uapcore/lightpit/resources/localization/error.properties file | annotate | diff | comparison | revisions
src/java/de/uapcore/lightpit/resources/localization/error_de.properties file | annotate | diff | comparison | revisions
src/java/de/uapcore/lightpit/resources/localization/home.properties file | annotate | diff | comparison | revisions
src/java/de/uapcore/lightpit/resources/localization/home_de.properties file | annotate | diff | comparison | revisions
src/java/de/uapcore/lightpit/resources/localization/language.properties file | annotate | diff | comparison | revisions
src/java/de/uapcore/lightpit/resources/localization/language_de.properties file | annotate | diff | comparison | revisions
src/java/de/uapcore/lightpit/resources/localization/modmgmt.properties file | annotate | diff | comparison | revisions
src/java/de/uapcore/lightpit/resources/localization/modmgmt_de.properties file | annotate | diff | comparison | revisions
src/java/de/uapcore/lightpit/resources/localization/versions.properties file | annotate | diff | comparison | revisions
src/java/de/uapcore/lightpit/resources/localization/versions_de.properties file | annotate | diff | comparison | revisions
src/java/log4j2.properties file | annotate | diff | comparison | revisions
src/main/java/de/uapcore/lightpit/AbstractLightPITServlet.java file | annotate | diff | comparison | revisions
src/main/java/de/uapcore/lightpit/Constants.java file | annotate | diff | comparison | revisions
src/main/java/de/uapcore/lightpit/DatabaseFacade.java file | annotate | diff | comparison | revisions
src/main/java/de/uapcore/lightpit/Functions.java file | annotate | diff | comparison | revisions
src/main/java/de/uapcore/lightpit/HttpMethod.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/Menu.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/RequestMapping.java file | annotate | diff | comparison | revisions
src/main/java/de/uapcore/lightpit/ResourceKey.java file | annotate | diff | comparison | revisions
src/main/java/de/uapcore/lightpit/ResponseType.java file | annotate | diff | comparison | revisions
src/main/java/de/uapcore/lightpit/entities/CoreDAOFactory.java file | annotate | diff | comparison | revisions
src/main/java/de/uapcore/lightpit/entities/Module.java file | annotate | diff | comparison | revisions
src/main/java/de/uapcore/lightpit/entities/ModuleDao.java file | annotate | diff | comparison | revisions
src/main/java/de/uapcore/lightpit/entities/PostgresModuleDao.java file | annotate | diff | comparison | revisions
src/main/java/de/uapcore/lightpit/entities/User.java file | annotate | diff | comparison | revisions
src/main/java/de/uapcore/lightpit/entities/UserDao.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/HomeModule.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/ModuleManagerModule.java file | annotate | diff | comparison | revisions
src/main/java/de/uapcore/lightpit/modules/VersionsModule.java file | annotate | diff | comparison | revisions
src/main/java/log4j2.properties file | annotate | diff | comparison | revisions
src/main/resources/META-INF/context.xml file | annotate | diff | comparison | revisions
src/main/resources/localization/error.properties file | annotate | diff | comparison | revisions
src/main/resources/localization/error_de.properties file | annotate | diff | comparison | revisions
src/main/resources/localization/home.properties file | annotate | diff | comparison | revisions
src/main/resources/localization/home_de.properties 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/modmgmt.properties file | annotate | diff | comparison | revisions
src/main/resources/localization/modmgmt_de.properties file | annotate | diff | comparison | revisions
src/main/resources/localization/versions.properties file | annotate | diff | comparison | revisions
src/main/resources/localization/versions_de.properties file | annotate | diff | comparison | revisions
src/main/webapp/WEB-INF/dynamic_fragments/error.jsp file | annotate | diff | comparison | revisions
src/main/webapp/WEB-INF/dynamic_fragments/language.jsp file | annotate | diff | comparison | revisions
src/main/webapp/WEB-INF/dynamic_fragments/modules.jsp file | annotate | diff | comparison | revisions
src/main/webapp/WEB-INF/jsp/html_full.jsp file | annotate | diff | comparison | revisions
src/main/webapp/WEB-INF/web.xml file | annotate | diff | comparison | revisions
src/main/webapp/error.css file | annotate | diff | comparison | revisions
src/main/webapp/index.jsp file | annotate | diff | comparison | revisions
src/main/webapp/language.css file | annotate | diff | comparison | revisions
src/main/webapp/lightpit.css file | annotate | diff | comparison | revisions
web/META-INF/context.xml file | annotate | diff | comparison | revisions
web/WEB-INF/dynamic_fragments/error.jsp file | annotate | diff | comparison | revisions
web/WEB-INF/dynamic_fragments/language.jsp file | annotate | diff | comparison | revisions
web/WEB-INF/dynamic_fragments/modules.jsp file | annotate | diff | comparison | revisions
web/WEB-INF/glassfish-web.xml file | annotate | diff | comparison | revisions
web/WEB-INF/jsp/html_full.jsp file | annotate | diff | comparison | revisions
web/WEB-INF/web.xml file | annotate | diff | comparison | revisions
web/error.css file | annotate | diff | comparison | revisions
web/index.jsp file | annotate | diff | comparison | revisions
web/language.css file | annotate | diff | comparison | revisions
web/lightpit.css file | annotate | diff | comparison | revisions
--- a/.hgignore	Sun Apr 08 16:51:15 2018 +0200
+++ b/.hgignore	Sat May 09 14:26:31 2020 +0200
@@ -1,9 +1,12 @@
 syntax: regexp
 ^nbproject/private/
 ^build/
+^target/
 ^dist/
 \.orig\..*$
 \.orig$
 \.chg\..*$
 \.rej$
 \.conflict\~$
+\.iml$
+\.idea/
--- a/build.xml	Sun Apr 08 16:51:15 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,71 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- You may freely edit this file. See commented blocks below for -->
-<!-- some examples of how to customize the build. -->
-<!-- (If you delete it and reopen the project it will be recreated.) -->
-<!-- By default, only the Clean and Build commands use this build script. -->
-<!-- Commands such as Run, Debug, and Test only use this build script if -->
-<!-- the Compile on Save feature is turned off for the project. -->
-<!-- You can turn off the Compile on Save (or Deploy on Save) setting -->
-<!-- in the project's Project Properties dialog box.-->
-<project name="LightPIT" default="default" basedir=".">
-    <description>Builds, tests, and runs the project LightPIT.</description>
-    <import file="nbproject/build-impl.xml"/>
-    <!--
-
-    There exist several targets which are by default empty and which can be 
-    used for execution of your tasks. These targets are usually executed 
-    before and after some main targets. They are: 
-
-      -pre-init:                 called before initialization of project properties 
-      -post-init:                called after initialization of project properties 
-      -pre-compile:              called before javac compilation 
-      -post-compile:             called after javac compilation 
-      -pre-compile-single:       called before javac compilation of single file
-      -post-compile-single:      called after javac compilation of single file
-      -pre-compile-test:         called before javac compilation of JUnit tests
-      -post-compile-test:        called after javac compilation of JUnit tests
-      -pre-compile-test-single:  called before javac compilation of single JUnit test
-      -post-compile-test-single: called after javac compilation of single JUunit test
-      -pre-dist:                 called before archive building 
-      -post-dist:                called after archive building 
-      -post-clean:               called after cleaning build products 
-      -pre-run-deploy:           called before deploying
-      -post-run-deploy:          called after deploying
-
-    Example of pluging an obfuscator after the compilation could look like 
-
-        <target name="-post-compile">
-            <obfuscate>
-                <fileset dir="${build.classes.dir}"/>
-            </obfuscate>
-        </target>
-
-    For list of available properties check the imported 
-    nbproject/build-impl.xml file. 
-
-
-    Other way how to customize the build is by overriding existing main targets.
-    The target of interest are: 
-
-      init-macrodef-javac:    defines macro for javac compilation
-      init-macrodef-junit:   defines macro for junit execution
-      init-macrodef-debug:    defines macro for class debugging
-      do-dist:                archive building
-      run:                    execution of project 
-      javadoc-build:          javadoc generation 
-
-    Example of overriding the target for project execution could look like 
-
-        <target name="run" depends="<PROJNAME>-impl.jar">
-            <exec dir="bin" executable="launcher.exe">
-                <arg file="${dist.jar}"/>
-            </exec>
-        </target>
-
-    Notice that overridden target depends on jar target and not only on 
-    compile target as regular run target does. Again, for list of available 
-    properties which you can use check the target you are overriding in 
-    nbproject/build-impl.xml file. 
-
-    -->
-</project>
--- a/nbproject/ant-deploy.xml	Sun Apr 08 16:51:15 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,76 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
-
-Copyright (c) 2006, 2016 Oracle and/or its affiliates. All rights reserved.
-
-Oracle and Java are registered trademarks of Oracle and/or its affiliates.
-Other names may be trademarks of their respective owners.
-
-The contents of this file are subject to the terms of either the GNU
-General Public License Version 2 only ("GPL") or the Common
-Development and Distribution License("CDDL") (collectively, the
-"License"). You may not use this file except in compliance with the
-License. You can obtain a copy of the License at
-http://www.netbeans.org/cddl-gplv2.html
-or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
-specific language governing permissions and limitations under the
-License.  When distributing the software, include this License Header
-Notice in each file and include the License file at
-nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
-particular file as subject to the "Classpath" exception as provided
-by Oracle in the GPL Version 2 section of the License file that
-accompanied this code. If applicable, add the following below the
-License Header, with the fields enclosed by brackets [] replaced by
-your own identifying information:
-"Portions Copyrighted [year] [name of copyright owner]"
-
-If you wish your version of this file to be governed by only the CDDL
-or only the GPL Version 2, indicate your decision by adding
-"[Contributor] elects to include this software in this distribution
-under the [CDDL or GPL Version 2] license." If you do not indicate a
-single choice of license, a recipient has the option to distribute
-your version of this file under either the CDDL, the GPL Version 2 or
-to extend the choice of license to its licensees as provided above.
-However, if you add GPL Version 2 code and therefore, elected the GPL
-Version 2 license, then the option applies only if the new code is
-made subject to such option by the copyright holder.
-
-Contributor(s):
--->
-<project default="-deploy-ant" basedir=".">
-    <target name="-init" if="deploy.ant.enabled">
-        <property file="${deploy.ant.properties.file}"/>
-        <tempfile property="temp.module.folder" prefix="tomcat" destdir="${java.io.tmpdir}"/>
-        <unwar src="${deploy.ant.archive}" dest="${temp.module.folder}">
-            <patternset includes="META-INF/context.xml"/>
-        </unwar>
-        <xmlproperty file="${temp.module.folder}/META-INF/context.xml"/>
-        <delete dir="${temp.module.folder}"/>
-    </target>
-    <target name="-check-credentials" if="deploy.ant.enabled" depends="-init">
-        <fail message="Tomcat password has to be passed as tomcat.password property.">
-            <condition>
-                <not>
-                    <isset property="tomcat.password"/>
-                </not>
-            </condition>
-        </fail>
-    </target>
-    <target name="-deploy-ant" if="deploy.ant.enabled" depends="-init,-check-credentials">
-        <echo message="Deploying ${deploy.ant.archive} to ${Context(path)}"/>
-        <taskdef name="deploy" classname="org.apache.catalina.ant.DeployTask"
-                 classpath="${tomcat.home}/server/lib/catalina-ant.jar"/>
-        <deploy url="${tomcat.url}/manager" username="${tomcat.username}"
-                password="${tomcat.password}" path="${Context(path)}"
-                war="${deploy.ant.archive}"/>
-        <property name="deploy.ant.client.url" value="${tomcat.url}${Context(path)}"/>
-    </target>
-    <target name="-undeploy-ant" if="deploy.ant.enabled" depends="-init,-check-credentials">
-        <echo message="Undeploying ${Context(path)}"/>
-        <taskdef name="undeploy"  classname="org.apache.catalina.ant.UndeployTask"
-                classpath="${tomcat.home}/server/lib/catalina-ant.jar"/>
-        <undeploy url="${tomcat.url}/manager" username="${tomcat.username}" 
-                  password="${tomcat.password}" path="${Context(path)}"/>
-    </target>
-</project>
--- a/nbproject/build-impl.xml	Sun Apr 08 16:51:15 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1448 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-        *** GENERATED FROM project.xml - DO NOT EDIT  ***
-        ***         EDIT ../build.xml INSTEAD         ***
-
-        For the purpose of easier reading the script
-        is divided into following sections:
-        - initialization
-        - compilation
-        - dist
-        - execution
-        - debugging
-        - javadoc
-        - test compilation
-        - test execution
-        - test debugging
-        - cleanup
-
-        -->
-<project xmlns:webproject1="http://www.netbeans.org/ns/web-project/1" xmlns:webproject2="http://www.netbeans.org/ns/web-project/2" xmlns:webproject3="http://www.netbeans.org/ns/web-project/3" basedir=".." default="default" name="LightPIT-impl">
-    <import file="ant-deploy.xml"/>
-    <fail message="Please build using Ant 1.7.1 or higher.">
-        <condition>
-            <not>
-                <antversion atleast="1.7.1"/>
-            </not>
-        </condition>
-    </fail>
-    <target depends="dist,javadoc" description="Build whole project." name="default"/>
-    <!--
-                INITIALIZATION SECTION
-            -->
-    <target name="-pre-init">
-        <!-- Empty placeholder for easier customization. -->
-        <!-- You can override this target in the ../build.xml file. -->
-    </target>
-    <target depends="-pre-init" name="-init-private">
-        <property file="nbproject/private/private.properties"/>
-    </target>
-    <target depends="-pre-init,-init-private" name="-init-user">
-        <property file="${user.properties.file}"/>
-        <!-- The two properties below are usually overridden -->
-        <!-- by the active platform. Just a fallback. -->
-        <property name="default.javac.source" value="1.4"/>
-        <property name="default.javac.target" value="1.4"/>
-    </target>
-    <target depends="-pre-init,-init-private,-init-user" name="-init-project">
-        <property file="nbproject/project.properties"/>
-    </target>
-    <target depends="-pre-init,-init-private,-init-user,-init-project,-init-macrodef-property" if="dist.ear.dir" name="-do-ear-init"/>
-    <target depends="-pre-init,-init-private,-init-user,-init-project,-init-macrodef-property" name="-do-init">
-        <condition property="have.tests">
-            <or>
-                <available file="${test.src.dir}"/>
-            </or>
-        </condition>
-        <condition property="have.sources">
-            <or>
-                <available file="${src.dir}"/>
-            </or>
-        </condition>
-        <condition property="netbeans.home+have.tests">
-            <and>
-                <isset property="netbeans.home"/>
-                <isset property="have.tests"/>
-            </and>
-        </condition>
-        <condition property="no.javadoc.preview">
-            <isfalse value="${javadoc.preview}"/>
-        </condition>
-        <property name="javac.compilerargs" value=""/>
-        <condition property="no.deps">
-            <and>
-                <istrue value="${no.dependencies}"/>
-            </and>
-        </condition>
-        <condition property="no.dist.ear.dir">
-            <not>
-                <isset property="dist.ear.dir"/>
-            </not>
-        </condition>
-        <property name="build.web.excludes" value="${build.classes.excludes}"/>
-        <condition property="do.compile.jsps">
-            <istrue value="${compile.jsps}"/>
-        </condition>
-        <condition property="do.debug.server">
-            <or>
-                <not>
-                    <isset property="debug.server"/>
-                </not>
-                <istrue value="${debug.server}"/>
-                <and>
-                    <not>
-                        <istrue value="${debug.server}"/>
-                    </not>
-                    <not>
-                        <istrue value="${debug.client}"/>
-                    </not>
-                </and>
-            </or>
-        </condition>
-        <condition property="do.debug.client">
-            <istrue value="${debug.client}"/>
-        </condition>
-        <condition property="do.display.browser">
-            <istrue value="${display.browser}"/>
-        </condition>
-        <condition property="do.display.browser.debug.old">
-            <and>
-                <isset property="do.display.browser"/>
-                <not>
-                    <isset property="do.debug.client"/>
-                </not>
-                <not>
-                    <isset property="browser.context"/>
-                </not>
-            </and>
-        </condition>
-        <condition property="do.display.browser.debug">
-            <and>
-                <isset property="do.display.browser"/>
-                <not>
-                    <isset property="do.debug.client"/>
-                </not>
-                <isset property="browser.context"/>
-            </and>
-        </condition>
-        <available file="${conf.dir}/MANIFEST.MF" property="has.custom.manifest"/>
-        <available file="${persistence.xml.dir}/persistence.xml" property="has.persistence.xml"/>
-        <condition property="do.war.package.with.custom.manifest">
-            <isset property="has.custom.manifest"/>
-        </condition>
-        <condition property="do.war.package.without.custom.manifest">
-            <not>
-                <isset property="has.custom.manifest"/>
-            </not>
-        </condition>
-        <condition property="do.tmp.war.package.with.custom.manifest">
-            <and>
-                <isset property="has.custom.manifest"/>
-                <or>
-                    <isfalse value="${directory.deployment.supported}"/>
-                    <isset property="dist.ear.dir"/>
-                </or>
-            </and>
-        </condition>
-        <condition property="do.tmp.war.package.without.custom.manifest">
-            <and>
-                <not>
-                    <isset property="has.custom.manifest"/>
-                </not>
-                <or>
-                    <isfalse value="${directory.deployment.supported}"/>
-                    <isset property="dist.ear.dir"/>
-                </or>
-            </and>
-        </condition>
-        <condition property="do.tmp.war.package">
-            <or>
-                <isfalse value="${directory.deployment.supported}"/>
-                <isset property="dist.ear.dir"/>
-            </or>
-        </condition>
-        <property name="build.meta.inf.dir" value="${build.web.dir}/META-INF"/>
-        <condition else="" property="application.args.param" value="${application.args}">
-            <and>
-                <isset property="application.args"/>
-                <not>
-                    <equals arg1="${application.args}" arg2="" trim="true"/>
-                </not>
-            </and>
-        </condition>
-        <property name="source.encoding" value="${file.encoding}"/>
-        <condition property="javadoc.encoding.used" value="${javadoc.encoding}">
-            <and>
-                <isset property="javadoc.encoding"/>
-                <not>
-                    <equals arg1="${javadoc.encoding}" arg2=""/>
-                </not>
-            </and>
-        </condition>
-        <property name="javadoc.encoding.used" value="${source.encoding}"/>
-        <property name="includes" value="**"/>
-        <property name="excludes" value=""/>
-        <property name="runmain.jvmargs" value=""/>
-        <path id="endorsed.classpath.path" path="${endorsed.classpath}"/>
-        <condition else="" property="endorsed.classpath.cmd.line.arg" value="-Xbootclasspath/p:'${toString:endorsed.classpath.path}'">
-            <and>
-                <isset property="endorsed.classpath"/>
-                <length length="0" string="${endorsed.classpath}" when="greater"/>
-            </and>
-        </condition>
-        <condition else="false" property="jdkBug6558476">
-            <and>
-                <matches pattern="1\.[56]" string="${java.specification.version}"/>
-                <not>
-                    <os family="unix"/>
-                </not>
-            </and>
-        </condition>
-        <property name="javac.fork" value="${jdkBug6558476}"/>
-        <condition property="junit.available">
-            <or>
-                <available classname="org.junit.Test" classpath="${run.test.classpath}"/>
-                <available classname="junit.framework.Test" classpath="${run.test.classpath}"/>
-            </or>
-        </condition>
-        <condition property="testng.available">
-            <available classname="org.testng.annotations.Test" classpath="${run.test.classpath}"/>
-        </condition>
-        <condition property="junit+testng.available">
-            <and>
-                <istrue value="${junit.available}"/>
-                <istrue value="${testng.available}"/>
-            </and>
-        </condition>
-        <condition else="testng" property="testng.mode" value="mixed">
-            <istrue value="${junit+testng.available}"/>
-        </condition>
-        <condition else="" property="testng.debug.mode" value="-mixed">
-            <istrue value="${junit+testng.available}"/>
-        </condition>
-    </target>
-    <target depends="init" name="-init-cos" unless="deploy.on.save">
-        <condition property="deploy.on.save" value="true">
-            <or>
-                <istrue value="${j2ee.deploy.on.save}"/>
-                <istrue value="${j2ee.compile.on.save}"/>
-            </or>
-        </condition>
-    </target>
-    <target name="-post-init">
-        <!-- Empty placeholder for easier customization. -->
-        <!-- You can override this target in the ../build.xml file. -->
-    </target>
-    <target depends="-pre-init,-init-private,-init-user,-init-project,-do-init" name="-init-check">
-        <fail unless="src.dir">Must set src.dir</fail>
-        <fail unless="test.src.dir">Must set test.src.dir</fail>
-        <fail unless="build.dir">Must set build.dir</fail>
-        <fail unless="build.web.dir">Must set build.web.dir</fail>
-        <fail unless="build.generated.dir">Must set build.generated.dir</fail>
-        <fail unless="dist.dir">Must set dist.dir</fail>
-        <fail unless="build.classes.dir">Must set build.classes.dir</fail>
-        <fail unless="dist.javadoc.dir">Must set dist.javadoc.dir</fail>
-        <fail unless="build.test.classes.dir">Must set build.test.classes.dir</fail>
-        <fail unless="build.test.results.dir">Must set build.test.results.dir</fail>
-        <fail unless="build.classes.excludes">Must set build.classes.excludes</fail>
-        <fail unless="dist.war">Must set dist.war</fail>
-        <condition property="missing.j2ee.server.home">
-            <and>
-                <matches pattern="j2ee.server.home" string="${j2ee.platform.classpath}"/>
-                <not>
-                    <isset property="j2ee.server.home"/>
-                </not>
-            </and>
-        </condition>
-        <fail if="missing.j2ee.server.home">
-The Java EE server classpath is not correctly set up - server home directory is missing.
-Either open the project in the IDE and assign the server or setup the server classpath manually.
-For example like this:
-   ant -Dj2ee.server.home=&lt;app_server_installation_directory&gt;
-                </fail>
-        <fail unless="j2ee.platform.classpath">
-The Java EE server classpath is not correctly set up. Your active server type is ${j2ee.server.type}.
-Either open the project in the IDE and assign the server or setup the server classpath manually.
-For example like this:
-   ant -Duser.properties.file=&lt;path_to_property_file&gt; (where you put the property "j2ee.platform.classpath" in a .properties file)
-or ant -Dj2ee.platform.classpath=&lt;server_classpath&gt; (where no properties file is used)
-                </fail>
-    </target>
-    <target name="-init-macrodef-property">
-        <macrodef name="property" uri="http://www.netbeans.org/ns/web-project/1">
-            <attribute name="name"/>
-            <attribute name="value"/>
-            <sequential>
-                <property name="@{name}" value="${@{value}}"/>
-            </sequential>
-        </macrodef>
-    </target>
-    <target depends="-init-ap-cmdline-properties" if="ap.supported.internal" name="-init-macrodef-javac-with-processors">
-        <macrodef name="javac" uri="http://www.netbeans.org/ns/web-project/2">
-            <attribute default="${src.dir}" name="srcdir"/>
-            <attribute default="${build.classes.dir}" name="destdir"/>
-            <attribute default="${javac.classpath}:${j2ee.platform.classpath}" name="classpath"/>
-            <attribute default="${javac.processorpath}" name="processorpath"/>
-            <attribute default="${build.generated.sources.dir}/ap-source-output" name="apgeneratedsrcdir"/>
-            <attribute default="${includes}" name="includes"/>
-            <attribute default="${excludes}" name="excludes"/>
-            <attribute default="${javac.debug}" name="debug"/>
-            <attribute default="${empty.dir}" name="gensrcdir"/>
-            <element name="customize" optional="true"/>
-            <sequential>
-                <property location="${build.dir}/empty" name="empty.dir"/>
-                <mkdir dir="${empty.dir}"/>
-                <mkdir dir="@{apgeneratedsrcdir}"/>
-                <javac debug="@{debug}" deprecation="${javac.deprecation}" destdir="@{destdir}" encoding="${source.encoding}" excludes="@{excludes}" fork="${javac.fork}" includeantruntime="false" includes="@{includes}" source="${javac.source}" srcdir="@{srcdir}" target="${javac.target}">
-                    <src>
-                        <dirset dir="@{gensrcdir}" erroronmissingdir="false">
-                            <include name="*"/>
-                        </dirset>
-                    </src>
-                    <classpath>
-                        <path path="@{classpath}"/>
-                    </classpath>
-                    <compilerarg line="${endorsed.classpath.cmd.line.arg}"/>
-                    <compilerarg line="${javac.compilerargs}"/>
-                    <compilerarg value="-processorpath"/>
-                    <compilerarg path="@{processorpath}:${empty.dir}"/>
-                    <compilerarg line="${ap.processors.internal}"/>
-                    <compilerarg value="-s"/>
-                    <compilerarg path="@{apgeneratedsrcdir}"/>
-                    <compilerarg line="${ap.proc.none.internal}"/>
-                    <customize/>
-                </javac>
-            </sequential>
-        </macrodef>
-    </target>
-    <target depends="-init-ap-cmdline-properties" name="-init-macrodef-javac-without-processors" unless="ap.supported.internal">
-        <macrodef name="javac" uri="http://www.netbeans.org/ns/web-project/2">
-            <attribute default="${src.dir}" name="srcdir"/>
-            <attribute default="${build.classes.dir}" name="destdir"/>
-            <attribute default="${javac.classpath}:${j2ee.platform.classpath}" name="classpath"/>
-            <attribute default="${javac.processorpath}" name="processorpath"/>
-            <attribute default="${build.generated.sources.dir}/ap-source-output" name="apgeneratedsrcdir"/>
-            <attribute default="${includes}" name="includes"/>
-            <attribute default="${excludes}" name="excludes"/>
-            <attribute default="${javac.debug}" name="debug"/>
-            <attribute default="${empty.dir}" name="gensrcdir"/>
-            <element name="customize" optional="true"/>
-            <sequential>
-                <property location="${build.dir}/empty" name="empty.dir"/>
-                <mkdir dir="${empty.dir}"/>
-                <javac debug="@{debug}" deprecation="${javac.deprecation}" destdir="@{destdir}" encoding="${source.encoding}" excludes="@{excludes}" includeantruntime="false" includes="@{includes}" source="${javac.source}" srcdir="@{srcdir}" target="${javac.target}">
-                    <src>
-                        <dirset dir="@{gensrcdir}" erroronmissingdir="false">
-                            <include name="*"/>
-                        </dirset>
-                    </src>
-                    <classpath>
-                        <path path="@{classpath}"/>
-                    </classpath>
-                    <compilerarg line="${endorsed.classpath.cmd.line.arg}"/>
-                    <compilerarg line="${javac.compilerargs}"/>
-                    <customize/>
-                </javac>
-            </sequential>
-        </macrodef>
-    </target>
-    <target depends="-init-macrodef-javac-with-processors,-init-macrodef-javac-without-processors" name="-init-macrodef-javac">
-        <macrodef name="depend" uri="http://www.netbeans.org/ns/web-project/2">
-            <attribute default="${src.dir}" name="srcdir"/>
-            <attribute default="${build.classes.dir}" name="destdir"/>
-            <attribute default="${javac.classpath}:${j2ee.platform.classpath}" name="classpath"/>
-            <sequential>
-                <depend cache="${build.dir}/depcache" destdir="@{destdir}" excludes="${excludes}" includes="${includes}" srcdir="@{srcdir}">
-                    <classpath>
-                        <path path="@{classpath}"/>
-                    </classpath>
-                </depend>
-            </sequential>
-        </macrodef>
-        <macrodef name="force-recompile" uri="http://www.netbeans.org/ns/web-project/2">
-            <attribute default="${build.classes.dir}" name="destdir"/>
-            <sequential>
-                <fail unless="javac.includes">Must set javac.includes</fail>
-                <pathconvert pathsep="${line.separator}" property="javac.includes.binary">
-                    <path>
-                        <filelist dir="@{destdir}" files="${javac.includes}"/>
-                    </path>
-                    <globmapper from="*.java" to="*.class"/>
-                </pathconvert>
-                <tempfile deleteonexit="true" property="javac.includesfile.binary"/>
-                <echo file="${javac.includesfile.binary}" message="${javac.includes.binary}"/>
-                <delete>
-                    <files includesfile="${javac.includesfile.binary}"/>
-                </delete>
-                <delete file="${javac.includesfile.binary}"/>
-            </sequential>
-        </macrodef>
-    </target>
-    <target if="${junit.available}" name="-init-macrodef-junit-init">
-        <condition else="false" property="nb.junit.batch" value="true">
-            <and>
-                <istrue value="${junit.available}"/>
-                <not>
-                    <isset property="test.method"/>
-                </not>
-            </and>
-        </condition>
-        <condition else="false" property="nb.junit.single" value="true">
-            <and>
-                <istrue value="${junit.available}"/>
-                <isset property="test.method"/>
-            </and>
-        </condition>
-    </target>
-    <target name="-init-test-properties">
-        <property name="test.binaryincludes" value="&lt;nothing&gt;"/>
-        <property name="test.binarytestincludes" value=""/>
-        <property name="test.binaryexcludes" value=""/>
-    </target>
-    <target if="${nb.junit.single}" name="-init-macrodef-junit-single" unless="${nb.junit.batch}">
-        <macrodef name="junit" uri="http://www.netbeans.org/ns/web-project/2">
-            <attribute default="${includes}" name="includes"/>
-            <attribute default="${excludes}" name="excludes"/>
-            <attribute default="**" name="testincludes"/>
-            <attribute default="" name="testmethods"/>
-            <element name="customize" optional="true"/>
-            <sequential>
-                <junit dir="${basedir}" errorproperty="tests.failed" failureproperty="tests.failed" fork="true" showoutput="true" tempdir="${java.io.tmpdir}">
-                    <test methods="@{testmethods}" name="@{testincludes}" todir="${build.test.results.dir}"/>
-                    <syspropertyset>
-                        <propertyref prefix="test-sys-prop."/>
-                        <mapper from="test-sys-prop.*" to="*" type="glob"/>
-                    </syspropertyset>
-                    <formatter type="brief" usefile="false"/>
-                    <formatter type="xml"/>
-                    <jvmarg value="-ea"/>
-                    <customize/>
-                </junit>
-            </sequential>
-        </macrodef>
-    </target>
-    <target depends="-init-test-properties" if="${nb.junit.batch}" name="-init-macrodef-junit-batch" unless="${nb.junit.single}">
-        <macrodef name="junit" uri="http://www.netbeans.org/ns/web-project/2">
-            <attribute default="${includes}" name="includes"/>
-            <attribute default="${excludes}" name="excludes"/>
-            <attribute default="**" name="testincludes"/>
-            <attribute default="" name="testmethods"/>
-            <element name="customize" optional="true"/>
-            <sequential>
-                <property name="run.jvmargs.ide" value=""/>
-                <junit dir="${basedir}" errorproperty="tests.failed" failureproperty="tests.failed" fork="true" showoutput="true" tempdir="${build.dir}">
-                    <batchtest todir="${build.test.results.dir}">
-                        <fileset dir="${test.src.dir}" excludes="@{excludes},${excludes}" includes="@{includes}">
-                            <filename name="@{testincludes}"/>
-                        </fileset>
-                        <fileset dir="${build.test.classes.dir}" excludes="@{excludes},${excludes},${test.binaryexcludes}" includes="${test.binaryincludes}">
-                            <filename name="${test.binarytestincludes}"/>
-                        </fileset>
-                    </batchtest>
-                    <syspropertyset>
-                        <propertyref prefix="test-sys-prop."/>
-                        <mapper from="test-sys-prop.*" to="*" type="glob"/>
-                    </syspropertyset>
-                    <formatter type="brief" usefile="false"/>
-                    <formatter type="xml"/>
-                    <jvmarg value="-ea"/>
-                    <jvmarg line="${run.jvmargs.ide}"/>
-                    <customize/>
-                </junit>
-            </sequential>
-        </macrodef>
-    </target>
-    <target depends="-init-macrodef-junit-init,-init-macrodef-junit-single, -init-macrodef-junit-batch" if="${junit.available}" name="-init-macrodef-junit"/>
-    <target if="${testng.available}" name="-init-macrodef-testng">
-        <macrodef name="testng" uri="http://www.netbeans.org/ns/web-project/2">
-            <attribute default="${includes}" name="includes"/>
-            <attribute default="${excludes}" name="excludes"/>
-            <attribute default="**" name="testincludes"/>
-            <attribute default="" name="testmethods"/>
-            <element name="customize" optional="true"/>
-            <sequential>
-                <condition else="" property="testng.methods.arg" value="@{testincludes}.@{testmethods}">
-                    <isset property="test.method"/>
-                </condition>
-                <union id="test.set">
-                    <fileset dir="${test.src.dir}" excludes="@{excludes},**/*.xml,${excludes}" includes="@{includes}">
-                        <filename name="@{testincludes}"/>
-                    </fileset>
-                </union>
-                <taskdef classname="org.testng.TestNGAntTask" classpath="${run.test.classpath}" name="testng"/>
-                <testng classfilesetref="test.set" failureProperty="tests.failed" listeners="org.testng.reporters.VerboseReporter" methods="${testng.methods.arg}" mode="${testng.mode}" outputdir="${build.test.results.dir}" suitename="LightPIT" testname="TestNG tests" workingDir="${basedir}">
-                    <xmlfileset dir="${build.test.classes.dir}" includes="@{testincludes}"/>
-                    <propertyset>
-                        <propertyref prefix="test-sys-prop."/>
-                        <mapper from="test-sys-prop.*" to="*" type="glob"/>
-                    </propertyset>
-                    <customize/>
-                </testng>
-            </sequential>
-        </macrodef>
-    </target>
-    <target name="-init-macrodef-test-impl">
-        <macrodef name="test-impl" uri="http://www.netbeans.org/ns/web-project/2">
-            <attribute default="${includes}" name="includes"/>
-            <attribute default="${excludes}" name="excludes"/>
-            <attribute default="**" name="testincludes"/>
-            <attribute default="" name="testmethods"/>
-            <element implicit="true" name="customize" optional="true"/>
-            <sequential>
-                <echo>No tests executed.</echo>
-            </sequential>
-        </macrodef>
-    </target>
-    <target depends="-init-macrodef-junit" if="${junit.available}" name="-init-macrodef-junit-impl">
-        <macrodef name="test-impl" uri="http://www.netbeans.org/ns/web-project/2">
-            <attribute default="${includes}" name="includes"/>
-            <attribute default="${excludes}" name="excludes"/>
-            <attribute default="**" name="testincludes"/>
-            <attribute default="" name="testmethods"/>
-            <element implicit="true" name="customize" optional="true"/>
-            <sequential>
-                <webproject2:junit excludes="@{excludes}" includes="@{includes}" testincludes="@{testincludes}" testmethods="@{testmethods}">
-                    <customize/>
-                </webproject2:junit>
-            </sequential>
-        </macrodef>
-    </target>
-    <target depends="-init-macrodef-testng" if="${testng.available}" name="-init-macrodef-testng-impl">
-        <macrodef name="test-impl" uri="http://www.netbeans.org/ns/web-project/2">
-            <attribute default="${includes}" name="includes"/>
-            <attribute default="${excludes}" name="excludes"/>
-            <attribute default="**" name="testincludes"/>
-            <attribute default="" name="testmethods"/>
-            <element implicit="true" name="customize" optional="true"/>
-            <sequential>
-                <webproject2:testng excludes="@{excludes}" includes="@{includes}" testincludes="@{testincludes}" testmethods="@{testmethods}">
-                    <customize/>
-                </webproject2:testng>
-            </sequential>
-        </macrodef>
-    </target>
-    <target depends="-init-macrodef-test-impl,-init-macrodef-junit-impl,-init-macrodef-testng-impl" name="-init-macrodef-test">
-        <macrodef name="test" uri="http://www.netbeans.org/ns/web-project/2">
-            <attribute default="${includes}" name="includes"/>
-            <attribute default="${excludes}" name="excludes"/>
-            <attribute default="**" name="testincludes"/>
-            <attribute default="" name="testmethods"/>
-            <sequential>
-                <webproject2:test-impl excludes="@{excludes}" includes="@{includes}" testincludes="@{testincludes}" testmethods="@{testmethods}">
-                    <customize>
-                        <classpath>
-                            <path path="${run.test.classpath}:${j2ee.platform.classpath}:${j2ee.platform.embeddableejb.classpath}"/>
-                        </classpath>
-                        <jvmarg line="${endorsed.classpath.cmd.line.arg}"/>
-                        <jvmarg line="${runmain.jvmargs}"/>
-                    </customize>
-                </webproject2:test-impl>
-            </sequential>
-        </macrodef>
-    </target>
-    <target if="${junit.available}" name="-init-macrodef-junit-debug" unless="${nb.junit.batch}">
-        <macrodef name="junit-debug" uri="http://www.netbeans.org/ns/web-project/2">
-            <attribute default="${includes}" name="includes"/>
-            <attribute default="${excludes}" name="excludes"/>
-            <attribute default="**" name="testincludes"/>
-            <attribute default="" name="testmethods"/>
-            <element name="customize" optional="true"/>
-            <sequential>
-                <junit dir="${basedir}" errorproperty="tests.failed" failureproperty="tests.failed" fork="true" showoutput="true" tempdir="${java.io.tmpdir}">
-                    <test methods="@{testmethods}" name="@{testincludes}" todir="${build.test.results.dir}"/>
-                    <syspropertyset>
-                        <propertyref prefix="test-sys-prop."/>
-                        <mapper from="test-sys-prop.*" to="*" type="glob"/>
-                    </syspropertyset>
-                    <formatter type="brief" usefile="false"/>
-                    <formatter type="xml"/>
-                    <jvmarg value="-ea"/>
-                    <jvmarg line="${debug-args-line}"/>
-                    <jvmarg value="-Xrunjdwp:transport=${debug-transport},address=${jpda.address}"/>
-                    <customize/>
-                </junit>
-            </sequential>
-        </macrodef>
-    </target>
-    <target depends="-init-test-properties" if="${nb.junit.batch}" name="-init-macrodef-junit-debug-batch">
-        <macrodef name="junit-debug" uri="http://www.netbeans.org/ns/web-project/2">
-            <attribute default="${includes}" name="includes"/>
-            <attribute default="${excludes}" name="excludes"/>
-            <attribute default="**" name="testincludes"/>
-            <attribute default="" name="testmethods"/>
-            <element name="customize" optional="true"/>
-            <sequential>
-                <property name="run.jvmargs.ide" value=""/>
-                <junit dir="${basedir}" errorproperty="tests.failed" failureproperty="tests.failed" fork="true" showoutput="true" tempdir="${build.dir}">
-                    <batchtest todir="${build.test.results.dir}">
-                        <fileset dir="${test.src.dir}" excludes="@{excludes},${excludes}" includes="@{includes}">
-                            <filename name="@{testincludes}"/>
-                        </fileset>
-                        <fileset dir="${build.test.classes.dir}" excludes="@{excludes},${excludes},${test.binaryexcludes}" includes="${test.binaryincludes}">
-                            <filename name="${test.binarytestincludes}"/>
-                        </fileset>
-                    </batchtest>
-                    <syspropertyset>
-                        <propertyref prefix="test-sys-prop."/>
-                        <mapper from="test-sys-prop.*" to="*" type="glob"/>
-                    </syspropertyset>
-                    <formatter type="brief" usefile="false"/>
-                    <formatter type="xml"/>
-                    <jvmarg value="-ea"/>
-                    <jvmarg line="${run.jvmargs.ide}"/>
-                    <jvmarg line="${debug-args-line}"/>
-                    <jvmarg value="-Xrunjdwp:transport=${debug-transport},address=${jpda.address}"/>
-                    <customize/>
-                </junit>
-            </sequential>
-        </macrodef>
-    </target>
-    <target depends="-init-macrodef-junit-debug,-init-macrodef-junit-debug-batch" if="${junit.available}" name="-init-macrodef-junit-debug-impl">
-        <macrodef name="test-debug-impl" uri="http://www.netbeans.org/ns/web-project/2">
-            <attribute default="${includes}" name="includes"/>
-            <attribute default="${excludes}" name="excludes"/>
-            <attribute default="**" name="testincludes"/>
-            <attribute default="" name="testmethods"/>
-            <element implicit="true" name="customize" optional="true"/>
-            <sequential>
-                <webproject2:junit-debug excludes="@{excludes}" includes="@{includes}" testincludes="@{testincludes}" testmethods="@{testmethods}">
-                    <customize/>
-                </webproject2:junit-debug>
-            </sequential>
-        </macrodef>
-    </target>
-    <target if="${testng.available}" name="-init-macrodef-testng-debug">
-        <macrodef name="testng-debug" uri="http://www.netbeans.org/ns/web-project/2">
-            <attribute default="${main.class}" name="testClass"/>
-            <attribute default="" name="testMethod"/>
-            <element name="customize2" optional="true"/>
-            <sequential>
-                <condition else="-testclass @{testClass}" property="test.class.or.method" value="-methods @{testClass}.@{testMethod}">
-                    <isset property="test.method"/>
-                </condition>
-                <condition else="-suitename LightPIT -testname @{testClass} ${test.class.or.method}" property="testng.cmd.args" value="@{testClass}">
-                    <matches pattern=".*\.xml" string="@{testClass}"/>
-                </condition>
-                <delete dir="${build.test.results.dir}" quiet="true"/>
-                <mkdir dir="${build.test.results.dir}"/>
-                <webproject1:debug args="${testng.cmd.args}" classname="org.testng.TestNG" classpath="${debug.test.classpath}:${j2ee.platform.embeddableejb.classpath}">
-                    <customize>
-                        <customize2/>
-                        <jvmarg value="-ea"/>
-                        <arg line="${testng.debug.mode}"/>
-                        <arg line="-d ${build.test.results.dir}"/>
-                        <arg line="-listener org.testng.reporters.VerboseReporter"/>
-                    </customize>
-                </webproject1:debug>
-            </sequential>
-        </macrodef>
-    </target>
-    <target depends="-init-macrodef-testng-debug" if="${testng.available}" name="-init-macrodef-testng-debug-impl">
-        <macrodef name="testng-debug-impl" uri="http://www.netbeans.org/ns/web-project/2">
-            <attribute default="${main.class}" name="testClass"/>
-            <attribute default="" name="testMethod"/>
-            <element implicit="true" name="customize2" optional="true"/>
-            <sequential>
-                <webproject2:testng-debug testClass="@{testClass}" testMethod="@{testMethod}">
-                    <customize2/>
-                </webproject2:testng-debug>
-            </sequential>
-        </macrodef>
-    </target>
-    <target depends="-init-macrodef-junit-debug-impl" if="${junit.available}" name="-init-macrodef-test-debug-junit">
-        <macrodef name="test-debug" uri="http://www.netbeans.org/ns/web-project/2">
-            <attribute default="${includes}" name="includes"/>
-            <attribute default="${excludes}" name="excludes"/>
-            <attribute default="**" name="testincludes"/>
-            <attribute default="" name="testmethods"/>
-            <attribute default="${main.class}" name="testClass"/>
-            <attribute default="" name="testMethod"/>
-            <sequential>
-                <webproject2:test-debug-impl excludes="@{excludes}" includes="@{includes}" testincludes="@{testincludes}" testmethods="@{testmethods}">
-                    <customize>
-                        <classpath>
-                            <path path="${run.test.classpath}:${j2ee.platform.classpath}:${j2ee.platform.embeddableejb.classpath}"/>
-                        </classpath>
-                        <jvmarg line="${endorsed.classpath.cmd.line.arg}"/>
-                        <jvmarg line="${runmain.jvmargs}"/>
-                    </customize>
-                </webproject2:test-debug-impl>
-            </sequential>
-        </macrodef>
-    </target>
-    <target depends="-init-macrodef-testng-debug-impl" if="${testng.available}" name="-init-macrodef-test-debug-testng">
-        <macrodef name="test-debug" uri="http://www.netbeans.org/ns/web-project/2">
-            <attribute default="${includes}" name="includes"/>
-            <attribute default="${excludes}" name="excludes"/>
-            <attribute default="**" name="testincludes"/>
-            <attribute default="" name="testmethods"/>
-            <attribute default="${main.class}" name="testClass"/>
-            <attribute default="" name="testMethod"/>
-            <sequential>
-                <webproject2:testng-debug-impl testClass="@{testClass}" testMethod="@{testMethod}">
-                    <customize2>
-                        <syspropertyset>
-                            <propertyref prefix="test-sys-prop."/>
-                            <mapper from="test-sys-prop.*" to="*" type="glob"/>
-                        </syspropertyset>
-                    </customize2>
-                </webproject2:testng-debug-impl>
-            </sequential>
-        </macrodef>
-    </target>
-    <target depends="-init-macrodef-test-debug-junit,-init-macrodef-test-debug-testng" name="-init-macrodef-test-debug"/>
-    <target name="-init-macrodef-java">
-        <macrodef name="java" uri="http://www.netbeans.org/ns/web-project/1">
-            <attribute default="${main.class}" name="classname"/>
-            <attribute default="${debug.classpath}" name="classpath"/>
-            <element name="customize" optional="true"/>
-            <sequential>
-                <java classname="@{classname}" fork="true">
-                    <jvmarg line="${endorsed.classpath.cmd.line.arg}"/>
-                    <jvmarg line="${runmain.jvmargs}"/>
-                    <classpath>
-                        <path path="@{classpath}:${j2ee.platform.classpath}"/>
-                    </classpath>
-                    <syspropertyset>
-                        <propertyref prefix="run-sys-prop."/>
-                        <mapper from="run-sys-prop.*" to="*" type="glob"/>
-                    </syspropertyset>
-                    <customize/>
-                </java>
-            </sequential>
-        </macrodef>
-    </target>
-    <target name="-init-macrodef-nbjsdebug">
-        <macrodef name="nbjsdebugstart" uri="http://www.netbeans.org/ns/web-project/1">
-            <attribute default="${client.url}" name="webUrl"/>
-            <sequential>
-                <nbjsdebugstart urlPart="${client.urlPart}" webUrl="@{webUrl}"/>
-            </sequential>
-        </macrodef>
-    </target>
-    <target depends="-init-debug-args" name="-init-macrodef-nbjpda">
-        <macrodef name="nbjpdastart" uri="http://www.netbeans.org/ns/web-project/1">
-            <attribute default="${main.class}" name="name"/>
-            <attribute default="${debug.classpath}:${j2ee.platform.classpath}" name="classpath"/>
-            <sequential>
-                <nbjpdastart addressproperty="jpda.address" name="@{name}" transport="${debug-transport}">
-                    <classpath>
-                        <path path="@{classpath}"/>
-                    </classpath>
-                </nbjpdastart>
-            </sequential>
-        </macrodef>
-        <macrodef name="nbjpdareload" uri="http://www.netbeans.org/ns/web-project/1">
-            <attribute default="${build.classes.dir}" name="dir"/>
-            <sequential>
-                <nbjpdareload>
-                    <fileset dir="@{dir}" includes="${fix.classes}">
-                        <include name="${fix.includes}*.class"/>
-                    </fileset>
-                </nbjpdareload>
-            </sequential>
-        </macrodef>
-        <macrodef name="nbjpdaappreloaded" uri="http://www.netbeans.org/ns/web-project/1">
-            <sequential>
-                <nbjpdaappreloaded/>
-            </sequential>
-        </macrodef>
-    </target>
-    <target name="-init-debug-args">
-        <property name="version-output" value="java version &quot;${ant.java.version}"/>
-        <condition property="have-jdk-older-than-1.4">
-            <or>
-                <contains string="${version-output}" substring="java version &quot;1.0"/>
-                <contains string="${version-output}" substring="java version &quot;1.1"/>
-                <contains string="${version-output}" substring="java version &quot;1.2"/>
-                <contains string="${version-output}" substring="java version &quot;1.3"/>
-            </or>
-        </condition>
-        <condition else="-Xdebug" property="debug-args-line" value="-Xdebug -Xnoagent -Djava.compiler=none">
-            <istrue value="${have-jdk-older-than-1.4}"/>
-        </condition>
-        <condition else="dt_socket" property="debug-transport-by-os" value="dt_shmem">
-            <os family="windows"/>
-        </condition>
-        <condition else="${debug-transport-by-os}" property="debug-transport" value="${debug.transport}">
-            <isset property="debug.transport"/>
-        </condition>
-    </target>
-    <target depends="-init-debug-args" name="-init-macrodef-debug">
-        <macrodef name="debug" uri="http://www.netbeans.org/ns/web-project/1">
-            <attribute default="${main.class}" name="classname"/>
-            <attribute default="${debug.classpath}:${j2ee.platform.classpath}" name="classpath"/>
-            <attribute default="${application.args.param}" name="args"/>
-            <element name="customize" optional="true"/>
-            <sequential>
-                <java classname="@{classname}" fork="true">
-                    <jvmarg line="${endorsed.classpath.cmd.line.arg}"/>
-                    <jvmarg line="${debug-args-line}"/>
-                    <jvmarg value="-Xrunjdwp:transport=${debug-transport},address=${jpda.address}"/>
-                    <jvmarg line="${runmain.jvmargs}"/>
-                    <classpath>
-                        <path path="@{classpath}"/>
-                    </classpath>
-                    <syspropertyset>
-                        <propertyref prefix="run-sys-prop."/>
-                        <mapper from="run-sys-prop.*" to="*" type="glob"/>
-                    </syspropertyset>
-                    <arg line="@{args}"/>
-                    <customize/>
-                </java>
-            </sequential>
-        </macrodef>
-    </target>
-    <target name="-init-taskdefs">
-        <fail unless="libs.CopyLibs.classpath">
-The libs.CopyLibs.classpath property is not set up.
-This property must point to 
-org-netbeans-modules-java-j2seproject-copylibstask.jar file which is part
-of NetBeans IDE installation and is usually located at 
-&lt;netbeans_installation&gt;/java&lt;version&gt;/ant/extra folder.
-Either open the project in the IDE and make sure CopyLibs library
-exists or setup the property manually. For example like this:
- ant -Dlibs.CopyLibs.classpath=a/path/to/org-netbeans-modules-java-j2seproject-copylibstask.jar
-                </fail>
-        <taskdef classpath="${libs.CopyLibs.classpath}" resource="org/netbeans/modules/java/j2seproject/copylibstask/antlib.xml"/>
-    </target>
-    <target name="-init-ap-cmdline-properties">
-        <property name="annotation.processing.enabled" value="true"/>
-        <property name="annotation.processing.processors.list" value=""/>
-        <property name="annotation.processing.run.all.processors" value="true"/>
-        <property name="javac.processorpath" value="${javac.classpath}"/>
-        <property name="javac.test.processorpath" value="${javac.test.classpath}"/>
-        <condition property="ap.supported.internal" value="true">
-            <not>
-                <matches pattern="1\.[0-5](\..*)?" string="${javac.source}"/>
-            </not>
-        </condition>
-    </target>
-    <target depends="-init-ap-cmdline-properties" if="ap.supported.internal" name="-init-ap-cmdline-supported">
-        <condition else="" property="ap.processors.internal" value="-processor ${annotation.processing.processors.list}">
-            <isfalse value="${annotation.processing.run.all.processors}"/>
-        </condition>
-        <condition else="" property="ap.proc.none.internal" value="-proc:none">
-            <isfalse value="${annotation.processing.enabled}"/>
-        </condition>
-    </target>
-    <target depends="-init-ap-cmdline-properties,-init-ap-cmdline-supported" name="-init-ap-cmdline">
-        <property name="ap.cmd.line.internal" value=""/>
-    </target>
-    <!--
-                pre NB7.2 profiling section; consider it deprecated
-            -->
-    <target depends="-profile-pre-init, init, -profile-post-init, -profile-init-check" if="profiler.info.jvmargs.agent" name="profile-init"/>
-    <target if="profiler.info.jvmargs.agent" name="-profile-pre-init">
-        <!-- Empty placeholder for easier customization. -->
-        <!-- You can override this target in the ../build.xml file. -->
-    </target>
-    <target if="profiler.info.jvmargs.agent" name="-profile-post-init">
-        <!-- Empty placeholder for easier customization. -->
-        <!-- You can override this target in the ../build.xml file. -->
-    </target>
-    <target depends="-profile-pre-init, init, -profile-post-init" if="profiler.info.jvmargs.agent" name="-profile-init-check">
-        <fail unless="profiler.info.jvm">Must set JVM to use for profiling in profiler.info.jvm</fail>
-        <fail unless="profiler.info.jvmargs.agent">Must set profiler agent JVM arguments in profiler.info.jvmargs.agent</fail>
-    </target>
-    <!--
-                end of pre NB7.2 profiling section
-            -->
-    <target depends="-pre-init,-init-private,-init-user,-init-project,-do-init,-post-init,-init-check,-init-macrodef-property,-init-macrodef-javac,-init-macrodef-test,-init-macrodef-test-debug,-init-macrodef-java,-init-macrodef-nbjpda,-init-macrodef-nbjsdebug,-init-macrodef-debug,-init-taskdefs,-init-ap-cmdline" name="init"/>
-    <!--
-                COMPILATION SECTION
-            -->
-    <target depends="init" if="no.dist.ear.dir" name="deps-module-jar" unless="no.deps"/>
-    <target depends="init" if="dist.ear.dir" name="deps-ear-jar" unless="no.deps"/>
-    <target depends="init, deps-module-jar, deps-ear-jar" name="deps-jar" unless="no.deps"/>
-    <target depends="init,deps-jar" name="-pre-pre-compile">
-        <mkdir dir="${build.classes.dir}"/>
-    </target>
-    <target name="-pre-compile">
-        <!-- Empty placeholder for easier customization. -->
-        <!-- You can override this target in the ../build.xml file. -->
-    </target>
-    <target name="-copy-webdir">
-        <copy todir="${build.web.dir}">
-            <fileset dir="${web.docbase.dir}" excludes="${build.web.excludes},${excludes}" includes="${includes}"/>
-        </copy>
-        <copy todir="${build.web.dir}/WEB-INF">
-            <fileset dir="${webinf.dir}" excludes="${build.web.excludes}"/>
-        </copy>
-    </target>
-    <target depends="init, deps-jar, -pre-pre-compile, -pre-compile, -copy-manifest, -copy-persistence-xml, -copy-webdir, library-inclusion-in-archive,library-inclusion-in-manifest" if="have.sources" name="-do-compile">
-        <webproject2:javac destdir="${build.classes.dir}" gensrcdir="${build.generated.sources.dir}"/>
-        <copy todir="${build.classes.dir}">
-            <fileset dir="${src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
-        </copy>
-    </target>
-    <target if="has.custom.manifest" name="-copy-manifest">
-        <mkdir dir="${build.meta.inf.dir}"/>
-        <copy todir="${build.meta.inf.dir}">
-            <fileset dir="${conf.dir}" includes="MANIFEST.MF"/>
-        </copy>
-    </target>
-    <target if="has.persistence.xml" name="-copy-persistence-xml">
-        <mkdir dir="${build.web.dir}/WEB-INF/classes/META-INF"/>
-        <copy todir="${build.web.dir}/WEB-INF/classes/META-INF">
-            <fileset dir="${persistence.xml.dir}" includes="persistence.xml orm.xml"/>
-        </copy>
-    </target>
-    <target name="-post-compile">
-        <!-- Empty placeholder for easier customization. -->
-        <!-- You can override this target in the ../build.xml file. -->
-    </target>
-    <target depends="init,deps-jar,-pre-pre-compile,-pre-compile,-do-compile,-post-compile" description="Compile project." name="compile"/>
-    <target name="-pre-compile-single">
-        <!-- Empty placeholder for easier customization. -->
-        <!-- You can override this target in the ../build.xml file. -->
-    </target>
-    <target depends="init,deps-jar,-pre-pre-compile" name="-do-compile-single">
-        <fail unless="javac.includes">Must select some files in the IDE or set javac.includes</fail>
-        <webproject2:javac excludes="" gensrcdir="${build.generated.sources.dir}" includes="${javac.includes}"/>
-        <copy todir="${build.classes.dir}">
-            <fileset dir="${src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
-        </copy>
-    </target>
-    <target name="-post-compile-single">
-        <!-- Empty placeholder for easier customization. -->
-        <!-- You can override this target in the ../build.xml file. -->
-    </target>
-    <target depends="init,deps-jar,-pre-pre-compile,-pre-compile-single,-do-compile-single,-post-compile-single" name="compile-single"/>
-    <property name="jspc.schemas" value="/resources/schemas/"/>
-    <property name="jspc.dtds" value="/resources/dtds/"/>
-    <target depends="compile" description="Test compile JSP pages to expose compilation errors." if="do.compile.jsps" name="compile-jsps">
-        <mkdir dir="${build.generated.dir}/src"/>
-        <java classname="org.netbeans.modules.web.project.ant.JspC" failonerror="true" fork="true">
-            <arg value="-uriroot"/>
-            <arg file="${basedir}/${build.web.dir}"/>
-            <arg value="-d"/>
-            <arg file="${basedir}/${build.generated.dir}/src"/>
-            <arg value="-die1"/>
-            <arg value="-schemas ${jspc.schemas}"/>
-            <arg value="-dtds ${jspc.dtds}"/>
-            <arg value="-compilerSourceVM ${javac.source}"/>
-            <arg value="-compilerTargetVM ${javac.target}"/>
-            <arg value="-javaEncoding ${source.encoding}"/>
-            <arg value="-sysClasspath ${libs.jsp-compilation-syscp.classpath}"/>
-            <classpath path="${java.home}/../lib/tools.jar:${libs.jsp-compiler.classpath}:${libs.jsp-compilation.classpath}"/>
-        </java>
-        <mkdir dir="${build.generated.dir}/classes"/>
-        <webproject2:javac classpath="${build.classes.dir}:${libs.jsp-compilation.classpath}:${javac.classpath}:${j2ee.platform.classpath}" destdir="${build.generated.dir}/classes" srcdir="${build.generated.dir}/src"/>
-    </target>
-    <target depends="compile" if="jsp.includes" name="-do-compile-single-jsp">
-        <fail unless="javac.jsp.includes">Must select some files in the IDE or set javac.jsp.includes</fail>
-        <mkdir dir="${build.generated.dir}/src"/>
-        <java classname="org.netbeans.modules.web.project.ant.JspCSingle" failonerror="true" fork="true">
-            <arg value="-uriroot"/>
-            <arg file="${basedir}/${build.web.dir}"/>
-            <arg value="-d"/>
-            <arg file="${basedir}/${build.generated.dir}/src"/>
-            <arg value="-die1"/>
-            <arg value="-schemas ${jspc.schemas}"/>
-            <arg value="-dtds ${jspc.dtds}"/>
-            <arg value="-sysClasspath ${libs.jsp-compilation-syscp.classpath}"/>
-            <arg value="-jspc.files"/>
-            <arg path="${jsp.includes}"/>
-            <arg value="-compilerSourceVM ${javac.source}"/>
-            <arg value="-compilerTargetVM ${javac.target}"/>
-            <arg value="-javaEncoding ${source.encoding}"/>
-            <classpath path="${java.home}/../lib/tools.jar:${libs.jsp-compiler.classpath}:${libs.jsp-compilation.classpath}"/>
-        </java>
-        <mkdir dir="${build.generated.dir}/classes"/>
-        <webproject2:javac classpath="${build.classes.dir}:${libs.jsp-compilation.classpath}:${javac.classpath}:${j2ee.platform.classpath}" destdir="${build.generated.dir}/classes" srcdir="${build.generated.dir}/src">
-            <customize>
-                <patternset includes="${javac.jsp.includes}"/>
-            </customize>
-        </webproject2:javac>
-    </target>
-    <target name="compile-single-jsp">
-        <fail unless="jsp.includes">Must select a file in the IDE or set jsp.includes</fail>
-        <antcall target="-do-compile-single-jsp"/>
-    </target>
-    <!--
-                DIST BUILDING SECTION
-            -->
-    <target name="-pre-dist">
-        <!-- Empty placeholder for easier customization. -->
-        <!-- You can override this target in the ../build.xml file. -->
-    </target>
-    <target depends="init,compile,compile-jsps,-pre-dist" if="do.war.package.without.custom.manifest" name="-do-dist-without-manifest">
-        <dirname file="${dist.war}" property="dist.jar.dir"/>
-        <mkdir dir="${dist.jar.dir}"/>
-        <jar compress="${jar.compress}" jarfile="${dist.war}">
-            <fileset dir="${build.web.dir}" excludes="WEB-INF/classes/.netbeans_*,${dist.archive.excludes}"/>
-        </jar>
-    </target>
-    <target depends="init,compile,compile-jsps,-pre-dist" if="do.war.package.with.custom.manifest" name="-do-dist-with-manifest">
-        <dirname file="${dist.war}" property="dist.jar.dir"/>
-        <mkdir dir="${dist.jar.dir}"/>
-        <jar compress="${jar.compress}" jarfile="${dist.war}" manifest="${build.meta.inf.dir}/MANIFEST.MF">
-            <fileset dir="${build.web.dir}" excludes="WEB-INF/classes/.netbeans_*,${dist.archive.excludes}"/>
-        </jar>
-    </target>
-    <target depends="init,compile,compile-jsps,-pre-dist" if="do.tmp.war.package.without.custom.manifest" name="-do-tmp-dist-without-manifest">
-        <dirname file="${dist.war}" property="dist.jar.dir"/>
-        <mkdir dir="${dist.jar.dir}"/>
-        <jar compress="${jar.compress}" jarfile="${dist.war}">
-            <fileset dir="${build.web.dir}" excludes="WEB-INF/classes/.netbeans_*,${dist.archive.excludes}"/>
-        </jar>
-    </target>
-    <target depends="init,compile,compile-jsps,-pre-dist" if="do.tmp.war.package.with.custom.manifest" name="-do-tmp-dist-with-manifest">
-        <dirname file="${dist.war}" property="dist.jar.dir"/>
-        <mkdir dir="${dist.jar.dir}"/>
-        <jar compress="${jar.compress}" jarfile="${dist.war}" manifest="${build.meta.inf.dir}/MANIFEST.MF">
-            <fileset dir="${build.web.dir}" excludes="WEB-INF/classes/.netbeans_*,${dist.archive.excludes}"/>
-        </jar>
-    </target>
-    <target depends="init,compile,compile-jsps,-pre-dist,-do-dist-with-manifest,-do-dist-without-manifest" name="do-dist"/>
-    <target depends="init" if="dist.ear.dir" name="library-inclusion-in-manifest">
-        <copyfiles files="${libs.jstl.classpath}" iftldtodir="${build.web.dir}/WEB-INF" todir="${dist.ear.dir}/lib"/>
-        <copyfiles files="${libs.SLF4J-LOG4J2.classpath}" iftldtodir="${build.web.dir}/WEB-INF" todir="${dist.ear.dir}/lib"/>
-        <copyfiles files="${libs.LOG4J2-WEB.classpath}" iftldtodir="${build.web.dir}/WEB-INF" todir="${dist.ear.dir}/lib"/>
-        <mkdir dir="${build.web.dir}/META-INF"/>
-        <manifest file="${build.web.dir}/META-INF/MANIFEST.MF" mode="update"/>
-    </target>
-    <target depends="init" name="library-inclusion-in-archive" unless="dist.ear.dir">
-        <copyfiles files="${libs.jstl.classpath}" todir="${build.web.dir}/WEB-INF/lib"/>
-        <copyfiles files="${libs.SLF4J-LOG4J2.classpath}" todir="${build.web.dir}/WEB-INF/lib"/>
-        <copyfiles files="${libs.LOG4J2-WEB.classpath}" todir="${build.web.dir}/WEB-INF/lib"/>
-    </target>
-    <target depends="init" if="dist.ear.dir" name="-clean-webinf-lib">
-        <delete dir="${build.web.dir}/WEB-INF/lib"/>
-    </target>
-    <target depends="init,-clean-webinf-lib,compile,compile-jsps,-pre-dist,library-inclusion-in-manifest" if="do.tmp.war.package" name="do-ear-dist">
-        <dirname file="${dist.ear.war}" property="dist.jar.dir"/>
-        <mkdir dir="${dist.jar.dir}"/>
-        <jar compress="${jar.compress}" jarfile="${dist.ear.war}" manifest="${build.web.dir}/META-INF/MANIFEST.MF">
-            <fileset dir="${build.web.dir}" excludes="WEB-INF/classes/.netbeans_*,${dist.archive.excludes}"/>
-        </jar>
-    </target>
-    <target name="-post-dist">
-        <!-- Empty placeholder for easier customization. -->
-        <!-- You can override this target in the ../build.xml file. -->
-    </target>
-    <target depends="init,compile,-pre-dist,do-dist,-post-dist" description="Build distribution (WAR)." name="dist"/>
-    <target depends="init,-clean-webinf-lib,-init-cos,compile,-pre-dist,do-ear-dist,-post-dist" description="Build distribution (WAR) to be packaged into an EAR." name="dist-ear"/>
-    <!--
-                EXECUTION SECTION
-            -->
-    <target depends="run-deploy,run-display-browser" description="Deploy to server and show in browser." name="run"/>
-    <target name="-pre-run-deploy">
-        <!-- Empty placeholder for easier customization. -->
-        <!-- You can override this target in the ../build.xml file. -->
-    </target>
-    <target name="-post-run-deploy">
-        <!-- Empty placeholder for easier customization. -->
-        <!-- You can override this target in the ../build.xml file. -->
-    </target>
-    <target name="-pre-nbmodule-run-deploy">
-        <!-- Empty placeholder for easier customization. -->
-        <!-- This target can be overriden by NetBeans modules. Don't override it directly, use -pre-run-deploy task instead. -->
-    </target>
-    <target name="-post-nbmodule-run-deploy">
-        <!-- Empty placeholder for easier customization. -->
-        <!-- This target can be overriden by NetBeans modules. Don't override it directly, use -post-run-deploy task instead. -->
-    </target>
-    <target name="-run-deploy-am">
-        <!-- Task to deploy to the Access Manager runtime. -->
-    </target>
-    <target depends="init,-init-cos,compile,compile-jsps,-do-compile-single-jsp,-pre-dist,-do-tmp-dist-with-manifest,-do-tmp-dist-without-manifest,-pre-run-deploy,-pre-nbmodule-run-deploy,-run-deploy-nb,-init-deploy-ant,-deploy-ant,-run-deploy-am,-post-nbmodule-run-deploy,-post-run-deploy,-do-update-breakpoints" name="run-deploy"/>
-    <target if="netbeans.home" name="-run-deploy-nb">
-        <nbdeploy clientUrlPart="${client.urlPart}" debugmode="false" forceRedeploy="${forceRedeploy}"/>
-    </target>
-    <target name="-init-deploy-ant" unless="netbeans.home">
-        <property name="deploy.ant.archive" value="${dist.war}"/>
-        <property name="deploy.ant.docbase.dir" value="${web.docbase.dir}"/>
-        <property name="deploy.ant.resource.dir" value="${resource.dir}"/>
-        <property name="deploy.ant.enabled" value="true"/>
-    </target>
-    <target depends="dist,-run-undeploy-nb,-init-deploy-ant,-undeploy-ant" name="run-undeploy"/>
-    <target if="netbeans.home" name="-run-undeploy-nb">
-        <fail message="Undeploy is not supported from within the IDE"/>
-    </target>
-    <target depends="init,-pre-dist,dist,-post-dist" name="verify">
-        <nbverify file="${dist.war}"/>
-    </target>
-    <target depends="run-deploy,-init-display-browser,-display-browser-nb-old,-display-browser-nb,-display-browser-cl" name="run-display-browser"/>
-    <target if="do.display.browser" name="-init-display-browser">
-        <condition property="do.display.browser.nb.old">
-            <and>
-                <isset property="netbeans.home"/>
-                <not>
-                    <isset property="browser.context"/>
-                </not>
-            </and>
-        </condition>
-        <condition property="do.display.browser.nb">
-            <and>
-                <isset property="netbeans.home"/>
-                <isset property="browser.context"/>
-            </and>
-        </condition>
-        <condition property="do.display.browser.cl">
-            <isset property="deploy.ant.enabled"/>
-        </condition>
-    </target>
-    <target if="do.display.browser.nb.old" name="-display-browser-nb-old">
-        <nbbrowse url="${client.url}"/>
-    </target>
-    <target if="do.display.browser.nb" name="-display-browser-nb">
-        <nbbrowse context="${browser.context}" url="${client.url}" urlPath="${client.urlPart}"/>
-    </target>
-    <target if="do.display.browser.cl" name="-get-browser" unless="browser">
-        <condition property="browser" value="rundll32">
-            <os family="windows"/>
-        </condition>
-        <condition else="" property="browser.args" value="url.dll,FileProtocolHandler">
-            <os family="windows"/>
-        </condition>
-        <condition property="browser" value="/usr/bin/open">
-            <os family="mac"/>
-        </condition>
-        <property environment="env"/>
-        <condition property="browser" value="${env.BROWSER}">
-            <isset property="env.BROWSER"/>
-        </condition>
-        <condition property="browser" value="/usr/bin/firefox">
-            <available file="/usr/bin/firefox"/>
-        </condition>
-        <condition property="browser" value="/usr/local/firefox/firefox">
-            <available file="/usr/local/firefox/firefox"/>
-        </condition>
-        <condition property="browser" value="/usr/bin/mozilla">
-            <available file="/usr/bin/mozilla"/>
-        </condition>
-        <condition property="browser" value="/usr/local/mozilla/mozilla">
-            <available file="/usr/local/mozilla/mozilla"/>
-        </condition>
-        <condition property="browser" value="/usr/sfw/lib/firefox/firefox">
-            <available file="/usr/sfw/lib/firefox/firefox"/>
-        </condition>
-        <condition property="browser" value="/opt/csw/bin/firefox">
-            <available file="/opt/csw/bin/firefox"/>
-        </condition>
-        <condition property="browser" value="/usr/sfw/lib/mozilla/mozilla">
-            <available file="/usr/sfw/lib/mozilla/mozilla"/>
-        </condition>
-        <condition property="browser" value="/opt/csw/bin/mozilla">
-            <available file="/opt/csw/bin/mozilla"/>
-        </condition>
-    </target>
-    <target depends="-get-browser" if="do.display.browser.cl" name="-display-browser-cl">
-        <fail unless="browser">
-                    Browser not found, cannot launch the deployed application. Try to set the BROWSER environment variable.
-                </fail>
-        <property name="browse.url" value="${deploy.ant.client.url}${client.urlPart}"/>
-        <echo>Launching ${browse.url}</echo>
-        <exec executable="${browser}" spawn="true">
-            <arg line="${browser.args} ${browse.url}"/>
-        </exec>
-    </target>
-    <target depends="init,-init-cos,compile-single" name="run-main">
-        <fail unless="run.class">Must select one file in the IDE or set run.class</fail>
-        <webproject1:java classname="${run.class}"/>
-    </target>
-    <target depends="init,compile-test-single,-pre-test-run-single" name="run-test-with-main">
-        <fail unless="run.class">Must select one file in the IDE or set run.class</fail>
-        <webproject1:java classname="${run.class}" classpath="${run.test.classpath}"/>
-    </target>
-    <target depends="init" if="netbeans.home" name="-do-update-breakpoints">
-        <webproject1:nbjpdaappreloaded/>
-    </target>
-    <!--
-                DEBUGGING SECTION
-            -->
-    <target depends="init,-init-cos,compile,compile-jsps,-do-compile-single-jsp,-pre-dist,-do-tmp-dist-with-manifest,-do-tmp-dist-without-manifest" description="Debug project in IDE." if="netbeans.home" name="debug">
-        <nbstartserver debugmode="true"/>
-        <antcall target="connect-debugger"/>
-        <nbdeploy clientUrlPart="${client.urlPart}" debugmode="true" forceRedeploy="true"/>
-        <antcall target="debug-display-browser-old"/>
-        <antcall target="debug-display-browser"/>
-        <antcall target="connect-client-debugger"/>
-    </target>
-    <target if="do.debug.server" name="connect-debugger" unless="is.debugged">
-        <condition property="listeningcp" value="sourcepath">
-            <istrue value="${j2ee.compile.on.save}"/>
-        </condition>
-        <nbjpdaconnect address="${jpda.address}" host="${jpda.host}" listeningcp="${listeningcp}" name="${name}" transport="${jpda.transport}">
-            <classpath>
-                <path path="${debug.classpath}:${j2ee.platform.classpath}"/>
-            </classpath>
-            <sourcepath>
-                <path path="${web.docbase.dir}"/>
-            </sourcepath>
-        </nbjpdaconnect>
-    </target>
-    <target if="do.display.browser.debug.old" name="debug-display-browser-old">
-        <nbbrowse url="${client.url}"/>
-    </target>
-    <target if="do.display.browser.debug" name="debug-display-browser">
-        <nbbrowse context="${browser.context}" url="${client.url}" urlPath="${client.urlPart}"/>
-    </target>
-    <target if="do.debug.client" name="connect-client-debugger">
-        <webproject1:nbjsdebugstart webUrl="${client.url}"/>
-    </target>
-    <target depends="init,compile-test-single" if="netbeans.home" name="-debug-start-debuggee-main-test">
-        <fail unless="debug.class">Must select one file in the IDE or set debug.class</fail>
-        <webproject1:debug classname="${debug.class}" classpath="${debug.test.classpath}"/>
-    </target>
-    <target depends="init,compile-test-single,-debug-start-debugger-main-test,-debug-start-debuggee-main-test" if="netbeans.home" name="debug-test-with-main"/>
-    <target depends="init,compile,compile-jsps,-do-compile-single-jsp,debug" if="netbeans.home" name="debug-single"/>
-    <target depends="init" if="netbeans.home" name="-debug-start-debugger-main-test">
-        <webproject1:nbjpdastart classpath="${debug.test.classpath}" name="${debug.class}"/>
-    </target>
-    <target depends="init" if="netbeans.home" name="-debug-start-debugger">
-        <webproject1:nbjpdastart name="${debug.class}"/>
-    </target>
-    <target depends="init,compile-single" if="netbeans.home" name="-debug-start-debuggee-single">
-        <fail unless="debug.class">Must select one file in the IDE or set debug.class</fail>
-        <webproject1:debug classname="${debug.class}"/>
-    </target>
-    <target depends="init,compile-single,-debug-start-debugger,-debug-start-debuggee-single" if="netbeans.home" name="debug-single-main"/>
-    <target depends="init" name="-pre-debug-fix">
-        <fail unless="fix.includes">Must set fix.includes</fail>
-        <property name="javac.includes" value="${fix.includes}.java"/>
-    </target>
-    <target depends="init,-pre-debug-fix,compile-single" if="netbeans.home" name="-do-debug-fix">
-        <webproject1:nbjpdareload/>
-    </target>
-    <target depends="init,-pre-debug-fix,-do-debug-fix" if="netbeans.home" name="debug-fix"/>
-    <!--
-            =================
-            PROFILING SECTION
-            =================
-            -->
-    <!--
-                pre NB7.2 profiling section; consider it deprecated
-            -->
-    <target description="Profile a J2EE project in the IDE." if="profiler.info.jvmargs.agent" name="-profile-pre72">
-        <condition else="start-profiled-server" property="profiler.startserver.target" value="start-profiled-server-extraargs">
-            <isset property="profiler.info.jvmargs.extra"/>
-        </condition>
-        <antcall target="${profiler.startserver.target}"/>
-        <antcall target="run"/>
-        <antcall target="-profile-start-loadgen"/>
-    </target>
-    <target if="profiler.info.jvmargs.agent" name="start-profiled-server">
-        <nbstartprofiledserver forceRestart="${profiler.j2ee.serverForceRestart}" javaPlatform="${profiler.info.javaPlatform}" startupTimeout="${profiler.j2ee.serverStartupTimeout}">
-            <jvmarg value="${profiler.info.jvmargs.agent}"/>
-            <jvmarg value="${profiler.j2ee.agentID}"/>
-        </nbstartprofiledserver>
-    </target>
-    <target if="profiler.info.jvmargs.agent" name="start-profiled-server-extraargs">
-        <nbstartprofiledserver forceRestart="${profiler.j2ee.serverForceRestart}" javaPlatform="${profiler.info.javaPlatform}" startupTimeout="${profiler.j2ee.serverStartupTimeout}">
-            <jvmarg value="${profiler.info.jvmargs.extra}"/>
-            <jvmarg value="${profiler.info.jvmargs.agent}"/>
-            <jvmarg value="${profiler.j2ee.agentID}"/>
-        </nbstartprofiledserver>
-    </target>
-    <target depends="profile-init,compile-test-single" if="profiler.info.jvmargs.agent" name="-profile-test-single-pre72">
-        <fail unless="netbeans.home">This target only works when run from inside the NetBeans IDE.</fail>
-        <nbprofiledirect>
-            <classpath>
-                <path path="${run.test.classpath}"/>
-                <path path="${j2ee.platform.classpath}"/>
-            </classpath>
-        </nbprofiledirect>
-        <junit dir="${profiler.info.dir}" errorproperty="tests.failed" failureproperty="tests.failed" fork="true" jvm="${profiler.info.jvm}" showoutput="true">
-            <env key="${profiler.info.pathvar}" path="${profiler.info.agentpath}:${profiler.current.path}"/>
-            <jvmarg value="${profiler.info.jvmargs.agent}"/>
-            <jvmarg line="${profiler.info.jvmargs}"/>
-            <test name="${profile.class}"/>
-            <classpath>
-                <path path="${run.test.classpath}"/>
-                <path path="${j2ee.platform.classpath}"/>
-            </classpath>
-            <syspropertyset>
-                <propertyref prefix="test-sys-prop."/>
-                <mapper from="test-sys-prop.*" to="*" type="glob"/>
-            </syspropertyset>
-            <formatter type="brief" usefile="false"/>
-            <formatter type="xml"/>
-        </junit>
-    </target>
-    <target if="netbeans.home" name="-profile-check">
-        <condition property="profiler.configured">
-            <or>
-                <contains casesensitive="true" string="${run.jvmargs.ide}" substring="-agentpath:"/>
-                <contains casesensitive="true" string="${run.jvmargs.ide}" substring="-javaagent:"/>
-            </or>
-        </condition>
-    </target>
-    <target depends="init,-init-cos,compile,compile-jsps,-do-compile-single-jsp,-pre-dist,-do-tmp-dist-with-manifest,-do-tmp-dist-without-manifest" name="-do-profile">
-        <startprofiler/>
-        <nbstartserver profilemode="true"/>
-        <nbdeploy clientUrlPart="${client.urlPart}" forceRedeploy="true" profilemode="true"/>
-        <antcall target="debug-display-browser-old"/>
-        <antcall target="debug-display-browser"/>
-        <antcall target="-profile-start-loadgen"/>
-    </target>
-    <target depends="-profile-check,-profile-pre72" description="Profile a J2EE project in the IDE." if="profiler.configured" name="profile" unless="profiler.info.jvmargs.agent">
-        <antcall target="-do-profile"/>
-    </target>
-    <target depends="-profile-test-single-pre72" name="profile-test-single"/>
-    <target depends="-profile-check" if="profiler.configured" name="profile-test" unless="profiler.info.jvmargs.agent">
-        <startprofiler/>
-        <antcall target="test-single"/>
-    </target>
-    <target if="profiler.loadgen.path" name="-profile-start-loadgen">
-        <loadgenstart path="${profiler.loadgen.path}"/>
-    </target>
-    <!--
-                JAVADOC SECTION
-            -->
-    <target depends="init" if="have.sources" name="javadoc-build">
-        <mkdir dir="${dist.javadoc.dir}"/>
-        <javadoc additionalparam="${javadoc.additionalparam}" author="${javadoc.author}" charset="UTF-8" destdir="${dist.javadoc.dir}" docencoding="UTF-8" encoding="${javadoc.encoding.used}" failonerror="true" noindex="${javadoc.noindex}" nonavbar="${javadoc.nonavbar}" notree="${javadoc.notree}" private="${javadoc.private}" source="${javac.source}" splitindex="${javadoc.splitindex}" use="${javadoc.use}" useexternalfile="true" version="${javadoc.version}" windowtitle="${javadoc.windowtitle}">
-            <classpath>
-                <path path="${javac.classpath}:${j2ee.platform.classpath}"/>
-            </classpath>
-            <fileset dir="${src.dir}" excludes="${excludes}" includes="${includes}">
-                <filename name="**/*.java"/>
-            </fileset>
-            <fileset dir="${build.generated.sources.dir}" erroronmissingdir="false">
-                <include name="**/*.java"/>
-            </fileset>
-        </javadoc>
-        <copy todir="${dist.javadoc.dir}">
-            <fileset dir="${src.dir}" excludes="${excludes}" includes="${includes}">
-                <filename name="**/doc-files/**"/>
-            </fileset>
-            <fileset dir="${build.generated.sources.dir}" erroronmissingdir="false">
-                <include name="**/doc-files/**"/>
-            </fileset>
-        </copy>
-    </target>
-    <target depends="init,javadoc-build" if="netbeans.home" name="javadoc-browse" unless="no.javadoc.preview">
-        <nbbrowse file="${dist.javadoc.dir}/index.html"/>
-    </target>
-    <target depends="init,javadoc-build,javadoc-browse" description="Build Javadoc." name="javadoc"/>
-    <!--
-                
-                TEST COMPILATION SECTION
-            -->
-    <target depends="init,compile" if="have.tests" name="-pre-pre-compile-test">
-        <mkdir dir="${build.test.classes.dir}"/>
-        <property name="j2ee.platform.embeddableejb.classpath" value=""/>
-    </target>
-    <target name="-pre-compile-test">
-        <!-- Empty placeholder for easier customization. -->
-        <!-- You can override this target in the ../build.xml file. -->
-    </target>
-    <target depends="init,compile,-pre-pre-compile-test,-pre-compile-test" if="have.tests" name="-do-compile-test">
-        <webproject2:javac classpath="${javac.test.classpath}:${j2ee.platform.classpath}:${j2ee.platform.embeddableejb.classpath}" debug="true" destdir="${build.test.classes.dir}" srcdir="${test.src.dir}"/>
-        <copy todir="${build.test.classes.dir}">
-            <fileset dir="${test.src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
-        </copy>
-    </target>
-    <target name="-post-compile-test">
-        <!-- Empty placeholder for easier customization. -->
-        <!-- You can override this target in the ../build.xml file. -->
-    </target>
-    <target depends="init,compile,-pre-pre-compile-test,-pre-compile-test,-do-compile-test,-post-compile-test" name="compile-test"/>
-    <target name="-pre-compile-test-single">
-        <!-- Empty placeholder for easier customization. -->
-        <!-- You can override this target in the ../build.xml file. -->
-    </target>
-    <target depends="init,compile,-pre-pre-compile-test,-pre-compile-test-single" if="have.tests" name="-do-compile-test-single">
-        <fail unless="javac.includes">Must select some files in the IDE or set javac.includes</fail>
-        <webproject2:javac classpath="${javac.test.classpath}:${j2ee.platform.classpath}:${j2ee.platform.embeddableejb.classpath}" debug="true" destdir="${build.test.classes.dir}" excludes="" includes="${javac.includes}" srcdir="${test.src.dir}"/>
-        <copy todir="${build.test.classes.dir}">
-            <fileset dir="${test.src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
-        </copy>
-    </target>
-    <target name="-post-compile-test-single">
-        <!-- Empty placeholder for easier customization. -->
-        <!-- You can override this target in the ../build.xml file. -->
-    </target>
-    <target depends="init,compile,-pre-pre-compile-test,-pre-compile-test-single,-do-compile-test-single,-post-compile-test-single" name="compile-test-single"/>
-    <!--
-                
-                TEST EXECUTION SECTION
-            -->
-    <target depends="init" if="have.tests" name="-pre-test-run">
-        <mkdir dir="${build.test.results.dir}"/>
-    </target>
-    <target depends="init,compile-test,-pre-test-run" if="have.tests" name="-do-test-run">
-        <webproject2:test includes="${includes}" testincludes="**/*Test.java"/>
-    </target>
-    <target depends="init,compile-test,-pre-test-run,-do-test-run" if="have.tests" name="-post-test-run">
-        <fail if="tests.failed" unless="ignore.failing.tests">Some tests failed; see details above.</fail>
-    </target>
-    <target depends="init" if="have.tests" name="test-report"/>
-    <target depends="init" if="netbeans.home+have.tests" name="-test-browse"/>
-    <target depends="init,compile-test,-pre-test-run,-do-test-run,test-report,-post-test-run,-test-browse" description="Run unit tests." name="test"/>
-    <target depends="init" if="have.tests" name="-pre-test-run-single">
-        <mkdir dir="${build.test.results.dir}"/>
-    </target>
-    <target depends="init,compile-test-single,-pre-test-run-single" if="have.tests" name="-do-test-run-single">
-        <fail unless="test.includes">Must select some files in the IDE or set test.includes</fail>
-        <webproject2:test excludes="" includes="${test.includes}" testincludes="${test.includes}"/>
-    </target>
-    <target depends="init,compile-test-single,-pre-test-run-single,-do-test-run-single" if="have.tests" name="-post-test-run-single">
-        <fail if="tests.failed" unless="ignore.failing.tests">Some tests failed; see details above.</fail>
-    </target>
-    <target depends="init,compile-test-single,-pre-test-run-single,-do-test-run-single,-post-test-run-single" description="Run single unit test." name="test-single"/>
-    <target depends="init,compile-test-single,-pre-test-run-single" if="have.tests" name="-do-test-run-single-method">
-        <fail unless="test.class">Must select some files in the IDE or set test.class</fail>
-        <fail unless="test.method">Must select some method in the IDE or set test.method</fail>
-        <webproject2:test excludes="" includes="${javac.includes}" testincludes="${test.class}" testmethods="${test.method}"/>
-    </target>
-    <target depends="init,compile-test-single,-pre-test-run-single,-do-test-run-single-method" if="have.tests" name="-post-test-run-single-method">
-        <fail if="tests.failed" unless="ignore.failing.tests">Some tests failed; see details above.</fail>
-    </target>
-    <target depends="init,compile-test-single,-pre-test-run-single,-do-test-run-single-method,-post-test-run-single-method" description="Run single unit test." name="test-single-method"/>
-    <!--
-                
-                TEST DEBUGGING SECTION
-            -->
-    <target depends="init,compile-test-single,-pre-test-run-single" if="have.tests" name="-debug-start-debuggee-test">
-        <fail unless="test.class">Must select one file in the IDE or set test.class</fail>
-        <webproject2:test-debug excludes="" includes="${javac.includes}" testClass="${test.class}" testincludes="${javac.includes}"/>
-    </target>
-    <target depends="init,compile-test-single,-pre-test-run-single" if="have.tests" name="-debug-start-debuggee-test-method">
-        <fail unless="test.class">Must select one file in the IDE or set test.class</fail>
-        <fail unless="test.method">Must select some method in the IDE or set test.method</fail>
-        <webproject2:test-debug excludes="" includes="${javac.includes}" testClass="${test.class}" testMethod="${test.method}" testincludes="${test.class}" testmethods="${test.method}"/>
-    </target>
-    <target depends="init,compile-test" if="netbeans.home+have.tests" name="-debug-start-debugger-test">
-        <webproject1:nbjpdastart classpath="${debug.test.classpath}" name="${test.class}"/>
-    </target>
-    <target depends="init,compile-test,-debug-start-debugger-test,-debug-start-debuggee-test" name="debug-test"/>
-    <target depends="init,compile-test-single,-debug-start-debugger-test,-debug-start-debuggee-test-method" name="debug-test-method"/>
-    <target depends="init,-pre-debug-fix,compile-test-single" if="netbeans.home" name="-do-debug-fix-test">
-        <webproject1:nbjpdareload dir="${build.test.classes.dir}"/>
-    </target>
-    <target depends="init,-pre-debug-fix,-do-debug-fix-test" if="netbeans.home" name="debug-fix-test"/>
-    <!--
-                
-                CLEANUP SECTION
-            -->
-    <target depends="init" name="deps-clean" unless="no.deps"/>
-    <target depends="init" name="do-clean">
-        <condition property="build.dir.to.clean" value="${build.web.dir}">
-            <isset property="dist.ear.dir"/>
-        </condition>
-        <property name="build.dir.to.clean" value="${build.web.dir}"/>
-        <delete includeEmptyDirs="true" quiet="true">
-            <fileset dir="${build.dir.to.clean}/WEB-INF/lib"/>
-        </delete>
-        <delete dir="${build.dir}"/>
-        <available file="${build.dir.to.clean}/WEB-INF/lib" property="status.clean-failed" type="dir"/>
-        <delete dir="${dist.dir}"/>
-    </target>
-    <target depends="do-clean" if="status.clean-failed" name="check-clean">
-        <echo message="Warning: unable to delete some files in ${build.web.dir}/WEB-INF/lib - they are probably locked by the J2EE server. "/>
-        <echo level="info" message="To delete all files undeploy the module from Server Registry in Runtime tab and then use Clean again."/>
-    </target>
-    <target depends="init" if="netbeans.home" name="undeploy-clean">
-        <nbundeploy failOnError="false" startServer="false"/>
-    </target>
-    <target name="-post-clean">
-        <!-- Empty placeholder for easier customization. -->
-        <!-- You can override this target in the ../build.xml file. -->
-    </target>
-    <target depends="init,undeploy-clean,deps-clean,do-clean,check-clean,-post-clean" description="Clean build products." name="clean"/>
-    <target depends="clean" description="Clean build products." name="clean-ear"/>
-</project>
--- a/nbproject/genfiles.properties	Sun Apr 08 16:51:15 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,8 +0,0 @@
-build.xml.data.CRC32=40807f5e
-build.xml.script.CRC32=1f023e98
-build.xml.stylesheet.CRC32=651128d4@1.77.1.1
-# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml.
-# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you.
-nbproject/build-impl.xml.data.CRC32=40807f5e
-nbproject/build-impl.xml.script.CRC32=0c71c5d8
-nbproject/build-impl.xml.stylesheet.CRC32=99ea4b56@1.77.1.1
--- a/nbproject/project.properties	Sun Apr 08 16:51:15 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,87 +0,0 @@
-annotation.processing.enabled=true
-annotation.processing.enabled.in.editor=true
-annotation.processing.processors.list=
-annotation.processing.run.all.processors=true
-annotation.processing.source.output=${build.generated.sources.dir}/ap-source-output
-build.classes.dir=${build.web.dir}/WEB-INF/classes
-build.classes.excludes=**/*.java,**/*.form
-build.dir=build
-build.generated.dir=${build.dir}/generated
-build.generated.sources.dir=${build.dir}/generated-sources
-build.test.classes.dir=${build.dir}/test/classes
-build.test.results.dir=${build.dir}/test/results
-build.web.dir=${build.dir}/web
-build.web.excludes=${build.classes.excludes}
-client.urlPart=
-compile.jsps=false
-conf.dir=${source.root}/conf
-debug.classpath=${build.classes.dir}:${javac.classpath}
-debug.test.classpath=\
-    ${run.test.classpath}
-display.browser=true
-# Files to be excluded from distribution war
-dist.archive.excludes=
-dist.dir=dist
-dist.ear.war=${dist.dir}/${war.ear.name}
-dist.javadoc.dir=${dist.dir}/javadoc
-dist.war=${dist.dir}/${war.name}
-endorsed.classpath=\
-    ${libs.javaee-endorsed-api-7.0.classpath}
-excludes=
-includes=**
-j2ee.compile.on.save=true
-j2ee.copy.static.files.on.save=true
-j2ee.deploy.on.save=true
-j2ee.platform=1.7-web
-j2ee.platform.classpath=${j2ee.server.home}/lib/annotations-api.jar:${j2ee.server.home}/lib/catalina-ant.jar:${j2ee.server.home}/lib/catalina-ha.jar:${j2ee.server.home}/lib/catalina-storeconfig.jar:${j2ee.server.home}/lib/catalina-tribes.jar:${j2ee.server.home}/lib/catalina.jar:${j2ee.server.home}/lib/ecj-4.6.3.jar:${j2ee.server.home}/lib/el-api.jar:${j2ee.server.home}/lib/jasper-el.jar:${j2ee.server.home}/lib/jasper.jar:${j2ee.server.home}/lib/jaspic-api.jar:${j2ee.server.home}/lib/jsp-api.jar:${j2ee.server.home}/lib/postgresql-42.1.4.jar:${j2ee.server.home}/lib/servlet-api.jar:${j2ee.server.home}/lib/tomcat-api.jar:${j2ee.server.home}/lib/tomcat-coyote.jar:${j2ee.server.home}/lib/tomcat-dbcp.jar:${j2ee.server.home}/lib/tomcat-i18n-es.jar:${j2ee.server.home}/lib/tomcat-i18n-fr.jar:${j2ee.server.home}/lib/tomcat-i18n-ja.jar:${j2ee.server.home}/lib/tomcat-jdbc.jar:${j2ee.server.home}/lib/tomcat-jni.jar:${j2ee.server.home}/lib/tomcat-util-scan.jar:${j2ee.server.home}/lib/tomcat-util.jar:${j2ee.server.home}/lib/tomcat-websocket.jar:${j2ee.server.home}/lib/websocket-api.jar
-j2ee.server.type=Tomcat
-jar.compress=false
-javac.classpath=\
-    ${libs.jstl.classpath}:\
-    ${libs.SLF4J-LOG4J2.classpath}:\
-    ${libs.LOG4J2-WEB.classpath}
-# Space-separated list of extra javac options
-javac.compilerargs=
-javac.debug=true
-javac.deprecation=false
-javac.processorpath=\
-    ${javac.classpath}
-javac.source=1.8
-javac.target=1.8
-javac.test.classpath=\
-    ${javac.classpath}:\
-    ${build.classes.dir}
-javac.test.processorpath=\
-    ${javac.test.classpath}
-javadoc.additionalparam=
-javadoc.author=false
-javadoc.encoding=${source.encoding}
-javadoc.noindex=false
-javadoc.nonavbar=false
-javadoc.notree=false
-javadoc.preview=true
-javadoc.private=false
-javadoc.splitindex=true
-javadoc.use=true
-javadoc.version=false
-javadoc.windowtitle=
-lib.dir=${web.docbase.dir}/WEB-INF/lib
-persistence.xml.dir=${conf.dir}
-platform.active=default_platform
-project.license=default
-resource.dir=setup
-run.test.classpath=\
-    ${javac.test.classpath}:\
-    ${build.test.classes.dir}
-# Space-separated list of JVM arguments used when running a class with a main method or a unit test
-# (you may also define separate properties like run-sys-prop.name=value instead of -Dname=value):
-runmain.jvmargs=
-source.encoding=UTF-8
-source.root=src
-src.dir=${source.root}/java
-test.src.dir=test
-war.content.additional=
-war.ear.name=${war.name}
-war.name=LightPIT.war
-web.docbase.dir=web
-webinf.dir=web/WEB-INF
--- a/nbproject/project.xml	Sun Apr 08 16:51:15 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project xmlns="http://www.netbeans.org/ns/project/1">
-    <type>org.netbeans.modules.web.project</type>
-    <configuration>
-        <data xmlns="http://www.netbeans.org/ns/web-project/3">
-            <name>LightPIT</name>
-            <minimum-ant-version>1.6.5</minimum-ant-version>
-            <web-module-libraries>
-                <library dirs="200">
-                    <file>${libs.jstl.classpath}</file>
-                    <path-in-war>WEB-INF/lib</path-in-war>
-                </library>
-                <library dirs="200">
-                    <file>${libs.SLF4J-LOG4J2.classpath}</file>
-                    <path-in-war>WEB-INF/lib</path-in-war>
-                </library>
-                <library dirs="200">
-                    <file>${libs.LOG4J2-WEB.classpath}</file>
-                    <path-in-war>WEB-INF/lib</path-in-war>
-                </library>
-            </web-module-libraries>
-            <web-module-additional-libraries/>
-            <source-roots>
-                <root id="src.dir"/>
-            </source-roots>
-            <test-roots>
-                <root id="test.src.dir"/>
-            </test-roots>
-        </data>
-    </configuration>
-</project>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pom.xml	Sat May 09 14:26:31 2020 +0200
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <groupId>de.uapcore</groupId>
+    <artifactId>lightpit</artifactId>
+    <version>0.1-SNAPSHOT</version>
+    <packaging>war</packaging>
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <maven.compiler.source>11</maven.compiler.source>
+        <maven.compiler.target>11</maven.compiler.target>
+        <version.maven.compiler>3.8.1</version.maven.compiler>
+        <version.maven.war>3.2.0</version.maven.war>
+        <version.slf4j>1.7.30</version.slf4j>
+        <version.log4j>2.13.1</version.log4j>
+    </properties>
+    <dependencies>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+            <version>${version.slf4j}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.logging.log4j</groupId>
+            <artifactId>log4j-core</artifactId>
+            <version>${version.log4j}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.logging.log4j</groupId>
+            <artifactId>log4j-slf4j-impl</artifactId>
+            <version>${version.log4j}</version>
+        </dependency>
+        <dependency>
+            <groupId>javax.servlet</groupId>
+            <artifactId>jstl</artifactId>
+            <version>1.2</version>
+        </dependency>
+        <dependency>
+            <groupId>javax.servlet</groupId>
+            <artifactId>javax.servlet-api</artifactId>
+            <version>3.1.0</version>
+            <scope>provided</scope>
+        </dependency>
+    </dependencies>
+    <build>
+        <finalName>${project.artifactId}</finalName>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <version>${version.maven.compiler}</version>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-war-plugin</artifactId>
+                <version>${version.maven.war}</version>
+                <configuration>
+                    <archive>
+                        <manifest>
+                            <addClasspath>true</addClasspath>
+                            <classpathPrefix>lib/</classpathPrefix>
+                        </manifest>
+                    </archive>
+                    <webResources>
+                        <resource>
+                            <directory>${project.basedir}/src/main/resources</directory>
+                        </resource>
+                    </webResources>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>
--- a/src/conf/MANIFEST.MF	Sun Apr 08 16:51:15 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,2 +0,0 @@
-Manifest-Version: 1.0
-
--- a/src/java/de/uapcore/lightpit/AbstractLightPITServlet.java	Sun Apr 08 16:51:15 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,296 +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 java.io.IOException;
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.Optional;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServlet;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import javax.servlet.http.HttpSession;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * A special implementation of a HTTPServlet which is focused on implementing
- * the necessary functionality for {@link LightPITModule}s.
- */
-public abstract class AbstractLightPITServlet extends HttpServlet {
-    
-    private static final Logger LOG = LoggerFactory.getLogger(AbstractLightPITServlet.class);
-    
-    private static final String HTML_FULL_DISPATCHER = Functions.jspPath("html_full");
-    
-    /**
-     * 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();
-    
-    
-    @FunctionalInterface
-    private static interface HandlerMethod {
-        ResponseType apply(HttpServletRequest t, HttpServletResponse u) throws IOException, ServletException;
-    }
-    
-    /**
-     * 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<>();
-
-    /**
-     * Gives implementing modules access to the {@link ModuleManager}.
-     * @return the module manager
-     */
-    protected final ModuleManager getModuleManager() {
-        return (ModuleManager) getServletContext().getAttribute(ModuleManager.SC_ATTR_NAME);
-    }
-    
-    /**
-     * Gives implementing modules access to the {@link DatabaseFacade}.
-     * @return the database facade
-     */
-    protected final DatabaseFacade getDatabaseFacade() {
-        return (DatabaseFacade) getServletContext().getAttribute(DatabaseFacade.SC_ATTR_NAME);
-    }
-    
-    private ResponseType invokeMapping(Method method, HttpServletRequest req, HttpServletResponse resp)
-            throws IOException, ServletException {
-        try {
-            LOG.trace("invoke {}#{}", method.getDeclaringClass().getName(), method.getName());
-            return (ResponseType) method.invoke(this, req, resp);
-        } catch (ReflectiveOperationException | ClassCastException ex) {
-            LOG.error(String.format("invocation of method %s failed", method.getName()), ex);
-            resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
-            return ResponseType.NONE;
-        }
-    }
-
-    @Override
-    public void init() throws ServletException {
-        moduleInfo = Optional.ofNullable(this.getClass().getAnnotation(LightPITModule.class));
-        moduleInfoELProxy = moduleInfo.map(LightPITModule.ELProxy::convert);
-        
-        if (moduleInfo.isPresent()) {
-            scanForRequestMappings();
-        }
-        
-        LOG.trace("{} initialized", getServletName());
-    }
-
-    private void scanForRequestMappings() {
-        try {
-            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;
-                    }
-                    if (!ResponseType.class.isAssignableFrom(method.getReturnType())) {
-                        LOG.warn("{} is annotated with {} but has the wrong return type - 'ResponseType' required",
-                                method.getName(), RequestMapping.class.getSimpleName()
-                        );
-                        continue;
-                    }
-
-                    Class<?>[] params = method.getParameterTypes();
-                    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(requestPath,
-                                        (req, resp) -> invokeMapping(method, req, resp)) != null) {
-                            LOG.warn("{} {} has multiple mappings",
-                                    mapping.get().method(),
-                                    mapping.get().requestPath()
-                            );
-                        }
-
-                        LOG.debug("{} {} maps to {}::{}",
-                                mapping.get().method(),
-                                requestPath,
-                                getClass().getSimpleName(),
-                                method.getName()
-                        );
-                    } else {
-                        LOG.warn("{} is annotated with {} but has the wrong parameters - (HttpServletRequest,HttpServletResponse) required",
-                                method.getName(), RequestMapping.class.getSimpleName()
-                        );
-                    }
-                }
-            }
-        } catch (SecurityException ex) {
-            LOG.error("Scan for request mappings on declared methods failed.", ex);
-        }
-    }
-
-    @Override
-    public void destroy() {
-        mappings.clear();
-        LOG.trace("{} destroyed", getServletName());
-    }
-    
-    /**
-     * Sets the name of the dynamic fragment.
-     * 
-     * It is sufficient to specify the name without any extension. The extension
-     * is added automatically if not specified.
-     * 
-     * The fragment must be located in the dynamic fragments folder.
-     * 
-     * @param req the servlet request object
-     * @param fragmentName the name of the fragment
-     * @see Constants#DYN_FRAGMENT_PATH_PREFIX
-     */
-    public void setDynamicFragment(HttpServletRequest req, String fragmentName) {
-        req.setAttribute(Constants.REQ_ATTR_FRAGMENT, Functions.dynFragmentPath(fragmentName));
-    }
-    
-    /**
-     * Specifies the name of an additional stylesheet used by the module.
-     * 
-     * Setting an additional stylesheet is optional, but quite common for HTML
-     * output.
-     * 
-     * It is sufficient to specify the name without any extension. The extension
-     * is added automatically if not specified.
-     * 
-     * @param req the servlet request object
-     * @param stylesheet the name of the stylesheet
-     */
-    public void setStylesheet(HttpServletRequest req, String stylesheet) {
-        req.setAttribute(Constants.REQ_ATTR_STYLESHEET, Functions.enforceExt(stylesheet, ".css"));
-    }
-    
-    private void forwardToFullView(HttpServletRequest req, HttpServletResponse resp)
-            throws IOException, ServletException {
-        
-        req.setAttribute(Constants.REQ_ATTR_MENU, getModuleManager().getMainMenu(getDatabaseFacade()));
-        req.getRequestDispatcher(HTML_FULL_DISPATCHER).forward(req, resp);
-    }
-    
-    private Optional<HandlerMethod> findMapping(HttpMethod method, HttpServletRequest req) {
-        return Optional.ofNullable(mappings.get(method)).map(
-                (rm) -> rm.get(Optional.ofNullable(req.getPathInfo()).orElse("/"))
-        );
-    }
-    
-    private void forwardAsSepcified(ResponseType type, HttpServletRequest req, HttpServletResponse resp)
-            throws ServletException, IOException {
-        switch (type) {
-            case NONE: return;
-            case HTML_FULL:
-                forwardToFullView(req, resp);
-                return;
-            // TODO: implement remaining response types
-            default:
-                // this code should be unreachable
-                LOG.error("ResponseType switch is not exhaustive - this is a bug!");
-                throw new UnsupportedOperationException();
-        }
-    }
-    
-    private void doProcess(HttpMethod method, HttpServletRequest req, HttpServletResponse resp)
-            throws ServletException, IOException {
-
-        // Synchronize module information with database
-        getModuleManager().syncWithDatabase(getDatabaseFacade());
-        
-        // choose the requested language as session language (if available) or fall back to english, otherwise
-        HttpSession session = req.getSession();
-        if (session.getAttribute(Constants.SESSION_ATTR_LANGUAGE) == null) {
-            Optional<List<String>> availableLanguages = Functions.availableLanguages(getServletContext()).map(Arrays::asList);
-            Optional<Locale> reqLocale = Optional.of(req.getLocale());
-            Locale sessionLocale = reqLocale.filter((rl) -> availableLanguages.map((al) -> al.contains(rl.getLanguage())).orElse(false)).orElse(Locale.ENGLISH);
-            session.setAttribute(Constants.SESSION_ATTR_LANGUAGE, sessionLocale);
-            LOG.debug("Settng language for new session {}: {}", session.getId(), sessionLocale.getDisplayLanguage());
-        } else {
-            Locale sessionLocale = (Locale) session.getAttribute(Constants.SESSION_ATTR_LANGUAGE);
-            resp.setLocale(sessionLocale);
-            LOG.trace("Continuing session {} with language {}", session.getId(), sessionLocale);
-        }
-        
-        // set some internal request attributes
-        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));
-        
-        
-        // call the handler, if available, or send an HTTP 404 error
-        Optional<HandlerMethod> mapping = findMapping(method, req);
-        if (mapping.isPresent()) {
-            forwardAsSepcified(mapping.get().apply(req, resp), req, resp);
-        } else {
-            resp.sendError(HttpServletResponse.SC_NOT_FOUND);
-        }
-    }
-    
-    @Override
-    protected final void doGet(HttpServletRequest req, HttpServletResponse resp)
-            throws ServletException, IOException {
-        doProcess(HttpMethod.GET, req, resp);
-    }
-
-    @Override
-    protected final void doPost(HttpServletRequest req, HttpServletResponse resp)
-            throws ServletException, IOException {
-        doProcess(HttpMethod.POST, req, resp);
-    }
-}
--- a/src/java/de/uapcore/lightpit/Constants.java	Sun Apr 08 16:51:15 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,106 +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 static de.uapcore.lightpit.Functions.fqn;
-
-/**
- * Contains all non-local scope constants used by the this application.
- * 
- * Constants with (class) local scope are defined in their respective classes.
- */
-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/";
-    
-    
-    /**
-     * Name for the context parameter specifying the available languages.
-     */
-    public static final String CTX_ATTR_LANGUAGES = "available-languages";
-    
-    /**
-     * Name for the context parameter optionally specifying the JNDI context;
-     */
-    public static final String CTX_ATTR_JNDI_CONTEXT = "jndi-context";
-    
-    /**
-     * Name for the context parameter optionally specifying a database schema.
-     */
-    public static final String CTX_ATTR_DB_SCHEMA = "db-schema";
-    
-    /**
-     * Name for the context parameter optionally specifying a database dialect.
-     */
-    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");
-    
-    /**
-     * 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");
-
-    /**
-     * Key for the name of the fragment which should be rendered.
-     */    
-    public static final String REQ_ATTR_FRAGMENT = fqn(AbstractLightPITServlet.class, "fragment");
-    
-    /**
-     * Key for the name of the additional stylesheet used by a module.
-     */    
-    public static final String REQ_ATTR_STYLESHEET = fqn(AbstractLightPITServlet.class, "extraCss");
-    
-    
-    /**
-     * Key for the current language selection within the session.
-     */
-    public static final String SESSION_ATTR_LANGUAGE = fqn(AbstractLightPITServlet.class, "language");
-    
-    /**
-     * This class is not instantiatable.
-     */
-    private Constants() {}
-}
--- a/src/java/de/uapcore/lightpit/DatabaseFacade.java	Sun Apr 08 16:51:15 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,178 +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 java.sql.Connection;
-import java.sql.DatabaseMetaData;
-import java.sql.SQLException;
-import java.util.Optional;
-import javax.naming.Context;
-import javax.naming.InitialContext;
-import javax.naming.NamingException;
-import javax.servlet.ServletContext;
-import javax.servlet.ServletContextEvent;
-import javax.servlet.ServletContextListener;
-import javax.servlet.annotation.WebListener;
-import javax.sql.DataSource;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Provides access to different privilege layers within the database.
- */
-@WebListener
-public final class DatabaseFacade implements ServletContextListener {
-    
-    private static final Logger LOG = LoggerFactory.getLogger(DatabaseFacade.class);
-    
-    /**
-     * Timeout in seconds for the validation test.
-     */
-    private static final int DB_TEST_TIMEOUT = 10;
-    
-    public static enum Dialect {
-        Postgres;
-    }
-    
-    /**
-     * The database dialect to use.
-     * 
-     * May be override by context parameter.
-     * 
-     * @see Constants#CTX_ATTR_DB_DIALECT
-     */
-    private Dialect dialect = Dialect.Postgres;
-    
-    /**
-     * The default schema to test against when validating the connection.
-     * 
-     * May be overridden by context parameter.
-     * 
-     * @see Constants#CTX_ATTR_DB_SCHEMA
-     */
-    private static final String DB_DEFAULT_SCHEMA = "lightpit";
-    
-    /**
-     * The attribute name in the Servlet context under which an instance of this class can be found.
-     */
-    public static final String SC_ATTR_NAME = DatabaseFacade.class.getName();
-    private ServletContext sc;
-    
-    private static final String DS_JNDI_NAME = "jdbc/lightpit/app";
-    private Optional<DataSource> dataSource;
-    
-    /**
-     * Returns the data source.
-     * 
-     * The Optional returned should never be empty. However, if something goes
-     * wrong during initialization, the data source might be absent.
-     * Hence, users of this data source are forced to check the existence.
-     * 
-     * @return a data source
-     */
-    public Optional<DataSource> getDataSource() {
-        return dataSource;
-    }
-    
-    public Dialect getSQLDialect() {
-        return dialect;
-    }
-    
-    private static void checkConnection(DataSource ds, String testSchema, String errMsg) {
-        try (Connection conn = ds.getConnection()) {
-            if (!conn.isValid(DB_TEST_TIMEOUT)) {
-                throw new SQLException("Validation check failed.");
-            }
-            if (conn.isReadOnly()) {
-                throw new SQLException("Connection is read-only and thus unusable.");
-            }
-            if (!conn.getSchema().equals(testSchema)) {
-                throw new SQLException(String.format("Connection is not configured to use the schema %s.", testSchema));
-            }
-            DatabaseMetaData metaData = conn.getMetaData();
-            LOG.info("Connections as {} to {}/{} ready to go.", metaData.getUserName(), metaData.getURL(), conn.getSchema());
-        } catch (SQLException ex) {
-            LOG.error(errMsg, ex);
-        }
-    }
-    
-    private static Optional<DataSource> retrieveDataSource(Context ctx) {
-        DataSource ret = null;
-        try {
-            ret = (DataSource)ctx.lookup(DS_JNDI_NAME);
-            LOG.info("Data source retrieved.");
-        } catch (NamingException ex) {
-            LOG.error("Data source {} not available.", DS_JNDI_NAME);
-            LOG.error("Reason for the missing data source: ", ex);
-        }
-        return Optional.ofNullable(ret);
-    }
-
-    @Override
-    public void contextInitialized(ServletContextEvent sce) {
-        sc = sce.getServletContext();
-        
-        dataSource = null;
-        
-        final String contextName = Optional
-                .ofNullable(sc.getInitParameter(Constants.CTX_ATTR_JNDI_CONTEXT))
-                .orElse("java:comp/env");
-        final String dbSchema = Optional
-                .ofNullable(sc.getInitParameter(Constants.CTX_ATTR_DB_SCHEMA))
-                .orElse(DB_DEFAULT_SCHEMA);
-        final String dbDialect = sc.getInitParameter(Constants.CTX_ATTR_DB_DIALECT);
-        if (dbDialect != null) {
-            try {
-                dialect = Dialect.valueOf(dbDialect);
-            } catch (IllegalArgumentException ex) {
-                LOG.error("Unknown or unsupported database dialect {}. Defaulting to {}.", dbDialect, dialect);
-            }
-        }
-
-        try {
-            LOG.debug("Trying to access JNDI context {}...", contextName);
-            Context initialCtx = new InitialContext();
-            Context ctx = (Context) initialCtx.lookup(contextName);
-            
-            dataSource = retrieveDataSource(ctx);
-            
-            dataSource.ifPresent((ds) -> checkConnection(ds, dbSchema, "Checking database connection failed"));
-        } catch (NamingException | ClassCastException ex) {
-            LOG.error("Cannot access JNDI resources.", ex);
-        }
-        
-        sc.setAttribute(SC_ATTR_NAME, this);
-        LOG.info("Database facade injected into ServletContext.");
-    }
-
-    @Override
-    public void contextDestroyed(ServletContextEvent sce) {
-        dataSource = null;
-    }    
-}
--- a/src/java/de/uapcore/lightpit/Functions.java	Sun Apr 08 16:51:15 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,113 +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 java.util.Optional;
-import javax.servlet.ServletContext;
-import javax.servlet.http.HttpServletRequest;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Contains common static functions.
- */
-public final class Functions {
-    
-    private static final Logger LOG = LoggerFactory.getLogger(Functions.class);
-
-    public static Optional<String[]> availableLanguages(ServletContext ctx) {
-        return Optional.ofNullable(ctx.getInitParameter(Constants.CTX_ATTR_LANGUAGES)).map((x) -> x.split("\\s*,\\s*"));
-    }
-    
-    public static String enforceExt(String filename, String ext) {
-        return filename.endsWith(ext) ? filename : filename + ext;
-    }
-
-    public static String jspPath(String filename) {
-        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");
-    }
-    
-    public static String fqn(String base, String name) {
-        return base+"."+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("");
-    }
-    
-    /**
-     * Returns the module path of the given LightPIT Servlet module.
-     * 
-     * If you specify a malformed LightPIT servlet, which does not have a module
-     * annotation, the path to the <code>/error/404.html</code> page is returned.
-     * 
-     * @param clazz the servlet class
-     * @return the module path
-     */
-    public static String modulePathOf(Class<? extends AbstractLightPITServlet> clazz) {
-        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";
-        }
-    }
-    
-    /**
-     * This class is not instantiatable.
-     */
-    private Functions() {}
-}
--- a/src/java/de/uapcore/lightpit/HttpMethod.java	Sun Apr 08 16:51:15 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,34 +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;
-
-
-public enum HttpMethod {
-    GET, POST, PUT, DELETE, TRACE, HEAD, OPTIONS
-}
--- a/src/java/de/uapcore/lightpit/LightPITModule.java	Sun Apr 08 16:51:15 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,170 +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 java.lang.annotation.Documented;
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-import javax.servlet.annotation.WebServlet;
-
-
-/**
- * Contains information about a LightPIT module.
- * 
- * 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();
-    
-    /**
-     * An array of required modules, identified by the string representation of
-     * their class names.
-     * @return an array of class names of required modules
-     */
-    String[] requires() default {};
-    
-    /**
-     * The path for this module, which will also be used for the menu entry.
-     * 
-     * 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();
-    
-    /**
-     * Returns the properties key for the module name.
-     * 
-     * @return the properties key
-     */
-    String nameKey() default "name";
-    
-    /**
-     * Returns the properties key for the module description.
-     * 
-     * @return the properties key
-     */
-    String descKey() default "description";
-    
-    
-    /**
-     * 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";
-    
-    /**
-     * 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";
-    
-    /**
-     * 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;
-    
-    /**
-     * 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, nameKey, descKey;
-        
-        public static ELProxy convert(LightPITModule annotation) {
-            return new ELProxy(
-                    annotation.bundleBaseName(),
-                    annotation.modulePath(),
-                    annotation.menuKey(),
-                    annotation.titleKey(),
-                    annotation.nameKey(),
-                    annotation.descKey()
-            );
-        }
-
-        private ELProxy(String bundleBaseName, String modulePath, String menuKey, String titleKey, String nameKey, String descKey) {
-            this.bundleBaseName = bundleBaseName;
-            this.modulePath = modulePath;
-            this.menuKey = menuKey;
-            this.titleKey = titleKey;
-            this.nameKey = nameKey;
-            this.descKey = descKey;
-        }
-
-        public String getBundleBaseName() {
-            return bundleBaseName;
-        }
-
-        public String getMenuKey() {
-            return menuKey;
-        }
-
-        public String getModulePath() {
-            return modulePath;
-        }
-
-        public String getTitleKey() {
-            return titleKey;
-        }
-
-        public String getNameKey() {
-            return nameKey;
-        }
-
-        public String getDescKey() {
-            return descKey;
-        }
-        
-    }
-}
--- a/src/java/de/uapcore/lightpit/Menu.java	Sun Apr 08 16:51:15 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,97 +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 java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-/**
- * Maps a resource key for the menu label to the path name for the underlying
- * site.
- * 
- * Objects of this class are internally instantiated by the
- * {@link ModuleManager}.
- */
-public class Menu extends MenuEntry {
-    
-    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(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;
-    }
-
-    /**
-     * Sets a new list of menu entries for this menu.
-     * 
-     * @param entries the list of new menu entries
-     */
-    public void setEntries(List<MenuEntry> entries) {
-        // in case the given list is immutable, we copy the contents
-        this.entries.clear();
-        this.entries.addAll(entries);
-    }
-
-    /**
-     * Retrieves an immutable list of menu entries for this menu.
-     * 
-     * @return the list of menu entries
-     */
-    public List<MenuEntry> getEntries() {
-        return immutableEntries;
-    }
-    
-    /**
-     * Adds a new menu entry to this menu.
-     * @param entry the menu entry to add
-     */
-    public void addMenuEntry(MenuEntry entry) {
-        entries.add(entry);
-    }
-}
--- a/src/java/de/uapcore/lightpit/MenuEntry.java	Sun Apr 08 16:51:15 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,74 +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;
-
-/**
- * Maps a resource key for the menu label to the path name for the underlying
- * site.
- * 
- * Objects of this class are internally instantiated by the
- * {@link ModuleManager}.
- */
-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() {
-    }
-
-    public MenuEntry(ResourceKey resourceKey, String pathName) {
-        this.resourceKey = resourceKey;
-        this.pathName = pathName;
-    }
-
-    public void setResourceKey(ResourceKey resourceKey) {
-        this.resourceKey = resourceKey;
-    }
-
-    public ResourceKey getResourceKey() {
-        return resourceKey;
-    }
-
-    public void setPathName(String pathName) {
-        this.pathName = pathName;
-    }
-
-    public String getPathName() {
-        return pathName;
-    }
-    
-}
--- a/src/java/de/uapcore/lightpit/ModuleManager.java	Sun Apr 08 16:51:15 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,231 +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 de.uapcore.lightpit.entities.CoreDAOFactory;
-import de.uapcore.lightpit.entities.Module;
-import de.uapcore.lightpit.entities.ModuleDao;
-import java.sql.Connection;
-import java.sql.SQLException;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.stream.Collectors;
-import javax.servlet.Registration;
-import javax.servlet.ServletContext;
-import javax.servlet.ServletContextEvent;
-import javax.servlet.ServletContextListener;
-import javax.servlet.annotation.WebListener;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * 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 Map<String, LightPITModule> registeredModules = new HashMap<>();
-    
-    /**
-     * This flag is true, when synchronization is needed.
-     */
-    private final AtomicBoolean dirty = new AtomicBoolean(true);
-    
-    @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 Class<? extends AbstractLightPITServlet> clazz = scclass;
-                final LightPITModule moduleInfo = clazz.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.put(reg.getClassName(), 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);
-        
-        // TODO: implement dependency resolver
-        
-        dirty.set(true);
-        LOG.info("Modules loaded.");
-    }
-    
-    /**
-     * Synchronizes module information with the database.
-     * 
-     * This must be called from the {@link AbstractLightPITServlet}.
-     * Admittedly the call will perform the synchronization once after reload
-     * and be a no-op, afterwards.
-     * However, we since the DatabaseFacade might be loaded after the module
-     * manager, we must defer the synchronization to the first request
-     * handled by the Servlet.
-     * 
-     * @param db interface to the database
-     */
-    public void syncWithDatabase(DatabaseFacade db) {
-        if (dirty.compareAndSet(true, false)) {
-            if (db.getDataSource().isPresent()) {
-                try (Connection conn = db.getDataSource().get().getConnection()) {
-                    final ModuleDao moduleDao = CoreDAOFactory.getModuleDao(db.getSQLDialect());
-                    moduleDao.syncRegisteredModuleClasses(conn, registeredModules.entrySet());
-                } catch (SQLException ex) {
-                    LOG.error("Unexpected SQL Exception", ex);
-                }
-            } else {
-                LOG.error("No datasource present. Cannot sync module information with database.");
-            }
-        } else {
-            LOG.trace("Module information clean - no synchronization required.");
-        }
-    }
-    
-    /**
-     * Unloads all found modules.
-     */
-    public void unloadAll() {
-        registeredModules.clear();
-        LOG.info("All modules unloaded.");
-    }
-
-    /**
-     * Returns the main menu.
-     * 
-     * @param db the interface to the database
-     * @return a list of menus belonging to the main menu
-     */
-    public List<Menu> getMainMenu(DatabaseFacade db) {
-        // TODO: user specific menu
-        
-        if (db.getDataSource().isPresent()) {
-            try (Connection conn = db.getDataSource().get().getConnection()) {
-                final ModuleDao dao = CoreDAOFactory.getModuleDao(db.getSQLDialect());
-                final List<Module> modules = dao.listAll(conn);
-                
-                final List<Menu> menu = modules
-                    .stream()
-                    .filter((mod) -> mod.isVisible())
-                    .collect(Collectors.mapping(
-                            (mod) -> new Menu(
-                                    mod.getClassname(),
-                                    new ResourceKey(
-                                            registeredModules.get(mod.getClassname()).bundleBaseName(),
-                                            registeredModules.get(mod.getClassname()).menuKey()),
-                                    registeredModules.get(mod.getClassname()).modulePath()),
-                            Collectors.toList())
-                    );
-                return menu;
-            } catch (SQLException ex) {
-                LOG.error("Unexpected SQLException when loading the main menu", ex);
-                return Collections.emptyList();
-            }
-        } else {
-            return Collections.emptyList();
-        }
-    }
-    
-    /**
-     * Returns an unmodifiable map of all registered modules.
-     * 
-     * The key is the classname of the module.
-     * 
-     * @return the map of registered modules
-     */
-    public Map<String, LightPITModule> getRegisteredModules() {
-        return Collections.unmodifiableMap(registeredModules);
-    }
-}
--- a/src/java/de/uapcore/lightpit/RequestMapping.java	Sun Apr 08 16:51:15 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,76 +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 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> leading and 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 "";
-}
--- a/src/java/de/uapcore/lightpit/ResourceKey.java	Sun Apr 08 16:51:15 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,62 +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;
-
-/**
- * Fully specifies a resource key by the bundle and the key name.
- */
-public final class ResourceKey {
-    private String bundle;
-    private String key;
-    
-    public ResourceKey() {
-        
-    }
-
-    public ResourceKey(String bundle, String key) {
-        this.bundle = bundle;
-        this.key = key;
-    }
-
-    public void setBundle(String bundle) {
-        this.bundle = bundle;
-    }
-
-    public String getBundle() {
-        return bundle;
-    }
-
-    public void setKey(String key) {
-        this.key = key;
-    }
-    
-    public String getKey() {
-        return key;
-    }
-}
--- a/src/java/de/uapcore/lightpit/ResponseType.java	Sun Apr 08 16:51:15 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,56 +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;
-
-
-public enum ResponseType {
-    /**
-     * Renders a full HTML view including the header.
-     */
-    HTML_FULL,
-    /**
-     * Renders a HTML fragment only.
-     * May be used for AJAX responses.
-     */
-    HTML_FRAGMENT,
-    /**
-     * Returns a fragment with content type 'text/plain'.
-     */
-    PLAIN,
-    /**
-     * Returns an object in JSON format and with content type
-     * 'application/json'.
-     */
-    JSON,
-    /**
-     * The handler already sent the output, nothing should be done
-     * additionally by the Servlet.
-     */
-    NONE
-}
--- a/src/java/de/uapcore/lightpit/entities/CoreDAOFactory.java	Sun Apr 08 16:51:15 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,47 +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.entities;
-
-import de.uapcore.lightpit.DatabaseFacade;
-
-public final class CoreDAOFactory {
-    
-    private CoreDAOFactory() {}
-    
-    private static class PostgresDaos {
-        static final ModuleDao MODULE_DAO = new PostgresModuleDao();
-    }
-    
-    public static ModuleDao getModuleDao(DatabaseFacade.Dialect dialect) {
-        switch (dialect) {
-            case Postgres: return PostgresDaos.MODULE_DAO;
-            default: assert(false); return null;
-        }
-    }
-}
--- a/src/java/de/uapcore/lightpit/entities/Module.java	Sun Apr 08 16:51:15 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,90 +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.entities;
-
-import de.uapcore.lightpit.LightPITModule;
-
-public final class Module {
-    private int modID;
-    private String classname;
-    private boolean visible;
-    
-    private LightPITModule.ELProxy annotatedInfos;
-
-    public int getModID() {
-        return modID;
-    }
-
-    public void setModID(int modID) {
-        this.modID = modID;
-    }
-
-    public String getClassname() {
-        return classname;
-    }
-
-    public void setClassname(String classname) {
-        this.classname = classname;
-    }
-
-    public boolean isVisible() {
-        return visible;
-    }
-
-    public void setVisible(boolean visible) {
-        this.visible = visible;
-    }
-
-    public LightPITModule.ELProxy getAnnotatedInfos() {
-        return annotatedInfos;
-    }
-
-    public void setAnnotatedInfos(LightPITModule.ELProxy annotatedInfos) {
-        this.annotatedInfos = annotatedInfos;
-    }
-
-    @Override
-    public int hashCode() {
-        int hash = 3;
-        hash = 41 * hash + this.modID;
-        return hash;
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj) {
-            return true;
-        }
-        if (obj == null || getClass() != obj.getClass()) {
-            return false;
-        } else {
-            return this.modID == ((Module) obj).modID;
-        }
-    }    
-}
--- a/src/java/de/uapcore/lightpit/entities/ModuleDao.java	Sun Apr 08 16:51:15 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,141 +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.entities;
-
-import de.uapcore.lightpit.LightPITModule;
-import java.sql.Connection;
-import java.sql.PreparedStatement;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.sql.Statement;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-public abstract class ModuleDao {
-    
-    /**
-     * Maps database columns to POJO fields.
-     * @param result the database result set
-     * @param mod the POJO
-     * @throws SQLException 
-     */
-    protected void mapColumns(ResultSet result, Module mod) throws SQLException {
-        mod.setModID(result.getInt("modid"));
-        mod.setClassname(result.getString("classname"));
-        mod.setVisible(result.getBoolean("visible"));
-    }
-            
-    
-    /**
-     * Must return a prepared statement for a single object query with the specified properties.
-     * 
-     * <ul>
-     * <li>Parameter 1: classname</li>
-     * <li>Result field 1: visible</li>
-     * </ul>
-     * 
-     * @param conn the connection to use
-     * @return the prepared statement
-     * @throws SQLException 
-     */
-    protected PreparedStatement moduleCheckStatement(Connection conn) throws SQLException {
-        return conn.prepareStatement("SELECT visible FROM lpitcore_module WHERE classname = ?");
-    }
-    
-    /**
-     * Must return a prepared statement for insertion with the specified properties.
-     * 
-     * <ul>
-     * <li>Parameter 1: classname</li>
-     * <li>Parameter 2: visible</li>
-     * </ul>
-     * 
-     * @param conn the connection to use
-     * @return the prepared statement
-     * @throws SQLException 
-     */
-    protected PreparedStatement moduleInsertStatement(Connection conn) throws SQLException {
-        return conn.prepareStatement("INSERT INTO lpitcore_module (classname, visible) VALUES (?, ?)");
-    }
-    
-    /**
-     * Synchronizes a set of registered module classes with the database.
-     * 
-     * Inserts module classes which are not known to the database and sets them to be visible by default.
-     * Module classes known to the database, which are not in the given set, are ignored.
-     * 
-     * @param conn the connection to use
-     * @param moduleSet the module set to synchronize
-     * @throws SQLException
-     */
-    public final void syncRegisteredModuleClasses(Connection conn, Set<Map.Entry<String, LightPITModule>> moduleSet) throws SQLException {
-                
-        PreparedStatement
-                check = moduleCheckStatement(conn),
-                insert = moduleInsertStatement(conn);
-        insert.setBoolean(2, true);
-        // update/delete not required, we do this in the module management UI
-
-        for (Map.Entry<String, LightPITModule> modEntry : moduleSet) {
-            if (modEntry.getValue().systemModule()) continue;
-
-            check.setString(1, modEntry.getKey());
-            try (ResultSet r = check.executeQuery()) {
-                if (!r.next()) {
-                    insert.setString(1, modEntry.getKey());
-                    insert.executeUpdate();
-                }
-            }
-        }
-    }
-
-    /**
-     * Returns a list of all modules known by the database.
-     * 
-     * Keep in mind, that system modules are never known to the database.
-     * 
-     * @param conn the connection to use
-     * @return a list of all modules known by the database
-     * @throws SQLException 
-     */
-    public List<Module> listAll(Connection conn) throws SQLException {
-        List<Module> list = new ArrayList<>();
-        try (Statement stmt = conn.createStatement();
-                ResultSet result = stmt.executeQuery("SELECT * FROM lpitcore_module")) {
-            while (result.next()) {
-                final Module mod = new Module();
-                mapColumns(result, mod);
-                list.add(mod);
-            }
-        }
-        return list;
-    }
-}
--- a/src/java/de/uapcore/lightpit/entities/PostgresModuleDao.java	Sun Apr 08 16:51:15 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,33 +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.entities;
-
-public class PostgresModuleDao extends ModuleDao {
-    // No overrides needed.
-}
--- a/src/java/de/uapcore/lightpit/entities/User.java	Sun Apr 08 16:51:15 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,92 +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.entities;
-
-import java.util.Optional;
-
-public final class User {
-    
-    public static final int ANONYMOUS_USERID = -1;
-    
-    private int userID;
-    private String username;
-    private Optional<String> givenname;
-    private Optional<String> lastname;
-
-    public int getUserID() {
-        return userID;
-    }
-
-    public void setUserID(int userID) {
-        this.userID = userID;
-    }
-
-    public String getUsername() {
-        return username;
-    }
-
-    public void setUsername(String username) {
-        this.username = username;
-    }
-
-    public Optional<String> getGivenname() {
-        return givenname;
-    }
-
-    public void setGivenname(Optional<String> givenname) {
-        this.givenname = givenname;
-    }
-
-    public Optional<String> getLastname() {
-        return lastname;
-    }
-
-    public void setLastname(Optional<String> lastname) {
-        this.lastname = lastname;
-    }
-
-    @Override
-    public int hashCode() {
-        int hash = 3;
-        hash = 41 * hash + this.userID;
-        return hash;
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj) {
-            return true;
-        }
-        if (obj == null || getClass() != obj.getClass()) {
-            return false;
-        } else {
-            return this.userID == ((User) obj).userID;
-        }
-    }    
-}
--- a/src/java/de/uapcore/lightpit/entities/UserDao.java	Sun Apr 08 16:51:15 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,77 +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.entities;
-
-import java.sql.Connection;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.sql.Statement;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Optional;
-
-public abstract class UserDao {
-    
-    /**
-     * Maps SQL columns to POJO fields.
-     * @param result the database result set
-     * @param user the POJO
-     * @throws SQLException 
-     */
-    protected void mapColumns(ResultSet result, User user) throws SQLException {
-        user.setUserID(result.getInt("userid"));
-        user.setUsername(result.getString("username"));
-        user.setGivenname(Optional.ofNullable(result.getString("givenname")));
-        user.setLastname(Optional.ofNullable(result.getString("lastname"))); 
-    }
-
-    /**
-     * Returns a list of all users ordered by their username.
-     * 
-     * Does not return reserved system users with negative user IDs.
-     * 
-     * @param conn the connection to use
-     * @return a list of all users
-     * @throws SQLException 
-     */
-    public List<User> listAll(Connection conn) throws SQLException {
-        List<User> list = new ArrayList<>();
-        try (
-                Statement stmt = conn.createStatement();
-                ResultSet result = stmt.executeQuery(
-                        "SELECT * FROM lpitcore_user WHERE userid >= 0 ORDER BY username")) {
-            while (result.next()) {
-                final User user = new User();
-                mapColumns(result, user);
-                list.add(user);
-            }
-        }
-        return list;
-    }
-}
--- a/src/java/de/uapcore/lightpit/modules/ErrorModule.java	Sun Apr 08 16:51:15 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,80 +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.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",
-        titleKey = "title",
-        systemModule = true
-)
-@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);
-    }
-}
--- a/src/java/de/uapcore/lightpit/modules/HomeModule.java	Sun Apr 08 16:51:15 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,58 +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.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.home",
-        modulePath = "home"
-)
-@WebServlet(
-        name = "HomeModule",
-        urlPatterns = "/home/*"
-)
-public final class HomeModule extends AbstractLightPITServlet {
-    
-    @RequestMapping(method = HttpMethod.GET)
-    public ResponseType handle(HttpServletRequest req, HttpServletResponse resp) {
-        
-        return ResponseType.HTML_FULL;
-    }
-}
--- a/src/java/de/uapcore/lightpit/modules/LanguageModule.java	Sun Apr 08 16:51:15 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,118 +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.LightPITModule;
-import de.uapcore.lightpit.AbstractLightPITServlet;
-import de.uapcore.lightpit.Constants;
-import de.uapcore.lightpit.Functions;
-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;
-import de.uapcore.lightpit.ResponseType;
-import java.util.ArrayList;
-import java.util.IllformedLocaleException;
-import java.util.List;
-import java.util.Locale;
-import java.util.Optional;
-import javax.servlet.ServletException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-
-@LightPITModule(
-        bundleBaseName = "de.uapcore.lightpit.resources.localization.language",
-        modulePath = "language"
-)
-@WebServlet(
-        name = "LanguageModule",
-        urlPatterns = "/language/*"
-)
-public final class LanguageModule extends AbstractLightPITServlet {
-    
-    private static final Logger LOG = LoggerFactory.getLogger(LanguageModule.class);
-    
-    private final List<Locale> languages = new ArrayList<>();
-
-    @Override
-    public void init() throws ServletException {
-        super.init();
-        
-        Optional<String[]> langs = Functions.availableLanguages(getServletContext());
-        if (langs.isPresent()) {
-            for (String lang : langs.get()) {
-                try {
-                    Locale locale = Locale.forLanguageTag(lang);
-                    if (locale.getLanguage().isEmpty()) {
-                        throw new IllformedLocaleException();
-                    }
-                    languages.add(locale);
-                } catch (IllformedLocaleException ex) {
-                    LOG.warn("Specified lanaguge {} in context parameter cannot be mapped to an existing locale - skipping.", lang);
-                }
-            }
-            
-        } else {
-            languages.add(Locale.ENGLISH);
-            LOG.warn("Context parameter 'available-languges' not found. Only english will be available.");
-        }
-    }
-
-    @Override
-    public void destroy() {
-        super.destroy();
-        languages.clear();
-    }
-    
-    @RequestMapping(method = HttpMethod.GET)
-    public ResponseType handle(HttpServletRequest req, HttpServletResponse resp) {
-
-        req.setAttribute("languages", languages);
-        req.setAttribute("browserLanguage", req.getLocale());
-        
-        setStylesheet(req, "language");
-        setDynamicFragment(req, "language");
-        return ResponseType.HTML_FULL;
-    }
-    
-    @RequestMapping(method = HttpMethod.POST)
-    public ResponseType switchLanguage(HttpServletRequest req, HttpServletResponse resp) {
-        
-        Optional<Locale> chosenLanguage = Optional.ofNullable(req.getParameter("language"))
-                .map(Locale::forLanguageTag)
-                .filter((l) -> !l.getLanguage().isEmpty());
-        
-        chosenLanguage.ifPresent((l) -> req.getSession().setAttribute(Constants.SESSION_ATTR_LANGUAGE, l));
-        chosenLanguage.ifPresent(resp::setLocale);
-        
-        return handle(req, resp);
-    }
-}
--- a/src/java/de/uapcore/lightpit/modules/ModuleManagerModule.java	Sun Apr 08 16:51:15 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,94 +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.LightPITModule;
-import de.uapcore.lightpit.AbstractLightPITServlet;
-import de.uapcore.lightpit.HttpMethod;
-import de.uapcore.lightpit.LightPITModule.ELProxy;
-import de.uapcore.lightpit.RequestMapping;
-import de.uapcore.lightpit.ResponseType;
-import de.uapcore.lightpit.entities.CoreDAOFactory;
-import de.uapcore.lightpit.entities.Module;
-import java.io.IOException;
-import java.sql.Connection;
-import java.sql.SQLException;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-import javax.servlet.annotation.WebServlet;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import javax.sql.DataSource;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Entry point for the application.
- */
-@LightPITModule(
-        bundleBaseName = "de.uapcore.lightpit.resources.localization.modmgmt",
-        modulePath = "modmgmt"
-)
-@WebServlet(
-        name = "ModuleManagerModule",
-        urlPatterns = "/modmgmt/*"
-)
-public final class ModuleManagerModule extends AbstractLightPITServlet {
-    
-    private static final Logger LOG = LoggerFactory.getLogger(ModuleManagerModule.class);
-    
-    private static final String REQ_ATTR_MODULES = "modules";
-    
-    
-    @RequestMapping(method = HttpMethod.GET)
-    public ResponseType handle(HttpServletRequest req, HttpServletResponse resp) throws IOException {
-        
-        Optional<DataSource> ds = getDatabaseFacade().getDataSource();
-        if (ds.isPresent()) {
-            try (Connection conn = ds.get().getConnection()) {
-                final List<Module> modules = CoreDAOFactory.getModuleDao(getDatabaseFacade().getSQLDialect()).listAll(conn);
-                
-                final Map<String, LightPITModule> registeredModules = getModuleManager().getRegisteredModules();
-                modules.forEach((mod) -> mod.setAnnotatedInfos(ELProxy.convert(registeredModules.get(mod.getClassname()))));
-                
-                req.setAttribute(REQ_ATTR_MODULES, modules);
-                setDynamicFragment(req, "modules");                
-                return ResponseType.HTML_FULL;
-            } catch (SQLException ex) {
-                LOG.error("Unexpected SQL Exception", ex);
-                resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
-                return ResponseType.NONE;
-            }
-        } else {
-            resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
-            return ResponseType.NONE;
-        }
-    }
-}
--- a/src/java/de/uapcore/lightpit/modules/VersionsModule.java	Sun Apr 08 16:51:15 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,55 +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.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;
-
-
-@LightPITModule(
-        bundleBaseName = "de.uapcore.lightpit.resources.localization.versions",
-        modulePath = "versions"
-)
-@WebServlet(
-        name = "VersionsModule",
-        urlPatterns = "/versions/*"
-)
-public final class VersionsModule extends AbstractLightPITServlet {
-    @RequestMapping(method = HttpMethod.GET)
-    public ResponseType handle(HttpServletRequest req, HttpServletResponse resp) {
-        
-        return ResponseType.HTML_FULL;
-    }
-}
--- a/src/java/de/uapcore/lightpit/resources/localization/error.properties	Sun Apr 08 16:51:15 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,35 +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. 
-
-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
--- a/src/java/de/uapcore/lightpit/resources/localization/error_de.properties	Sun Apr 08 16:51:15 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,35 +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. 
-
-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
--- a/src/java/de/uapcore/lightpit/resources/localization/home.properties	Sun Apr 08 16:51:15 2018 +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 = Home Page
-description = The default page that is displayed when visiting the site.
-menuLabel = Home
--- a/src/java/de/uapcore/lightpit/resources/localization/home_de.properties	Sun Apr 08 16:51:15 2018 +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 = Startseite
-description = Die Seite, die dem Benutzer standardm\u00e4\u00dfig beim Besuch angezeigt wird.
-menuLabel = Startseite
--- a/src/java/de/uapcore/lightpit/resources/localization/language.properties	Sun Apr 08 16:51:15 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,30 +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 = Language Selector
-description = Where the user can choose his / her language setting.
-menuLabel = Languages
-
-submit = Switch language
-browserLanguage = Browser language
-browserLanguageNotAvailable = Browser language not available.
--- a/src/java/de/uapcore/lightpit/resources/localization/language_de.properties	Sun Apr 08 16:51:15 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,31 +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 = Sprachauswahl
-description = Hier kann der Benutzer die Sprache f\u00fcr die Website ausw\u00e4hlen.
-
-menuLabel = Sprache
-
-submit = Sprache ausw\u00e4hlen
-browserLanguage = Browsersprache
-browserLanguageNotAvailable = Browsersprache nicht verf\u00fcgbar.
--- a/src/java/de/uapcore/lightpit/resources/localization/modmgmt.properties	Sun Apr 08 16:51:15 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,36 +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 = Module Management
-description = Configure the visible LightPIT modules and the required access powers.
-menuLabel = Modules
-
-section.modlist.title = List of Modules
-
-caption.module = Module
-caption.path = Path
-caption.desc = Description
-caption.active = Active
-caption.class = Class
-caption.bundle = Resource Bundle
-
--- a/src/java/de/uapcore/lightpit/resources/localization/modmgmt_de.properties	Sun Apr 08 16:51:15 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,35 +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 = Modulverwaltung
-description = Konfiguration der sichtbaren LightPIT Module und deren Zugriffsrechte.
-menuLabel = Module
-
-section.modlist.title = Liste der Module
-
-caption.module = Modul
-caption.path = Pfad
-caption.desc = Beschreibung
-caption.active = Aktiv
-caption.class = Klasse
-caption.bundle = Ressourcen-Datei
--- a/src/java/de/uapcore/lightpit/resources/localization/versions.properties	Sun Apr 08 16:51:15 2018 +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
--- a/src/java/de/uapcore/lightpit/resources/localization/versions_de.properties	Sun Apr 08 16:51:15 2018 +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
--- a/src/java/log4j2.properties	Sun Apr 08 16:51:15 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,36 +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. 
-
-
-status = warn
-dest = err
-name = PropertiesConfig
- 
-appender.console.type = Console
-appender.console.name = STDOUT
-appender.console.layout.type = PatternLayout
-appender.console.layout.pattern = %d{ISO8601} [%highlight{%p}] %c{1}: %m %n
- 
-rootLogger.appenderRef.stdout.ref = STDOUT
-
-rootLogger.level = debug
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/de/uapcore/lightpit/AbstractLightPITServlet.java	Sat May 09 14:26:31 2020 +0200
@@ -0,0 +1,296 @@
+/*
+ * 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 java.io.IOException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Optional;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A special implementation of a HTTPServlet which is focused on implementing
+ * the necessary functionality for {@link LightPITModule}s.
+ */
+public abstract class AbstractLightPITServlet extends HttpServlet {
+    
+    private static final Logger LOG = LoggerFactory.getLogger(AbstractLightPITServlet.class);
+    
+    private static final String HTML_FULL_DISPATCHER = Functions.jspPath("html_full");
+    
+    /**
+     * 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();
+    
+    
+    @FunctionalInterface
+    private static interface HandlerMethod {
+        ResponseType apply(HttpServletRequest t, HttpServletResponse u) throws IOException, ServletException;
+    }
+    
+    /**
+     * 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<>();
+
+    /**
+     * Gives implementing modules access to the {@link ModuleManager}.
+     * @return the module manager
+     */
+    protected final ModuleManager getModuleManager() {
+        return (ModuleManager) getServletContext().getAttribute(ModuleManager.SC_ATTR_NAME);
+    }
+    
+    /**
+     * Gives implementing modules access to the {@link DatabaseFacade}.
+     * @return the database facade
+     */
+    protected final DatabaseFacade getDatabaseFacade() {
+        return (DatabaseFacade) getServletContext().getAttribute(DatabaseFacade.SC_ATTR_NAME);
+    }
+    
+    private ResponseType invokeMapping(Method method, HttpServletRequest req, HttpServletResponse resp)
+            throws IOException, ServletException {
+        try {
+            LOG.trace("invoke {}#{}", method.getDeclaringClass().getName(), method.getName());
+            return (ResponseType) method.invoke(this, req, resp);
+        } catch (ReflectiveOperationException | ClassCastException ex) {
+            LOG.error(String.format("invocation of method %s failed", method.getName()), ex);
+            resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
+            return ResponseType.NONE;
+        }
+    }
+
+    @Override
+    public void init() throws ServletException {
+        moduleInfo = Optional.ofNullable(this.getClass().getAnnotation(LightPITModule.class));
+        moduleInfoELProxy = moduleInfo.map(LightPITModule.ELProxy::convert);
+        
+        if (moduleInfo.isPresent()) {
+            scanForRequestMappings();
+        }
+        
+        LOG.trace("{} initialized", getServletName());
+    }
+
+    private void scanForRequestMappings() {
+        try {
+            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;
+                    }
+                    if (!ResponseType.class.isAssignableFrom(method.getReturnType())) {
+                        LOG.warn("{} is annotated with {} but has the wrong return type - 'ResponseType' required",
+                                method.getName(), RequestMapping.class.getSimpleName()
+                        );
+                        continue;
+                    }
+
+                    Class<?>[] params = method.getParameterTypes();
+                    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(requestPath,
+                                        (req, resp) -> invokeMapping(method, req, resp)) != null) {
+                            LOG.warn("{} {} has multiple mappings",
+                                    mapping.get().method(),
+                                    mapping.get().requestPath()
+                            );
+                        }
+
+                        LOG.debug("{} {} maps to {}::{}",
+                                mapping.get().method(),
+                                requestPath,
+                                getClass().getSimpleName(),
+                                method.getName()
+                        );
+                    } else {
+                        LOG.warn("{} is annotated with {} but has the wrong parameters - (HttpServletRequest,HttpServletResponse) required",
+                                method.getName(), RequestMapping.class.getSimpleName()
+                        );
+                    }
+                }
+            }
+        } catch (SecurityException ex) {
+            LOG.error("Scan for request mappings on declared methods failed.", ex);
+        }
+    }
+
+    @Override
+    public void destroy() {
+        mappings.clear();
+        LOG.trace("{} destroyed", getServletName());
+    }
+    
+    /**
+     * Sets the name of the dynamic fragment.
+     * 
+     * It is sufficient to specify the name without any extension. The extension
+     * is added automatically if not specified.
+     * 
+     * The fragment must be located in the dynamic fragments folder.
+     * 
+     * @param req the servlet request object
+     * @param fragmentName the name of the fragment
+     * @see Constants#DYN_FRAGMENT_PATH_PREFIX
+     */
+    public void setDynamicFragment(HttpServletRequest req, String fragmentName) {
+        req.setAttribute(Constants.REQ_ATTR_FRAGMENT, Functions.dynFragmentPath(fragmentName));
+    }
+    
+    /**
+     * Specifies the name of an additional stylesheet used by the module.
+     * 
+     * Setting an additional stylesheet is optional, but quite common for HTML
+     * output.
+     * 
+     * It is sufficient to specify the name without any extension. The extension
+     * is added automatically if not specified.
+     * 
+     * @param req the servlet request object
+     * @param stylesheet the name of the stylesheet
+     */
+    public void setStylesheet(HttpServletRequest req, String stylesheet) {
+        req.setAttribute(Constants.REQ_ATTR_STYLESHEET, Functions.enforceExt(stylesheet, ".css"));
+    }
+    
+    private void forwardToFullView(HttpServletRequest req, HttpServletResponse resp)
+            throws IOException, ServletException {
+        
+        req.setAttribute(Constants.REQ_ATTR_MENU, getModuleManager().getMainMenu(getDatabaseFacade()));
+        req.getRequestDispatcher(HTML_FULL_DISPATCHER).forward(req, resp);
+    }
+    
+    private Optional<HandlerMethod> findMapping(HttpMethod method, HttpServletRequest req) {
+        return Optional.ofNullable(mappings.get(method)).map(
+                (rm) -> rm.get(Optional.ofNullable(req.getPathInfo()).orElse("/"))
+        );
+    }
+    
+    private void forwardAsSepcified(ResponseType type, HttpServletRequest req, HttpServletResponse resp)
+            throws ServletException, IOException {
+        switch (type) {
+            case NONE: return;
+            case HTML_FULL:
+                forwardToFullView(req, resp);
+                return;
+            // TODO: implement remaining response types
+            default:
+                // this code should be unreachable
+                LOG.error("ResponseType switch is not exhaustive - this is a bug!");
+                throw new UnsupportedOperationException();
+        }
+    }
+    
+    private void doProcess(HttpMethod method, HttpServletRequest req, HttpServletResponse resp)
+            throws ServletException, IOException {
+
+        // Synchronize module information with database
+        getModuleManager().syncWithDatabase(getDatabaseFacade());
+        
+        // choose the requested language as session language (if available) or fall back to english, otherwise
+        HttpSession session = req.getSession();
+        if (session.getAttribute(Constants.SESSION_ATTR_LANGUAGE) == null) {
+            Optional<List<String>> availableLanguages = Functions.availableLanguages(getServletContext()).map(Arrays::asList);
+            Optional<Locale> reqLocale = Optional.of(req.getLocale());
+            Locale sessionLocale = reqLocale.filter((rl) -> availableLanguages.map((al) -> al.contains(rl.getLanguage())).orElse(false)).orElse(Locale.ENGLISH);
+            session.setAttribute(Constants.SESSION_ATTR_LANGUAGE, sessionLocale);
+            LOG.debug("Settng language for new session {}: {}", session.getId(), sessionLocale.getDisplayLanguage());
+        } else {
+            Locale sessionLocale = (Locale) session.getAttribute(Constants.SESSION_ATTR_LANGUAGE);
+            resp.setLocale(sessionLocale);
+            LOG.trace("Continuing session {} with language {}", session.getId(), sessionLocale);
+        }
+        
+        // set some internal request attributes
+        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));
+        
+        
+        // call the handler, if available, or send an HTTP 404 error
+        Optional<HandlerMethod> mapping = findMapping(method, req);
+        if (mapping.isPresent()) {
+            forwardAsSepcified(mapping.get().apply(req, resp), req, resp);
+        } else {
+            resp.sendError(HttpServletResponse.SC_NOT_FOUND);
+        }
+    }
+    
+    @Override
+    protected final void doGet(HttpServletRequest req, HttpServletResponse resp)
+            throws ServletException, IOException {
+        doProcess(HttpMethod.GET, req, resp);
+    }
+
+    @Override
+    protected final void doPost(HttpServletRequest req, HttpServletResponse resp)
+            throws ServletException, IOException {
+        doProcess(HttpMethod.POST, req, resp);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/de/uapcore/lightpit/Constants.java	Sat May 09 14:26:31 2020 +0200
@@ -0,0 +1,106 @@
+/*
+ * 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 static de.uapcore.lightpit.Functions.fqn;
+
+/**
+ * Contains all non-local scope constants used by the this application.
+ * 
+ * Constants with (class) local scope are defined in their respective classes.
+ */
+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/";
+    
+    
+    /**
+     * Name for the context parameter specifying the available languages.
+     */
+    public static final String CTX_ATTR_LANGUAGES = "available-languages";
+    
+    /**
+     * Name for the context parameter optionally specifying the JNDI context;
+     */
+    public static final String CTX_ATTR_JNDI_CONTEXT = "jndi-context";
+    
+    /**
+     * Name for the context parameter optionally specifying a database schema.
+     */
+    public static final String CTX_ATTR_DB_SCHEMA = "db-schema";
+    
+    /**
+     * Name for the context parameter optionally specifying a database dialect.
+     */
+    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");
+    
+    /**
+     * 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");
+
+    /**
+     * Key for the name of the fragment which should be rendered.
+     */    
+    public static final String REQ_ATTR_FRAGMENT = fqn(AbstractLightPITServlet.class, "fragment");
+    
+    /**
+     * Key for the name of the additional stylesheet used by a module.
+     */    
+    public static final String REQ_ATTR_STYLESHEET = fqn(AbstractLightPITServlet.class, "extraCss");
+    
+    
+    /**
+     * Key for the current language selection within the session.
+     */
+    public static final String SESSION_ATTR_LANGUAGE = fqn(AbstractLightPITServlet.class, "language");
+    
+    /**
+     * This class is not instantiatable.
+     */
+    private Constants() {}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/de/uapcore/lightpit/DatabaseFacade.java	Sat May 09 14:26:31 2020 +0200
@@ -0,0 +1,178 @@
+/*
+ * 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 java.sql.Connection;
+import java.sql.DatabaseMetaData;
+import java.sql.SQLException;
+import java.util.Optional;
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import javax.naming.NamingException;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletContextEvent;
+import javax.servlet.ServletContextListener;
+import javax.servlet.annotation.WebListener;
+import javax.sql.DataSource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Provides access to different privilege layers within the database.
+ */
+@WebListener
+public final class DatabaseFacade implements ServletContextListener {
+    
+    private static final Logger LOG = LoggerFactory.getLogger(DatabaseFacade.class);
+    
+    /**
+     * Timeout in seconds for the validation test.
+     */
+    private static final int DB_TEST_TIMEOUT = 10;
+    
+    public static enum Dialect {
+        Postgres;
+    }
+    
+    /**
+     * The database dialect to use.
+     * 
+     * May be override by context parameter.
+     * 
+     * @see Constants#CTX_ATTR_DB_DIALECT
+     */
+    private Dialect dialect = Dialect.Postgres;
+    
+    /**
+     * The default schema to test against when validating the connection.
+     * 
+     * May be overridden by context parameter.
+     * 
+     * @see Constants#CTX_ATTR_DB_SCHEMA
+     */
+    private static final String DB_DEFAULT_SCHEMA = "lightpit";
+    
+    /**
+     * The attribute name in the Servlet context under which an instance of this class can be found.
+     */
+    public static final String SC_ATTR_NAME = DatabaseFacade.class.getName();
+    private ServletContext sc;
+    
+    private static final String DS_JNDI_NAME = "jdbc/lightpit/app";
+    private Optional<DataSource> dataSource;
+    
+    /**
+     * Returns the data source.
+     * 
+     * The Optional returned should never be empty. However, if something goes
+     * wrong during initialization, the data source might be absent.
+     * Hence, users of this data source are forced to check the existence.
+     * 
+     * @return a data source
+     */
+    public Optional<DataSource> getDataSource() {
+        return dataSource;
+    }
+    
+    public Dialect getSQLDialect() {
+        return dialect;
+    }
+    
+    private static void checkConnection(DataSource ds, String testSchema, String errMsg) {
+        try (Connection conn = ds.getConnection()) {
+            if (!conn.isValid(DB_TEST_TIMEOUT)) {
+                throw new SQLException("Validation check failed.");
+            }
+            if (conn.isReadOnly()) {
+                throw new SQLException("Connection is read-only and thus unusable.");
+            }
+            if (!conn.getSchema().equals(testSchema)) {
+                throw new SQLException(String.format("Connection is not configured to use the schema %s.", testSchema));
+            }
+            DatabaseMetaData metaData = conn.getMetaData();
+            LOG.info("Connections as {} to {}/{} ready to go.", metaData.getUserName(), metaData.getURL(), conn.getSchema());
+        } catch (SQLException ex) {
+            LOG.error(errMsg, ex);
+        }
+    }
+    
+    private static Optional<DataSource> retrieveDataSource(Context ctx) {
+        DataSource ret = null;
+        try {
+            ret = (DataSource)ctx.lookup(DS_JNDI_NAME);
+            LOG.info("Data source retrieved.");
+        } catch (NamingException ex) {
+            LOG.error("Data source {} not available.", DS_JNDI_NAME);
+            LOG.error("Reason for the missing data source: ", ex);
+        }
+        return Optional.ofNullable(ret);
+    }
+
+    @Override
+    public void contextInitialized(ServletContextEvent sce) {
+        sc = sce.getServletContext();
+        
+        dataSource = null;
+        
+        final String contextName = Optional
+                .ofNullable(sc.getInitParameter(Constants.CTX_ATTR_JNDI_CONTEXT))
+                .orElse("java:comp/env");
+        final String dbSchema = Optional
+                .ofNullable(sc.getInitParameter(Constants.CTX_ATTR_DB_SCHEMA))
+                .orElse(DB_DEFAULT_SCHEMA);
+        final String dbDialect = sc.getInitParameter(Constants.CTX_ATTR_DB_DIALECT);
+        if (dbDialect != null) {
+            try {
+                dialect = Dialect.valueOf(dbDialect);
+            } catch (IllegalArgumentException ex) {
+                LOG.error("Unknown or unsupported database dialect {}. Defaulting to {}.", dbDialect, dialect);
+            }
+        }
+
+        try {
+            LOG.debug("Trying to access JNDI context {}...", contextName);
+            Context initialCtx = new InitialContext();
+            Context ctx = (Context) initialCtx.lookup(contextName);
+            
+            dataSource = retrieveDataSource(ctx);
+            
+            dataSource.ifPresent((ds) -> checkConnection(ds, dbSchema, "Checking database connection failed"));
+        } catch (NamingException | ClassCastException ex) {
+            LOG.error("Cannot access JNDI resources.", ex);
+        }
+        
+        sc.setAttribute(SC_ATTR_NAME, this);
+        LOG.info("Database facade injected into ServletContext.");
+    }
+
+    @Override
+    public void contextDestroyed(ServletContextEvent sce) {
+        dataSource = null;
+    }    
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/de/uapcore/lightpit/Functions.java	Sat May 09 14:26:31 2020 +0200
@@ -0,0 +1,113 @@
+/*
+ * 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 java.util.Optional;
+import javax.servlet.ServletContext;
+import javax.servlet.http.HttpServletRequest;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Contains common static functions.
+ */
+public final class Functions {
+    
+    private static final Logger LOG = LoggerFactory.getLogger(Functions.class);
+
+    public static Optional<String[]> availableLanguages(ServletContext ctx) {
+        return Optional.ofNullable(ctx.getInitParameter(Constants.CTX_ATTR_LANGUAGES)).map((x) -> x.split("\\s*,\\s*"));
+    }
+    
+    public static String enforceExt(String filename, String ext) {
+        return filename.endsWith(ext) ? filename : filename + ext;
+    }
+
+    public static String jspPath(String filename) {
+        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");
+    }
+    
+    public static String fqn(String base, String name) {
+        return base+"."+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("");
+    }
+    
+    /**
+     * Returns the module path of the given LightPIT Servlet module.
+     * 
+     * If you specify a malformed LightPIT servlet, which does not have a module
+     * annotation, the path to the <code>/error/404.html</code> page is returned.
+     * 
+     * @param clazz the servlet class
+     * @return the module path
+     */
+    public static String modulePathOf(Class<? extends AbstractLightPITServlet> clazz) {
+        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";
+        }
+    }
+    
+    /**
+     * This class is not instantiatable.
+     */
+    private Functions() {}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/de/uapcore/lightpit/HttpMethod.java	Sat May 09 14:26:31 2020 +0200
@@ -0,0 +1,34 @@
+/*
+ * 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;
+
+
+public enum HttpMethod {
+    GET, POST, PUT, DELETE, TRACE, HEAD, OPTIONS
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/de/uapcore/lightpit/LightPITModule.java	Sat May 09 14:26:31 2020 +0200
@@ -0,0 +1,170 @@
+/*
+ * 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 java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import javax.servlet.annotation.WebServlet;
+
+
+/**
+ * Contains information about a LightPIT module.
+ * 
+ * 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();
+    
+    /**
+     * An array of required modules, identified by the string representation of
+     * their class names.
+     * @return an array of class names of required modules
+     */
+    String[] requires() default {};
+    
+    /**
+     * The path for this module, which will also be used for the menu entry.
+     * 
+     * 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();
+    
+    /**
+     * Returns the properties key for the module name.
+     * 
+     * @return the properties key
+     */
+    String nameKey() default "name";
+    
+    /**
+     * Returns the properties key for the module description.
+     * 
+     * @return the properties key
+     */
+    String descKey() default "description";
+    
+    
+    /**
+     * 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";
+    
+    /**
+     * 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";
+    
+    /**
+     * 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;
+    
+    /**
+     * 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, nameKey, descKey;
+        
+        public static ELProxy convert(LightPITModule annotation) {
+            return new ELProxy(
+                    annotation.bundleBaseName(),
+                    annotation.modulePath(),
+                    annotation.menuKey(),
+                    annotation.titleKey(),
+                    annotation.nameKey(),
+                    annotation.descKey()
+            );
+        }
+
+        private ELProxy(String bundleBaseName, String modulePath, String menuKey, String titleKey, String nameKey, String descKey) {
+            this.bundleBaseName = bundleBaseName;
+            this.modulePath = modulePath;
+            this.menuKey = menuKey;
+            this.titleKey = titleKey;
+            this.nameKey = nameKey;
+            this.descKey = descKey;
+        }
+
+        public String getBundleBaseName() {
+            return bundleBaseName;
+        }
+
+        public String getMenuKey() {
+            return menuKey;
+        }
+
+        public String getModulePath() {
+            return modulePath;
+        }
+
+        public String getTitleKey() {
+            return titleKey;
+        }
+
+        public String getNameKey() {
+            return nameKey;
+        }
+
+        public String getDescKey() {
+            return descKey;
+        }
+        
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/de/uapcore/lightpit/Menu.java	Sat May 09 14:26:31 2020 +0200
@@ -0,0 +1,97 @@
+/*
+ * 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 java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Maps a resource key for the menu label to the path name for the underlying
+ * site.
+ * 
+ * Objects of this class are internally instantiated by the
+ * {@link ModuleManager}.
+ */
+public class Menu extends MenuEntry {
+    
+    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(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;
+    }
+
+    /**
+     * Sets a new list of menu entries for this menu.
+     * 
+     * @param entries the list of new menu entries
+     */
+    public void setEntries(List<MenuEntry> entries) {
+        // in case the given list is immutable, we copy the contents
+        this.entries.clear();
+        this.entries.addAll(entries);
+    }
+
+    /**
+     * Retrieves an immutable list of menu entries for this menu.
+     * 
+     * @return the list of menu entries
+     */
+    public List<MenuEntry> getEntries() {
+        return immutableEntries;
+    }
+    
+    /**
+     * Adds a new menu entry to this menu.
+     * @param entry the menu entry to add
+     */
+    public void addMenuEntry(MenuEntry entry) {
+        entries.add(entry);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/de/uapcore/lightpit/MenuEntry.java	Sat May 09 14:26:31 2020 +0200
@@ -0,0 +1,74 @@
+/*
+ * 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;
+
+/**
+ * Maps a resource key for the menu label to the path name for the underlying
+ * site.
+ * 
+ * Objects of this class are internally instantiated by the
+ * {@link ModuleManager}.
+ */
+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() {
+    }
+
+    public MenuEntry(ResourceKey resourceKey, String pathName) {
+        this.resourceKey = resourceKey;
+        this.pathName = pathName;
+    }
+
+    public void setResourceKey(ResourceKey resourceKey) {
+        this.resourceKey = resourceKey;
+    }
+
+    public ResourceKey getResourceKey() {
+        return resourceKey;
+    }
+
+    public void setPathName(String pathName) {
+        this.pathName = pathName;
+    }
+
+    public String getPathName() {
+        return pathName;
+    }
+    
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/de/uapcore/lightpit/ModuleManager.java	Sat May 09 14:26:31 2020 +0200
@@ -0,0 +1,231 @@
+/*
+ * 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 de.uapcore.lightpit.entities.CoreDAOFactory;
+import de.uapcore.lightpit.entities.Module;
+import de.uapcore.lightpit.entities.ModuleDao;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.stream.Collectors;
+import javax.servlet.Registration;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletContextEvent;
+import javax.servlet.ServletContextListener;
+import javax.servlet.annotation.WebListener;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * 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 Map<String, LightPITModule> registeredModules = new HashMap<>();
+    
+    /**
+     * This flag is true, when synchronization is needed.
+     */
+    private final AtomicBoolean dirty = new AtomicBoolean(true);
+    
+    @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 Class<? extends AbstractLightPITServlet> clazz = scclass;
+                final LightPITModule moduleInfo = clazz.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.put(reg.getClassName(), 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);
+        
+        // TODO: implement dependency resolver
+        
+        dirty.set(true);
+        LOG.info("Modules loaded.");
+    }
+    
+    /**
+     * Synchronizes module information with the database.
+     * 
+     * This must be called from the {@link AbstractLightPITServlet}.
+     * Admittedly the call will perform the synchronization once after reload
+     * and be a no-op, afterwards.
+     * However, we since the DatabaseFacade might be loaded after the module
+     * manager, we must defer the synchronization to the first request
+     * handled by the Servlet.
+     * 
+     * @param db interface to the database
+     */
+    public void syncWithDatabase(DatabaseFacade db) {
+        if (dirty.compareAndSet(true, false)) {
+            if (db.getDataSource().isPresent()) {
+                try (Connection conn = db.getDataSource().get().getConnection()) {
+                    final ModuleDao moduleDao = CoreDAOFactory.getModuleDao(db.getSQLDialect());
+                    moduleDao.syncRegisteredModuleClasses(conn, registeredModules.entrySet());
+                } catch (SQLException ex) {
+                    LOG.error("Unexpected SQL Exception", ex);
+                }
+            } else {
+                LOG.error("No datasource present. Cannot sync module information with database.");
+            }
+        } else {
+            LOG.trace("Module information clean - no synchronization required.");
+        }
+    }
+    
+    /**
+     * Unloads all found modules.
+     */
+    public void unloadAll() {
+        registeredModules.clear();
+        LOG.info("All modules unloaded.");
+    }
+
+    /**
+     * Returns the main menu.
+     * 
+     * @param db the interface to the database
+     * @return a list of menus belonging to the main menu
+     */
+    public List<Menu> getMainMenu(DatabaseFacade db) {
+        // TODO: user specific menu
+        
+        if (db.getDataSource().isPresent()) {
+            try (Connection conn = db.getDataSource().get().getConnection()) {
+                final ModuleDao dao = CoreDAOFactory.getModuleDao(db.getSQLDialect());
+                final List<Module> modules = dao.listAll(conn);
+                
+                final List<Menu> menu = modules
+                    .stream()
+                    .filter((mod) -> mod.isVisible())
+                    .collect(Collectors.mapping(
+                            (mod) -> new Menu(
+                                    mod.getClassname(),
+                                    new ResourceKey(
+                                            registeredModules.get(mod.getClassname()).bundleBaseName(),
+                                            registeredModules.get(mod.getClassname()).menuKey()),
+                                    registeredModules.get(mod.getClassname()).modulePath()),
+                            Collectors.toList())
+                    );
+                return menu;
+            } catch (SQLException ex) {
+                LOG.error("Unexpected SQLException when loading the main menu", ex);
+                return Collections.emptyList();
+            }
+        } else {
+            return Collections.emptyList();
+        }
+    }
+    
+    /**
+     * Returns an unmodifiable map of all registered modules.
+     * 
+     * The key is the classname of the module.
+     * 
+     * @return the map of registered modules
+     */
+    public Map<String, LightPITModule> getRegisteredModules() {
+        return Collections.unmodifiableMap(registeredModules);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/de/uapcore/lightpit/RequestMapping.java	Sat May 09 14:26:31 2020 +0200
@@ -0,0 +1,76 @@
+/*
+ * 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 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> leading and 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/main/java/de/uapcore/lightpit/ResourceKey.java	Sat May 09 14:26:31 2020 +0200
@@ -0,0 +1,62 @@
+/*
+ * 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;
+
+/**
+ * Fully specifies a resource key by the bundle and the key name.
+ */
+public final class ResourceKey {
+    private String bundle;
+    private String key;
+    
+    public ResourceKey() {
+        
+    }
+
+    public ResourceKey(String bundle, String key) {
+        this.bundle = bundle;
+        this.key = key;
+    }
+
+    public void setBundle(String bundle) {
+        this.bundle = bundle;
+    }
+
+    public String getBundle() {
+        return bundle;
+    }
+
+    public void setKey(String key) {
+        this.key = key;
+    }
+    
+    public String getKey() {
+        return key;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/de/uapcore/lightpit/ResponseType.java	Sat May 09 14:26:31 2020 +0200
@@ -0,0 +1,56 @@
+/*
+ * 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;
+
+
+public enum ResponseType {
+    /**
+     * Renders a full HTML view including the header.
+     */
+    HTML_FULL,
+    /**
+     * Renders a HTML fragment only.
+     * May be used for AJAX responses.
+     */
+    HTML_FRAGMENT,
+    /**
+     * Returns a fragment with content type 'text/plain'.
+     */
+    PLAIN,
+    /**
+     * Returns an object in JSON format and with content type
+     * 'application/json'.
+     */
+    JSON,
+    /**
+     * The handler already sent the output, nothing should be done
+     * additionally by the Servlet.
+     */
+    NONE
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/de/uapcore/lightpit/entities/CoreDAOFactory.java	Sat May 09 14:26:31 2020 +0200
@@ -0,0 +1,47 @@
+/*
+ * 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.entities;
+
+import de.uapcore.lightpit.DatabaseFacade;
+
+public final class CoreDAOFactory {
+    
+    private CoreDAOFactory() {}
+    
+    private static class PostgresDaos {
+        static final ModuleDao MODULE_DAO = new PostgresModuleDao();
+    }
+    
+    public static ModuleDao getModuleDao(DatabaseFacade.Dialect dialect) {
+        switch (dialect) {
+            case Postgres: return PostgresDaos.MODULE_DAO;
+            default: assert(false); return null;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/de/uapcore/lightpit/entities/Module.java	Sat May 09 14:26:31 2020 +0200
@@ -0,0 +1,90 @@
+/*
+ * 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.entities;
+
+import de.uapcore.lightpit.LightPITModule;
+
+public final class Module {
+    private int modID;
+    private String classname;
+    private boolean visible;
+    
+    private LightPITModule.ELProxy annotatedInfos;
+
+    public int getModID() {
+        return modID;
+    }
+
+    public void setModID(int modID) {
+        this.modID = modID;
+    }
+
+    public String getClassname() {
+        return classname;
+    }
+
+    public void setClassname(String classname) {
+        this.classname = classname;
+    }
+
+    public boolean isVisible() {
+        return visible;
+    }
+
+    public void setVisible(boolean visible) {
+        this.visible = visible;
+    }
+
+    public LightPITModule.ELProxy getAnnotatedInfos() {
+        return annotatedInfos;
+    }
+
+    public void setAnnotatedInfos(LightPITModule.ELProxy annotatedInfos) {
+        this.annotatedInfos = annotatedInfos;
+    }
+
+    @Override
+    public int hashCode() {
+        int hash = 3;
+        hash = 41 * hash + this.modID;
+        return hash;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null || getClass() != obj.getClass()) {
+            return false;
+        } else {
+            return this.modID == ((Module) obj).modID;
+        }
+    }    
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/de/uapcore/lightpit/entities/ModuleDao.java	Sat May 09 14:26:31 2020 +0200
@@ -0,0 +1,141 @@
+/*
+ * 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.entities;
+
+import de.uapcore.lightpit.LightPITModule;
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+public abstract class ModuleDao {
+    
+    /**
+     * Maps database columns to POJO fields.
+     * @param result the database result set
+     * @param mod the POJO
+     * @throws SQLException 
+     */
+    protected void mapColumns(ResultSet result, Module mod) throws SQLException {
+        mod.setModID(result.getInt("modid"));
+        mod.setClassname(result.getString("classname"));
+        mod.setVisible(result.getBoolean("visible"));
+    }
+            
+    
+    /**
+     * Must return a prepared statement for a single object query with the specified properties.
+     * 
+     * <ul>
+     * <li>Parameter 1: classname</li>
+     * <li>Result field 1: visible</li>
+     * </ul>
+     * 
+     * @param conn the connection to use
+     * @return the prepared statement
+     * @throws SQLException 
+     */
+    protected PreparedStatement moduleCheckStatement(Connection conn) throws SQLException {
+        return conn.prepareStatement("SELECT visible FROM lpitcore_module WHERE classname = ?");
+    }
+    
+    /**
+     * Must return a prepared statement for insertion with the specified properties.
+     * 
+     * <ul>
+     * <li>Parameter 1: classname</li>
+     * <li>Parameter 2: visible</li>
+     * </ul>
+     * 
+     * @param conn the connection to use
+     * @return the prepared statement
+     * @throws SQLException 
+     */
+    protected PreparedStatement moduleInsertStatement(Connection conn) throws SQLException {
+        return conn.prepareStatement("INSERT INTO lpitcore_module (classname, visible) VALUES (?, ?)");
+    }
+    
+    /**
+     * Synchronizes a set of registered module classes with the database.
+     * 
+     * Inserts module classes which are not known to the database and sets them to be visible by default.
+     * Module classes known to the database, which are not in the given set, are ignored.
+     * 
+     * @param conn the connection to use
+     * @param moduleSet the module set to synchronize
+     * @throws SQLException
+     */
+    public final void syncRegisteredModuleClasses(Connection conn, Set<Map.Entry<String, LightPITModule>> moduleSet) throws SQLException {
+                
+        PreparedStatement
+                check = moduleCheckStatement(conn),
+                insert = moduleInsertStatement(conn);
+        insert.setBoolean(2, true);
+        // update/delete not required, we do this in the module management UI
+
+        for (Map.Entry<String, LightPITModule> modEntry : moduleSet) {
+            if (modEntry.getValue().systemModule()) continue;
+
+            check.setString(1, modEntry.getKey());
+            try (ResultSet r = check.executeQuery()) {
+                if (!r.next()) {
+                    insert.setString(1, modEntry.getKey());
+                    insert.executeUpdate();
+                }
+            }
+        }
+    }
+
+    /**
+     * Returns a list of all modules known by the database.
+     * 
+     * Keep in mind, that system modules are never known to the database.
+     * 
+     * @param conn the connection to use
+     * @return a list of all modules known by the database
+     * @throws SQLException 
+     */
+    public List<Module> listAll(Connection conn) throws SQLException {
+        List<Module> list = new ArrayList<>();
+        try (Statement stmt = conn.createStatement();
+                ResultSet result = stmt.executeQuery("SELECT * FROM lpitcore_module")) {
+            while (result.next()) {
+                final Module mod = new Module();
+                mapColumns(result, mod);
+                list.add(mod);
+            }
+        }
+        return list;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/de/uapcore/lightpit/entities/PostgresModuleDao.java	Sat May 09 14:26:31 2020 +0200
@@ -0,0 +1,33 @@
+/*
+ * 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.entities;
+
+public class PostgresModuleDao extends ModuleDao {
+    // No overrides needed.
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/de/uapcore/lightpit/entities/User.java	Sat May 09 14:26:31 2020 +0200
@@ -0,0 +1,92 @@
+/*
+ * 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.entities;
+
+import java.util.Optional;
+
+public final class User {
+    
+    public static final int ANONYMOUS_USERID = -1;
+    
+    private int userID;
+    private String username;
+    private Optional<String> givenname;
+    private Optional<String> lastname;
+
+    public int getUserID() {
+        return userID;
+    }
+
+    public void setUserID(int userID) {
+        this.userID = userID;
+    }
+
+    public String getUsername() {
+        return username;
+    }
+
+    public void setUsername(String username) {
+        this.username = username;
+    }
+
+    public Optional<String> getGivenname() {
+        return givenname;
+    }
+
+    public void setGivenname(Optional<String> givenname) {
+        this.givenname = givenname;
+    }
+
+    public Optional<String> getLastname() {
+        return lastname;
+    }
+
+    public void setLastname(Optional<String> lastname) {
+        this.lastname = lastname;
+    }
+
+    @Override
+    public int hashCode() {
+        int hash = 3;
+        hash = 41 * hash + this.userID;
+        return hash;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null || getClass() != obj.getClass()) {
+            return false;
+        } else {
+            return this.userID == ((User) obj).userID;
+        }
+    }    
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/de/uapcore/lightpit/entities/UserDao.java	Sat May 09 14:26:31 2020 +0200
@@ -0,0 +1,77 @@
+/*
+ * 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.entities;
+
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+
+public abstract class UserDao {
+    
+    /**
+     * Maps SQL columns to POJO fields.
+     * @param result the database result set
+     * @param user the POJO
+     * @throws SQLException 
+     */
+    protected void mapColumns(ResultSet result, User user) throws SQLException {
+        user.setUserID(result.getInt("userid"));
+        user.setUsername(result.getString("username"));
+        user.setGivenname(Optional.ofNullable(result.getString("givenname")));
+        user.setLastname(Optional.ofNullable(result.getString("lastname"))); 
+    }
+
+    /**
+     * Returns a list of all users ordered by their username.
+     * 
+     * Does not return reserved system users with negative user IDs.
+     * 
+     * @param conn the connection to use
+     * @return a list of all users
+     * @throws SQLException 
+     */
+    public List<User> listAll(Connection conn) throws SQLException {
+        List<User> list = new ArrayList<>();
+        try (
+                Statement stmt = conn.createStatement();
+                ResultSet result = stmt.executeQuery(
+                        "SELECT * FROM lpitcore_user WHERE userid >= 0 ORDER BY username")) {
+            while (result.next()) {
+                final User user = new User();
+                mapColumns(result, user);
+                list.add(user);
+            }
+        }
+        return list;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/de/uapcore/lightpit/modules/ErrorModule.java	Sat May 09 14:26:31 2020 +0200
@@ -0,0 +1,80 @@
+/*
+ * 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.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 = "localization.error",
+        modulePath = "error",
+        titleKey = "title",
+        systemModule = true
+)
+@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/main/java/de/uapcore/lightpit/modules/HomeModule.java	Sat May 09 14:26:31 2020 +0200
@@ -0,0 +1,58 @@
+/*
+ * 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.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 = "localization.home",
+        modulePath = "home"
+)
+@WebServlet(
+        name = "HomeModule",
+        urlPatterns = "/home/*"
+)
+public final class HomeModule extends AbstractLightPITServlet {
+    
+    @RequestMapping(method = HttpMethod.GET)
+    public ResponseType handle(HttpServletRequest req, HttpServletResponse resp) {
+        
+        return ResponseType.HTML_FULL;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/de/uapcore/lightpit/modules/LanguageModule.java	Sat May 09 14:26:31 2020 +0200
@@ -0,0 +1,118 @@
+/*
+ * 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.LightPITModule;
+import de.uapcore.lightpit.AbstractLightPITServlet;
+import de.uapcore.lightpit.Constants;
+import de.uapcore.lightpit.Functions;
+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;
+import de.uapcore.lightpit.ResponseType;
+import java.util.ArrayList;
+import java.util.IllformedLocaleException;
+import java.util.List;
+import java.util.Locale;
+import java.util.Optional;
+import javax.servlet.ServletException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+@LightPITModule(
+        bundleBaseName = "localization.language",
+        modulePath = "language"
+)
+@WebServlet(
+        name = "LanguageModule",
+        urlPatterns = "/language/*"
+)
+public final class LanguageModule extends AbstractLightPITServlet {
+    
+    private static final Logger LOG = LoggerFactory.getLogger(LanguageModule.class);
+    
+    private final List<Locale> languages = new ArrayList<>();
+
+    @Override
+    public void init() throws ServletException {
+        super.init();
+        
+        Optional<String[]> langs = Functions.availableLanguages(getServletContext());
+        if (langs.isPresent()) {
+            for (String lang : langs.get()) {
+                try {
+                    Locale locale = Locale.forLanguageTag(lang);
+                    if (locale.getLanguage().isEmpty()) {
+                        throw new IllformedLocaleException();
+                    }
+                    languages.add(locale);
+                } catch (IllformedLocaleException ex) {
+                    LOG.warn("Specified lanaguge {} in context parameter cannot be mapped to an existing locale - skipping.", lang);
+                }
+            }
+            
+        } else {
+            languages.add(Locale.ENGLISH);
+            LOG.warn("Context parameter 'available-languges' not found. Only english will be available.");
+        }
+    }
+
+    @Override
+    public void destroy() {
+        super.destroy();
+        languages.clear();
+    }
+    
+    @RequestMapping(method = HttpMethod.GET)
+    public ResponseType handle(HttpServletRequest req, HttpServletResponse resp) {
+
+        req.setAttribute("languages", languages);
+        req.setAttribute("browserLanguage", req.getLocale());
+        
+        setStylesheet(req, "language");
+        setDynamicFragment(req, "language");
+        return ResponseType.HTML_FULL;
+    }
+    
+    @RequestMapping(method = HttpMethod.POST)
+    public ResponseType switchLanguage(HttpServletRequest req, HttpServletResponse resp) {
+        
+        Optional<Locale> chosenLanguage = Optional.ofNullable(req.getParameter("language"))
+                .map(Locale::forLanguageTag)
+                .filter((l) -> !l.getLanguage().isEmpty());
+        
+        chosenLanguage.ifPresent((l) -> req.getSession().setAttribute(Constants.SESSION_ATTR_LANGUAGE, l));
+        chosenLanguage.ifPresent(resp::setLocale);
+        
+        return handle(req, resp);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/de/uapcore/lightpit/modules/ModuleManagerModule.java	Sat May 09 14:26:31 2020 +0200
@@ -0,0 +1,94 @@
+/*
+ * 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.LightPITModule;
+import de.uapcore.lightpit.AbstractLightPITServlet;
+import de.uapcore.lightpit.HttpMethod;
+import de.uapcore.lightpit.LightPITModule.ELProxy;
+import de.uapcore.lightpit.RequestMapping;
+import de.uapcore.lightpit.ResponseType;
+import de.uapcore.lightpit.entities.CoreDAOFactory;
+import de.uapcore.lightpit.entities.Module;
+import java.io.IOException;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import javax.servlet.annotation.WebServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.sql.DataSource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Entry point for the application.
+ */
+@LightPITModule(
+        bundleBaseName = "localization.modmgmt",
+        modulePath = "modmgmt"
+)
+@WebServlet(
+        name = "ModuleManagerModule",
+        urlPatterns = "/modmgmt/*"
+)
+public final class ModuleManagerModule extends AbstractLightPITServlet {
+    
+    private static final Logger LOG = LoggerFactory.getLogger(ModuleManagerModule.class);
+    
+    private static final String REQ_ATTR_MODULES = "modules";
+    
+    
+    @RequestMapping(method = HttpMethod.GET)
+    public ResponseType handle(HttpServletRequest req, HttpServletResponse resp) throws IOException {
+        
+        Optional<DataSource> ds = getDatabaseFacade().getDataSource();
+        if (ds.isPresent()) {
+            try (Connection conn = ds.get().getConnection()) {
+                final List<Module> modules = CoreDAOFactory.getModuleDao(getDatabaseFacade().getSQLDialect()).listAll(conn);
+                
+                final Map<String, LightPITModule> registeredModules = getModuleManager().getRegisteredModules();
+                modules.forEach((mod) -> mod.setAnnotatedInfos(ELProxy.convert(registeredModules.get(mod.getClassname()))));
+                
+                req.setAttribute(REQ_ATTR_MODULES, modules);
+                setDynamicFragment(req, "modules");                
+                return ResponseType.HTML_FULL;
+            } catch (SQLException ex) {
+                LOG.error("Unexpected SQL Exception", ex);
+                resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
+                return ResponseType.NONE;
+            }
+        } else {
+            resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
+            return ResponseType.NONE;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/de/uapcore/lightpit/modules/VersionsModule.java	Sat May 09 14:26:31 2020 +0200
@@ -0,0 +1,55 @@
+/*
+ * 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.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;
+
+
+@LightPITModule(
+        bundleBaseName = "localization.versions",
+        modulePath = "versions"
+)
+@WebServlet(
+        name = "VersionsModule",
+        urlPatterns = "/versions/*"
+)
+public final class VersionsModule extends AbstractLightPITServlet {
+    @RequestMapping(method = HttpMethod.GET)
+    public ResponseType handle(HttpServletRequest req, HttpServletResponse resp) {
+        
+        return ResponseType.HTML_FULL;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/java/log4j2.properties	Sat May 09 14:26:31 2020 +0200
@@ -0,0 +1,36 @@
+# 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. 
+
+
+status = warn
+dest = err
+name = LightPITLoggingConfig
+ 
+appender.console.type = Console
+appender.console.name = STDOUT
+appender.console.layout.type = PatternLayout
+appender.console.layout.pattern = %d{ISO8601} [%highlight{%p}] %c{1}: %m %n
+ 
+rootLogger.appenderRef.stdout.ref = STDOUT
+
+rootLogger.level = debug
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/resources/META-INF/context.xml	Sat May 09 14:26:31 2020 +0200
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Context path="/lightpit">
+    <ResourceLink name="jdbc/lightpit/app"
+                  global="jdbc/lightpit/app"
+                  type="javax.sql.DataSource" />
+</Context>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/resources/localization/error.properties	Sat May 09 14:26:31 2020 +0200
@@ -0,0 +1,35 @@
+# 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. 
+
+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/main/resources/localization/error_de.properties	Sat May 09 14:26:31 2020 +0200
@@ -0,0 +1,35 @@
+# 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. 
+
+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/src/main/resources/localization/home.properties	Sat May 09 14:26:31 2020 +0200
@@ -0,0 +1,26 @@
+# 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 = Home Page
+description = The default page that is displayed when visiting the site.
+menuLabel = Home
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/resources/localization/home_de.properties	Sat May 09 14:26:31 2020 +0200
@@ -0,0 +1,26 @@
+# 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 = Startseite
+description = Die Seite, die dem Benutzer standardm\u00e4\u00dfig beim Besuch angezeigt wird.
+menuLabel = Startseite
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/resources/localization/language.properties	Sat May 09 14:26:31 2020 +0200
@@ -0,0 +1,30 @@
+# 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 = Language Selector
+description = Where the user can choose his / her language setting.
+menuLabel = Languages
+
+submit = Switch language
+browserLanguage = Browser language
+browserLanguageNotAvailable = Browser language not available.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/resources/localization/language_de.properties	Sat May 09 14:26:31 2020 +0200
@@ -0,0 +1,31 @@
+# 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 = Sprachauswahl
+description = Hier kann der Benutzer die Sprache f\u00fcr die Website ausw\u00e4hlen.
+
+menuLabel = Sprache
+
+submit = Sprache ausw\u00e4hlen
+browserLanguage = Browsersprache
+browserLanguageNotAvailable = Browsersprache nicht verf\u00fcgbar.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/resources/localization/modmgmt.properties	Sat May 09 14:26:31 2020 +0200
@@ -0,0 +1,36 @@
+# 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 = Module Management
+description = Configure the visible LightPIT modules and the required access powers.
+menuLabel = Modules
+
+section.modlist.title = List of Modules
+
+caption.module = Module
+caption.path = Path
+caption.desc = Description
+caption.active = Active
+caption.class = Class
+caption.bundle = Resource Bundle
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/resources/localization/modmgmt_de.properties	Sat May 09 14:26:31 2020 +0200
@@ -0,0 +1,35 @@
+# 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 = Modulverwaltung
+description = Konfiguration der sichtbaren LightPIT Module und deren Zugriffsrechte.
+menuLabel = Module
+
+section.modlist.title = Liste der Module
+
+caption.module = Modul
+caption.path = Pfad
+caption.desc = Beschreibung
+caption.active = Aktiv
+caption.class = Klasse
+caption.bundle = Ressourcen-Datei
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/resources/localization/versions.properties	Sat May 09 14:26:31 2020 +0200
@@ -0,0 +1,26 @@
+# 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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/resources/localization/versions_de.properties	Sat May 09 14:26:31 2020 +0200
@@ -0,0 +1,26 @@
+# 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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/webapp/WEB-INF/dynamic_fragments/error.jsp	Sat May 09 14:26:31 2020 +0200
@@ -0,0 +1,56 @@
+<%-- 
+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. 
+--%>
+<%@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>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/webapp/WEB-INF/dynamic_fragments/language.jsp	Sat May 09 14:26:31 2020 +0200
@@ -0,0 +1,47 @@
+<%-- 
+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. 
+--%>
+<%@page pageEncoding="UTF-8" session="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" %>
+
+<c:set scope="page" var="currentLanguage" value="${sessionScope[Constants.SESSION_ATTR_LANGUAGE]}" />
+
+<form method="POST"id="lang-selector">
+    <c:forEach items="${languages}" var="l">
+        <label>
+            <input type="radio" name="language" value="${l.language}"
+                   <c:if test="${l.language eq currentLanguage.language}">checked</c:if>/>
+            ${l.displayLanguage}
+            (${l.getDisplayLanguage(currentLanguage)}<c:if test="${not empty browserLanguage and l.language eq browserLanguage.language}"><c:set var="browserLanguagePresent" value="true"/>&nbsp;-&nbsp;<fmt:message key="browserLanguage"/></c:if>)
+        </label>
+    </c:forEach>
+    <c:if test="${not browserLanguagePresent}">
+        <span class="blNA"><fmt:message key="browserLanguageNotAvailable" /></span>
+    </c:if>
+    <input type="submit" value="<fmt:message key="submit" />"/>
+</form>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/webapp/WEB-INF/dynamic_fragments/modules.jsp	Sat May 09 14:26:31 2020 +0200
@@ -0,0 +1,54 @@
+<%-- 
+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. 
+--%>
+<%@page pageEncoding="UTF-8" session="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" %>
+
+<h2><fmt:message key="section.modlist.title"/></h2>
+<table class="datatable">
+    <tr>
+        <th class="hcenter"><fmt:message key="caption.active" /></th>
+        <th><fmt:message key="caption.module" /></th>
+        <th><fmt:message key="caption.path" /></th>
+        <th><fmt:message key="caption.desc" /></th>
+        <th><fmt:message key="caption.class" /></th>
+        <th><fmt:message key="caption.bundle" /></th>
+    </tr>
+    <c:forEach items="${modules}" var="module">
+        <tr>
+            <td class="hcenter">${module.visible}</td>
+            <fmt:bundle basename="${module.annotatedInfos.bundleBaseName}">
+            <td class="nowrap"><fmt:message key="${module.annotatedInfos.nameKey}" /></td>
+            <td>/${module.annotatedInfos.modulePath}</td>
+            <td><fmt:message key="${module.annotatedInfos.descKey}" /></td>
+            <td class="smalltext">${module.classname}</td>
+            <td class="smalltext">${module.annotatedInfos.bundleBaseName}</td>
+            </fmt:bundle>
+        </tr>
+    </c:forEach>
+</table>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/webapp/WEB-INF/jsp/html_full.jsp	Sat May 09 14:26:31 2020 +0200
@@ -0,0 +1,91 @@
+<%-- 
+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. 
+--%>
+<%@page contentType="text/html" pageEncoding="UTF-8" trimDirectiveWhitespaces="true" session="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 fragment name --%>
+<c:set scope="page" var="fragment" value="${requestScope[Constants.REQ_ATTR_FRAGMENT]}"/>
+
+<%-- Define an alias for the additional stylesheet --%>
+<c:set scope="page" var="extraCss" value="${requestScope[Constants.REQ_ATTR_STYLESHEET]}"/>
+
+<%-- Define an alias for the module info --%>
+<c:set scope="page" var="moduleInfo" value="${requestScope[Constants.REQ_ATTR_MODULE_INFO]}"/>
+
+<%-- Apply the session locale (should always be present, but check nevertheless) --%>
+<c:if test="${not empty sessionScope[Constants.SESSION_ATTR_LANGUAGE]}">
+<fmt:setLocale scope="request" value="${sessionScope[Constants.SESSION_ATTR_LANGUAGE]}"/>
+</c:if>
+
+<!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">
+        <c:if test="${not empty extraCss}">
+        <link rel="stylesheet" href="${extraCss}" type="text/css">
+        </c:if>
+    </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">
+            <c:if test="${not empty fragment}">
+                <fmt:setBundle scope="request" basename="${moduleInfo.bundleBaseName}"/>
+                <c:import url="${fragment}" />
+            </c:if>
+        </div>
+    </body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/webapp/WEB-INF/web.xml	Sat May 09 14:26:31 2020 +0200
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<web-app version="3.1" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd">
+    <session-config>
+        <session-timeout>
+            30
+        </session-timeout>
+    </session-config>
+    <context-param>
+        <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/src/main/webapp/error.css	Sat May 09 14:26:31 2020 +0200
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ * 
+ */
+
+#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%;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/webapp/index.jsp	Sat May 09 14:26:31 2020 +0200
@@ -0,0 +1,32 @@
+<%-- 
+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. 
+--%>
+<%@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));
+%>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/webapp/language.css	Sat May 09 14:26:31 2020 +0200
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ * 
+ */
+
+#lang-selector {
+    max-width: 30%;
+    display: flex;
+    flex-basis: content;
+    flex-direction: column;
+}
+
+input {
+    margin: .5em;
+}
+
+span.blNA {
+    margin: .5em;
+    color: red;
+    font-style: italic;
+    font-size: smaller;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main/webapp/lightpit.css	Sat May 09 14:26:31 2020 +0200
@@ -0,0 +1,129 @@
+/*
+ * 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.
+ * 
+ */
+
+html {
+    background: #f8f8f8;
+}
+
+body {
+    background: white;
+    font-family: serif;
+    
+    border-color: #505050;
+    border-style: solid;
+    border-width: 1pt;
+    
+    color: #1c202e;
+}
+
+h1, h2, h3, h4, #mainMenu, #subMenu {
+    font-family: sans-serif;
+}
+
+a {
+    color: #3060f8;
+    text-decoration: none;
+}
+
+#mainMenu {
+    width: 100%;
+    display: flex;
+    flex-flow: row wrap;
+    background: #f0f0f5;
+}
+
+#subMenu {
+    background: #f7f7ff;
+
+    border-image: 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 {
+    padding: .25em 1em .25em 1em;
+    border-right-style: solid;
+    border-right-width: 1pt;
+    border-right-color: #9095a1;
+}
+
+#mainMenu .menuEntry[data-active] {
+    background: #e0e0e5;
+}
+
+#subMenu .menuEntry[data-active] {
+    background: #e7e7ef
+}
+
+#content-area {
+    padding: 1em;
+}
+
+th {
+    text-align: left;
+}
+
+table.datatable {
+    width: 100%;
+    border-style: solid;
+    border-width: 1pt;
+    border-color: black;
+    border-collapse: collapse;
+}
+
+table.datatable th {
+    font-weight: bold;
+    background: lightsteelblue;
+}
+
+table.datatable th, table.datatable td {
+    border-style: solid;
+    border-width: 1pt;
+    border-color: black;
+    padding: .4em;
+}
+
+table.datatable tr:nth-child(2n) {
+    background: lightblue;
+}
+
+.hcenter {
+    text-align: center;
+}
+
+.smalltext {
+    font-size: smaller;
+}
+
+.nowrap {
+    white-space: nowrap;
+}
\ No newline at end of file
--- a/web/META-INF/context.xml	Sun Apr 08 16:51:15 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<Context path="/lightpit">
-    <ResourceLink name="jdbc/lightpit/app"
-                  global="jdbc/lightpit/app"
-                  type="javax.sql.DataSource" />
-</Context>
--- a/web/WEB-INF/dynamic_fragments/error.jsp	Sun Apr 08 16:51:15 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,56 +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. 
---%>
-<%@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/dynamic_fragments/language.jsp	Sun Apr 08 16:51:15 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,47 +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. 
---%>
-<%@page pageEncoding="UTF-8" session="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" %>
-
-<c:set scope="page" var="currentLanguage" value="${sessionScope[Constants.SESSION_ATTR_LANGUAGE]}" />
-
-<form method="POST"id="lang-selector">
-    <c:forEach items="${languages}" var="l">
-        <label>
-            <input type="radio" name="language" value="${l.language}"
-                   <c:if test="${l.language eq currentLanguage.language}">checked</c:if>/>
-            ${l.displayLanguage}
-            (${l.getDisplayLanguage(currentLanguage)}<c:if test="${not empty browserLanguage and l.language eq browserLanguage.language}"><c:set var="browserLanguagePresent" value="true"/>&nbsp;-&nbsp;<fmt:message key="browserLanguage"/></c:if>)
-        </label>
-    </c:forEach>
-    <c:if test="${not browserLanguagePresent}">
-        <span class="blNA"><fmt:message key="browserLanguageNotAvailable" /></span>
-    </c:if>
-    <input type="submit" value="<fmt:message key="submit" />"/>
-</form>
--- a/web/WEB-INF/dynamic_fragments/modules.jsp	Sun Apr 08 16:51:15 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,54 +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. 
---%>
-<%@page pageEncoding="UTF-8" session="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" %>
-
-<h2><fmt:message key="section.modlist.title"/></h2>
-<table class="datatable">
-    <tr>
-        <th class="hcenter"><fmt:message key="caption.active" /></th>
-        <th><fmt:message key="caption.module" /></th>
-        <th><fmt:message key="caption.path" /></th>
-        <th><fmt:message key="caption.desc" /></th>
-        <th><fmt:message key="caption.class" /></th>
-        <th><fmt:message key="caption.bundle" /></th>
-    </tr>
-    <c:forEach items="${modules}" var="module">
-        <tr>
-            <td class="hcenter">${module.visible}</td>
-            <fmt:bundle basename="${module.annotatedInfos.bundleBaseName}">
-            <td class="nowrap"><fmt:message key="${module.annotatedInfos.nameKey}" /></td>
-            <td>/${module.annotatedInfos.modulePath}</td>
-            <td><fmt:message key="${module.annotatedInfos.descKey}" /></td>
-            <td class="smalltext">${module.classname}</td>
-            <td class="smalltext">${module.annotatedInfos.bundleBaseName}</td>
-            </fmt:bundle>
-        </tr>
-    </c:forEach>
-</table>
\ No newline at end of file
--- a/web/WEB-INF/glassfish-web.xml	Sun Apr 08 16:51:15 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,11 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE glassfish-web-app PUBLIC "-//GlassFish.org//DTD GlassFish Application Server 3.1 Servlet 3.0//EN" "http://glassfish.org/dtds/glassfish-web-app_3_0-1.dtd">
-<glassfish-web-app error-url="">
-    <context-root>/lightpit</context-root>
-    <class-loader delegate="true"/>
-    <jsp-config>
-        <property name="keepgenerated" value="true">
-            <description>Keep a copy of the generated servlet class' java code.</description>
-        </property>
-    </jsp-config>
-</glassfish-web-app>
--- a/web/WEB-INF/jsp/html_full.jsp	Sun Apr 08 16:51:15 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,91 +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. 
---%>
-<%@page contentType="text/html" pageEncoding="UTF-8" trimDirectiveWhitespaces="true" session="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 fragment name --%>
-<c:set scope="page" var="fragment" value="${requestScope[Constants.REQ_ATTR_FRAGMENT]}"/>
-
-<%-- Define an alias for the additional stylesheet --%>
-<c:set scope="page" var="extraCss" value="${requestScope[Constants.REQ_ATTR_STYLESHEET]}"/>
-
-<%-- Define an alias for the module info --%>
-<c:set scope="page" var="moduleInfo" value="${requestScope[Constants.REQ_ATTR_MODULE_INFO]}"/>
-
-<%-- Apply the session locale (should always be present, but check nevertheless) --%>
-<c:if test="${not empty sessionScope[Constants.SESSION_ATTR_LANGUAGE]}">
-<fmt:setLocale scope="request" value="${sessionScope[Constants.SESSION_ATTR_LANGUAGE]}"/>
-</c:if>
-
-<!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">
-        <c:if test="${not empty extraCss}">
-        <link rel="stylesheet" href="${extraCss}" type="text/css">
-        </c:if>
-    </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">
-            <c:if test="${not empty fragment}">
-                <fmt:setBundle scope="request" basename="${moduleInfo.bundleBaseName}"/>
-                <c:import url="${fragment}" />
-            </c:if>
-        </div>
-    </body>
-</html>
--- a/web/WEB-INF/web.xml	Sun Apr 08 16:51:15 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<web-app version="3.1" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd">
-    <session-config>
-        <session-timeout>
-            30
-        </session-timeout>
-    </session-config>
-    <context-param>
-        <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>
--- a/web/error.css	Sun Apr 08 16:51:15 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,55 +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.
- * 
- */
-
-#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%;
-}
--- a/web/index.jsp	Sun Apr 08 16:51:15 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,32 +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. 
---%>
-<%@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));
-%>
--- a/web/language.css	Sun Apr 08 16:51:15 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,46 +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.
- * 
- */
-
-#lang-selector {
-    max-width: 30%;
-    display: flex;
-    flex-basis: content;
-    flex-direction: column;
-}
-
-input {
-    margin: .5em;
-}
-
-span.blNA {
-    margin: .5em;
-    color: red;
-    font-style: italic;
-    font-size: smaller;
-}
--- a/web/lightpit.css	Sun Apr 08 16:51:15 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,129 +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.
- * 
- */
-
-html {
-    background: #f8f8f8;
-}
-
-body {
-    background: white;
-    font-family: serif;
-    
-    border-color: #505050;
-    border-style: solid;
-    border-width: 1pt;
-    
-    color: #1c202e;
-}
-
-h1, h2, h3, h4, #mainMenu, #subMenu {
-    font-family: sans-serif;
-}
-
-a {
-    color: #3060f8;
-    text-decoration: none;
-}
-
-#mainMenu {
-    width: 100%;
-    display: flex;
-    flex-flow: row wrap;
-    background: #f0f0f5;
-}
-
-#subMenu {
-    background: #f7f7ff;
-
-    border-image: 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 {
-    padding: .25em 1em .25em 1em;
-    border-right-style: solid;
-    border-right-width: 1pt;
-    border-right-color: #9095a1;
-}
-
-#mainMenu .menuEntry[data-active] {
-    background: #e0e0e5;
-}
-
-#subMenu .menuEntry[data-active] {
-    background: #e7e7ef
-}
-
-#content-area {
-    padding: 1em;
-}
-
-th {
-    text-align: left;
-}
-
-table.datatable {
-    width: 100%;
-    border-style: solid;
-    border-width: 1pt;
-    border-color: black;
-    border-collapse: collapse;
-}
-
-table.datatable th {
-    font-weight: bold;
-    background: lightsteelblue;
-}
-
-table.datatable th, table.datatable td {
-    border-style: solid;
-    border-width: 1pt;
-    border-color: black;
-    padding: .4em;
-}
-
-table.datatable tr:nth-child(2n) {
-    background: lightblue;
-}
-
-.hcenter {
-    text-align: center;
-}
-
-.smalltext {
-    font-size: smaller;
-}
-
-.nowrap {
-    white-space: nowrap;
-}
\ No newline at end of file

mercurial