diff --git a/pom.xml b/pom.xml index 0be6495..c73bd45 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ 4.0.0 org.summerboot jexpress - 2.4.18 + 2.5.0 jar Summer Boot jExpress Summer Boot jExpress focuses on solving non-functional and operational maintainability requirements, @@ -60,7 +60,7 @@ release UTF-8 - 17 + 21 2.1.0 3.3.1 3.11.2 @@ -181,7 +181,7 @@ UTF-8 - 17 + 21 3.4.0 3.13.0 3.8.1 @@ -201,19 +201,19 @@ 2.0.1 - 1.79 + 1.80 0.12.6 - 4.1.116.Final + 4.1.117.Final 2.0.69.Final - 1.69.0 + 1.70.0 33.4.0-jre - 4.29.2 + 4.29.3 - 2.2.27 + 2.2.28 @@ -235,7 +235,7 @@ 7.0.0 - 6.6.4.Final + 6.6.5.Final 6.2.1 @@ -259,7 +259,7 @@ 7.10.2 - 9.1.0 + 9.2.0 diff --git a/src/main/java/org/summerboot/jexpress/boot/BootConstant.java b/src/main/java/org/summerboot/jexpress/boot/BootConstant.java index a63734c..0f4d404 100644 --- a/src/main/java/org/summerboot/jexpress/boot/BootConstant.java +++ b/src/main/java/org/summerboot/jexpress/boot/BootConstant.java @@ -27,7 +27,7 @@ public interface BootConstant { String APP_ID = String.format("%06d", new Random().nextInt(999999)); //version - String VERSION = "jExpress 2.4.18"; + String VERSION = "jExpress 2.5.0"; String JEXPRESS_PACKAGE_NAME = "org.summerboot.jexpress"; String DEFAULT_ADMIN_MM = "changeit"; diff --git a/src/main/java/org/summerboot/jexpress/boot/config/BootConfig.java b/src/main/java/org/summerboot/jexpress/boot/config/BootConfig.java index af358ef..f59eb5e 100644 --- a/src/main/java/org/summerboot/jexpress/boot/config/BootConfig.java +++ b/src/main/java/org/summerboot/jexpress/boot/config/BootConfig.java @@ -606,7 +606,21 @@ public static ThreadPoolExecutor buildThreadPoolExecutor(ThreadPoolExecutor tpe, boolean prestartAllCoreThreads, boolean allowCoreThreadTimeOut, boolean isSingleton) { boolean useVirtualThread = false; switch (threadingMode) { - case Mixed, VirtualThread -> {// manual config is required when it is mixed + case VirtualThread -> { // Java 21+ only + useVirtualThread = true; + if (core < 1) { + core = Integer.MAX_VALUE; + allowCoreThreadTimeOut = true; + } + if (max < 1) { + max = Integer.MAX_VALUE; + } + if (max < core) { + //helper.addError("BizExecutor.MaxSize should not less than BizExecutor.CoreSize"); + max = core; + } + } + case Mixed/*, VirtualThread*/ -> {// manual config is required when it is mixed if (core < 1) { core = CPU_CORE * 2 + 1; } diff --git a/src/main/java/org/summerboot/jexpress/boot/config/NamedDefaultThreadFactory.java b/src/main/java/org/summerboot/jexpress/boot/config/NamedDefaultThreadFactory.java index 1f6aae7..10bef82 100644 --- a/src/main/java/org/summerboot/jexpress/boot/config/NamedDefaultThreadFactory.java +++ b/src/main/java/org/summerboot/jexpress/boot/config/NamedDefaultThreadFactory.java @@ -31,6 +31,8 @@ public static ThreadFactory build(String tpeName, boolean useVirtualThread) { String namePrefix = tpeName + "-" + poolNumber.getAndIncrement() + (useVirtualThread ? "-vt-" : "-pt-"); - return new NamedDefaultThreadFactory(namePrefix); + return useVirtualThread + ? Thread.ofVirtual().name(namePrefix, 0).factory() // Java 21+ only + : new NamedDefaultThreadFactory(namePrefix); } } diff --git a/src/main/java/org/summerboot/jexpress/nio/server/NioHttpUtil.java b/src/main/java/org/summerboot/jexpress/nio/server/NioHttpUtil.java index 37952a3..74222be 100644 --- a/src/main/java/org/summerboot/jexpress/nio/server/NioHttpUtil.java +++ b/src/main/java/org/summerboot/jexpress/nio/server/NioHttpUtil.java @@ -105,6 +105,7 @@ private static void sendRedirect(ChannelHandlerContext ctx, String newUri, HttpR ctx.writeAndFlush(resp).addListener(ChannelFutureListener.CLOSE); } + public static long sendResponse(ChannelHandlerContext ctx, boolean isKeepAlive, final ServiceContext serviceContext, final ErrorAuditor errorAuditor, final ProcessorSettings processorSettings) { String headerKey_reference; String headerKey_serverTimestamp; @@ -117,44 +118,40 @@ public static long sendResponse(ChannelHandlerContext ctx, boolean isKeepAlive, } serviceContext.responseHeader(headerKey_reference, serviceContext.txId()); serviceContext.responseHeader(headerKey_serverTimestamp, OffsetDateTime.now().format(TimeUtil.ISO_ZONED_DATE_TIME3)); + final HttpResponseStatus status = serviceContext.status(); if (serviceContext.file() != null) { return sendFile(ctx, isKeepAlive, serviceContext); } + if (serviceContext.redirect() != null) { + sendRedirect(ctx, serviceContext.redirect(), status); + return 0; + } - HttpResponseStatus status = serviceContext.status(); - ResponseEncoder responseEncoder = serviceContext.responseEncoder(); - if (StringUtils.isBlank(serviceContext.txt()) && status.code() >= 400) { + boolean hasErrorContent = StringUtils.isEmpty(serviceContext.txt()) && status.code() >= 400; + if (hasErrorContent) { if (serviceContext.error() == null) { serviceContext.error(null); } - String clientAcceptContentType = serviceContext.clientAcceptContentType(); - String textResponse; + String errorResponse; if (clientAcceptContentType != null && clientAcceptContentType.contains("xml")) { - textResponse = serviceContext.error().toXML(); + errorResponse = serviceContext.error().toXML(); serviceContext.contentType(MediaType.APPLICATION_XML); } else { - textResponse = serviceContext.error().toJson(); + errorResponse = serviceContext.error().toJson(); serviceContext.contentType(MediaType.APPLICATION_JSON); } if (errorAuditor != null) { - textResponse = errorAuditor.beforeSendingError(textResponse); + errorResponse = errorAuditor.beforeSendingError(errorResponse); } - serviceContext.txt(textResponse); - } - if (StringUtils.isNotBlank(serviceContext.txt())) { - return sendText(ctx, isKeepAlive, serviceContext.responseHeaders(), status, serviceContext.txt(), serviceContext.contentType(), serviceContext.charsetName(), true, responseEncoder); - } - if (serviceContext.redirect() != null) { - sendRedirect(ctx, serviceContext.redirect(), status); - return 0; + serviceContext.txt(errorResponse); } - if (serviceContext.autoConvertBlank200To204() && HttpResponseStatus.OK.equals(status)) { - status = HttpResponseStatus.NO_CONTENT; + if (HttpResponseStatus.OK.equals(status) && serviceContext.autoConvertBlank200To204() && StringUtils.isEmpty(serviceContext.txt())) { + serviceContext.status(HttpResponseStatus.NO_CONTENT); } - return sendText(ctx, isKeepAlive, serviceContext.responseHeaders(), status, null, serviceContext.contentType(), serviceContext.charsetName(), true, responseEncoder); + return sendText(ctx, isKeepAlive, serviceContext.responseHeaders(), serviceContext.status(), serviceContext.txt(), serviceContext.contentType(), serviceContext.charsetName(), true, serviceContext.responseEncoder()); } protected static final String DEFAULT_CHARSET = "UTF-8"; @@ -195,13 +192,8 @@ protected static long sendText(ChannelHandlerContext ctx, boolean isKeepAlive, H if (contentType != null) { h.set(HttpHeaderNames.CONTENT_TYPE, contentType + ";charset=" + charsetName); } - long contentLength = resp.content().readableBytes(); - - if (contentLength > Integer.MAX_VALUE) { - h.set(HttpHeaderNames.CONTENT_LENGTH, String.valueOf(contentLength)); - } else { - h.setInt(HttpHeaderNames.CONTENT_LENGTH, (int) contentLength); - } + int contentLength = resp.content().readableBytes(); + h.set(HttpHeaderNames.CONTENT_LENGTH, String.valueOf(contentLength)); // send if (isKeepAlive) {//HttpUtil.isKeepAlive(req); @@ -221,6 +213,9 @@ protected static long sendText(ChannelHandlerContext ctx, boolean isKeepAlive, H ctx.write(resp).addListener(ChannelFutureListener.CLOSE); } } + if (serviceHeaders != null) { + serviceHeaders.set(h); + } return contentLength; } @@ -231,6 +226,7 @@ private static long sendFile(ChannelHandlerContext ctx, boolean isKeepAlive, fin long fileLength = -1; final RandomAccessFile randomAccessFile; File file = serviceContext.file(); + serviceContext.memo("sendFile", file.getAbsolutePath()); String filePath = file.getName(); try { randomAccessFile = new RandomAccessFile(file, "r"); diff --git a/src/main/java/org/summerboot/jexpress/nio/server/domain/LoginVo.java b/src/main/java/org/summerboot/jexpress/nio/server/domain/LoginVo.java index 742bfdc..2efc919 100644 --- a/src/main/java/org/summerboot/jexpress/nio/server/domain/LoginVo.java +++ b/src/main/java/org/summerboot/jexpress/nio/server/domain/LoginVo.java @@ -1,7 +1,15 @@ package org.summerboot.jexpress.nio.server.domain; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; + public class LoginVo { + @NotNull + @NotEmpty protected String username; + + @NotNull + @NotEmpty protected String password; public LoginVo() { diff --git a/src/main/java/org/summerboot/jexpress/nio/server/ws/rs/BootController.java b/src/main/java/org/summerboot/jexpress/nio/server/ws/rs/BootController.java index 19961b7..f91d829 100644 --- a/src/main/java/org/summerboot/jexpress/nio/server/ws/rs/BootController.java +++ b/src/main/java/org/summerboot/jexpress/nio/server/ws/rs/BootController.java @@ -35,6 +35,7 @@ import io.swagger.v3.oas.annotations.servers.Server; import jakarta.annotation.Nonnull; import jakarta.annotation.security.RolesAllowed; +import jakarta.validation.Valid; import jakarta.ws.rs.Consumes; import jakarta.ws.rs.DELETE; import jakarta.ws.rs.FormParam; @@ -384,7 +385,7 @@ public Caller longin_jSecurityCheck(@Parameter(required = true) @Nonnull @FormPa @Deamon //@CaptureTransaction("user.signJWT") @Log(requestBody = false, responseHeader = false) - public Caller longin_JSON(@Nonnull LoginVo loginVo, + public Caller longin_JSON(@Valid @Nonnull LoginVo loginVo, @Parameter(hidden = true) final ServiceContext context) throws IOException, NamingException { return login(auth, loginVo.getUsername(), loginVo.getPassword(), context); } diff --git a/src/main/java/org/summerboot/jexpress/security/auth/BootAuthenticator.java b/src/main/java/org/summerboot/jexpress/security/auth/BootAuthenticator.java index 89e56e3..dd7f362 100644 --- a/src/main/java/org/summerboot/jexpress/security/auth/BootAuthenticator.java +++ b/src/main/java/org/summerboot/jexpress/security/auth/BootAuthenticator.java @@ -85,6 +85,7 @@ public String signJWT(String username, String pwd, E metaData, int validForMinut Caller caller = authenticate(username, pwd, (E) metaData, authenticatorListener, context); context.poi(BootPOI.LDAP_END); + context.caller(caller); return signJWT(caller, validForMinutes, context); } @@ -109,7 +110,6 @@ public String signJWT(Caller caller, int validForMinutes, final ServiceContext c if (authenticatorListener != null) { authenticatorListener.onLoginSuccess(caller.getUid(), token); } - context.caller(caller); return token; }