Skip to content

Commit 46ceb5f

Browse files
authored
Merge pull request #50 from cloudoptlab/3.x
3.0.2.0
2 parents 0fd7cfa + 1dd39a0 commit 46ceb5f

39 files changed

Lines changed: 343 additions & 350 deletions

File tree

cloudopt-next-core/build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
dependencies {
22
api project(":cloudopt-next-json")
33
api project(":cloudopt-next-logging")
4+
api "io.vertx:vertx-core:${rootProject.property('vertx_version')}"
45
api "io.vertx:vertx-lang-kotlin:${rootProject.property('vertx_version')}"
56
api "io.vertx:vertx-lang-kotlin-coroutines:${rootProject.property('vertx_version')}"
67
}

cloudopt-next-web/src/main/kotlin/net/cloudopt/next/web/NextServer.kt

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,9 @@ object NextServer {
5050

5151
open val interceptors = mutableMapOf<String, MutableList<KClass<out Interceptor>>>()
5252

53-
val beforeRouteHandlersTable = mutableMapOf<String, MutableMap<HttpMethod, Array<Annotation>>>()
53+
val beforeRouteHandlersTable = mutableMapOf<String, MutableMap<HttpMethod, MutableList<Annotation>>>()
5454

55-
val afterRouteHandlersTable = mutableMapOf<String, MutableMap<HttpMethod, Array<Annotation>>>()
55+
val afterRouteHandlersTable = mutableMapOf<String, MutableMap<HttpMethod, MutableList<Annotation>>>()
5656

5757
val resourceTable = arrayListOf<ResourceTable>()
5858

@@ -166,27 +166,27 @@ object NextServer {
166166
if (annotation.annotationClass.hasAnnotation<Before>()) {
167167
if (beforeRouteHandlersTable.containsKey(resourceUrl)) {
168168
if (beforeRouteHandlersTable[resourceUrl]?.containsKey(httpMethod) == true) {
169-
beforeRouteHandlersTable[resourceUrl]?.get(httpMethod)?.plus(annotation)
169+
beforeRouteHandlersTable[resourceUrl]?.get(httpMethod)?.add(annotation)
170170
} else {
171-
beforeRouteHandlersTable[resourceUrl]?.set(httpMethod, arrayOf(annotation))
171+
beforeRouteHandlersTable[resourceUrl]?.set(httpMethod, mutableListOf(annotation))
172172
}
173173
} else {
174-
val temp = mutableMapOf<HttpMethod, Array<Annotation>>()
175-
temp[httpMethod] = arrayOf(annotation)
174+
val temp = mutableMapOf<HttpMethod, MutableList<Annotation>>()
175+
temp[httpMethod] = mutableListOf(annotation)
176176
beforeRouteHandlersTable[resourceUrl] = temp
177177
}
178178
}
179179
if (annotation.annotationClass.hasAnnotation<After>()) {
180180

181181
if (afterRouteHandlersTable.containsKey(resourceUrl)) {
182182
if (afterRouteHandlersTable[resourceUrl]?.containsKey(httpMethod) == true) {
183-
afterRouteHandlersTable[resourceUrl]?.get(httpMethod)?.plus(annotation)
183+
afterRouteHandlersTable[resourceUrl]?.get(httpMethod)?.add(annotation)
184184
} else {
185-
afterRouteHandlersTable[resourceUrl]?.set(httpMethod, arrayOf(annotation))
185+
afterRouteHandlersTable[resourceUrl]?.set(httpMethod, mutableListOf(annotation))
186186
}
187187
} else {
188-
val temp = mutableMapOf<HttpMethod, Array<Annotation>>()
189-
temp[httpMethod] = arrayOf(annotation)
188+
val temp = mutableMapOf<HttpMethod, MutableList<Annotation>>()
189+
temp[httpMethod] = mutableListOf(annotation)
190190
afterRouteHandlersTable[resourceUrl] = temp
191191
}
192192
}
@@ -205,7 +205,7 @@ object NextServer {
205205
Logger.configuration.color = webConfig.logColor
206206

207207
//Scan cloudopt handler
208-
Classer.scanPackageByAnnotation("net.cloudopt.next", true, AutoHandler::class)
208+
Classer.scanPackageByAnnotation("net.cloudopt.next.web", true, AutoHandler::class)
209209
.forEach { kclass ->
210210
handlers.add(kclass.createInstance() as Handler)
211211
}

cloudopt-next-web/src/main/kotlin/net/cloudopt/next/web/NextServerVerticle.kt

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import net.cloudopt.next.validator.ValidatorTool
3131
import net.cloudopt.next.waf.Wafer
3232
import net.cloudopt.next.web.annotation.*
3333
import net.cloudopt.next.web.handler.ErrorHandler
34+
import java.lang.RuntimeException
3435
import java.sql.Timestamp
3536
import java.text.DateFormat
3637
import java.time.LocalDate
@@ -171,7 +172,7 @@ class NextServerVerticle : CoroutineVerticle() {
171172
* Set csrf
172173
*/
173174
if (Wafer.config.csrf) {
174-
router.route("/*").handler(CSRFHandler.create(vertx, Wafer.config.encryption))
175+
router.route("/*").handler(CSRFHandler.create(Worker.vertx, Wafer.config.encryption))
175176
}
176177

177178
/**
@@ -180,12 +181,12 @@ class NextServerVerticle : CoroutineVerticle() {
180181
NextServer.logger.info("[FAILURE HANDLER] Registered failure handler:${NextServer.webConfig.errorHandler}")
181182

182183
router.route("/*").failureHandler { context ->
183-
errorProcessing(context)
184+
errorProcessing(context, context.failure())
184185
}
185186

186187
for (i in 400..500) {
187188
router.errorHandler(i) { context ->
188-
errorProcessing(context)
189+
errorProcessing(context, context.failure())
189190
}
190191
}
191192

@@ -354,15 +355,15 @@ class NextServerVerticle : CoroutineVerticle() {
354355
* @see ErrorHandler
355356
* @see RoutingContext
356357
*/
357-
private fun errorProcessing(context: RoutingContext) {
358+
private fun errorProcessing(context: RoutingContext, throwable: Throwable? = RuntimeException()) {
358359
context.response().endHandler {
359360
NextServer.handlers.forEach { handler ->
360361
handler.afterCompletion(Resource().init(context))
361362
}
362363
}
363364
val errorHandler = NextServer.errorHandler.createInstance()
364365
errorHandler.init(context)
365-
errorHandler.handle()
366+
errorHandler.handle(context.response().statusCode, throwable)
366367
if (context.failure() != null) {
367368
context.failure().printStackTrace()
368369
logger.error(context.failure().toString())

cloudopt-next-web/src/main/kotlin/net/cloudopt/next/web/Resource.kt

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import net.cloudopt.next.json.Jsoner.toJsonString
3333
import net.cloudopt.next.waf.Wafer
3434
import net.cloudopt.next.web.render.RenderFactory
3535
import net.cloudopt.next.web.render.Template
36+
import java.lang.RuntimeException
3637
import kotlin.reflect.KClass
3738

3839
open class Resource {
@@ -118,7 +119,6 @@ open class Resource {
118119
fun <T> getAttrs(clazz: KClass<*>): Any {
119120
val map = context.request().formAttributes()
120121
map.forEach {
121-
it
122122
map[it.key] = Wafer.contentFilter(it.value)
123123
}
124124
return (context.request().formAttributes() as MutableMap<String, Any>).toObject(clazz)
@@ -202,7 +202,7 @@ open class Resource {
202202
cookie.domain = domain
203203
}
204204
if (age > 0) {
205-
cookie.setMaxAge(age)
205+
cookie.maxAge = age
206206
}
207207
if (path.isNotBlank()) {
208208
cookie.path = path
@@ -236,10 +236,10 @@ open class Resource {
236236
*/
237237
fun getIp(): String {
238238
var ip: String = request.getHeader("x-forwarded-for") ?: ""
239-
if (ip.isBlank()) {
240-
ip = request.getHeader("X-Real-IP") ?: ""
239+
ip = if (ip.isBlank()) {
240+
request.getHeader("X-Real-IP") ?: ""
241241
} else {
242-
ip = ip.split(",".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()[0]
242+
ip.split(",".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()[0]
243243
}
244244
if (ip.isBlank() || "unknown".equals(ip, ignoreCase = true)) {
245245
ip = request.getHeader("Proxy-Client-IP") ?: ""
@@ -379,10 +379,11 @@ open class Resource {
379379
* {@link Router#errorHandler(int, Handler)}. If no error handler is not defined, It will send a default failure
380380
* response with provided status code.
381381
*
382-
* @param code the HTTP status code
382+
* @param statusCode Int the HTTP status code of the response
383+
* @param throwable Throwable the throwable used when signalling failure
383384
*/
384-
fun fail(code: Int) {
385-
context.fail(code)
385+
fun fail(statusCode: Int, throwable: Throwable? = null) {
386+
context.fail(statusCode, throwable)
386387
}
387388

388389
/**

cloudopt-next-web/src/main/kotlin/net/cloudopt/next/web/handler/DefaultErrorHandler.kt

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import kotlin.math.abs
2222
class DefaultErrorHandler : ErrorHandler() {
2323

2424

25-
override fun handle() {
25+
override fun handle(statusCode: Int, throwable: Throwable?) {
2626
if (abs(errorStatusCode) == 404) {
2727
response.putHeader(HttpHeaders.CONTENT_TYPE, "text/html;charset=utf-8")
2828
context.response().end(Welcomer.notFound())
@@ -34,15 +34,17 @@ class DefaultErrorHandler : ErrorHandler() {
3434
context.response().end(Welcomer.systemError())
3535
return
3636
}
37-
val errorMessage = if (context.data().containsKey("errorMessage")) {
37+
val errorMessage = if ((throwable?.message ?: "").isNotBlank()) {
38+
throwable?.message ?: ""
39+
} else if (context.data().containsKey("errorMessage")) {
3840
context.data()["errorMessage"].toString()
3941
} else {
4042
"This is a bad http request, please check if the parameters match the requirements."
4143
}
42-
renderJson(restult(errorStatusCode.toString(), errorMessage))
44+
renderJson(creatResult(errorStatusCode.toString(), errorMessage))
4345
}
4446

45-
private fun restult(error: String, errorMessage: String): HashMap<String, String> {
47+
private fun creatResult(error: String, errorMessage: String): HashMap<String, String> {
4648
val map = hashMapOf<String, String>()
4749
map["error"] = error
4850
map["errorMessage"] = errorMessage

cloudopt-next-web/src/main/kotlin/net/cloudopt/next/web/handler/ErrorHandler.kt

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,12 @@ import net.cloudopt.next.web.Resource
1919

2020
abstract class ErrorHandler : Resource() {
2121

22-
abstract fun handle()
22+
/**
23+
* Used to catch exceptions in context.
24+
* @param statusCode Int the HTTP status code of the response
25+
* @param throwable Throwable the throwable used when signalling failure
26+
*/
27+
abstract fun handle(statusCode: Int, throwable: Throwable?)
2328

2429
}
2530

cloudopt-next-web/src/test/kotlin/net/cloudopt/next/web/test/TestRestful.kt

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package net.cloudopt.next.web.test
22

3+
import io.vertx.kotlin.core.json.get
34
import io.vertx.kotlin.coroutines.await
45
import kotlinx.coroutines.runBlocking
56
import net.cloudopt.next.client.HttpClient
@@ -50,4 +51,20 @@ class TestRestful : TestStart() {
5051
}
5152
}
5253

54+
@Test
55+
fun testDefaultError() = runBlocking {
56+
val httpCode = client.get("/restful/defaultError").send().await().statusCode()
57+
assertTrue {
58+
httpCode == 402
59+
}
60+
}
61+
62+
@Test
63+
fun testCustomError() = runBlocking {
64+
val result = client.get("/restful/customError").send().await().bodyAsJsonObject()
65+
assertTrue {
66+
result.get<String>("errorMessage") == "401"
67+
}
68+
}
69+
5370
}

cloudopt-next-web/src/test/kotlin/net/cloudopt/next/web/test/WebSocketHandler.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import io.vertx.core.http.ServerWebSocket
55
import io.vertx.core.http.WebSocketFrame
66
import net.cloudopt.next.web.WebSocketResource
77
import net.cloudopt.next.web.annotation.WebSocket
8+
import net.cloudopt.next.web.getCookie
9+
import net.cloudopt.next.web.getIP
810

911
@WebSocket("/websocket")
1012
class WebSocketHandler : WebSocketResource {
@@ -19,6 +21,8 @@ class WebSocketHandler : WebSocketResource {
1921
websocket.writeBinaryMessage(buffer) {
2022
println("The event of after write binary.")
2123
}
24+
websocket.getCookie("key")
25+
websocket.getIP()
2226
}
2327

2428
override suspend fun onConnectionFailure(throwable: Throwable) {

cloudopt-next-web/src/test/kotlin/net/cloudopt/next/web/test/controller/RestController.kt

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,18 @@ package net.cloudopt.next.web.test.controller
33
import net.cloudopt.next.json.Jsoner.json
44
import net.cloudopt.next.web.Resource
55
import net.cloudopt.next.web.annotation.*
6+
import net.cloudopt.next.web.test.handler.TestAfterPrint2Annotation
7+
import net.cloudopt.next.web.test.handler.TestAfterPrintAnnotation
8+
import net.cloudopt.next.web.test.handler.TestBeforePrint2Annotation
9+
import net.cloudopt.next.web.test.handler.TestBeforePrintAnnotation
610

711
@API("/restful")
812
class RestController : Resource() {
913

14+
@TestBeforePrintAnnotation
15+
@TestBeforePrint2Annotation
16+
@TestAfterPrintAnnotation
17+
@TestAfterPrint2Annotation
1018
@GET
1119
fun get() {
1220
renderJson(json("result" to "get"))
@@ -32,4 +40,15 @@ class RestController : Resource() {
3240
renderJson(json("result" to "patch"))
3341
}
3442

43+
@GET("/defaultError")
44+
fun defaultError() {
45+
fail(402)
46+
}
47+
48+
49+
@GET("/customError")
50+
fun customError() {
51+
fail(401, RuntimeException("401"))
52+
}
53+
3554
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package net.cloudopt.next.web.test.handler
2+
3+
import net.cloudopt.next.web.annotation.Before
4+
5+
@Retention(AnnotationRetention.RUNTIME)
6+
@Target(AnnotationTarget.FUNCTION)
7+
@MustBeDocumented
8+
@Before(invokeBy = [TestAfterPrint2Handler::class])
9+
annotation class TestAfterPrint2Annotation()

0 commit comments

Comments
 (0)