--- a/src/main/kotlin/de/uapcore/lightpit/RequestMapping.kt Sat Jan 23 14:47:59 2021 +0100 +++ b/src/main/kotlin/de/uapcore/lightpit/RequestMapping.kt Fri Apr 02 11:59:14 2021 +0200 @@ -25,45 +25,106 @@ package de.uapcore.lightpit +import de.uapcore.lightpit.dao.DataAccessObject +import de.uapcore.lightpit.viewmodel.NavMenu +import de.uapcore.lightpit.viewmodel.View +import javax.servlet.http.HttpServletRequest +import javax.servlet.http.HttpServletResponse +import javax.servlet.http.HttpSession import kotlin.math.min -/** - * Maps requests to methods. - * - * This annotation is used to annotate methods within classes which - * override [AbstractServlet]. - */ -@MustBeDocumented -@Retention(AnnotationRetention.RUNTIME) -@Target(AnnotationTarget.FUNCTION) -annotation class RequestMapping( +typealias MappingMethod = (HttpRequest, DataAccessObject) -> Unit +typealias PathParameters = Map<String, String> + +class HttpRequest( + val request: HttpServletRequest, + val response: HttpServletResponse, + val pathParams: PathParameters = emptyMap() +) { + val session: HttpSession = request.session + + val remoteUser: String? = request.remoteUser + + /** + * The name of the content page. + * + * @see Constants#REQ_ATTR_CONTENT_PAGE + */ + var contentPage = "" + set(value) { + field = value + request.setAttribute(Constants.REQ_ATTR_CONTENT_PAGE, jspPath(value)) + } + + /** + * A list of additional style sheets. + * + * @see Constants#REQ_ATTR_STYLESHEET + */ + var styleSheets = emptyList<String>() + set(value) { + field = value + request.setAttribute(Constants.REQ_ATTR_STYLESHEET, + value.map { it.withExt(".css") } + ) + } /** - * Specifies the HTTP method. + * The name of the navigation menu JSP. * - * @return the HTTP method handled by the annotated Java method + * @see Constants#REQ_ATTR_NAVIGATION */ - val method: HttpMethod, + var navigationMenu: NavMenu? = null + set(value) { + field = value + request.setAttribute(Constants.REQ_ATTR_NAVIGATION, navigationMenu) + } + + var redirectLocation = "" + set(value) { + field = value + request.setAttribute(Constants.REQ_ATTR_REDIRECT_LOCATION, baseHref + value) + } /** - * Specifies the request path relative to the module path. - * The trailing slash is important. - * A node may start with a dollar ($) sign. - * This part of the path is then treated as an path parameter. - * Path parameters can be obtained by including the [PathParameters] type in the signature. + * The view object. * - * @return the request path the annotated method should handle + * @see Constants#REQ_ATTR_VIEWMODEL + */ + var view: View? = null + set(value) { + field = value + request.setAttribute(Constants.REQ_ATTR_VIEWMODEL, value) + } + + /** + * The base path of this application. */ - val requestPath: String = "/" -) + val baseHref get() = "${request.scheme}://${request.serverName}:${request.serverPort}${request.contextPath}/" + + private fun String.withExt(ext: String) = if (endsWith(ext)) this else plus(ext) + private fun jspPath(name: String) = Constants.JSP_PATH_PREFIX.plus(name).withExt(".jsp") + + fun param(name: String): String? = request.getParameter(name) + fun paramArray(name: String): Array<String> = request.getParameterValues(name) ?: emptyArray() -class PathParameters : HashMap<String, String>() + fun render(page: String? = null) { + page?.let { contentPage = it } + request.getRequestDispatcher(jspPath("site")).forward(request, response) + } + + fun renderCommit(location: String? = null) { + location?.let { redirectLocation = it } + contentPage = Constants.JSP_COMMIT_SUCCESSFUL + render() + } +} /** * A path pattern optionally containing placeholders. * * The special directories . and .. are disallowed in the pattern. - * Placeholders start with a $ sign. + * Placeholders start with a % sign. * * @param pattern the pattern */ @@ -91,7 +152,7 @@ for (i in nodePatterns.indices) { val pattern = nodePatterns[i] val node = nodes[i] - if (pattern.startsWith("$")) continue + if (pattern.startsWith("%")) continue if (pattern != node) return false } return true @@ -106,12 +167,12 @@ * @see .matches */ fun obtainPathParameters(path: String): PathParameters { - val params = PathParameters() + val params = mutableMapOf<String, String>() val nodes = parse(path) for (i in 0 until min(nodes.size, nodePatterns.size)) { val pattern = nodePatterns[i] val node = nodes[i] - if (pattern.startsWith("$")) { + if (pattern.startsWith("%")) { params[pattern.substring(1)] = node } } @@ -121,8 +182,8 @@ override fun hashCode(): Int { val str = StringBuilder() for (node in nodePatterns) { - if (node.startsWith("$")) { - str.append("/$") + if (node.startsWith("%")) { + str.append("/%") } else { str.append('/') str.append(node) @@ -138,7 +199,7 @@ for (i in nodePatterns.indices) { val left = nodePatterns[i] val right = other.nodePatterns[i] - if (left.startsWith("$") && right.startsWith("$")) continue + if (left.startsWith("%") && right.startsWith("%")) continue if (left != right) return false } return true