1.1 --- a/src/main/kotlin/de/uapcore/lightpit/RequestMapping.kt Sat Jan 23 14:47:59 2021 +0100 1.2 +++ b/src/main/kotlin/de/uapcore/lightpit/RequestMapping.kt Fri Apr 02 11:59:14 2021 +0200 1.3 @@ -25,45 +25,106 @@ 1.4 1.5 package de.uapcore.lightpit 1.6 1.7 +import de.uapcore.lightpit.dao.DataAccessObject 1.8 +import de.uapcore.lightpit.viewmodel.NavMenu 1.9 +import de.uapcore.lightpit.viewmodel.View 1.10 +import javax.servlet.http.HttpServletRequest 1.11 +import javax.servlet.http.HttpServletResponse 1.12 +import javax.servlet.http.HttpSession 1.13 import kotlin.math.min 1.14 1.15 -/** 1.16 - * Maps requests to methods. 1.17 - * 1.18 - * This annotation is used to annotate methods within classes which 1.19 - * override [AbstractServlet]. 1.20 - */ 1.21 -@MustBeDocumented 1.22 -@Retention(AnnotationRetention.RUNTIME) 1.23 -@Target(AnnotationTarget.FUNCTION) 1.24 -annotation class RequestMapping( 1.25 +typealias MappingMethod = (HttpRequest, DataAccessObject) -> Unit 1.26 +typealias PathParameters = Map<String, String> 1.27 + 1.28 +class HttpRequest( 1.29 + val request: HttpServletRequest, 1.30 + val response: HttpServletResponse, 1.31 + val pathParams: PathParameters = emptyMap() 1.32 +) { 1.33 + val session: HttpSession = request.session 1.34 + 1.35 + val remoteUser: String? = request.remoteUser 1.36 1.37 /** 1.38 - * Specifies the HTTP method. 1.39 + * The name of the content page. 1.40 * 1.41 - * @return the HTTP method handled by the annotated Java method 1.42 + * @see Constants#REQ_ATTR_CONTENT_PAGE 1.43 */ 1.44 - val method: HttpMethod, 1.45 + var contentPage = "" 1.46 + set(value) { 1.47 + field = value 1.48 + request.setAttribute(Constants.REQ_ATTR_CONTENT_PAGE, jspPath(value)) 1.49 + } 1.50 1.51 /** 1.52 - * Specifies the request path relative to the module path. 1.53 - * The trailing slash is important. 1.54 - * A node may start with a dollar ($) sign. 1.55 - * This part of the path is then treated as an path parameter. 1.56 - * Path parameters can be obtained by including the [PathParameters] type in the signature. 1.57 + * A list of additional style sheets. 1.58 * 1.59 - * @return the request path the annotated method should handle 1.60 + * @see Constants#REQ_ATTR_STYLESHEET 1.61 */ 1.62 - val requestPath: String = "/" 1.63 -) 1.64 + var styleSheets = emptyList<String>() 1.65 + set(value) { 1.66 + field = value 1.67 + request.setAttribute(Constants.REQ_ATTR_STYLESHEET, 1.68 + value.map { it.withExt(".css") } 1.69 + ) 1.70 + } 1.71 1.72 -class PathParameters : HashMap<String, String>() 1.73 + /** 1.74 + * The name of the navigation menu JSP. 1.75 + * 1.76 + * @see Constants#REQ_ATTR_NAVIGATION 1.77 + */ 1.78 + var navigationMenu: NavMenu? = null 1.79 + set(value) { 1.80 + field = value 1.81 + request.setAttribute(Constants.REQ_ATTR_NAVIGATION, navigationMenu) 1.82 + } 1.83 + 1.84 + var redirectLocation = "" 1.85 + set(value) { 1.86 + field = value 1.87 + request.setAttribute(Constants.REQ_ATTR_REDIRECT_LOCATION, baseHref + value) 1.88 + } 1.89 + 1.90 + /** 1.91 + * The view object. 1.92 + * 1.93 + * @see Constants#REQ_ATTR_VIEWMODEL 1.94 + */ 1.95 + var view: View? = null 1.96 + set(value) { 1.97 + field = value 1.98 + request.setAttribute(Constants.REQ_ATTR_VIEWMODEL, value) 1.99 + } 1.100 + 1.101 + /** 1.102 + * The base path of this application. 1.103 + */ 1.104 + val baseHref get() = "${request.scheme}://${request.serverName}:${request.serverPort}${request.contextPath}/" 1.105 + 1.106 + private fun String.withExt(ext: String) = if (endsWith(ext)) this else plus(ext) 1.107 + private fun jspPath(name: String) = Constants.JSP_PATH_PREFIX.plus(name).withExt(".jsp") 1.108 + 1.109 + fun param(name: String): String? = request.getParameter(name) 1.110 + fun paramArray(name: String): Array<String> = request.getParameterValues(name) ?: emptyArray() 1.111 + 1.112 + fun render(page: String? = null) { 1.113 + page?.let { contentPage = it } 1.114 + request.getRequestDispatcher(jspPath("site")).forward(request, response) 1.115 + } 1.116 + 1.117 + fun renderCommit(location: String? = null) { 1.118 + location?.let { redirectLocation = it } 1.119 + contentPage = Constants.JSP_COMMIT_SUCCESSFUL 1.120 + render() 1.121 + } 1.122 +} 1.123 1.124 /** 1.125 * A path pattern optionally containing placeholders. 1.126 * 1.127 * The special directories . and .. are disallowed in the pattern. 1.128 - * Placeholders start with a $ sign. 1.129 + * Placeholders start with a % sign. 1.130 * 1.131 * @param pattern the pattern 1.132 */ 1.133 @@ -91,7 +152,7 @@ 1.134 for (i in nodePatterns.indices) { 1.135 val pattern = nodePatterns[i] 1.136 val node = nodes[i] 1.137 - if (pattern.startsWith("$")) continue 1.138 + if (pattern.startsWith("%")) continue 1.139 if (pattern != node) return false 1.140 } 1.141 return true 1.142 @@ -106,12 +167,12 @@ 1.143 * @see .matches 1.144 */ 1.145 fun obtainPathParameters(path: String): PathParameters { 1.146 - val params = PathParameters() 1.147 + val params = mutableMapOf<String, String>() 1.148 val nodes = parse(path) 1.149 for (i in 0 until min(nodes.size, nodePatterns.size)) { 1.150 val pattern = nodePatterns[i] 1.151 val node = nodes[i] 1.152 - if (pattern.startsWith("$")) { 1.153 + if (pattern.startsWith("%")) { 1.154 params[pattern.substring(1)] = node 1.155 } 1.156 } 1.157 @@ -121,8 +182,8 @@ 1.158 override fun hashCode(): Int { 1.159 val str = StringBuilder() 1.160 for (node in nodePatterns) { 1.161 - if (node.startsWith("$")) { 1.162 - str.append("/$") 1.163 + if (node.startsWith("%")) { 1.164 + str.append("/%") 1.165 } else { 1.166 str.append('/') 1.167 str.append(node) 1.168 @@ -138,7 +199,7 @@ 1.169 for (i in nodePatterns.indices) { 1.170 val left = nodePatterns[i] 1.171 val right = other.nodePatterns[i] 1.172 - if (left.startsWith("$") && right.startsWith("$")) continue 1.173 + if (left.startsWith("%") && right.startsWith("%")) continue 1.174 if (left != right) return false 1.175 } 1.176 return true