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;
}