From 55d5448537b40bac974626dd381539a1ae6832be Mon Sep 17 00:00:00 2001 From: Summer Boot Framework Date: Wed, 7 Aug 2024 15:37:22 -0400 Subject: [PATCH 01/19] BootHttpFileUploadHandler.T onFileUploaded() accepts return object T --- pom.xml | 2 +- .../jexpress/boot/BootConstant.java | 2 +- .../nio/server/BootHttpFileUploadHandler.java | 11 ++-- .../nio/server/domain/ServiceContext.java | 53 ++++++++++++++++++- 4 files changed, 62 insertions(+), 6 deletions(-) diff --git a/pom.xml b/pom.xml index bbfb826..0191295 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ 4.0.0 org.summerboot jexpress - 2.4.10 + 2.4.11-SNAPSHOT jar Summer Boot jExpress Summer Boot jExpress focuses on solving non-functional and operational maintainability requirements, diff --git a/src/main/java/org/summerboot/jexpress/boot/BootConstant.java b/src/main/java/org/summerboot/jexpress/boot/BootConstant.java index 8f7469e..61a69fd 100644 --- a/src/main/java/org/summerboot/jexpress/boot/BootConstant.java +++ b/src/main/java/org/summerboot/jexpress/boot/BootConstant.java @@ -25,7 +25,7 @@ public interface BootConstant { String APP_ID = String.format("%06d", new Random().nextInt(999999)); //version - String VERSION = "SummerBoot.jExpress 2.4.10"; + String VERSION = "SummerBoot.jExpress 2.4.11"; String JEXPRESS_PACKAGE_NAME = "org.summerboot.jexpress"; String DEFAULT_ADMIN_MM = "changeit"; diff --git a/src/main/java/org/summerboot/jexpress/nio/server/BootHttpFileUploadHandler.java b/src/main/java/org/summerboot/jexpress/nio/server/BootHttpFileUploadHandler.java index 3c3e836..a6f563e 100644 --- a/src/main/java/org/summerboot/jexpress/nio/server/BootHttpFileUploadHandler.java +++ b/src/main/java/org/summerboot/jexpress/nio/server/BootHttpFileUploadHandler.java @@ -60,7 +60,7 @@ */ //NOT @ChannelHandler.Sharable due to BootHttpFileUploadHandler is stateful //NOT @Singleton -public abstract class BootHttpFileUploadHandler extends SimpleChannelInboundHandler { +public abstract class BootHttpFileUploadHandler extends SimpleChannelInboundHandler { protected Logger log = LogManager.getLogger(this.getClass()); @@ -209,7 +209,9 @@ protected boolean onPartialChunk(ChannelHandlerContext ctx, long maxAllowedSize) FileUpload fileUpload = (FileUpload) data; if (fileUpload.isCompleted()) { log.debug("file completed " + fileUpload.length()); - onFileUploaded(ctx, fileUpload.getFilename(), fileUpload.getFile(), params, caller, context); + T ret = onFileUploaded(ctx, fileUpload.getFilename(), fileUpload.getFile(), params, caller, context); + context.content(ret); + NioHttpUtil.sendResponse(ctx, true, context, null, null); } break; } @@ -307,6 +309,9 @@ protected long precheck(ChannelHandlerContext ctx, HttpRequest req) { NioHttpUtil.sendResponse(ctx, true, context, null, null); return 0; } + + context.clientAcceptContentType(httpHeaders.get(HttpHeaderNames.ACCEPT)); + return maxAllowedSize; } @@ -316,6 +321,6 @@ protected long precheck(ChannelHandlerContext ctx, HttpRequest req) { protected abstract long getCallerFileUploadSizeLimit_Bytes(Caller caller, ServiceContext context); - protected abstract void onFileUploaded(ChannelHandlerContext ctx, String fileName, File file, Map params, Caller caller, ServiceContext context); + protected abstract T onFileUploaded(ChannelHandlerContext ctx, String fileName, File file, Map params, Caller caller, ServiceContext context); } diff --git a/src/main/java/org/summerboot/jexpress/nio/server/domain/ServiceContext.java b/src/main/java/org/summerboot/jexpress/nio/server/domain/ServiceContext.java index b72013c..fdd72b8 100644 --- a/src/main/java/org/summerboot/jexpress/nio/server/domain/ServiceContext.java +++ b/src/main/java/org/summerboot/jexpress/nio/server/domain/ServiceContext.java @@ -16,12 +16,14 @@ package org.summerboot.jexpress.nio.server.domain; import com.fasterxml.jackson.annotation.JsonAutoDetect; +import com.fasterxml.jackson.core.JsonProcessingException; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.http.DefaultHttpHeaders; import io.netty.handler.codec.http.HttpHeaderNames; import io.netty.handler.codec.http.HttpHeaders; import io.netty.handler.codec.http.HttpMethod; import io.netty.handler.codec.http.HttpResponseStatus; +import jakarta.ws.rs.core.MediaType; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.exception.ExceptionUtils; import org.apache.logging.log4j.Level; @@ -34,6 +36,7 @@ import org.summerboot.jexpress.nio.server.ResponseEncoder; import org.summerboot.jexpress.security.auth.Caller; import org.summerboot.jexpress.util.ApplicationUtil; +import org.summerboot.jexpress.util.BeanUtil; import java.io.BufferedReader; import java.io.File; @@ -634,6 +637,54 @@ public ServiceContext file(File file, boolean isDownloadMode) { return this; } + public ServiceContext content(Object ret) throws JsonProcessingException { + if (ret == null) { + return this; + } + if (ret instanceof File) { + this.file((File) ret, true); + } else { + String responseContentType; + //1. calculate responseContentType + if (clientAcceptContentType == null) {// client not specified + responseContentType = MediaType.APPLICATION_JSON; + } else if (clientAcceptContentType.contains("json")) { + responseContentType = MediaType.APPLICATION_JSON; + } else if (clientAcceptContentType.contains("xml")) { + responseContentType = MediaType.APPLICATION_XML; + } else if (clientAcceptContentType.contains("txt")) { + responseContentType = MediaType.TEXT_HTML; + } else { + responseContentType = MediaType.APPLICATION_JSON; + } + + //2. set content and contentType + if (ret instanceof String) { + this.txt((String) ret); + } else { + switch (responseContentType) { + case MediaType.APPLICATION_JSON: + this.txt(BeanUtil.toJson(ret)); + break; + case MediaType.APPLICATION_XML: + case MediaType.TEXT_XML: + this.txt(BeanUtil.toXML(ret)); + break; + case MediaType.TEXT_HTML: + case MediaType.TEXT_PLAIN: + this.txt(ret.toString()); + break; + } + } + //3. update content type + if (this.contentType() == null) { + this.contentType(responseContentType); + } + } + + return this; + } + //@JsonInclude(JsonInclude.Include.NON_NULL) public T caller() { return (T) caller; @@ -654,7 +705,7 @@ public ServiceContext callerId(String callerId) { return this; } - // public int errorCode() { +// public int errorCode() { // return errorCode; // } // From c3fc52e367762aa9cfae581b782e6c50f30139e6 Mon Sep 17 00:00:00 2001 From: Summer Boot Framework Date: Thu, 8 Aug 2024 19:31:29 -0400 Subject: [PATCH 02/19] enhanced email alert and logging --- .../jexpress/boot/SummerApplication.java | 13 +++++---- .../boot/event/AppLifecycleHandler.java | 10 +++---- .../boot/instrumentation/HealthMonitor.java | 8 +++--- .../integration/smtp/BootPostOfficeImpl.java | 3 +- .../jexpress/nio/grpc/GRPCServer.java | 13 +++++---- .../jexpress/nio/server/NioServer.java | 17 ++++++----- .../jexpress/template/log4j2.xml.temp | 28 +++++++------------ 7 files changed, 47 insertions(+), 45 deletions(-) diff --git a/src/main/java/org/summerboot/jexpress/boot/SummerApplication.java b/src/main/java/org/summerboot/jexpress/boot/SummerApplication.java index 2c5bb1d..772032d 100644 --- a/src/main/java/org/summerboot/jexpress/boot/SummerApplication.java +++ b/src/main/java/org/summerboot/jexpress/boot/SummerApplication.java @@ -282,11 +282,12 @@ public void start() { log.info(() -> sb.toString()); } - long timeoutMs = BackOffice.agent.getProcessTimeoutMilliseconds(); - String timeoutDesc = BackOffice.agent.getProcessTimeoutAlertMessage(); // 4. health inspection log.trace("4. health inspection"); String serviceStatus = HealthMonitor.start(true); + long timeoutMs = BackOffice.agent.getProcessTimeoutMilliseconds(); + String timeoutDesc = BackOffice.agent.getProcessTimeoutAlertMessage(); + StringBuilder startingMemo = new StringBuilder(); // 5a. start server: gRPC if (hasGRPCImpl) { @@ -316,7 +317,7 @@ public void start() { serverBuilder.addService(impl); } if (gRPCCfg.isAutoStart()) { - gRPCServer.start(); + gRPCServer.start(startingMemo); } gRPCServerList.add(gRPCServer); } @@ -330,14 +331,16 @@ public void start() { NioChannelInitializer channelInitializer = super.guiceInjector.getInstance(NioChannelInitializer.class); NIOStatusListener nioListener = super.guiceInjector.getInstance(NIOStatusListener.class); httpServer = new NioServer(channelInitializer.init(guiceInjector, channelHandlerNames), nioListener); - httpServer.bind(NioConfig.cfg); + httpServer.bind(NioConfig.cfg, startingMemo); } } // 6. announcement + startingMemo.append(BootConstant.BR).append(serviceStatus); + startingMemo.append(BootConstant.BR).append("pid#" + BootConstant.PID); log.info(() -> BootConstant.BR + BootConstant.BR + I18n.info.launched.format(userSpecifiedResourceBundle, appVersion + " pid#" + BootConstant.PID) + serviceStatus); if (appLifecycleListener != null) { - appLifecycleListener.onApplicationStart(super.appVersion, serviceStatus); + appLifecycleListener.onApplicationStart(super.appVersion, startingMemo.toString()); } } catch (java.net.BindException ex) {// from NioServer log.fatal(ex + BootConstant.BR + BackOffice.agent.getPortInUseAlertMessage()); diff --git a/src/main/java/org/summerboot/jexpress/boot/event/AppLifecycleHandler.java b/src/main/java/org/summerboot/jexpress/boot/event/AppLifecycleHandler.java index 9d33792..ea73951 100644 --- a/src/main/java/org/summerboot/jexpress/boot/event/AppLifecycleHandler.java +++ b/src/main/java/org/summerboot/jexpress/boot/event/AppLifecycleHandler.java @@ -19,13 +19,13 @@ import com.google.inject.Singleton; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.summerboot.jexpress.boot.BootConstant; import org.summerboot.jexpress.boot.config.JExpressConfig; import org.summerboot.jexpress.boot.instrumentation.HealthMonitor; import org.summerboot.jexpress.integration.smtp.PostOffice; import org.summerboot.jexpress.integration.smtp.SMTPClientConfig; import java.io.File; -import java.time.OffsetDateTime; /** * @author Changski Tie Zheng Zhang 张铁铮, 魏泽北, 杜旺财, 杜富贵 @@ -41,15 +41,15 @@ public class AppLifecycleHandler implements AppLifecycleListener { @Override public void onApplicationStart(String appVersion, String fullConfigInfo) { if (postOffice != null) { - postOffice.sendAlertAsync(SMTPClientConfig.cfg.getEmailToAppSupport(), "Started at " + OffsetDateTime.now(), fullConfigInfo, null, false); + postOffice.sendAlertAsync(SMTPClientConfig.cfg.getEmailToAppSupport(), "Started", fullConfigInfo, null, false); } } @Override public void onApplicationStop(String appVersion) { - log.info(appVersion); + log.warn(appVersion); if (postOffice != null) { - postOffice.sendAlertSync(SMTPClientConfig.cfg.getEmailToAppSupport(), "Shutdown at " + OffsetDateTime.now() + " - " + appVersion, "EOM", null, false); + postOffice.sendAlertSync(SMTPClientConfig.cfg.getEmailToAppSupport(), "Shutdow", "pid#" + BootConstant.PID, null, false); } } @@ -68,7 +68,7 @@ public void onApplicationStatusUpdated(boolean healthOk, boolean paused, boolean boolean serviceAvaliable = healthOk && !paused; String content = HealthMonitor.buildMessage(); if (postOffice != null) { - postOffice.sendAlertAsync(SMTPClientConfig.cfg.getEmailToAppSupport(), "Service Status Changed at " + OffsetDateTime.now(), content, null, false); + postOffice.sendAlertAsync(SMTPClientConfig.cfg.getEmailToAppSupport(), "Service Status Changed", content, null, false); } } } diff --git a/src/main/java/org/summerboot/jexpress/boot/instrumentation/HealthMonitor.java b/src/main/java/org/summerboot/jexpress/boot/instrumentation/HealthMonitor.java index 551790b..69572e5 100644 --- a/src/main/java/org/summerboot/jexpress/boot/instrumentation/HealthMonitor.java +++ b/src/main/java/org/summerboot/jexpress/boot/instrumentation/HealthMonitor.java @@ -286,12 +286,12 @@ protected static void updateServiceStatus(boolean serviceStatusChanged, String r public static String buildMessage() { StringBuilder sb = new StringBuilder(); sb.append(BootConstant.BR) - .append("\t Self Inspection Result: ").append(isHealthCheckSuccess ? "passed" : "failed").append(BootConstant.BR); + .append("Self Inspection Result: ").append(isHealthCheckSuccess ? "passed" : "failed").append(BootConstant.BR); if (!isHealthCheckSuccess) { - sb.append("\t\t cause: ").append(statusReasonHealthCheck).append(BootConstant.BR); + sb.append("\t cause: ").append(statusReasonHealthCheck).append(BootConstant.BR); } - sb.append("\t Service Status: ").append(isServicePaused ? "paused" : "running").append(BootConstant.BR) - .append("\t\t cause: ").append(statusReasonPaused).append(BootConstant.BR); + sb.append("Service Status: ").append(isServicePaused ? "paused" : "running").append(BootConstant.BR) + .append("\t cause: ").append(statusReasonPaused).append(BootConstant.BR); return sb.toString(); } diff --git a/src/main/java/org/summerboot/jexpress/integration/smtp/BootPostOfficeImpl.java b/src/main/java/org/summerboot/jexpress/integration/smtp/BootPostOfficeImpl.java index 4404e89..79f6cfd 100644 --- a/src/main/java/org/summerboot/jexpress/integration/smtp/BootPostOfficeImpl.java +++ b/src/main/java/org/summerboot/jexpress/integration/smtp/BootPostOfficeImpl.java @@ -25,6 +25,7 @@ import org.summerboot.jexpress.boot.SummerApplication; import org.summerboot.jexpress.nio.server.domain.Err; +import java.time.OffsetDateTime; import java.util.ArrayList; import java.util.Collection; import java.util.List; @@ -54,7 +55,7 @@ public void setAppVersion(String appVersion) { * @return */ protected String updateAlertTitle(String title) { - return "Alert@" + SummerApplication.HOST + " " + appVersion + " - " + title; + return "Alert@" + SummerApplication.HOST + " " + appVersion + "[" + BootConstant.APP_ID + "] - " + title + " [" + OffsetDateTime.now() + "]"; } /** diff --git a/src/main/java/org/summerboot/jexpress/nio/grpc/GRPCServer.java b/src/main/java/org/summerboot/jexpress/nio/grpc/GRPCServer.java index ba0b6e3..36e96df 100644 --- a/src/main/java/org/summerboot/jexpress/nio/grpc/GRPCServer.java +++ b/src/main/java/org/summerboot/jexpress/nio/grpc/GRPCServer.java @@ -24,6 +24,7 @@ import io.grpc.netty.shaded.io.grpc.netty.NettyServerBuilder; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.summerboot.jexpress.boot.BootConstant; import org.summerboot.jexpress.boot.config.NamedDefaultThreadFactory; import org.summerboot.jexpress.boot.instrumentation.NIOStatusListener; @@ -191,8 +192,8 @@ protected GRPCServiceCounter initThreadPool(ThreadPoolExecutor tpe, NIOStatusLis return serviceCounter; } - public void start() throws IOException { - this.start(false); + public void start(StringBuilder memo) throws IOException { + this.start(false, memo); } /** @@ -201,14 +202,16 @@ public void start() throws IOException { * @param isBlockingMode * @throws IOException */ - public void start(boolean isBlockingMode) throws IOException { + public void start(boolean isBlockingMode, StringBuilder memo) throws IOException { if (server != null) { shutdown(); } - + String appInfo = BootConstant.VERSION + " " + BootConstant.PID; server = serverBuilder.build().start(); String schema = serverCredentials == null ? "grpc" : "grpcs"; - log.info("*** GRPCServer is listening on " + schema + "://" + bindingAddr + ":" + port); + String info = "Netty GRPC server [" + appInfo + "] is listening on " + schema + "://" + bindingAddr + ":" + port; + memo.append(BootConstant.BR).append(info); + log.info(info); Runtime.getRuntime().addShutdownHook( new Thread(() -> { shutdown(); diff --git a/src/main/java/org/summerboot/jexpress/nio/server/NioServer.java b/src/main/java/org/summerboot/jexpress/nio/server/NioServer.java index 508023b..034d8a2 100644 --- a/src/main/java/org/summerboot/jexpress/nio/server/NioServer.java +++ b/src/main/java/org/summerboot/jexpress/nio/server/NioServer.java @@ -84,7 +84,7 @@ public NioServer(NioChannelInitializer channelInitializer, NIOStatusListener nio * @throws InterruptedException * @throws SSLException */ - public void bind(NioConfig nioCfg) throws InterruptedException, SSLException { + public void bind(NioConfig nioCfg, StringBuilder memo) throws InterruptedException, SSLException { List bindingAddresses = nioCfg.getBindingAddresses(); if (bindingAddresses == null || bindingAddresses.isEmpty()) { log.info("Skip HTTP server due to no bindingAddresses in config file: " + nioCfg.getCfgFile()); @@ -188,26 +188,29 @@ public void bind(NioConfig nioCfg) throws InterruptedException, SSLException { String protocol; if (jdkSslContext == null && nettySslContext == null) { sslMode = "non-ssl"; - protocol = multiplexer + " http://"; + protocol = "http://"; } else { sslMode = "Client Auth: " + clientAuth; - protocol = multiplexer + " https://"; + protocol = "https://"; } + String listenerInfo = "[multiplexer=" + multiplexer + "] " + sslMode; String bindAddr = addr.getAddress().getHostAddress(); int listeningPort = addr.getPort(); - // bind +// bind ChannelFuture f = boot.bind(bindAddr, listeningPort).sync(); f.channel().closeFuture().addListener((ChannelFutureListener) (ChannelFuture f1) -> { //shutdown(); - System.out.println("Server " + appInfo + " (" + sslMode + ") is stopped"); + System.out.println("Server " + appInfo + " (" + listenerInfo + ") is stopped"); }); List loadBalancingPingEndpoints = BackOffice.agent.getLoadBalancingPingEndpoints(); for (String loadBalancingPingEndpoint : loadBalancingPingEndpoints) { - log.info(() -> "Server " + appInfo + " (" + sslMode + ") is listening on " + protocol + bindAddr + ":" + listeningPort + (loadBalancingPingEndpoint == null ? "" : loadBalancingPingEndpoint)); + String info = "Netty HTTP server [" + appInfo + "] (" + listenerInfo + ") is listening on " + protocol + bindAddr + ":" + listeningPort + (loadBalancingPingEndpoint == null ? "" : loadBalancingPingEndpoint); + memo.append(BootConstant.BR).append(info); + log.info(() -> info); } if (nioListener != null) { - nioListener.onNIOBindNewPort(appInfo, sslMode, protocol, bindAddr, listeningPort, loadBalancingEndpoints); + nioListener.onNIOBindNewPort(appInfo, listenerInfo, protocol, bindAddr, listeningPort, loadBalancingEndpoints); } } diff --git a/src/main/resources/org/summerboot/jexpress/template/log4j2.xml.temp b/src/main/resources/org/summerboot/jexpress/template/log4j2.xml.temp index 1e8272f..8cb31aa 100644 --- a/src/main/resources/org/summerboot/jexpress/template/log4j2.xml.temp +++ b/src/main/resources/org/summerboot/jexpress/template/log4j2.xml.temp @@ -1,14 +1,16 @@ - + - + - + + @@ -58,7 +60,6 @@ - @@ -74,42 +75,33 @@ - - + - - + - - - + - - + - - - + \ No newline at end of file From 49a0fd2c8fa11c56c6f86f1140a3906d98e7004c Mon Sep 17 00:00:00 2001 From: Summer Boot Framework Date: Thu, 8 Aug 2024 19:35:08 -0400 Subject: [PATCH 03/19] enhanced email alert and logging --- .../java/org/summerboot/jexpress/boot/SummerApplication.java | 2 +- .../org/summerboot/jexpress/boot/event/AppLifecycleHandler.java | 2 +- .../resources/org/summerboot/jexpress/template/log4j2.xml.temp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/summerboot/jexpress/boot/SummerApplication.java b/src/main/java/org/summerboot/jexpress/boot/SummerApplication.java index 772032d..ad045a3 100644 --- a/src/main/java/org/summerboot/jexpress/boot/SummerApplication.java +++ b/src/main/java/org/summerboot/jexpress/boot/SummerApplication.java @@ -285,10 +285,10 @@ public void start() { // 4. health inspection log.trace("4. health inspection"); String serviceStatus = HealthMonitor.start(true); + long timeoutMs = BackOffice.agent.getProcessTimeoutMilliseconds(); String timeoutDesc = BackOffice.agent.getProcessTimeoutAlertMessage(); StringBuilder startingMemo = new StringBuilder(); - // 5a. start server: gRPC if (hasGRPCImpl) { log.trace("5a. start server: gRPC hasGRPCImpl.bs={}", gRPCBindableServiceImplClasses); diff --git a/src/main/java/org/summerboot/jexpress/boot/event/AppLifecycleHandler.java b/src/main/java/org/summerboot/jexpress/boot/event/AppLifecycleHandler.java index ea73951..d15732a 100644 --- a/src/main/java/org/summerboot/jexpress/boot/event/AppLifecycleHandler.java +++ b/src/main/java/org/summerboot/jexpress/boot/event/AppLifecycleHandler.java @@ -49,7 +49,7 @@ public void onApplicationStart(String appVersion, String fullConfigInfo) { public void onApplicationStop(String appVersion) { log.warn(appVersion); if (postOffice != null) { - postOffice.sendAlertSync(SMTPClientConfig.cfg.getEmailToAppSupport(), "Shutdow", "pid#" + BootConstant.PID, null, false); + postOffice.sendAlertSync(SMTPClientConfig.cfg.getEmailToAppSupport(), "Shutdown", "pid#" + BootConstant.PID, null, false); } } diff --git a/src/main/resources/org/summerboot/jexpress/template/log4j2.xml.temp b/src/main/resources/org/summerboot/jexpress/template/log4j2.xml.temp index 8cb31aa..ff64c6b 100644 --- a/src/main/resources/org/summerboot/jexpress/template/log4j2.xml.temp +++ b/src/main/resources/org/summerboot/jexpress/template/log4j2.xml.temp @@ -5,7 +5,7 @@ + --> From 12dc9aa1485a572c16072a28d5717a5de28daacc Mon Sep 17 00:00:00 2001 From: Summer Boot Framework Date: Thu, 8 Aug 2024 19:37:54 -0400 Subject: [PATCH 04/19] updated dependencies --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 0191295..638b59d 100644 --- a/pom.xml +++ b/pom.xml @@ -190,7 +190,7 @@ 3.3.1 3.2.5 - 3.15.0 + 3.16.0 1.8.0 2.16.1 @@ -209,7 +209,7 @@ 4.1.112.Final 2.0.65.Final - 1.65.1 + 1.66.0 33.2.1-jre 4.27.3 From baf25e49d18e8d5585334f555a9dbb88cd158166 Mon Sep 17 00:00:00 2001 From: Summer Boot Framework Date: Thu, 8 Aug 2024 20:46:53 -0400 Subject: [PATCH 05/19] fixed log file name issue --- .../org/summerboot/jexpress/template/log4j2.xml.temp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/resources/org/summerboot/jexpress/template/log4j2.xml.temp b/src/main/resources/org/summerboot/jexpress/template/log4j2.xml.temp index ff64c6b..e2eb26a 100644 --- a/src/main/resources/org/summerboot/jexpress/template/log4j2.xml.temp +++ b/src/main/resources/org/summerboot/jexpress/template/log4j2.xml.temp @@ -23,7 +23,7 @@ @@ -35,7 +35,7 @@ @@ -47,7 +47,7 @@ From 949ae4c0db44545ba42b46becb522140b8c0c3e6 Mon Sep 17 00:00:00 2001 From: Summer Boot Framework Date: Fri, 9 Aug 2024 15:46:18 -0400 Subject: [PATCH 06/19] refactoring --- pom.xml | 2 +- .../resources/org/summerboot/jexpress/template/log4j2.xml.temp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 638b59d..6d69a1e 100644 --- a/pom.xml +++ b/pom.xml @@ -234,7 +234,7 @@ 7.0.0 - 6.5.2.Final + 6.6.0.Final 5.1.0 diff --git a/src/main/resources/org/summerboot/jexpress/template/log4j2.xml.temp b/src/main/resources/org/summerboot/jexpress/template/log4j2.xml.temp index e2eb26a..28c7dc4 100644 --- a/src/main/resources/org/summerboot/jexpress/template/log4j2.xml.temp +++ b/src/main/resources/org/summerboot/jexpress/template/log4j2.xml.temp @@ -9,7 +9,7 @@ - + From 187d586b685de0bbd21e4c011f719939d0db7462 Mon Sep 17 00:00:00 2001 From: Summer Boot Framework Date: Fri, 9 Aug 2024 20:39:16 -0400 Subject: [PATCH 07/19] migrate to jjwt 0.12 --- pom.xml | 2 +- .../jexpress/boot/SummerBigBang.java | 16 ++- .../nio/grpc/BearerAuthCredential.java | 4 - .../jexpress/nio/server/NioConfig.java | 2 +- .../nio/server/domain/ServiceContext.java | 10 +- .../summerboot/jexpress/security/JwtUtil.java | 98 +++++++++++-------- .../jexpress/security/auth/AuthConfig.java | 9 +- .../security/auth/BootAuthenticator.java | 37 +++---- 8 files changed, 100 insertions(+), 78 deletions(-) diff --git a/pom.xml b/pom.xml index 6d69a1e..ab3a8ec 100644 --- a/pom.xml +++ b/pom.xml @@ -203,7 +203,7 @@ 1.78.1 - 0.11.5 + 0.12.6 4.1.112.Final diff --git a/src/main/java/org/summerboot/jexpress/boot/SummerBigBang.java b/src/main/java/org/summerboot/jexpress/boot/SummerBigBang.java index 6e4488e..f8aad60 100644 --- a/src/main/java/org/summerboot/jexpress/boot/SummerBigBang.java +++ b/src/main/java/org/summerboot/jexpress/boot/SummerBigBang.java @@ -21,7 +21,8 @@ import com.google.inject.Module; import com.google.inject.Stage; import com.google.inject.util.Modules; -import io.jsonwebtoken.SignatureAlgorithm; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.security.MacAlgorithm; import org.apache.commons.cli.CommandLineParser; import org.apache.commons.cli.DefaultParser; import org.apache.commons.cli.Option; @@ -310,8 +311,17 @@ protected boolean runCLI_Utils() { // generate CLI_JWT root signing key if (cli.hasOption(BootConstant.CLI_JWT)) { continueCLI = false; - String algorithm = cli.getOptionValue(BootConstant.CLI_JWT); - SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.forName(algorithm); + String algorithm = cli.getOptionValue(BootConstant.CLI_JWT);// + MacAlgorithm signatureAlgorithm; + switch (algorithm) { + case "HS256" -> signatureAlgorithm = Jwts.SIG.HS256; + case "HS384" -> signatureAlgorithm = Jwts.SIG.HS384; + case "HS512" -> signatureAlgorithm = Jwts.SIG.HS512; + default -> { + System.out.println("invalid -" + BootConstant.CLI_JWT + " value: " + algorithm + ", valid -" + BootConstant.CLI_JWT + " values: "); + return false; + } + } String jwt = JwtUtil.buildSigningKey(signatureAlgorithm); System.out.println(jwt); } diff --git a/src/main/java/org/summerboot/jexpress/nio/grpc/BearerAuthCredential.java b/src/main/java/org/summerboot/jexpress/nio/grpc/BearerAuthCredential.java index 2426251..fd55830 100644 --- a/src/main/java/org/summerboot/jexpress/nio/grpc/BearerAuthCredential.java +++ b/src/main/java/org/summerboot/jexpress/nio/grpc/BearerAuthCredential.java @@ -48,8 +48,4 @@ public void applyRequestMetadata(RequestInfo requestInfo, Executor executor, Met } }); } - - @Override - public void thisUsesUnstableApi() { - } } diff --git a/src/main/java/org/summerboot/jexpress/nio/server/NioConfig.java b/src/main/java/org/summerboot/jexpress/nio/server/NioConfig.java index 1daf4b0..b24ef37 100644 --- a/src/main/java/org/summerboot/jexpress/nio/server/NioConfig.java +++ b/src/main/java/org/summerboot/jexpress/nio/server/NioConfig.java @@ -389,7 +389,7 @@ protected void loadCustomizedConfigs(File cfgFile, boolean isReal, ConfigUtil he tempUoloadDir = rootFolder.getAbsolutePath() + File.separator + tempUoload; //8. Default NIO Response HTTP Headers - serverDefaultResponseHeaders = new DefaultHttpHeaders(true); + serverDefaultResponseHeaders = new DefaultHttpHeaders(); Set _keys = props.keySet().stream().map(o -> o.toString()).collect(Collectors.toSet()); List keys = new ArrayList<>(_keys); keys.forEach((name) -> { diff --git a/src/main/java/org/summerboot/jexpress/nio/server/domain/ServiceContext.java b/src/main/java/org/summerboot/jexpress/nio/server/domain/ServiceContext.java index fdd72b8..8a5fdc9 100644 --- a/src/main/java/org/summerboot/jexpress/nio/server/domain/ServiceContext.java +++ b/src/main/java/org/summerboot/jexpress/nio/server/domain/ServiceContext.java @@ -309,7 +309,7 @@ public ServiceContext responseHeaders(HttpHeaders headers) { return this; } if (this.responseHeaders == null) { - this.responseHeaders = new DefaultHttpHeaders(true); + this.responseHeaders = new DefaultHttpHeaders(); } this.responseHeaders.set(headers); return this; @@ -330,7 +330,7 @@ public ServiceContext responseHeader(String key, Object value) { return this; } if (responseHeaders == null) { - responseHeaders = new DefaultHttpHeaders(true); + responseHeaders = new DefaultHttpHeaders(); } if (value == null) { responseHeaders.remove(key); @@ -355,7 +355,7 @@ public ServiceContext responseHeader(String key, Iterable values) { return this; } if (responseHeaders == null) { - responseHeaders = new DefaultHttpHeaders(true); + responseHeaders = new DefaultHttpHeaders(); } if (values == null) { responseHeaders.remove(key); @@ -370,7 +370,7 @@ public ServiceContext responseHeaders(Map> hs) { return this; } if (responseHeaders == null) { - responseHeaders = new DefaultHttpHeaders(true); + responseHeaders = new DefaultHttpHeaders(); } hs.keySet().stream().filter((key) -> (StringUtils.isNotBlank(key))).forEachOrdered((key) -> { Iterable values = hs.get(key); @@ -617,7 +617,7 @@ public ServiceContext file(File file, boolean isDownloadMode) { // } if (responseHeaders == null) { - responseHeaders = new DefaultHttpHeaders(true); + responseHeaders = new DefaultHttpHeaders(); } long fileLength = file.length(); if (fileLength > Integer.MAX_VALUE) { diff --git a/src/main/java/org/summerboot/jexpress/security/JwtUtil.java b/src/main/java/org/summerboot/jexpress/security/JwtUtil.java index 50d45e0..0d6508c 100644 --- a/src/main/java/org/summerboot/jexpress/security/JwtUtil.java +++ b/src/main/java/org/summerboot/jexpress/security/JwtUtil.java @@ -20,14 +20,18 @@ import io.jsonwebtoken.JwtBuilder; import io.jsonwebtoken.JwtParser; import io.jsonwebtoken.Jwts; -import io.jsonwebtoken.SignatureAlgorithm; import io.jsonwebtoken.security.Keys; +import io.jsonwebtoken.security.MacAlgorithm; +import io.jsonwebtoken.security.SignatureAlgorithm; +import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; import java.security.Key; import java.security.KeyPair; +import java.security.PublicKey; import java.time.Duration; import java.util.Base64; +import java.util.Collection; import java.util.Date; /** @@ -35,9 +39,15 @@ */ public class JwtUtil { - public static String buildSigningKey(SignatureAlgorithm signatureAlgorithm) { - final Key signingKey = Keys.secretKeyFor(signatureAlgorithm); - return EncryptorUtil.keyToString(signingKey); + public static String buildSigningKey(MacAlgorithm signatureAlgorithm) { + SecretKey key = signatureAlgorithm.key().build(); + return EncryptorUtil.keyToString(key); + } + + public static Key parseSigningKey(String encodedKey) { + //return EncryptorUtil.keyFromString(sk, signatureAlgorithm.getJcaName()); "HmacSHA256" + byte[] decodedKey = Base64.getDecoder().decode(encodedKey); + return Keys.hmacShaKeyFor(decodedKey); } /** @@ -50,13 +60,7 @@ public static String buildSigningKey(SignatureAlgorithm signatureAlgorithm) { * @return */ public static KeyPair buildSigningParsingKeyPair(SignatureAlgorithm signatureAlgorithm) { - return Keys.keyPairFor(signatureAlgorithm); - } - - public static Key parseSigningKey(String encodedKey) { - //return EncryptorUtil.keyFromString(sk, signatureAlgorithm.getJcaName()); "HmacSHA256" - byte[] decodedKey = Base64.getDecoder().decode(encodedKey); - return Keys.hmacShaKeyFor(decodedKey); + return signatureAlgorithm.keyPair().build(); } // @Deprecated @@ -119,12 +123,12 @@ public static Key parseSigningKey(String encodedKey) { // return builder.compact(); // } - public static String createJWT(String keyAlgorithm, String jwtSigningKey, String id, String issuer, String subject, String audience, int ttlSeconds) { + public static String createJWT(String keyAlgorithm, String jwtSigningKey, int ttlSeconds, String id, String issuer, String subject, Collection audience) { JwtBuilder builder = Jwts.builder() - .setId(id) - .setIssuer(issuer) - .setSubject(subject) - .setAudience(audience); + .id(id) + .issuer(issuer) + .subject(subject); + builder.audience().add(audience); return createJWT(keyAlgorithm, jwtSigningKey, builder, Duration.ofSeconds(ttlSeconds)); } @@ -133,12 +137,12 @@ public static String createJWT(String keyAlgorithm, String jwtSigningKey, JwtBui return createJWT(keyAlgorithm, key, builder, ttl); } - public static String createJWT(String keyAlgorithm, byte[] jwtSigningKey, String id, String issuer, String subject, String audience, int ttlSeconds) { + public static String createJWT(String keyAlgorithm, byte[] jwtSigningKey, int ttlSeconds, String id, String issuer, String subject, Collection audience) { JwtBuilder builder = Jwts.builder() - .setId(id) - .setIssuer(issuer) - .setSubject(subject) - .setAudience(audience); + .id(id) + .issuer(issuer) + .subject(subject); + builder.audience().add(audience); return createJWT(keyAlgorithm, jwtSigningKey, builder, Duration.ofSeconds(ttlSeconds)); } @@ -156,17 +160,17 @@ public static void setJwtExpireTime(JwtBuilder builder, Duration ttl) { long expireTimeMilsec = System.currentTimeMillis() + ttlMilsec; if (expireTimeMilsec > 0) {// no expire if (nowMillis + ttlMillis) overflow Date exp = new Date(expireTimeMilsec); - builder.setExpiration(exp); + builder.expiration(exp); } } } - public static String createJWT(Key privateKey, String id, String issuer, String subject, String audience, int ttlSeconds) { + public static String createJWT(Key privateKey, int ttlSeconds, String id, String issuer, String subject, Collection audience) { JwtBuilder builder = Jwts.builder() - .setId(id) - .setIssuer(issuer) - .setSubject(subject) - .setAudience(audience); + .id(id) + .issuer(issuer) + .subject(subject); + builder.audience().add(audience); return createJWT(privateKey, builder, Duration.ofSeconds(ttlSeconds)); } @@ -180,7 +184,7 @@ public static String createJWT(Key privateKey, JwtBuilder builder, Duration ttl) setJwtExpireTime(builder, ttl); //2. Let's set the JWT Claims - builder.setIssuedAt(new Date()); + builder.issuedAt(new Date()); //builder.signWith(signatureAlgorithm, privateKey); builder.signWith(privateKey); @@ -188,24 +192,40 @@ public static String createJWT(Key privateKey, JwtBuilder builder, Duration ttl) return builder.compact(); } - public static Jws parseJWT(Key jwtRootSigningKey, String token) { - JwtParser parser = Jwts.parserBuilder() // (1) - .setSigningKey(jwtRootSigningKey) // (2) + public static Jws parseJWT(Key verifyKey, String token) { + if (verifyKey instanceof SecretKey) { + return parseJWT((SecretKey) verifyKey, token); + } else if (verifyKey instanceof PublicKey) { + return parseJWT((PublicKey) verifyKey, token); + } else { + throw new IllegalArgumentException("Unsupported Key type: " + verifyKey.getClass().getName()); + } + } + + public static Jws parseJWT(SecretKey jwtRootSigningKey, String token) { + JwtParser parser = Jwts.parser() // (1) + .verifyWith(jwtRootSigningKey) // (2) .build(); // (3) - return parser.parseClaimsJws(token); // (4) -// JwsHeader h = ret.getHeader(); -// return ret.getBody(); + return parseJWT(parser, token); // (4) } - public static Jws parseJWT(byte[] jwtRootSigningKey, String token) { - JwtParser parser = Jwts.parserBuilder() // (1) - .setSigningKey(jwtRootSigningKey) // (2) + public static Jws parseJWT(PublicKey publicKey, String token) { + JwtParser parser = Jwts.parser() // (1) + .verifyWith(publicKey) // (2) .build(); // (3) - return parser.parseClaimsJws(token); // (4) + return parseJWT(parser, token); // (4) } - public static Jws parseJWT(JwtParser parser, String token) { + /*public static Jws parseJWT(byte[] jwtRootSigningKey, String token) { + JwtParser parser = Jwts.parser() // (1) + .verifyWith(jwtRootSigningKey) // (2) + .build(); // (3) return parser.parseClaimsJws(token); // (4) + }*/ + + public static Jws parseJWT(JwtParser parser, String token) { + //return parser.parseClaimsJws(token); // (4) + return parser.parseSignedClaims(token); } } diff --git a/src/main/java/org/summerboot/jexpress/security/auth/AuthConfig.java b/src/main/java/org/summerboot/jexpress/security/auth/AuthConfig.java index 1d84dc3..7e2a40c 100644 --- a/src/main/java/org/summerboot/jexpress/security/auth/AuthConfig.java +++ b/src/main/java/org/summerboot/jexpress/security/auth/AuthConfig.java @@ -29,6 +29,7 @@ import org.summerboot.jexpress.security.EncryptorUtil; import org.summerboot.jexpress.security.JwtUtil; +import javax.crypto.SecretKey; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.TrustManagerFactory; import java.io.File; @@ -239,8 +240,8 @@ protected void loadCustomizedConfigs(File cfgFile, boolean isReal, ConfigUtil he if (symmetricKey != null) { //jwtSigningKey = EncryptorUtil.keyFromString(jwtSigningKeyString, jwtSignatureAlgorithm.getJcaName()); jwtSigningKey = JwtUtil.parseSigningKey(symmetricKey); - jwtParser = Jwts.parserBuilder() // (1) - .setSigningKey(jwtSigningKey) // (2) + jwtParser = Jwts.parser() // (1) + .verifyWith((SecretKey) jwtSigningKey) // (2) .build(); // (3) } //File rootFolder = cfgFile.getParentFile().getParentFile(); @@ -251,8 +252,8 @@ protected void loadCustomizedConfigs(File cfgFile, boolean isReal, ConfigUtil he if (publicKeyFile != null) { createIfNotExist(JWT_PUBLIC_KEY_FILE, JWT_PUBLIC_KEY_FILE); PublicKey publicKey = EncryptorUtil.loadPublicKey(EncryptorUtil.KeyFileType.PKCS12, publicKeyFile); - jwtParser = Jwts.parserBuilder() // (1) - .setSigningKey(publicKey) // (2) + jwtParser = Jwts.parser() // (1) + .verifyWith(publicKey) // (2) .build(); // (3) } 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 cfd4572..fe65636 100644 --- a/src/main/java/org/summerboot/jexpress/security/auth/BootAuthenticator.java +++ b/src/main/java/org/summerboot/jexpress/security/auth/BootAuthenticator.java @@ -42,14 +42,12 @@ import org.summerboot.jexpress.nio.server.domain.Err; import org.summerboot.jexpress.nio.server.domain.ServiceContext; import org.summerboot.jexpress.security.JwtUtil; -import org.summerboot.jexpress.util.FormatterUtil; import javax.naming.NamingException; import java.security.Key; import java.time.Duration; import java.util.Date; import java.util.Set; -import java.util.stream.Collectors; /** * @param authenticate(T metaData) @@ -137,35 +135,34 @@ public JwtBuilder toJwt(Caller caller) { String issuer = AuthConfig.cfg.getJwtIssuer(); String userName = caller.getUid(); Set groups = caller.getGroups(); - String groupsCsv = groups == null || groups.size() < 1 + /*String groupsCsv = groups == null || groups.size() < 1 ? null : groups.stream().collect(Collectors.joining(",")); - String audience = groupsCsv; + String audience = groupsCsv;*/ - Claims claims = Jwts.claims(); - claims.setId(jti) - .setIssuer(issuer) - .setSubject(userName) - .setAudience(audience); + JwtBuilder builder = Jwts.builder(); + builder.id(jti) + .issuer(issuer) + .subject(userName) + .audience().add(groups); if (caller.getId() != null) { - claims.put("callerId", caller.getId()); + builder.claim("callerId", caller.getId()); } if (caller.getTenantId() != null) { - claims.put("tenantId", caller.getTenantId()); + builder.claim("tenantId", caller.getTenantId()); } if (caller.getTenantName() != null) { - claims.put("tenantName", caller.getTenantName()); + builder.claim("tenantName", caller.getTenantName()); } Set keys = caller.propKeySet(); if (keys != null) { for (String key : keys) { Object v = caller.getProp(key, Object.class); - claims.put(key, v); + builder.claim(key, v); } } - JwtBuilder builder = Jwts.builder().setClaims(claims); - + //JwtBuilder builder = Jwts.builder().setClaims(claims); return builder; } @@ -174,7 +171,7 @@ protected Claims parseJWT(String jwt) { if (jwtParser == null) { throw new UnsupportedOperationException(ERROR_NO_CFG); } - return JwtUtil.parseJWT(jwtParser, jwt).getBody(); + return JwtUtil.parseJWT(jwtParser, jwt).getPayload(); } /** @@ -188,17 +185,15 @@ protected Caller fromJwt(Claims claims) { //String jti = claims.getId(); //String issuer = claims.getIssuer(); String userName = claims.getSubject(); - String audience = claims.getAudience(); + Set audience = claims.getAudience(); Long userId = claims.get("callerId", Long.class); Long tenantId = claims.get("tenantId", Long.class); String tenantName = claims.get("tenantName", String.class); User caller = new User(tenantId, tenantName, userId, userName); - String userGroups = audience; - if (StringUtils.isNotBlank(userGroups)) { - String[] groups = FormatterUtil.parseCsv(userGroups); - for (String group : groups) { + if (audience != null) { + for (String group : audience) { caller.addGroup(group); } } From 5301edd914f295d039fe62ac6659cab29076251b Mon Sep 17 00:00:00 2001 From: Summer Boot Framework Date: Tue, 20 Aug 2024 11:16:38 -0400 Subject: [PATCH 08/19] repleace Glassfish EL impl with Tomcat Embed EL; refactoring --- pom.xml | 47 ++++++----- .../jexpress/boot/BootConstant.java | 2 +- .../jexpress/boot/BootGuiceModule.java | 16 +++- .../jexpress/boot/ScanedGuiceModule.java | 4 +- .../jexpress/boot/SummerApplication.java | 44 ++++++++++- .../boot/instrumentation/HealthMonitor.java | 63 ++++++++++++--- .../integration/smtp/BootPostOfficeImpl.java | 79 ++++++++----------- .../jexpress/nio/server/NioServer.java | 34 ++++---- .../summerboot/jexpress/security/JwtUtil.java | 15 +--- .../jexpress/template/log4j2.xml.temp | 14 +++- 10 files changed, 203 insertions(+), 115 deletions(-) diff --git a/pom.xml b/pom.xml index ab3a8ec..24e9b2e 100644 --- a/pom.xml +++ b/pom.xml @@ -191,7 +191,7 @@ 3.2.5 3.16.0 - 1.8.0 + 1.9.0 2.16.1 @@ -210,7 +210,7 @@ 2.0.65.Final 1.66.0 - 33.2.1-jre + 33.3.0-jre 4.27.3 2.2.22 @@ -227,8 +227,9 @@ 2.17.2 - 8.0.1.Final 6.0.1 + 11.0.0-M24 + 8.0.1.Final 7.0.0 @@ -263,12 +264,6 @@ - - - org.apache.commons - commons-lang3 - ${commons-lang3.version} - commons-cli @@ -282,6 +277,12 @@ commons-io ${commons-io.version} + + + org.apache.commons + commons-lang3 + ${commons-lang3.version} + - + - org.hibernate.validator - hibernate-validator - ${hibernate-validator.version} + jakarta.el + jakarta.el-api + ${jakarta.el.version} + + + + + + - org.glassfish - jakarta.el - 4.0.2 + org.apache.tomcat.embed + tomcat-embed-el + ${tomcat-embed-el.version} - + - jakarta.el - jakarta.el-api - ${jakarta.el.version} + org.hibernate.validator + hibernate-validator + ${hibernate-validator.version} diff --git a/src/main/java/org/summerboot/jexpress/boot/BootConstant.java b/src/main/java/org/summerboot/jexpress/boot/BootConstant.java index 61a69fd..5ab36c9 100644 --- a/src/main/java/org/summerboot/jexpress/boot/BootConstant.java +++ b/src/main/java/org/summerboot/jexpress/boot/BootConstant.java @@ -25,7 +25,7 @@ public interface BootConstant { String APP_ID = String.format("%06d", new Random().nextInt(999999)); //version - String VERSION = "SummerBoot.jExpress 2.4.11"; + String VERSION = "jExpress 2.4.11"; String JEXPRESS_PACKAGE_NAME = "org.summerboot.jexpress"; String DEFAULT_ADMIN_MM = "changeit"; diff --git a/src/main/java/org/summerboot/jexpress/boot/BootGuiceModule.java b/src/main/java/org/summerboot/jexpress/boot/BootGuiceModule.java index 7fd6f1b..7d8d089 100644 --- a/src/main/java/org/summerboot/jexpress/boot/BootGuiceModule.java +++ b/src/main/java/org/summerboot/jexpress/boot/BootGuiceModule.java @@ -25,6 +25,7 @@ import org.quartz.Scheduler; import org.summerboot.jexpress.boot.annotation.Controller; import org.summerboot.jexpress.boot.annotation.Inspector; +import org.summerboot.jexpress.boot.annotation.Service; import org.summerboot.jexpress.boot.event.AppLifecycleHandler; import org.summerboot.jexpress.boot.event.AppLifecycleListener; import org.summerboot.jexpress.boot.event.HttpExceptionHandler; @@ -76,7 +77,7 @@ public BootGuiceModule(Object caller, Class callerClass, Set userSpecifi this.memo = memo; } - protected boolean isCliUseImplTag(String implTag) { + protected boolean isTagSpecifiedViaCLI(String implTag) { return userSpecifiedImplTags != null && userSpecifiedImplTags.contains(implTag); } @@ -171,13 +172,20 @@ protected void scanAnnotation_BindInstance(Binder binder, Class specified + if (StringUtils.isNotBlank(implTag) && !isTagSpecifiedViaCLI(implTag)) { + continue; + } classesAll.add(c); } //} diff --git a/src/main/java/org/summerboot/jexpress/boot/ScanedGuiceModule.java b/src/main/java/org/summerboot/jexpress/boot/ScanedGuiceModule.java index 9dc1b14..6a2f3cc 100644 --- a/src/main/java/org/summerboot/jexpress/boot/ScanedGuiceModule.java +++ b/src/main/java/org/summerboot/jexpress/boot/ScanedGuiceModule.java @@ -50,7 +50,7 @@ public ScanedGuiceModule(Map as = c.getContext().getConfiguration().getAppenders(); + int countConsoleAppender = 0; + for (Map.Entry entry : as.entrySet()) { + Appender appender = entry.getValue(); + if (appender instanceof ConsoleAppender) { + countConsoleAppender++; + if (countConsoleAppender > 1) { + prompt = null; + break; + } + ConsoleAppender sa = (ConsoleAppender) appender; + Filter f = sa.getFilter(); + if (f instanceof LevelRangeFilter) { + LevelRangeFilter lrf = (LevelRangeFilter) f; + Level maxLevel = lrf.getMaxLevel(); + if (!Level.ALL.equals(maxLevel)) { + prompt = "\nTo show logs in console, please edit " + this.userSpecifiedConfigDir + File.separator + + "log4j2.xml \n\t\n\t \n\t \n\t \n\tchange around line#13: set maxLevel=\"" + Level.ALL + "\""; + } + } + } + } + } catch (Throwable ex) { + log.error("Failed to inspect " + this.userSpecifiedConfigDir + File.separator + "log4j2.xml", ex); + } + if (prompt != null) { + System.out.println(prompt); + } } } - protected static boolean a = true; - public void shutdown() { log.trace(""); if (gRPCServerList != null && !gRPCServerList.isEmpty()) { diff --git a/src/main/java/org/summerboot/jexpress/boot/instrumentation/HealthMonitor.java b/src/main/java/org/summerboot/jexpress/boot/instrumentation/HealthMonitor.java index 69572e5..9537f83 100644 --- a/src/main/java/org/summerboot/jexpress/boot/instrumentation/HealthMonitor.java +++ b/src/main/java/org/summerboot/jexpress/boot/instrumentation/HealthMonitor.java @@ -15,11 +15,13 @@ */ package org.summerboot.jexpress.boot.instrumentation; +import com.google.inject.Injector; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.summerboot.jexpress.boot.BackOffice; import org.summerboot.jexpress.boot.BootConstant; import org.summerboot.jexpress.boot.annotation.Inspector; +import org.summerboot.jexpress.boot.annotation.Service; import org.summerboot.jexpress.boot.event.AppLifecycleListener; import org.summerboot.jexpress.nio.server.NioConfig; import org.summerboot.jexpress.nio.server.domain.Err; @@ -27,6 +29,7 @@ import org.summerboot.jexpress.util.BeanUtil; import java.util.HashSet; +import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; @@ -82,7 +85,7 @@ public static void registerDefaultHealthInspectors(Map defaultHe Object healthInspector = entry.getValue(); if (healthInspector instanceof HealthInspector) { registeredHealthInspectors.add((HealthInspector) healthInspector); - memo.append(BootConstant.BR).append("\t- @DefaultHealthInspector registered: ").append(name).append("=").append(healthInspector.getClass().getName()); + memo.append(BootConstant.BR).append("\t- @Inspector registered: ").append(name).append("=").append(healthInspector.getClass().getName()); } else { error = true; sb.append(BootConstant.BR).append("\tCoding Error: class ").append(healthInspector.getClass().getName()).append(" has annotation @").append(Inspector.class.getSimpleName()).append(", should implement ").append(HealthInspector.class.getName()); @@ -97,8 +100,9 @@ public static void registerDefaultHealthInspectors(Map defaultHe /** * use default inspectors */ - public static void inspect() { + public static int inspect() { registeredHealthInspectors.forEach(healthInspectorQueue::offer); + return registeredHealthInspectors.size(); } /** @@ -184,18 +188,19 @@ public static void inspect(HealthInspector... healthInspectors) { String inspectionReport; if (healthCheckAllPassed) { inspectionReport = "Current all health inspectors passed"; + setHealthStatus(healthCheckAllPassed, inspectionReport); } else { try { inspectionReport = BeanUtil.toJson(healthCheckFailedReport, true, true); } catch (Throwable ex) { inspectionReport = " toJson failed " + ex; } + setHealthStatus(healthCheckAllPassed, inspectionReport); long retryIndex = HealthInspector.retryIndex.get();// not being set yet - if (appLifecycleListener != null) { + if (appLifecycleListener != null && started) { appLifecycleListener.onHealthInspectionFailed(isHealthCheckSuccess, isServicePaused, retryIndex, inspectionIntervalSeconds); } } - setHealthStatus(healthCheckAllPassed, inspectionReport); } started = true; @@ -208,17 +213,57 @@ public static void inspect(HealthInspector... healthInspectors) { } while (keepRunning); }; - public static String start(boolean returnRsult) { + public static String start(boolean returnRsult, Injector guiceInjector) { + if (keepRunning) { + return "HealthMonitor is already running"; + } + StringBuilder memo = new StringBuilder(); + boolean hasUnregistered = false; + // 1. remove unused (via -use ) inspectors with @Service annotation + Iterator iterator = registeredHealthInspectors.iterator(); + while (iterator.hasNext()) { + HealthInspector healthInspector = iterator.next(); + Service serviceAnnotation = healthInspector.getClass().getAnnotation(Service.class); + if (serviceAnnotation != null) { + Class c = healthInspector.getClass(); + boolean usedByTag = false; + Class[] bindingClasses = serviceAnnotation.binding(); + if (bindingClasses == null || bindingClasses.length < 1) { + bindingClasses = c.getInterfaces(); + } + for (Class bindingClasse : bindingClasses) { + Object o = guiceInjector.getInstance(bindingClasse); + if (o.getClass().equals(c)) { + usedByTag = true; + break; + } + } + if (!usedByTag) { + hasUnregistered = true; + memo.append(BootConstant.BR).append("\t- @Inspector unused due to CLI argument -" + BootConstant.CLI_USE_IMPL + " : ").append(c.getName()); + iterator.remove(); + } + } + } + if (hasUnregistered) { + log.warn(memo); + } + + // 2. start health monitor sync to return result String ret = null; if (returnRsult) { // start sync to get result - inspect(); + int size = inspect(); keepRunning = false; - AsyncTask.run(); - ret = buildMessage(); + if (size > 0) { + AsyncTask.run(); + ret = buildMessage(); + } else { + ret = "No health inspectors registered"; + } } - // start async in background + // 3. start async in background keepRunning = true; if (!isServiceAvailable()) { inspect(); diff --git a/src/main/java/org/summerboot/jexpress/integration/smtp/BootPostOfficeImpl.java b/src/main/java/org/summerboot/jexpress/integration/smtp/BootPostOfficeImpl.java index 79f6cfd..bb643ab 100644 --- a/src/main/java/org/summerboot/jexpress/integration/smtp/BootPostOfficeImpl.java +++ b/src/main/java/org/summerboot/jexpress/integration/smtp/BootPostOfficeImpl.java @@ -94,36 +94,20 @@ public void sendAlertSync(Collection to, final String title, final Strin * @param async */ protected void sendAlert(Collection to, final String title, final String content, final Throwable cause, boolean debouncing, boolean async) { - if (to == null || to.isEmpty()) { - //log.warn(() -> "unknown recipient: " + title + "\n" + _content); - return; - } - Runnable postman = () -> { - if (debouncing) { - String key = title; - Throwable rootCause = ExceptionUtils.getRootCause(cause); - if (rootCause == null) { - rootCause = cause; - } - if (rootCause != null) { - key = key + rootCause.getClass().getName(); - } - if (debounced(key, SMTPClientConfig.cfg.getEmailAlertDebouncingIntervalMinutes())) { - return; - } + if (debouncing) { + String key = title; + Throwable rootCause = ExceptionUtils.getRootCause(cause); + if (rootCause == null) { + rootCause = cause; } - Email email = Email.compose(updateAlertTitle(title), updateAlertContent(content, cause), Email.Format.text).to(to); - try { - email.send(SMTPClientConfig.cfg.getMailSession()); - } catch (Throwable ex) { - log.fatal("Failed to send email: " + ExceptionUtils.getRootCause(ex).toString()); + if (rootCause != null) { + key = key + rootCause.getClass().getName(); + } + if (debounced(key, SMTPClientConfig.cfg.getEmailAlertDebouncingIntervalMinutes())) { + return; } - }; - if (async) { - BackOffice.execute(postman); - } else { - postman.run(); } + sendEmail(to, updateAlertTitle(title), updateAlertContent(content, cause), false, async); } @Override @@ -137,28 +121,29 @@ public boolean sendEmailSync(Collection to, String title, String content } protected boolean sendEmail(Collection to, String title, String content, boolean isHTMLFormat, boolean async) { - boolean success = false; Email email = Email.compose(title, content, isHTMLFormat ? Email.Format.html : Email.Format.text).to(to); - if (to != null && !to.isEmpty()) { - try { - if (async) { - Runnable postman = () -> { - try { - email.send(SMTPClientConfig.cfg.getMailSession()); - } catch (Throwable ex) { - log.fatal("Failed to send email: " + ExceptionUtils.getRootCause(ex).toString()); - } - }; - BackOffice.execute(postman); - } else { - email.send(SMTPClientConfig.cfg.getMailSession()); - } - success = true; - } catch (Throwable ex) { - log.fatal("Failed to send email: " + ExceptionUtils.getRootCause(ex).toString()); + if (to == null || to.isEmpty()) { + log.warn(() -> "unknown recipient: " + email); + return false; + } + + boolean success = false; + try { + if (async) { + Runnable postman = () -> { + try { + email.send(SMTPClientConfig.cfg.getMailSession()); + } catch (Throwable ex) { + log.fatal("Failed to send email: " + ExceptionUtils.getRootCause(ex).toString()); + } + }; + BackOffice.execute(postman); + } else { + email.send(SMTPClientConfig.cfg.getMailSession()); } - } else { - log.error(() -> "unknown recipient: " + email); + success = true; + } catch (Throwable ex) { + log.fatal("Failed to send email: " + ExceptionUtils.getRootCause(ex).toString()); } return success; } diff --git a/src/main/java/org/summerboot/jexpress/nio/server/NioServer.java b/src/main/java/org/summerboot/jexpress/nio/server/NioServer.java index 034d8a2..68d8288 100644 --- a/src/main/java/org/summerboot/jexpress/nio/server/NioServer.java +++ b/src/main/java/org/summerboot/jexpress/nio/server/NioServer.java @@ -42,7 +42,6 @@ import org.summerboot.jexpress.boot.BackOffice; import org.summerboot.jexpress.boot.BootConstant; import org.summerboot.jexpress.boot.config.NamedDefaultThreadFactory; -import org.summerboot.jexpress.boot.instrumentation.HealthMonitor; import org.summerboot.jexpress.boot.instrumentation.NIOStatusListener; import javax.net.ssl.KeyManagerFactory; @@ -57,6 +56,7 @@ import java.util.concurrent.ThreadFactory; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicReference; /** @@ -218,6 +218,7 @@ public void bind(NioConfig nioCfg, StringBuilder memo) throws InterruptedExcepti final AtomicReference lastBizHitRef = new AtomicReference<>(); lastBizHitRef.set(-1L); if (nioListener != null || log.isDebugEnabled()) { + final AtomicLong lastChecksum = new AtomicLong(0); int interval = 1; QPS_SERVICE = Executors.newSingleThreadScheduledExecutor(new NamedDefaultThreadFactory("NIO.QPS_SERVICE")); QPS_SERVICE.scheduleAtFixedRate(() -> { @@ -228,26 +229,29 @@ public void bind(NioConfig nioCfg, StringBuilder memo) throws InterruptedExcepti } long bizHit = NioCounter.COUNTER_BIZ_HIT.get(); //if (lastBizHit[0] == bizHit && !servicePaused) { - if (lastBizHitRef.get() == bizHit && !HealthMonitor.isServicePaused()) { - return; - } +// if (lastBizHitRef.get() == bizHit && !HealthMonitor.isServicePaused()) { +// return; +// } //lastBizHit[0] = bizHit; lastBizHitRef.set(bizHit); ThreadPoolExecutor tpe = nioCfg.getBizExecutor(); int active = tpe.getActiveCount(); int queue = tpe.getQueue().size(); long activeChannel = NioCounter.COUNTER_ACTIVE_CHANNEL.get(); - if (hps > 0 || tps > 0 || active > 0 || queue > 0 || activeChannel > 0) { - long totalChannel = NioCounter.COUNTER_TOTAL_CHANNEL.get(); - long pool = tpe.getPoolSize(); - int core = tpe.getCorePoolSize(); - //int queueRemainingCapacity = tpe.getQueue().remainingCapacity(); - long max = tpe.getMaximumPoolSize(); - long largest = tpe.getLargestPoolSize(); - long task = tpe.getTaskCount(); - long completed = tpe.getCompletedTaskCount(); - long pingHit = NioCounter.COUNTER_PING_HIT.get(); - long totalHit = bizHit + pingHit; + //if (hps > 0 || tps > 0 || active > 0 || queue > 0 || activeChannel > 0) { + long totalChannel = NioCounter.COUNTER_TOTAL_CHANNEL.get(); + long pool = tpe.getPoolSize(); + int core = tpe.getCorePoolSize(); + //int queueRemainingCapacity = tpe.getQueue().remainingCapacity(); + long max = tpe.getMaximumPoolSize(); + long largest = tpe.getLargestPoolSize(); + long task = tpe.getTaskCount(); + long completed = tpe.getCompletedTaskCount(); + long pingHit = NioCounter.COUNTER_PING_HIT.get(); + long totalHit = bizHit + pingHit; + long checksum = hps + tps + active + queue + activeChannel + totalChannel + totalHit + bizHit + task + completed + active + pool + core + max + largest; + if (lastChecksum.get() != checksum) { + lastChecksum.set(checksum); log.debug(() -> "hps=" + hps + ", tps=" + tps + ", activeChannel=" + activeChannel + ", totalChannel=" + totalChannel + ", totalHit=" + totalHit + " (ping" + pingHit + " + biz" + bizHit + "), task=" + task + ", completed=" + completed + ", queue=" + queue + ", active=" + active + ", pool=" + pool + ", core=" + core + ", max=" + max + ", largest=" + largest); if (nioListener != null) { nioListener.onNIOAccessReportUpdate(appInfo, hps, tps, totalHit, pingHit, bizHit, totalChannel, activeChannel, task, completed, queue, active, pool, core, max, largest); diff --git a/src/main/java/org/summerboot/jexpress/security/JwtUtil.java b/src/main/java/org/summerboot/jexpress/security/JwtUtil.java index 0d6508c..21d2f6c 100644 --- a/src/main/java/org/summerboot/jexpress/security/JwtUtil.java +++ b/src/main/java/org/summerboot/jexpress/security/JwtUtil.java @@ -175,20 +175,9 @@ public static String createJWT(Key privateKey, int ttlSeconds, String id, String } public static String createJWT(Key privateKey, JwtBuilder builder, Duration ttl) { - //0. We will sign our JWT with our ApiKey secret - //byte[] apiKeySecretBytes = parseSigningKey(jwtRootSigningKeyString); - //The JWT signature algorithm we will be using to sign the token - //Key signingKey = new SecretKeySpec(jwtSigningKey, signatureAlgorithm.getJcaName()); - - //1. set ecpire time setJwtExpireTime(builder, ttl); - - //2. Let's set the JWT Claims - builder.issuedAt(new Date()); - //builder.signWith(signatureAlgorithm, privateKey); - builder.signWith(privateKey); - - //3. Builds the JWT and serializes it to a compact, URL-safe string + builder.issuedAt(new Date()).signWith(privateKey); + // Builds the JWT and serializes it to a compact, URL-safe string return builder.compact(); } diff --git a/src/main/resources/org/summerboot/jexpress/template/log4j2.xml.temp b/src/main/resources/org/summerboot/jexpress/template/log4j2.xml.temp index 28c7dc4..e0f6d0d 100644 --- a/src/main/resources/org/summerboot/jexpress/template/log4j2.xml.temp +++ b/src/main/resources/org/summerboot/jexpress/template/log4j2.xml.temp @@ -10,7 +10,7 @@ - + @@ -55,6 +55,18 @@ + + + + + + + From edfe677033f2d0a19a62ac0f2a20bb4439806f33 Mon Sep 17 00:00:00 2001 From: Summer Boot Framework Date: Tue, 20 Aug 2024 15:11:46 -0400 Subject: [PATCH 09/19] version 2.5.0 --- pom.xml | 2 +- src/main/java/org/summerboot/jexpress/boot/BootConstant.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 24e9b2e..0343343 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ 4.0.0 org.summerboot jexpress - 2.4.11-SNAPSHOT + 2.5.0-SNAPSHOT jar Summer Boot jExpress Summer Boot jExpress focuses on solving non-functional and operational maintainability requirements, diff --git a/src/main/java/org/summerboot/jexpress/boot/BootConstant.java b/src/main/java/org/summerboot/jexpress/boot/BootConstant.java index 5ab36c9..4b113d3 100644 --- a/src/main/java/org/summerboot/jexpress/boot/BootConstant.java +++ b/src/main/java/org/summerboot/jexpress/boot/BootConstant.java @@ -25,7 +25,7 @@ public interface BootConstant { String APP_ID = String.format("%06d", new Random().nextInt(999999)); //version - String VERSION = "jExpress 2.4.11"; + String VERSION = "jExpress 2.5.0"; String JEXPRESS_PACKAGE_NAME = "org.summerboot.jexpress"; String DEFAULT_ADMIN_MM = "changeit"; From 491e8226297850eff7a10e86aaefa4f2b836812f Mon Sep 17 00:00:00 2001 From: Summer Boot Framework Date: Sun, 25 Aug 2024 12:25:28 -0400 Subject: [PATCH 10/19] refactoring --- pom.xml | 6 +- .../jexpress/boot/BootConstant.java | 2 +- .../nio/server/ws/rs/BootController.java | 57 +++++++++++++++++++ 3 files changed, 61 insertions(+), 4 deletions(-) diff --git a/pom.xml b/pom.xml index 0343343..7b5dee2 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ 4.0.0 org.summerboot jexpress - 2.5.0-SNAPSHOT + 2.4.11-SNAPSHOT jar Summer Boot jExpress Summer Boot jExpress focuses on solving non-functional and operational maintainability requirements, @@ -207,7 +207,7 @@ 4.1.112.Final - 2.0.65.Final + 2.0.66.Final 1.66.0 33.3.0-jre @@ -239,7 +239,7 @@ 5.1.0 - 5.1.4 + 5.1.5 2.5.0-rc1 1.2.5 diff --git a/src/main/java/org/summerboot/jexpress/boot/BootConstant.java b/src/main/java/org/summerboot/jexpress/boot/BootConstant.java index 4b113d3..5ab36c9 100644 --- a/src/main/java/org/summerboot/jexpress/boot/BootConstant.java +++ b/src/main/java/org/summerboot/jexpress/boot/BootConstant.java @@ -25,7 +25,7 @@ public interface BootConstant { String APP_ID = String.format("%06d", new Random().nextInt(999999)); //version - String VERSION = "jExpress 2.5.0"; + String VERSION = "jExpress 2.4.11"; String JEXPRESS_PACKAGE_NAME = "org.summerboot.jexpress"; String DEFAULT_ADMIN_MM = "changeit"; 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 3c77479..ac42e0c 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 @@ -103,9 +103,12 @@ abstract public class BootController extends PingController { public static final String DESC_401 = "Unauthorized. The client should sign-on again, but not retransmit the same request again"; public static final String DESC_403 = "Client has no permission. Client should not retransmit the same request again."; public static final String DESC_404 = "Not Found. The client should not retransmit the same request again."; + private static final String DESC_429 = "Too Many Requests"; public static final String DESC_500 = "All other 5xx code. Server errors due to unexpected failures. The client can continue and try again with the request without modification."; public static final String DESC_501 = "Not Implemented. The client can continue and try again with the request without modification."; public static final String DESC_503 = "Service Unavailable. The client can continue and try again with the request without modification."; + private static final String DESC_504 = "Gateway Timeout. The client can continue and try again with the request without modification."; + private static final String DESC_507 = "Insufficient Storage. The client should contact the system administrator. Do not try the request again."; @Inject protected AuthTokenCache authTokenCache; @@ -135,6 +138,9 @@ abstract public class BootController extends PingController { @ApiResponse(responseCode = "404", description = DESC_404, content = @Content(schema = @Schema(implementation = ServiceError.class)) ), + @ApiResponse(responseCode = "429", description = DESC_429, + content = @Content(schema = @Schema(implementation = ServiceError.class)) + ), @ApiResponse(responseCode = "500", description = DESC_500, content = @Content(schema = @Schema(implementation = ServiceError.class)) ), @@ -143,6 +149,12 @@ abstract public class BootController extends PingController { ), @ApiResponse(responseCode = "503", description = DESC_503, content = @Content(schema = @Schema(implementation = ServiceError.class)) + ), + @ApiResponse(responseCode = "504", description = DESC_504, + content = @Content(schema = @Schema(implementation = ServiceError.class)) + ), + @ApiResponse(responseCode = "507", description = DESC_507, + content = @Content(schema = @Schema(implementation = ServiceError.class)) ) }, security = { @@ -186,6 +198,9 @@ protected String getVersion() { @ApiResponse(responseCode = "404", description = DESC_404, content = @Content(schema = @Schema(implementation = ServiceError.class)) ), + @ApiResponse(responseCode = "429", description = DESC_429, + content = @Content(schema = @Schema(implementation = ServiceError.class)) + ), @ApiResponse(responseCode = "500", description = DESC_500, content = @Content(schema = @Schema(implementation = ServiceError.class)) ), @@ -194,6 +209,12 @@ protected String getVersion() { ), @ApiResponse(responseCode = "503", description = DESC_503, content = @Content(schema = @Schema(implementation = ServiceError.class)) + ), + @ApiResponse(responseCode = "504", description = DESC_504, + content = @Content(schema = @Schema(implementation = ServiceError.class)) + ), + @ApiResponse(responseCode = "507", description = DESC_507, + content = @Content(schema = @Schema(implementation = ServiceError.class)) ) }, security = { @@ -227,6 +248,9 @@ public void inspect(@Parameter(hidden = true) final ServiceContext context) { @ApiResponse(responseCode = "404", description = DESC_404, content = @Content(schema = @Schema(implementation = ServiceError.class)) ), + @ApiResponse(responseCode = "429", description = DESC_429, + content = @Content(schema = @Schema(implementation = ServiceError.class)) + ), @ApiResponse(responseCode = "500", description = DESC_500, content = @Content(schema = @Schema(implementation = ServiceError.class)) ), @@ -235,6 +259,12 @@ public void inspect(@Parameter(hidden = true) final ServiceContext context) { ), @ApiResponse(responseCode = "503", description = DESC_503, content = @Content(schema = @Schema(implementation = ServiceError.class)) + ), + @ApiResponse(responseCode = "504", description = DESC_504, + content = @Content(schema = @Schema(implementation = ServiceError.class)) + ), + @ApiResponse(responseCode = "507", description = DESC_507, + content = @Content(schema = @Schema(implementation = ServiceError.class)) ) }, security = { @@ -273,6 +303,9 @@ public void pause(@QueryParam("pause") boolean pause, @Parameter(hidden = true) @ApiResponse(responseCode = "404", description = DESC_404, content = @Content(schema = @Schema(implementation = ServiceError.class)) ), + @ApiResponse(responseCode = "429", description = DESC_429, + content = @Content(schema = @Schema(implementation = ServiceError.class)) + ), @ApiResponse(responseCode = "500", description = DESC_500, content = @Content(schema = @Schema(implementation = ServiceError.class)) ), @@ -281,6 +314,12 @@ public void pause(@QueryParam("pause") boolean pause, @Parameter(hidden = true) ), @ApiResponse(responseCode = "503", description = DESC_503, content = @Content(schema = @Schema(implementation = ServiceError.class)) + ), + @ApiResponse(responseCode = "504", description = DESC_504, + content = @Content(schema = @Schema(implementation = ServiceError.class)) + ), + @ApiResponse(responseCode = "507", description = DESC_507, + content = @Content(schema = @Schema(implementation = ServiceError.class)) ) } ) @@ -319,6 +358,9 @@ public Caller longin_jSecurityCheck(@Parameter(required = true) @Nonnull @FormPa @ApiResponse(responseCode = "404", description = DESC_404, content = @Content(schema = @Schema(implementation = ServiceError.class)) ), + @ApiResponse(responseCode = "429", description = DESC_429, + content = @Content(schema = @Schema(implementation = ServiceError.class)) + ), @ApiResponse(responseCode = "500", description = DESC_500, content = @Content(schema = @Schema(implementation = ServiceError.class)) ), @@ -327,6 +369,12 @@ public Caller longin_jSecurityCheck(@Parameter(required = true) @Nonnull @FormPa ), @ApiResponse(responseCode = "503", description = DESC_503, content = @Content(schema = @Schema(implementation = ServiceError.class)) + ), + @ApiResponse(responseCode = "504", description = DESC_504, + content = @Content(schema = @Schema(implementation = ServiceError.class)) + ), + @ApiResponse(responseCode = "507", description = DESC_507, + content = @Content(schema = @Schema(implementation = ServiceError.class)) ) } ) @@ -373,6 +421,9 @@ public static Caller login(Authenticator auth, String userId, String password, S @ApiResponse(responseCode = "404", description = DESC_404, content = @Content(schema = @Schema(implementation = ServiceError.class)) ), + @ApiResponse(responseCode = "429", description = DESC_429, + content = @Content(schema = @Schema(implementation = ServiceError.class)) + ), @ApiResponse(responseCode = "500", description = DESC_500, content = @Content(schema = @Schema(implementation = ServiceError.class)) ), @@ -381,6 +432,12 @@ public static Caller login(Authenticator auth, String userId, String password, S ), @ApiResponse(responseCode = "503", description = DESC_503, content = @Content(schema = @Schema(implementation = ServiceError.class)) + ), + @ApiResponse(responseCode = "504", description = DESC_504, + content = @Content(schema = @Schema(implementation = ServiceError.class)) + ), + @ApiResponse(responseCode = "507", description = DESC_507, + content = @Content(schema = @Schema(implementation = ServiceError.class)) ) }, security = { From 8bb411ac9dcc22a06e4e33beabd46a9bfd7ba106 Mon Sep 17 00:00:00 2001 From: Summer Boot Framework Date: Tue, 27 Aug 2024 20:37:48 -0400 Subject: [PATCH 11/19] refactor gRPC status logging --- .../jexpress/nio/grpc/GRPCServer.java | 50 ++++++++++--------- .../nio/server/ws/rs/BootController.java | 6 +-- 2 files changed, 29 insertions(+), 27 deletions(-) diff --git a/src/main/java/org/summerboot/jexpress/nio/grpc/GRPCServer.java b/src/main/java/org/summerboot/jexpress/nio/grpc/GRPCServer.java index 36e96df..98e5e87 100644 --- a/src/main/java/org/summerboot/jexpress/nio/grpc/GRPCServer.java +++ b/src/main/java/org/summerboot/jexpress/nio/grpc/GRPCServer.java @@ -36,6 +36,7 @@ import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicReference; /** @@ -45,10 +46,6 @@ public class GRPCServer { protected static final Logger log = LogManager.getLogger(GRPCServer.class.getName()); - // @Inject -// protected NIOStatusListener nioListener; -// @Inject -// protected ServerInterceptor serverInterceptor; protected final String bindingAddr; protected final int port; protected final ServerCredentials serverCredentials; @@ -58,7 +55,6 @@ public class GRPCServer { protected Server server = null; protected ScheduledExecutorService statusReporter = null; - //protected ThreadPoolExecutor tpe = null; protected boolean servicePaused = false; protected final GRPCServiceCounter serviceCounter = new GRPCServiceCounter(); @@ -122,7 +118,8 @@ public GRPCServer(String bindingAddr, int port, KeyManagerFactory kmf, TrustMana if (serverInterceptor != null) { serverBuilder.intercept(serverInterceptor); } - initThreadPool(tpe, nioListener); + serverBuilder.executor(tpe); + initThreadPool(tpe, nioListener, bindingAddr, port); } protected ServerCredentials initTLS(KeyManagerFactory kmf, TrustManagerFactory tmf) { @@ -142,25 +139,24 @@ protected ServerCredentials initTLS(KeyManagerFactory kmf, TrustManagerFactory t * @param nioListener * @return */ - protected GRPCServiceCounter initThreadPool(ThreadPoolExecutor tpe, NIOStatusListener nioListener) { - serverBuilder.executor(tpe); - + protected GRPCServiceCounter initThreadPool(ThreadPoolExecutor tpe, NIOStatusListener nioListener, String bindingAddr, int port) { int interval = 1; final AtomicReference lastBizHitRef = new AtomicReference<>(); lastBizHitRef.set(-1L); long totalChannel = -1;//NioServerContext.COUNTER_TOTAL_CHANNEL.get(); long activeChannel = -1;//NioServerContext.COUNTER_ACTIVE_CHANNEL.get(); ScheduledExecutorService old2 = statusReporter; - statusReporter = Executors.newSingleThreadScheduledExecutor(new NamedDefaultThreadFactory("gRPC.QPS_SERVICE")); + statusReporter = Executors.newSingleThreadScheduledExecutor(new NamedDefaultThreadFactory("gRPC.QPS_SERVICE@" + bindingAddr + ":" + port)); + final AtomicLong lastChecksum = new AtomicLong(0); + String appInfo = "gRPC@" + BootConstant.VERSION + " " + BootConstant.PID; statusReporter.scheduleAtFixedRate(() -> { if (nioListener == null && !log.isDebugEnabled()) { return; } long bizHit = serviceCounter.getBiz(); - //if (lastBizHit[0] == bizHit && !servicePaused) { - if (lastBizHitRef.get() == bizHit && !servicePaused) { - return; - } +// if (lastBizHitRef.get() == bizHit && !servicePaused) { +// return; +// } lastBizHitRef.set(bizHit); long hps = serviceCounter.getHitAndReset(); long tps = serviceCounter.getProcessedAndReset(); @@ -169,22 +165,28 @@ protected GRPCServiceCounter initThreadPool(ThreadPoolExecutor tpe, NIOStatusLis int active = tpe.getActiveCount(); int queue = tpe.getQueue().size(); - if (hps > 0 || tps > 0 || active > 0 || queue > 0 || servicePaused) { + //if (hps > 0 || tps > 0 || active > 0 || queue > 0 || servicePaused) { // long totalChannel = NioServerContext.COUNTER_TOTAL_CHANNEL.get(); // long activeChannel = NioServerContext.COUNTER_ACTIVE_CHANNEL.get(); - long pool = tpe.getPoolSize(); - int core = tpe.getCorePoolSize(); - //int queueRemainingCapacity = tpe.getQueue().remainingCapacity(); - long max = tpe.getMaximumPoolSize(); - long largest = tpe.getLargestPoolSize(); - long task = tpe.getTaskCount(); - long completed = tpe.getCompletedTaskCount(); - log.debug(() -> "hps=" + hps + ", tps=" + tps + ", totalHit=" + totalHit + " (ping " + pingHit + " + biz " + bizHit + "), queue=" + queue + ", active=" + active + ", pool=" + pool + ", core=" + core + ", max=" + max + ", largest=" + largest + ", task=" + task + ", completed=" + completed + ", activeChannel=" + activeChannel + ", totalChannel=" + totalChannel); + long pool = tpe.getPoolSize(); + int core = tpe.getCorePoolSize(); + //int queueRemainingCapacity = tpe.getQueue().remainingCapacity(); + long max = tpe.getMaximumPoolSize(); + long largest = tpe.getLargestPoolSize(); + long task = tpe.getTaskCount(); + long completed = tpe.getCompletedTaskCount(); + //long checksum = hps + tps + active + queue + activeChannel + totalChannel + totalHit + bizHit + task + completed + active + pool + core + max + largest; + long checksum = hps + tps + active + queue + totalHit + bizHit + /*task + completed +*/ active + pool + core + max + largest; + if (lastChecksum.get() != checksum) { + lastChecksum.set(checksum); + //log.debug(() -> "hps=" + hps + ", tps=" + tps + ", activeChannel=" + activeChannel + ", totalChannel=" + totalChannel + ", totalHit=" + totalHit + " (ping" + pingHit + " + biz" + bizHit + "), task=" + task + ", completed=" + completed + ", queue=" + queue + ", active=" + active + ", pool=" + pool + ", core=" + core + ", max=" + max + ", largest=" + largest); + log.debug(() -> "hps=" + hps + ", tps=" + tps + ", totalHit=" + totalHit + " (ping" + pingHit + " + biz" + bizHit + "), task=" + task + ", completed=" + completed + ", queue=" + queue + ", active=" + active + ", pool=" + pool + ", core=" + core + ", max=" + max + ", largest=" + largest); if (nioListener != null) { - nioListener.onNIOAccessReportUpdate("gRPC", hps, tps, totalHit, pingHit, bizHit, totalChannel, activeChannel, task, completed, queue, active, pool, core, max, largest); + nioListener.onNIOAccessReportUpdate(appInfo, hps, tps, totalHit, pingHit, bizHit, totalChannel, activeChannel, task, completed, queue, active, pool, core, max, largest); //listener.onUpdate(data);//bad performance } } + //} }, 0, interval, TimeUnit.SECONDS); if (old2 != null) { old2.shutdownNow(); 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 ac42e0c..42ed13f 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 @@ -103,12 +103,12 @@ abstract public class BootController extends PingController { public static final String DESC_401 = "Unauthorized. The client should sign-on again, but not retransmit the same request again"; public static final String DESC_403 = "Client has no permission. Client should not retransmit the same request again."; public static final String DESC_404 = "Not Found. The client should not retransmit the same request again."; - private static final String DESC_429 = "Too Many Requests"; + public static final String DESC_429 = "Too Many Requests"; public static final String DESC_500 = "All other 5xx code. Server errors due to unexpected failures. The client can continue and try again with the request without modification."; public static final String DESC_501 = "Not Implemented. The client can continue and try again with the request without modification."; public static final String DESC_503 = "Service Unavailable. The client can continue and try again with the request without modification."; - private static final String DESC_504 = "Gateway Timeout. The client can continue and try again with the request without modification."; - private static final String DESC_507 = "Insufficient Storage. The client should contact the system administrator. Do not try the request again."; + public static final String DESC_504 = "Gateway Timeout. The client can continue and try again with the request without modification."; + public static final String DESC_507 = "Insufficient Storage. The client should contact the system administrator. Do not try the request again."; @Inject protected AuthTokenCache authTokenCache; From 7c068133f1f21c4c592fb7f81dfb147cc9c327bc Mon Sep 17 00:00:00 2001 From: Summer Boot Framework Date: Wed, 28 Aug 2024 21:48:11 -0400 Subject: [PATCH 12/19] refactoring grpc client --- .../jexpress/nio/grpc/GRPCClient.java | 25 ++++++----- .../jexpress/nio/grpc/GRPCClientConfig.java | 28 ++++++++----- .../jexpress/nio/grpc/GRPCServer.java | 42 +------------------ .../security/auth/BootAuthenticator.java | 3 ++ 4 files changed, 36 insertions(+), 62 deletions(-) diff --git a/src/main/java/org/summerboot/jexpress/nio/grpc/GRPCClient.java b/src/main/java/org/summerboot/jexpress/nio/grpc/GRPCClient.java index 7faf184..6233077 100644 --- a/src/main/java/org/summerboot/jexpress/nio/grpc/GRPCClient.java +++ b/src/main/java/org/summerboot/jexpress/nio/grpc/GRPCClient.java @@ -33,8 +33,6 @@ import javax.net.ssl.SSLException; import javax.net.ssl.TrustManagerFactory; import java.net.URI; -import java.util.ArrayList; -import java.util.List; /** * @param @@ -57,7 +55,7 @@ public String getValue() { } - protected static final List NR_Providers = new ArrayList(); + //protected static final List NR_Providers = new ArrayList(); /** * @param nameResolverProvider for client side load balancing @@ -75,7 +73,7 @@ public String getValue() { public static NettyChannelBuilder getNettyChannelBuilder(NameResolverProvider nameResolverProvider, LoadBalancingPolicy loadBalancingPolicy, URI uri, @Nullable KeyManagerFactory keyManagerFactory, @Nullable TrustManagerFactory trustManagerFactory, @Nullable String overrideAuthority, @Nullable Iterable ciphers, @Nullable String... tlsVersionProtocols) throws SSLException { final NettyChannelBuilder channelBuilder; - String target = uri.toString();//"grpcs://"+uri.getAuthority()+"/service";// "grpcs:///" + //String target = uri.toString();//"grpcs://"+uri.getAuthority()+"/service";// "grpcs:///" switch (uri.getScheme()) { case "unix": //https://github.com/grpc/grpc-java/issues/1539 channelBuilder = NettyChannelBuilder.forAddress(new DomainSocketAddress(uri.getPath())) @@ -85,14 +83,19 @@ public static NettyChannelBuilder getNettyChannelBuilder(NameResolverProvider na break; default: if (nameResolverProvider != null) { - NameResolverRegistry nameResolverRegistry = NameResolverRegistry.getDefaultRegistry(); - for (NameResolverProvider nrp : NR_Providers) { - nameResolverRegistry.deregister(nrp); - } - nameResolverRegistry.register(nameResolverProvider);// use client side load balancing - NR_Providers.add(nameResolverProvider); + //NameResolverRegistry nameResolverRegistry = new NameResolverRegistry(); + NameResolverRegistry nameResolverRegistry = NameResolverRegistry.getDefaultRegistry();// this is a singleton instance in new API to replace deprecated channelBuilder.nameResolverFactory(nameResolverRegistry.asFactory()); + nameResolverRegistry.register(nameResolverProvider);// use client side load balancing +// for (NameResolverProvider nrp : NR_Providers) { +// nameResolverRegistry.deregister(nrp); +// } +// NR_Providers.add(nameResolverProvider); String policy = loadBalancingPolicy.getValue(); - channelBuilder = NettyChannelBuilder.forTarget(target).defaultLoadBalancingPolicy(policy); + String target = uri.toString();//"grpcs://"+uri.getAuthority()+"/service";// "grpcs:///" nameResolverProvider.getDefaultScheme() + target = nameResolverProvider.getDefaultScheme() + ":///"; + channelBuilder = NettyChannelBuilder.forTarget(target) + .defaultLoadBalancingPolicy(policy); + //.nameResolverFactory(nameResolverRegistry.asFactory());deprecated use target to distinguish different gRPC services } else { String host = uri.getHost(); int port = uri.getPort(); diff --git a/src/main/java/org/summerboot/jexpress/nio/grpc/GRPCClientConfig.java b/src/main/java/org/summerboot/jexpress/nio/grpc/GRPCClientConfig.java index 98b0a2b..369b9eb 100644 --- a/src/main/java/org/summerboot/jexpress/nio/grpc/GRPCClientConfig.java +++ b/src/main/java/org/summerboot/jexpress/nio/grpc/GRPCClientConfig.java @@ -61,18 +61,20 @@ protected GRPCClientConfig() { example = "localhost:8424, remotehost:8425, 127.0.0.1:8426") @Config(key = ID + ".LoadBalancing.servers", predefinedValue = "0.0.0.0:8424, 0.0.0.0:8425", required = false) protected volatile List loadBalancingServers; + @Config(key = ID + ".LoadBalancing.schema", defaultValue = "grpc", desc = "In case you have more than one gRPC client needs to connect to different gRPC services, you can set this to distinguish them") + protected volatile String loadBalancingTargetSchema = "grpc"; @Config(key = ID + ".LoadBalancing.policy", defaultValue = "ROUND_ROBIN", desc = "available options: ROUND_ROBIN, PICK_FIRST") protected volatile GRPCClient.LoadBalancingPolicy loadBalancingPolicy; protected volatile NameResolverProvider nameResolverProvider; - //1. gRPC connection - @Config(key = ID + ".target.url", defaultValue = "grpc:///", - desc = "grpc:///\n" - + "grpc://127.0.0.1:8424\n" - + "unix:/tmp/grpcsrver.socket") - protected volatile URI uri; +// //1. gRPC connection +// @Config(key = ID + ".target.url", defaultValue = "grpc:///", +// desc = "grpc:///\n" +// + "grpc://127.0.0.1:8424\n" +// + "unix:/tmp/grpcsrver.socket") +// protected volatile URI uri; @Config(key = ID + ".ssl.Protocols", defaultValue = "TLSv1.3")// "TLSv1.2, TLSv1.3" protected String[] sslProtocols; @@ -134,8 +136,9 @@ protected void preLoad(File cfgFile, boolean isReal, ConfigUtil helper, Properti @Override protected void loadCustomizedConfigs(File cfgFile, boolean isReal, ConfigUtil helper, Properties props) throws IOException { if (loadBalancingServers != null && !loadBalancingServers.isEmpty()) { - nameResolverProvider = new BootLoadBalancerProvider(uri.getScheme(), loadBalancingServers); + nameResolverProvider = new BootLoadBalancerProvider(loadBalancingTargetSchema, loadBalancingServers); } + URI uri = null;//new URI("grpc:///"); channelBuilder = GRPCClient.getNettyChannelBuilder(nameResolverProvider, loadBalancingPolicy, uri, kmf, tmf, overrideAuthority, ciphers, sslProtocols); } @@ -147,6 +150,10 @@ public List getLoadBalancingServers() { return loadBalancingServers; } + public String getLoadBalancingTargetSchema() { + return loadBalancingTargetSchema; + } + public GRPCClient.LoadBalancingPolicy getLoadBalancingPolicy() { return loadBalancingPolicy; } @@ -155,9 +162,10 @@ public NameResolverProvider getNameResolverProvider() { return nameResolverProvider; } - public URI getUri() { - return uri; - } + +// public URI getUri() { +// return uri; +// } public String[] getSslProtocols() { return sslProtocols; diff --git a/src/main/java/org/summerboot/jexpress/nio/grpc/GRPCServer.java b/src/main/java/org/summerboot/jexpress/nio/grpc/GRPCServer.java index 98e5e87..7482bdc 100644 --- a/src/main/java/org/summerboot/jexpress/nio/grpc/GRPCServer.java +++ b/src/main/java/org/summerboot/jexpress/nio/grpc/GRPCServer.java @@ -55,7 +55,7 @@ public class GRPCServer { protected Server server = null; protected ScheduledExecutorService statusReporter = null; - protected boolean servicePaused = false; + //protected boolean servicePaused = false; protected final GRPCServiceCounter serviceCounter = new GRPCServiceCounter(); public ServerBuilder getServerBuilder() { @@ -65,46 +65,6 @@ public ServerBuilder getServerBuilder() { public GRPCServiceCounter getServiceCounter() { return serviceCounter; } -// public GRPCServer(String bindingAddr, int port, KeyManagerFactory kmf, TrustManagerFactory tmf) { -// this(bindingAddr, port, initTLS(kmf, tmf)); -// } -// -// public GRPCServer(String bindingAddr, int port, ServerCredentials serverCredentials) { -// this.bindingAddr = bindingAddr; -// this.port = port; -// this.serverCredentials = serverCredentials; -// if (serverCredentials == null) { -// serverBuilder = NettyServerBuilder.forAddress(new InetSocketAddress(bindingAddr, port)); -// } else { -// serverBuilder = Grpc.newServerBuilderForPort(port, serverCredentials); -// } -// if (serverInterceptor != null) { -// serverBuilder.intercept(serverInterceptor); -// } -// //serverBuilder.executor(tpe) -// //AbstractImplBase implBase = -// //serverBuilder.addService(implBase); -// } -// public ServerInterceptor getServerInterceptor() { -// return serverInterceptor; -// } -// -// public void setContext(SummerRunner.RunnerContext context) { -// this.context = context; -// try { -// serverInterceptor = context.getGuiceInjector().getInstance(ServerInterceptor.class); -// } catch (ConfigurationException ex) { -// -// } -// if (serverInterceptor != null) { -// serverBuilder.intercept(serverInterceptor); -// } -// } - - public GRPCServer(String bindingAddr, int port, KeyManagerFactory kmf, TrustManagerFactory tmf) { - //ServerInterceptor serverInterceptor, int poolCoreSize, int poolMaxSizeMaxSize, int poolQueueSize, long keepAliveSeconds, NIOStatusListener nioListener; - this(bindingAddr, port, kmf, tmf, null, GRPCServerConfig.cfg.getTpe(), null); - } public GRPCServer(String bindingAddr, int port, KeyManagerFactory kmf, TrustManagerFactory tmf, ServerInterceptor serverInterceptor, ThreadPoolExecutor tpe, NIOStatusListener nioListener) { this.bindingAddr = bindingAddr; 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 fe65636..ba5b085 100644 --- a/src/main/java/org/summerboot/jexpress/security/auth/BootAuthenticator.java +++ b/src/main/java/org/summerboot/jexpress/security/auth/BootAuthenticator.java @@ -386,6 +386,9 @@ public ServerCall.Listener interceptCall(ServerCall Date: Thu, 29 Aug 2024 20:46:31 -0400 Subject: [PATCH 13/19] wip --- pom.xml | 2 +- .../nio/grpc/BootLoadBalancerProvider.java | 33 +++++++------- .../jexpress/nio/grpc/GRPCClient.java | 45 ++++++++----------- .../jexpress/nio/grpc/GRPCClientConfig.java | 38 ++++++++-------- 4 files changed, 58 insertions(+), 60 deletions(-) diff --git a/pom.xml b/pom.xml index 7b5dee2..78255eb 100644 --- a/pom.xml +++ b/pom.xml @@ -211,7 +211,7 @@ 1.66.0 33.3.0-jre - 4.27.3 + 4.28.0 2.2.22 diff --git a/src/main/java/org/summerboot/jexpress/nio/grpc/BootLoadBalancerProvider.java b/src/main/java/org/summerboot/jexpress/nio/grpc/BootLoadBalancerProvider.java index b46b86e..2804888 100644 --- a/src/main/java/org/summerboot/jexpress/nio/grpc/BootLoadBalancerProvider.java +++ b/src/main/java/org/summerboot/jexpress/nio/grpc/BootLoadBalancerProvider.java @@ -33,33 +33,36 @@ public class BootLoadBalancerProvider extends NameResolverProvider { protected final List servers; protected final String scheme; - protected final String authority; + protected final int priority; + //protected final String authority; - public BootLoadBalancerProvider(String scheme, InetSocketAddress... addresses) { + public BootLoadBalancerProvider(String scheme, int priority, InetSocketAddress... addresses) { this.scheme = scheme; + this.priority = priority; // this.authority = Arrays.stream(addresses) // .map(InetSocketAddress::getHostName) // .collect(Collectors.joining(", ")); - if (addresses != null && addresses.length > 0) { - this.authority = addresses[0].getHostName(); - } else { - this.authority = "unknownhost"; - } +// if (addresses != null && addresses.length > 0) { +// this.authority = addresses[0].getHostName(); +// } else { +// this.authority = "unknownhost"; +// } this.servers = Arrays.stream(addresses) .map(EquivalentAddressGroup::new) .collect(Collectors.toList()); } - public BootLoadBalancerProvider(String scheme, List addresses) { + public BootLoadBalancerProvider(String scheme, int priority, List addresses) { this.scheme = scheme; + this.priority = priority; // this.authority = addresses.stream() // .map(InetSocketAddress::getHostName)// getHostString // .collect(Collectors.joining(", ")); - if (addresses != null && !addresses.isEmpty()) { - this.authority = addresses.get(0).getHostName(); - } else { - this.authority = "unknownhost"; - } +// if (addresses != null && !addresses.isEmpty()) { +// this.authority = addresses.get(0).getHostName(); +// } else { +// this.authority = "unknownhost"; +// } this.servers = addresses.stream() .map(EquivalentAddressGroup::new) .collect(Collectors.toList()); @@ -70,8 +73,8 @@ public NameResolver newNameResolver(URI notUsedTargetUri, NameResolver.Args args return new NameResolver() { @Override public String getServiceAuthority() { - //return notUsedTargetUri.toString(); - return authority; + return notUsedTargetUri.getAuthority(); + //return authority; } @Override diff --git a/src/main/java/org/summerboot/jexpress/nio/grpc/GRPCClient.java b/src/main/java/org/summerboot/jexpress/nio/grpc/GRPCClient.java index 6233077..5fba727 100644 --- a/src/main/java/org/summerboot/jexpress/nio/grpc/GRPCClient.java +++ b/src/main/java/org/summerboot/jexpress/nio/grpc/GRPCClient.java @@ -73,38 +73,31 @@ public String getValue() { public static NettyChannelBuilder getNettyChannelBuilder(NameResolverProvider nameResolverProvider, LoadBalancingPolicy loadBalancingPolicy, URI uri, @Nullable KeyManagerFactory keyManagerFactory, @Nullable TrustManagerFactory trustManagerFactory, @Nullable String overrideAuthority, @Nullable Iterable ciphers, @Nullable String... tlsVersionProtocols) throws SSLException { final NettyChannelBuilder channelBuilder; - //String target = uri.toString();//"grpcs://"+uri.getAuthority()+"/service";// "grpcs:///" - switch (uri.getScheme()) { - case "unix": //https://github.com/grpc/grpc-java/issues/1539 - channelBuilder = NettyChannelBuilder.forAddress(new DomainSocketAddress(uri.getPath())) - .eventLoopGroup(new EpollEventLoopGroup()) - .channelType(EpollDomainSocketChannel.class) - .usePlaintext(); - break; - default: - if (nameResolverProvider != null) { - //NameResolverRegistry nameResolverRegistry = new NameResolverRegistry(); - NameResolverRegistry nameResolverRegistry = NameResolverRegistry.getDefaultRegistry();// this is a singleton instance in new API to replace deprecated channelBuilder.nameResolverFactory(nameResolverRegistry.asFactory()); - nameResolverRegistry.register(nameResolverProvider);// use client side load balancing -// for (NameResolverProvider nrp : NR_Providers) { -// nameResolverRegistry.deregister(nrp); -// } -// NR_Providers.add(nameResolverProvider); - String policy = loadBalancingPolicy.getValue(); - String target = uri.toString();//"grpcs://"+uri.getAuthority()+"/service";// "grpcs:///" nameResolverProvider.getDefaultScheme() - target = nameResolverProvider.getDefaultScheme() + ":///"; - channelBuilder = NettyChannelBuilder.forTarget(target) - .defaultLoadBalancingPolicy(policy); - //.nameResolverFactory(nameResolverRegistry.asFactory());deprecated use target to distinguish different gRPC services - } else { + if (nameResolverProvider != null) {// use client side load balancing + // register + NameResolverRegistry nameResolverRegistry = NameResolverRegistry.getDefaultRegistry();// Use singleton instance in new API to replace deprecated channelBuilder.nameResolverFactory(new nameResolverRegistry().asFactory()); + nameResolverRegistry.register(nameResolverProvider); + // init + String policy = loadBalancingPolicy.getValue(); + String target = nameResolverProvider.getDefaultScheme() + ":///"; // build target as URI + channelBuilder = NettyChannelBuilder.forTarget(target) + .defaultLoadBalancingPolicy(policy); + } else { + switch (uri.getScheme()) { + case "unix": //https://github.com/grpc/grpc-java/issues/1539 + channelBuilder = NettyChannelBuilder.forAddress(new DomainSocketAddress(uri.getPath())) + .eventLoopGroup(new EpollEventLoopGroup()) + .channelType(EpollDomainSocketChannel.class); + break; + default: String host = uri.getHost(); int port = uri.getPort(); if (host == null) { throw new IllegalArgumentException("The URI format should contains host information, like ://[host:port]/[service], like grpc:///, grpc://host:port, grpcs://host:port, or unix:///path/to/uds.sock. gRpc.client.LoadBalancing.servers should be provided when host/port are not provided."); } channelBuilder = NettyChannelBuilder.forAddress(host, port); - } - break; + break; + } } if (keyManagerFactory == null) { channelBuilder.usePlaintext(); diff --git a/src/main/java/org/summerboot/jexpress/nio/grpc/GRPCClientConfig.java b/src/main/java/org/summerboot/jexpress/nio/grpc/GRPCClientConfig.java index 369b9eb..0aa0e25 100644 --- a/src/main/java/org/summerboot/jexpress/nio/grpc/GRPCClientConfig.java +++ b/src/main/java/org/summerboot/jexpress/nio/grpc/GRPCClientConfig.java @@ -18,6 +18,7 @@ import com.fasterxml.jackson.annotation.JsonAutoDetect; import com.fasterxml.jackson.annotation.JsonIgnore; import io.grpc.NameResolverProvider; +import io.grpc.NameResolverRegistry; import io.grpc.netty.shaded.io.grpc.netty.NettyChannelBuilder; import org.summerboot.jexpress.boot.BootConstant; import org.summerboot.jexpress.boot.config.BootConfig; @@ -61,20 +62,20 @@ protected GRPCClientConfig() { example = "localhost:8424, remotehost:8425, 127.0.0.1:8426") @Config(key = ID + ".LoadBalancing.servers", predefinedValue = "0.0.0.0:8424, 0.0.0.0:8425", required = false) protected volatile List loadBalancingServers; - @Config(key = ID + ".LoadBalancing.schema", defaultValue = "grpc", desc = "In case you have more than one gRPC client needs to connect to different gRPC services, you can set this to distinguish them") - protected volatile String loadBalancingTargetSchema = "grpc"; + @Config(key = ID + ".LoadBalancing.scheme", defaultValue = "grpc", desc = "In case you have more than one gRPC client needs to connect to different gRPC services, you can set this to distinguish them") + protected volatile String loadBalancingTargetScheme = "grpc"; @Config(key = ID + ".LoadBalancing.policy", defaultValue = "ROUND_ROBIN", desc = "available options: ROUND_ROBIN, PICK_FIRST") protected volatile GRPCClient.LoadBalancingPolicy loadBalancingPolicy; protected volatile NameResolverProvider nameResolverProvider; -// //1. gRPC connection -// @Config(key = ID + ".target.url", defaultValue = "grpc:///", -// desc = "grpc:///\n" -// + "grpc://127.0.0.1:8424\n" -// + "unix:/tmp/grpcsrver.socket") -// protected volatile URI uri; + //1. gRPC connection + @Config(key = ID + ".target.url", defaultValue = "grpc:///", + desc = "grpc:///\n" + + "grpc://127.0.0.1:8424\n" + + "unix:/tmp/grpcsrver.socket") + protected volatile URI uri; @Config(key = ID + ".ssl.Protocols", defaultValue = "TLSv1.3")// "TLSv1.2, TLSv1.3" protected String[] sslProtocols; @@ -133,12 +134,18 @@ protected void preLoad(File cfgFile, boolean isReal, ConfigUtil helper, Properti createIfNotExist(FILENAME_SRC_TRUSTSTORE, FILENAME_TRUSTSTORE_4CLIENT); } + protected static int priority = 0; + @Override protected void loadCustomizedConfigs(File cfgFile, boolean isReal, ConfigUtil helper, Properties props) throws IOException { + if (!isReal) { + return; + } if (loadBalancingServers != null && !loadBalancingServers.isEmpty()) { - nameResolverProvider = new BootLoadBalancerProvider(loadBalancingTargetSchema, loadBalancingServers); + nameResolverProvider = new BootLoadBalancerProvider(loadBalancingTargetScheme, ++priority, loadBalancingServers); + NameResolverRegistry nameResolverRegistry = NameResolverRegistry.getDefaultRegistry();// Use singleton instance in new API to replace deprecated channelBuilder.nameResolverFactory(new nameResolverRegistry().asFactory()); + nameResolverRegistry.register(nameResolverProvider); } - URI uri = null;//new URI("grpc:///"); channelBuilder = GRPCClient.getNettyChannelBuilder(nameResolverProvider, loadBalancingPolicy, uri, kmf, tmf, overrideAuthority, ciphers, sslProtocols); } @@ -150,10 +157,6 @@ public List getLoadBalancingServers() { return loadBalancingServers; } - public String getLoadBalancingTargetSchema() { - return loadBalancingTargetSchema; - } - public GRPCClient.LoadBalancingPolicy getLoadBalancingPolicy() { return loadBalancingPolicy; } @@ -162,10 +165,9 @@ public NameResolverProvider getNameResolverProvider() { return nameResolverProvider; } - -// public URI getUri() { -// return uri; -// } + public URI getUri() { + return uri; + } public String[] getSslProtocols() { return sslProtocols; From 4de4143fed8b8f2197bc944a06d105e9c3900965 Mon Sep 17 00:00:00 2001 From: Summer Boot Framework Date: Thu, 29 Aug 2024 23:31:08 -0400 Subject: [PATCH 14/19] wip --- .../org/summerboot/jexpress/nio/grpc/GRPCClientConfig.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/summerboot/jexpress/nio/grpc/GRPCClientConfig.java b/src/main/java/org/summerboot/jexpress/nio/grpc/GRPCClientConfig.java index 0aa0e25..863bacf 100644 --- a/src/main/java/org/summerboot/jexpress/nio/grpc/GRPCClientConfig.java +++ b/src/main/java/org/summerboot/jexpress/nio/grpc/GRPCClientConfig.java @@ -141,9 +141,12 @@ protected void loadCustomizedConfigs(File cfgFile, boolean isReal, ConfigUtil he if (!isReal) { return; } + NameResolverRegistry nameResolverRegistry = NameResolverRegistry.getDefaultRegistry();// Use singleton instance in new API to replace deprecated channelBuilder.nameResolverFactory(new nameResolverRegistry().asFactory()); + if (nameResolverProvider != null) { + nameResolverRegistry.deregister(nameResolverProvider); + } if (loadBalancingServers != null && !loadBalancingServers.isEmpty()) { nameResolverProvider = new BootLoadBalancerProvider(loadBalancingTargetScheme, ++priority, loadBalancingServers); - NameResolverRegistry nameResolverRegistry = NameResolverRegistry.getDefaultRegistry();// Use singleton instance in new API to replace deprecated channelBuilder.nameResolverFactory(new nameResolverRegistry().asFactory()); nameResolverRegistry.register(nameResolverProvider); } channelBuilder = GRPCClient.getNettyChannelBuilder(nameResolverProvider, loadBalancingPolicy, uri, kmf, tmf, overrideAuthority, ciphers, sslProtocols); From be504f09a6a7126307269917675960e859ecd297 Mon Sep 17 00:00:00 2001 From: Summer Boot Framework Date: Sat, 31 Aug 2024 19:44:31 -0400 Subject: [PATCH 15/19] refactoring --- pom.xml | 2 +- .../jexpress/nio/grpc/GRPCClient.java | 238 +++++++----------- .../jexpress/nio/grpc/GRPCClientConfig.java | 123 ++++++++- 3 files changed, 211 insertions(+), 152 deletions(-) diff --git a/pom.xml b/pom.xml index 78255eb..939ea36 100644 --- a/pom.xml +++ b/pom.xml @@ -190,7 +190,7 @@ 3.3.1 3.2.5 - 3.16.0 + 3.17.0 1.9.0 2.16.1 diff --git a/src/main/java/org/summerboot/jexpress/nio/grpc/GRPCClient.java b/src/main/java/org/summerboot/jexpress/nio/grpc/GRPCClient.java index 5fba727..06fb418 100644 --- a/src/main/java/org/summerboot/jexpress/nio/grpc/GRPCClient.java +++ b/src/main/java/org/summerboot/jexpress/nio/grpc/GRPCClient.java @@ -1,3 +1,4 @@ + /* * Copyright 2005-2022 Du Law Office - The Summer Boot Framework Project * @@ -16,23 +17,12 @@ package org.summerboot.jexpress.nio.grpc; import io.grpc.ManagedChannel; -import io.grpc.NameResolverProvider; -import io.grpc.NameResolverRegistry; -import io.grpc.netty.shaded.io.grpc.netty.GrpcSslContexts; import io.grpc.netty.shaded.io.grpc.netty.NettyChannelBuilder; -import io.grpc.netty.shaded.io.netty.channel.epoll.EpollDomainSocketChannel; -import io.grpc.netty.shaded.io.netty.channel.epoll.EpollEventLoopGroup; -import io.grpc.netty.shaded.io.netty.channel.unix.DomainSocketAddress; -import io.grpc.netty.shaded.io.netty.handler.ssl.SslContext; -import io.grpc.netty.shaded.io.netty.handler.ssl.SslContextBuilder; -import io.grpc.netty.shaded.io.netty.handler.ssl.SslProvider; -import io.grpc.netty.shaded.io.netty.handler.ssl.util.InsecureTrustManagerFactory; -import jakarta.annotation.Nullable; - -import javax.net.ssl.KeyManagerFactory; -import javax.net.ssl.SSLException; -import javax.net.ssl.TrustManagerFactory; -import java.net.URI; + +import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; /** * @param @@ -40,165 +30,118 @@ */ public abstract class GRPCClient> { - public enum LoadBalancingPolicy { - ROUND_ROBIN("round_robin"), PICK_FIRST("pick_first"); - - private final String value; - - private LoadBalancingPolicy(String value) { - this.value = value; - } + protected NettyChannelBuilder channelBuilder; + protected ManagedChannel channel; + protected final ReadWriteLock rwLock = new ReentrantReadWriteLock(); + protected final Lock readLock = rwLock.readLock(); + protected Thread shutdownHook; - public String getValue() { - return value; - } + public GRPCClient(GRPCClientConfig cfg) { + this.channelBuilder = cfg.getChannelBuilder(); + cfg.addConfigUpdateListener(this); + } + /** + * @param channelBuilder + */ + public GRPCClient(NettyChannelBuilder channelBuilder) { + this.channelBuilder = channelBuilder; } - //protected static final List NR_Providers = new ArrayList(); + /** + * callback when config file updated if GRPCClientConfig.addConfigUpdateListener(this); + * + * @param channelBuilder + */ + protected void updateChannelBuilder(NettyChannelBuilder channelBuilder) { + rwLock.writeLock().lock(); + this.channelBuilder = channelBuilder; + rwLock.writeLock().unlock(); + onChannelBuilderUpdated(); + } /** - * @param nameResolverProvider for client side load balancing - * @param loadBalancingPolicy - * @param uri The URI format should be one of grpc://host:port, - * grpcs://host:port, or unix:///path/to/uds.sock - * @param keyManagerFactory The Remote Caller identity - * @param trustManagerFactory The Remote Caller trusted identities - * @param overrideAuthority - * @param ciphers - * @param tlsVersionProtocols "TLSv1.2", "TLSv1.3" + * Disconnect the current connection and build a new connection within a write lock + * * @return - * @throws javax.net.ssl.SSLException */ - public static NettyChannelBuilder getNettyChannelBuilder(NameResolverProvider nameResolverProvider, LoadBalancingPolicy loadBalancingPolicy, URI uri, @Nullable KeyManagerFactory keyManagerFactory, @Nullable TrustManagerFactory trustManagerFactory, - @Nullable String overrideAuthority, @Nullable Iterable ciphers, @Nullable String... tlsVersionProtocols) throws SSLException { - final NettyChannelBuilder channelBuilder; - if (nameResolverProvider != null) {// use client side load balancing - // register - NameResolverRegistry nameResolverRegistry = NameResolverRegistry.getDefaultRegistry();// Use singleton instance in new API to replace deprecated channelBuilder.nameResolverFactory(new nameResolverRegistry().asFactory()); - nameResolverRegistry.register(nameResolverProvider); - // init - String policy = loadBalancingPolicy.getValue(); - String target = nameResolverProvider.getDefaultScheme() + ":///"; // build target as URI - channelBuilder = NettyChannelBuilder.forTarget(target) - .defaultLoadBalancingPolicy(policy); - } else { - switch (uri.getScheme()) { - case "unix": //https://github.com/grpc/grpc-java/issues/1539 - channelBuilder = NettyChannelBuilder.forAddress(new DomainSocketAddress(uri.getPath())) - .eventLoopGroup(new EpollEventLoopGroup()) - .channelType(EpollDomainSocketChannel.class); - break; - default: - String host = uri.getHost(); - int port = uri.getPort(); - if (host == null) { - throw new IllegalArgumentException("The URI format should contains host information, like ://[host:port]/[service], like grpc:///, grpc://host:port, grpcs://host:port, or unix:///path/to/uds.sock. gRpc.client.LoadBalancing.servers should be provided when host/port are not provided."); - } - channelBuilder = NettyChannelBuilder.forAddress(host, port); - break; - } - } - if (keyManagerFactory == null) { - channelBuilder.usePlaintext(); - } else { - final SslContextBuilder sslBuilder = GrpcSslContexts.forClient(); - sslBuilder.keyManager(keyManagerFactory); - if (trustManagerFactory == null) {//ignore Server Certificate - sslBuilder.trustManager(InsecureTrustManagerFactory.INSTANCE); - } else { - sslBuilder.trustManager(trustManagerFactory); - if (overrideAuthority != null) { - channelBuilder.overrideAuthority(overrideAuthority); + public T connect() { + rwLock.writeLock().lock(); + try { + disconnect(); + channel = channelBuilder.build(); + String info = channel.authority(); + shutdownHook = new Thread(() -> { + try { + channel.shutdownNow(); + } catch (Throwable ex) { } - } - GrpcSslContexts.configure(sslBuilder, SslProvider.OPENSSL); - if (tlsVersionProtocols != null) { - sslBuilder.protocols(tlsVersionProtocols); - } - if (ciphers != null) { - sslBuilder.ciphers(ciphers); - } - SslContext sslContext = sslBuilder.build(); - channelBuilder.sslContext(sslContext).useTransportSecurity(); + }, "GRPCClient.shutdown and disconnect from " + info); + Runtime.getRuntime().addShutdownHook(shutdownHook); + onConnected(channel); + } finally { + rwLock.writeLock().unlock(); } - return channelBuilder; + return (T) this; } /** - * @param nameResolverProvider for client side load balancing - * @param uri The URI format should be one of grpc://host:port or - * unix:///path/to/uds.sock - * @return - * @throws SSLException + * normally just call connect() to establish a new connection with the updated settings; or do nothing to keep using current connection. */ - public static NettyChannelBuilder NettyChannelBuilder(NameResolverProvider nameResolverProvider, URI uri) throws SSLException { - return getNettyChannelBuilder(nameResolverProvider, LoadBalancingPolicy.ROUND_ROBIN, uri, null, null, null, null); - } + protected abstract void onChannelBuilderUpdated(); - protected final NameResolverProvider nameResolverProvider; - protected final URI uri; - protected final NettyChannelBuilder channelBuilder; - protected ManagedChannel channel; + /** + * @param channel + */ + protected abstract void onConnected(ManagedChannel channel); /** - * @param nameResolverProvider for client side load balancing - * @param uri The URI format should be one of grpc://host:port or - * unix:///path/to/uds.sock - * @throws SSLException + * Set a read lock for business method to prevent being called while connect/disconnect */ - public GRPCClient(NameResolverProvider nameResolverProvider, URI uri) throws SSLException { - this(nameResolverProvider, uri, null, null, null, null); + protected void lock() { + readLock.lock(); } /** - * @param nameResolverProvider for client side load balancing - * @param uri The URI format should be one of grpc://host:port, - * grpcs://host:port, or unix:///path/to/uds.sock - * @param keyManagerFactory The Remote Caller identity - * @param trustManagerFactory The Remote Caller trusted identities - * @param overrideAuthority - * @param ciphers - * @param tlsVersionProtocols "TLSv1.2", "TLSv1.3" - * @throws SSLException + * Try a read lock for business method to prevent being called while connect/disconnect + * + * @return */ - public GRPCClient(NameResolverProvider nameResolverProvider, URI uri, @Nullable KeyManagerFactory keyManagerFactory, @Nullable TrustManagerFactory trustManagerFactory, - @Nullable String overrideAuthority, @Nullable Iterable ciphers, @Nullable String... tlsVersionProtocols) throws SSLException { - this.nameResolverProvider = nameResolverProvider; - this.uri = uri; - this.channelBuilder = getNettyChannelBuilder(nameResolverProvider, LoadBalancingPolicy.ROUND_ROBIN, uri, keyManagerFactory, trustManagerFactory, overrideAuthority, ciphers, tlsVersionProtocols); + protected boolean tryLock() { + return readLock.tryLock(); } /** - * @param channelBuilder + * Try a read lock in a given time period for business method to prevent being called while connect/disconnect + * + * @param time + * @param unit + * @return + * @throws InterruptedException */ - public GRPCClient(NettyChannelBuilder channelBuilder) { - this.nameResolverProvider = null; - this.uri = null; - this.channelBuilder = channelBuilder; + protected boolean tryLock(long time, TimeUnit unit) throws InterruptedException { + return readLock.tryLock(time, unit); } - public T connect() { - disconnect(); - channel = channelBuilder.build(); - //String info = uri == null ? channel.toString() : uri.toString(); - String info = channel.authority(); - Runtime.getRuntime().addShutdownHook( - new Thread(() -> { - try { - channel.shutdownNow(); - } catch (Throwable ex) { - } - }, "GRPCClient.shutdown and disconnect from " + info)); - onConnected(channel); - return (T) this; + /** + * Release the read lock for business method to prevent being called while connect/disconnect + */ + protected void unlock() { + readLock.unlock(); } /** - * @param channel + * Get the read lock + * + * @return */ - protected abstract void onConnected(ManagedChannel channel); + protected Lock getLock() { + return readLock; + } + /** + * Disconnect the current connection + */ public void disconnect() { // ManagedChannel c = (ManagedChannel) blockingStub.getChannel(); if (channel != null) { @@ -209,8 +152,13 @@ public void disconnect() { channel = null; } } -// if(nameResolverProvider!=null) { -// NameResolverRegistry.getDefaultRegistry().deregister(nameResolverProvider); -// } + if (shutdownHook != null) { + try { + Runtime.getRuntime().removeShutdownHook(shutdownHook); + } catch (Throwable ex) { + } finally { + shutdownHook = null; + } + } } } diff --git a/src/main/java/org/summerboot/jexpress/nio/grpc/GRPCClientConfig.java b/src/main/java/org/summerboot/jexpress/nio/grpc/GRPCClientConfig.java index 863bacf..311e4cc 100644 --- a/src/main/java/org/summerboot/jexpress/nio/grpc/GRPCClientConfig.java +++ b/src/main/java/org/summerboot/jexpress/nio/grpc/GRPCClientConfig.java @@ -19,7 +19,16 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import io.grpc.NameResolverProvider; import io.grpc.NameResolverRegistry; +import io.grpc.netty.shaded.io.grpc.netty.GrpcSslContexts; import io.grpc.netty.shaded.io.grpc.netty.NettyChannelBuilder; +import io.grpc.netty.shaded.io.netty.channel.epoll.EpollDomainSocketChannel; +import io.grpc.netty.shaded.io.netty.channel.epoll.EpollEventLoopGroup; +import io.grpc.netty.shaded.io.netty.channel.unix.DomainSocketAddress; +import io.grpc.netty.shaded.io.netty.handler.ssl.SslContext; +import io.grpc.netty.shaded.io.netty.handler.ssl.SslContextBuilder; +import io.grpc.netty.shaded.io.netty.handler.ssl.SslProvider; +import io.grpc.netty.shaded.io.netty.handler.ssl.util.InsecureTrustManagerFactory; +import jakarta.annotation.Nullable; import org.summerboot.jexpress.boot.BootConstant; import org.summerboot.jexpress.boot.config.BootConfig; import org.summerboot.jexpress.boot.config.ConfigUtil; @@ -27,13 +36,16 @@ import org.summerboot.jexpress.boot.config.annotation.ConfigHeader; import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLException; import javax.net.ssl.TrustManagerFactory; import java.io.File; import java.io.IOException; import java.net.InetSocketAddress; import java.net.URI; +import java.util.HashSet; import java.util.List; import java.util.Properties; +import java.util.Set; /** * @author Changski Tie Zheng Zhang 张铁铮, 魏泽北, 杜旺财, 杜富贵 @@ -53,6 +65,21 @@ class a extends GRPCClientConfig { protected final static String ID = "gRpc.client"; + public enum LoadBalancingPolicy { + ROUND_ROBIN("round_robin"), PICK_FIRST("pick_first"); + + private final String value; + + private LoadBalancingPolicy(String value) { + this.value = value; + } + + public String getValue() { + return value; + } + + } + protected GRPCClientConfig() { } @@ -66,7 +93,7 @@ protected GRPCClientConfig() { protected volatile String loadBalancingTargetScheme = "grpc"; @Config(key = ID + ".LoadBalancing.policy", defaultValue = "ROUND_ROBIN", desc = "available options: ROUND_ROBIN, PICK_FIRST") - protected volatile GRPCClient.LoadBalancingPolicy loadBalancingPolicy; + protected volatile LoadBalancingPolicy loadBalancingPolicy; protected volatile NameResolverProvider nameResolverProvider; @@ -127,9 +154,6 @@ protected void generateTemplate_truststore(StringBuilder sb) { @Override protected void preLoad(File cfgFile, boolean isReal, ConfigUtil helper, Properties props) { - loadBalancingServers = null; - nameResolverProvider = null; - channelBuilder = null; createIfNotExist(FILENAME_KEYSTORE, FILENAME_KEYSTORE); createIfNotExist(FILENAME_SRC_TRUSTSTORE, FILENAME_TRUSTSTORE_4CLIENT); } @@ -149,18 +173,105 @@ protected void loadCustomizedConfigs(File cfgFile, boolean isReal, ConfigUtil he nameResolverProvider = new BootLoadBalancerProvider(loadBalancingTargetScheme, ++priority, loadBalancingServers); nameResolverRegistry.register(nameResolverProvider); } - channelBuilder = GRPCClient.getNettyChannelBuilder(nameResolverProvider, loadBalancingPolicy, uri, kmf, tmf, overrideAuthority, ciphers, sslProtocols); + channelBuilder = initNettyChannelBuilder(nameResolverProvider, loadBalancingPolicy, uri, kmf, tmf, overrideAuthority, ciphers, sslProtocols); + for (GRPCClient listener : listeners) { + listener.updateChannelBuilder(channelBuilder); + } } @Override public void shutdown() { } + private Set listeners = new HashSet<>(); + + public void addConfigUpdateListener(GRPCClient listener) { + if (listener == null) { + return; + } + listeners.add(listener); + } + + public void removeConfigUpdateListener(GRPCClient listener) { + if (listener == null) { + return; + } + listeners.remove(listener); + } + + /** + * @param nameResolverProvider for client side load balancing + * @param loadBalancingPolicy + * @param uri The URI format should be one of grpc://host:port, + * grpcs://host:port, or unix:///path/to/uds.sock + * @param keyManagerFactory The Remote Caller identity + * @param trustManagerFactory The Remote Caller trusted identities + * @param overrideAuthority + * @param ciphers + * @param tlsVersionProtocols "TLSv1.2", "TLSv1.3" + * @return + * @throws javax.net.ssl.SSLException + */ + public static NettyChannelBuilder initNettyChannelBuilder(NameResolverProvider nameResolverProvider, LoadBalancingPolicy loadBalancingPolicy, URI uri, @Nullable KeyManagerFactory keyManagerFactory, @Nullable TrustManagerFactory trustManagerFactory, + @Nullable String overrideAuthority, @Nullable Iterable ciphers, @Nullable String... tlsVersionProtocols) throws SSLException { + final NettyChannelBuilder channelBuilder; + if (nameResolverProvider != null) {// use client side load balancing + // register + NameResolverRegistry nameResolverRegistry = NameResolverRegistry.getDefaultRegistry();// Use singleton instance in new API to replace deprecated channelBuilder.nameResolverFactory(new nameResolverRegistry().asFactory()); + nameResolverRegistry.register(nameResolverProvider); + // init + String policy = loadBalancingPolicy.getValue(); + String target = nameResolverProvider.getDefaultScheme() + ":///"; // build target as URI + channelBuilder = NettyChannelBuilder.forTarget(target) + .defaultLoadBalancingPolicy(policy); + } else { + switch (uri.getScheme()) { + case "unix": //https://github.com/grpc/grpc-java/issues/1539 + channelBuilder = NettyChannelBuilder.forAddress(new DomainSocketAddress(uri.getPath())) + .eventLoopGroup(new EpollEventLoopGroup()) + .channelType(EpollDomainSocketChannel.class); + break; + default: + String host = uri.getHost(); + int port = uri.getPort(); + if (host == null) { + throw new IllegalArgumentException("The URI format should contains host information, like ://[host:port]/[service], like grpc:///, grpc://host:port, grpcs://host:port, or unix:///path/to/uds.sock. gRpc.client.LoadBalancing.servers should be provided when host/port are not provided."); + } + channelBuilder = NettyChannelBuilder.forAddress(host, port); + break; + } + } + if (keyManagerFactory == null) { + channelBuilder.usePlaintext(); + } else { + final SslContextBuilder sslBuilder = GrpcSslContexts.forClient(); + sslBuilder.keyManager(keyManagerFactory); + if (trustManagerFactory == null) {//ignore Server Certificate + sslBuilder.trustManager(InsecureTrustManagerFactory.INSTANCE); + } else { + sslBuilder.trustManager(trustManagerFactory); + if (overrideAuthority != null) { + channelBuilder.overrideAuthority(overrideAuthority); + } + } + GrpcSslContexts.configure(sslBuilder, SslProvider.OPENSSL); + if (tlsVersionProtocols != null) { + sslBuilder.protocols(tlsVersionProtocols); + } + if (ciphers != null) { + sslBuilder.ciphers(ciphers); + } + SslContext sslContext = sslBuilder.build(); + channelBuilder.sslContext(sslContext).useTransportSecurity(); + } + return channelBuilder; + } + public List getLoadBalancingServers() { return loadBalancingServers; } - public GRPCClient.LoadBalancingPolicy getLoadBalancingPolicy() { + public LoadBalancingPolicy getLoadBalancingPolicy() { return loadBalancingPolicy; } From 842ca7d5aa1b8b4c878d993deda5a39056648ec4 Mon Sep 17 00:00:00 2001 From: Summer Boot Framework Date: Sun, 1 Sep 2024 19:43:37 -0400 Subject: [PATCH 16/19] enhanced GRPC client config --- .../jexpress/nio/grpc/GRPCClient.java | 77 +++++++++++------- .../jexpress/nio/grpc/GRPCClientConfig.java | 80 +++++++++++++++++++ 2 files changed, 127 insertions(+), 30 deletions(-) diff --git a/src/main/java/org/summerboot/jexpress/nio/grpc/GRPCClient.java b/src/main/java/org/summerboot/jexpress/nio/grpc/GRPCClient.java index 06fb418..866e539 100644 --- a/src/main/java/org/summerboot/jexpress/nio/grpc/GRPCClient.java +++ b/src/main/java/org/summerboot/jexpress/nio/grpc/GRPCClient.java @@ -36,16 +36,18 @@ public abstract class GRPCClient> { protected final Lock readLock = rwLock.readLock(); protected Thread shutdownHook; - public GRPCClient(GRPCClientConfig cfg) { + public T withConfig(GRPCClientConfig cfg) { this.channelBuilder = cfg.getChannelBuilder(); cfg.addConfigUpdateListener(this); + return (T) this; } /** * @param channelBuilder */ - public GRPCClient(NettyChannelBuilder channelBuilder) { + public T withNettyChannelBuilder(NettyChannelBuilder channelBuilder) { this.channelBuilder = channelBuilder; + return (T) this; } /** @@ -60,6 +62,13 @@ protected void updateChannelBuilder(NettyChannelBuilder channelBuilder) { onChannelBuilderUpdated(); } + /** + * By default, just call connect() to establish a new connection with the updated settings; or do nothing to keep using current connection. + */ + protected void onChannelBuilderUpdated() { + connect(); + } + /** * Disconnect the current connection and build a new connection within a write lock * @@ -68,7 +77,7 @@ protected void updateChannelBuilder(NettyChannelBuilder channelBuilder) { public T connect() { rwLock.writeLock().lock(); try { - disconnect(); + disconnect(false); channel = channelBuilder.build(); String info = channel.authority(); shutdownHook = new Thread(() -> { @@ -86,14 +95,45 @@ public T connect() { } /** - * normally just call connect() to establish a new connection with the updated settings; or do nothing to keep using current connection. + * @param channel */ - protected abstract void onChannelBuilderUpdated(); + protected abstract void onConnected(ManagedChannel channel); /** - * @param channel + * Disconnect the current connection */ - protected abstract void onConnected(ManagedChannel channel); + public void disconnect() { + disconnect(true); + } + + protected void disconnect(boolean withLock) { +// ManagedChannel c = (ManagedChannel) blockingStub.getChannel(); + if (withLock) { + rwLock.writeLock().lock(); + } + try { + if (channel != null) { + try { + channel.shutdownNow(); + } catch (Throwable ex) { + } finally { + channel = null; + } + } + if (shutdownHook != null) { + try { + Runtime.getRuntime().removeShutdownHook(shutdownHook); + } catch (Throwable ex) { + } finally { + shutdownHook = null; + } + } + } finally { + if (withLock) { + rwLock.writeLock().unlock(); + } + } + } /** * Set a read lock for business method to prevent being called while connect/disconnect @@ -138,27 +178,4 @@ protected void unlock() { protected Lock getLock() { return readLock; } - - /** - * Disconnect the current connection - */ - public void disconnect() { -// ManagedChannel c = (ManagedChannel) blockingStub.getChannel(); - if (channel != null) { - try { - channel.shutdownNow(); - } catch (Throwable ex) { - } finally { - channel = null; - } - } - if (shutdownHook != null) { - try { - Runtime.getRuntime().removeShutdownHook(shutdownHook); - } catch (Throwable ex) { - } finally { - shutdownHook = null; - } - } - } } diff --git a/src/main/java/org/summerboot/jexpress/nio/grpc/GRPCClientConfig.java b/src/main/java/org/summerboot/jexpress/nio/grpc/GRPCClientConfig.java index 311e4cc..8a9ba69 100644 --- a/src/main/java/org/summerboot/jexpress/nio/grpc/GRPCClientConfig.java +++ b/src/main/java/org/summerboot/jexpress/nio/grpc/GRPCClientConfig.java @@ -46,6 +46,7 @@ import java.util.List; import java.util.Properties; import java.util.Set; +import java.util.concurrent.TimeUnit; /** * @author Changski Tie Zheng Zhang 张铁铮, 魏泽北, 杜旺财, 杜富贵 @@ -152,6 +153,34 @@ protected void generateTemplate_truststore(StringBuilder sb) { @JsonIgnore protected volatile NettyChannelBuilder channelBuilder; + @ConfigHeader(title = "4. " + ID + " Channel Settings") + @Config(key = ID + ".channel.userAgent", desc = "string: default null") + protected volatile String userAgent = null; + @Config(key = ID + ".channel.maxInboundMessageSize", desc = "int: default 4194304 is not set") + protected volatile Integer maxInboundMessageSize = null;//4194304; + @Config(key = ID + ".channel.maxHeaderListSize", desc = "int: default 8192 is not set") + protected volatile Integer maxHeaderListSize = null;//8192; + @Config(key = ID + ".channel.perRpcBufferLimit", desc = "long: default 1048576L is not set") + protected volatile Long perRpcBufferLimit = null;//1048576L; + @Config(key = ID + ".channel.maxHedgedAttempts", desc = "int: default 5 is not set") + protected volatile Integer maxHedgedAttempts = null;//5; + + @Config(key = ID + ".channel.idleTimeoutSeconds", desc = "long: default 1800 (30 minutes) is not set") + protected volatile Long idleTimeoutSeconds = null;//TimeUnit.MINUTES.toSeconds(30L); + @Config(key = ID + ".channel.keepAliveTimeSeconds", desc = "long: default Long.MAX_VALUE is not set") + protected volatile Long keepAliveTimeSeconds = null;//Long.MAX_VALUE; + @Config(key = ID + ".channel.keepAliveTimeoutSeconds", desc = "long: default 20 seconds is not set") + protected volatile Long keepAliveTimeoutSeconds = null;//TimeUnit.SECONDS.toSeconds(20L); + @Config(key = ID + ".channel.keepAliveWithoutCalls", desc = "boolean: default false is not set") + protected volatile Boolean keepAliveWithoutCalls = null;//false + + @Config(key = ID + ".channel.retryEnabled", desc = "boolean: default true is not set") + protected volatile Boolean retryEnabled = null;// true + @Config(key = ID + ".channel.maxRetryAttempts", desc = "int: default 5 is not set") + protected volatile Integer maxRetryAttempts = null;//5; + @Config(key = ID + ".channel.retryBufferSize", desc = "int: default 16777216L is not set") + protected volatile Long retryBufferSize = null;//16777216L + @Override protected void preLoad(File cfgFile, boolean isReal, ConfigUtil helper, Properties props) { createIfNotExist(FILENAME_KEYSTORE, FILENAME_KEYSTORE); @@ -174,11 +203,62 @@ protected void loadCustomizedConfigs(File cfgFile, boolean isReal, ConfigUtil he nameResolverRegistry.register(nameResolverProvider); } channelBuilder = initNettyChannelBuilder(nameResolverProvider, loadBalancingPolicy, uri, kmf, tmf, overrideAuthority, ciphers, sslProtocols); + configNettyChannelBuilder(cfgFile, isReal, helper, props); for (GRPCClient listener : listeners) { listener.updateChannelBuilder(channelBuilder); } } + protected void configNettyChannelBuilder(File cfgFile, boolean isReal, ConfigUtil helper, Properties props) { + if (userAgent != null) { + channelBuilder.userAgent(userAgent); + } + if (maxInboundMessageSize != null) { + channelBuilder.maxInboundMessageSize(maxInboundMessageSize); + } + if (maxHeaderListSize != null) { + channelBuilder.maxInboundMetadataSize(maxHeaderListSize); + } + if (perRpcBufferLimit != null) { + channelBuilder.perRpcBufferLimit(perRpcBufferLimit); + } + if (maxHedgedAttempts != null) { + channelBuilder.maxHedgedAttempts(maxHedgedAttempts); + } + + // channel timeout + if (idleTimeoutSeconds != null) { + channelBuilder.idleTimeout(idleTimeoutSeconds, TimeUnit.SECONDS); + } + if (keepAliveTimeSeconds != null) { + channelBuilder.keepAliveTime(keepAliveTimeSeconds, TimeUnit.SECONDS); + } + if (keepAliveTimeoutSeconds != null) { + channelBuilder.keepAliveTimeout(keepAliveTimeoutSeconds, TimeUnit.SECONDS); + } + if (keepAliveWithoutCalls != null) { + channelBuilder.keepAliveWithoutCalls(keepAliveWithoutCalls); + } + + // channel retry + if (retryEnabled != null) { + if (retryEnabled) { + channelBuilder.enableRetry(); + if (maxRetryAttempts != null) { + channelBuilder.maxRetryAttempts(maxRetryAttempts); + } + if (retryBufferSize != null) { + channelBuilder.retryBufferSize(retryBufferSize); + } + } else { + channelBuilder.disableRetry(); + } + } + + //channelBuilder.flowControlWindow(NettyChannelBuilder.DEFAULT_FLOW_CONTROL_WINDOW); + //channelBuilder.initialFlowControlWindow(NettyChannelBuilder.DEFAULT_FLOW_CONTROL_WINDOW); + } + @Override public void shutdown() { } From 4d7c1a706bf306126a4548b79b4129c1da8c51f0 Mon Sep 17 00:00:00 2001 From: Summer Boot Framework Date: Mon, 2 Sep 2024 17:14:55 -0400 Subject: [PATCH 17/19] enhanced GRPC client config --- .../jexpress/nio/grpc/GRPCClientConfig.java | 69 ++++++++++--------- 1 file changed, 37 insertions(+), 32 deletions(-) diff --git a/src/main/java/org/summerboot/jexpress/nio/grpc/GRPCClientConfig.java b/src/main/java/org/summerboot/jexpress/nio/grpc/GRPCClientConfig.java index 8a9ba69..d0ba482 100644 --- a/src/main/java/org/summerboot/jexpress/nio/grpc/GRPCClientConfig.java +++ b/src/main/java/org/summerboot/jexpress/nio/grpc/GRPCClientConfig.java @@ -153,32 +153,37 @@ protected void generateTemplate_truststore(StringBuilder sb) { @JsonIgnore protected volatile NettyChannelBuilder channelBuilder; - @ConfigHeader(title = "4. " + ID + " Channel Settings") + @ConfigHeader(title = "4. " + ID + " Channel Settings", + desc = "To see debug info, use JAVA_OPTS=-Djava.util.logging.config.file=logging.properties \n" + + "-Dio.grpc.internal.DnsNameResolverProvider.enable_grpclb=true \n" + + "-Dio.grpc.internal.DnsNameResolverProvider.enable_service_config=true \n" + + "-Dio.grpc.internal.DnsNameResolverProvider.enable_service_config_ttl=true \n" + + "-Dio.grpc.internal.DnsNameResolverProvider.enable_service_config_retries=true \n") @Config(key = ID + ".channel.userAgent", desc = "string: default null") protected volatile String userAgent = null; - @Config(key = ID + ".channel.maxInboundMessageSize", desc = "int: default 4194304 is not set") + @Config(key = ID + ".channel.maxInboundMessageSize", desc = "int: default 4194304 if not set") protected volatile Integer maxInboundMessageSize = null;//4194304; - @Config(key = ID + ".channel.maxHeaderListSize", desc = "int: default 8192 is not set") + @Config(key = ID + ".channel.maxHeaderListSize", desc = "int: default 8192 if not set") protected volatile Integer maxHeaderListSize = null;//8192; - @Config(key = ID + ".channel.perRpcBufferLimit", desc = "long: default 1048576L is not set") + @Config(key = ID + ".channel.perRpcBufferLimit", desc = "long: default 1048576L if not set") protected volatile Long perRpcBufferLimit = null;//1048576L; - @Config(key = ID + ".channel.maxHedgedAttempts", desc = "int: default 5 is not set") + @Config(key = ID + ".channel.maxHedgedAttempts", desc = "int: default 5 if not set") protected volatile Integer maxHedgedAttempts = null;//5; - @Config(key = ID + ".channel.idleTimeoutSeconds", desc = "long: default 1800 (30 minutes) is not set") + @Config(key = ID + ".channel.idleTimeoutSeconds", desc = "long: default 1800 (30 minutes) if not set") protected volatile Long idleTimeoutSeconds = null;//TimeUnit.MINUTES.toSeconds(30L); - @Config(key = ID + ".channel.keepAliveTimeSeconds", desc = "long: default Long.MAX_VALUE is not set") + @Config(key = ID + ".channel.keepAliveWithoutCalls", desc = "boolean: default false if not set. keepAliveWithoutCalls is used when you are willing to spend client, server, and network resources to have lower latency for very infrequent RPCs") + protected volatile Boolean keepAliveWithoutCalls = null;//false + @Config(key = ID + ".channel.keepAliveTimeSeconds", desc = "long: default Long.MAX_VALUE (never) if not set. The interval in seconds between PING frames.") protected volatile Long keepAliveTimeSeconds = null;//Long.MAX_VALUE; - @Config(key = ID + ".channel.keepAliveTimeoutSeconds", desc = "long: default 20 seconds is not set") + @Config(key = ID + ".channel.keepAliveTimeoutSeconds", desc = "long: default 20 seconds if not set. The timeout in seconds for a PING frame to be acknowledged. If sender does not receive an acknowledgment within this time, it will close the connection.") protected volatile Long keepAliveTimeoutSeconds = null;//TimeUnit.SECONDS.toSeconds(20L); - @Config(key = ID + ".channel.keepAliveWithoutCalls", desc = "boolean: default false is not set") - protected volatile Boolean keepAliveWithoutCalls = null;//false - @Config(key = ID + ".channel.retryEnabled", desc = "boolean: default true is not set") + @Config(key = ID + ".channel.retryEnabled", desc = "boolean: default true if not set") protected volatile Boolean retryEnabled = null;// true - @Config(key = ID + ".channel.maxRetryAttempts", desc = "int: default 5 is not set") + @Config(key = ID + ".channel.maxRetryAttempts", desc = "int: default 5 if not set") protected volatile Integer maxRetryAttempts = null;//5; - @Config(key = ID + ".channel.retryBufferSize", desc = "int: default 16777216L is not set") + @Config(key = ID + ".channel.retryBufferSize", desc = "int: default 16777216L if not set") protected volatile Long retryBufferSize = null;//16777216L @Override @@ -203,60 +208,60 @@ protected void loadCustomizedConfigs(File cfgFile, boolean isReal, ConfigUtil he nameResolverRegistry.register(nameResolverProvider); } channelBuilder = initNettyChannelBuilder(nameResolverProvider, loadBalancingPolicy, uri, kmf, tmf, overrideAuthority, ciphers, sslProtocols); - configNettyChannelBuilder(cfgFile, isReal, helper, props); + configNettyChannelBuilder(channelBuilder); for (GRPCClient listener : listeners) { listener.updateChannelBuilder(channelBuilder); } } - protected void configNettyChannelBuilder(File cfgFile, boolean isReal, ConfigUtil helper, Properties props) { + protected void configNettyChannelBuilder(NettyChannelBuilder nettyChannelBuilder) { if (userAgent != null) { - channelBuilder.userAgent(userAgent); + nettyChannelBuilder.userAgent(userAgent); } if (maxInboundMessageSize != null) { - channelBuilder.maxInboundMessageSize(maxInboundMessageSize); + nettyChannelBuilder.maxInboundMessageSize(maxInboundMessageSize); } if (maxHeaderListSize != null) { - channelBuilder.maxInboundMetadataSize(maxHeaderListSize); + nettyChannelBuilder.maxInboundMetadataSize(maxHeaderListSize); } if (perRpcBufferLimit != null) { - channelBuilder.perRpcBufferLimit(perRpcBufferLimit); + nettyChannelBuilder.perRpcBufferLimit(perRpcBufferLimit); } if (maxHedgedAttempts != null) { - channelBuilder.maxHedgedAttempts(maxHedgedAttempts); + nettyChannelBuilder.maxHedgedAttempts(maxHedgedAttempts); } // channel timeout if (idleTimeoutSeconds != null) { - channelBuilder.idleTimeout(idleTimeoutSeconds, TimeUnit.SECONDS); + nettyChannelBuilder.idleTimeout(idleTimeoutSeconds, TimeUnit.SECONDS); + } + if (keepAliveWithoutCalls != null) { + nettyChannelBuilder.keepAliveWithoutCalls(keepAliveWithoutCalls); } if (keepAliveTimeSeconds != null) { - channelBuilder.keepAliveTime(keepAliveTimeSeconds, TimeUnit.SECONDS); + nettyChannelBuilder.keepAliveTime(keepAliveTimeSeconds, TimeUnit.SECONDS); } if (keepAliveTimeoutSeconds != null) { - channelBuilder.keepAliveTimeout(keepAliveTimeoutSeconds, TimeUnit.SECONDS); - } - if (keepAliveWithoutCalls != null) { - channelBuilder.keepAliveWithoutCalls(keepAliveWithoutCalls); + nettyChannelBuilder.keepAliveTimeout(keepAliveTimeoutSeconds, TimeUnit.SECONDS); } // channel retry if (retryEnabled != null) { if (retryEnabled) { - channelBuilder.enableRetry(); + nettyChannelBuilder.enableRetry(); if (maxRetryAttempts != null) { - channelBuilder.maxRetryAttempts(maxRetryAttempts); + nettyChannelBuilder.maxRetryAttempts(maxRetryAttempts); } if (retryBufferSize != null) { - channelBuilder.retryBufferSize(retryBufferSize); + nettyChannelBuilder.retryBufferSize(retryBufferSize); } } else { - channelBuilder.disableRetry(); + nettyChannelBuilder.disableRetry(); } } - //channelBuilder.flowControlWindow(NettyChannelBuilder.DEFAULT_FLOW_CONTROL_WINDOW); - //channelBuilder.initialFlowControlWindow(NettyChannelBuilder.DEFAULT_FLOW_CONTROL_WINDOW); + //nettyChannelBuilder.flowControlWindow(NettyChannelBuilder.DEFAULT_FLOW_CONTROL_WINDOW); + //nettyChannelBuilder.initialFlowControlWindow(NettyChannelBuilder.DEFAULT_FLOW_CONTROL_WINDOW); } @Override From 5b6393d45ab904b5286f59dfb8c89308a33d1859 Mon Sep 17 00:00:00 2001 From: Summer Boot Framework Date: Tue, 3 Sep 2024 01:19:10 -0400 Subject: [PATCH 18/19] enhanced GRPC client config --- .../org/summerboot/jexpress/nio/grpc/GRPCClientConfig.java | 6 +----- .../org/summerboot/jexpress/template/log4j2.xml.temp | 3 ++- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/summerboot/jexpress/nio/grpc/GRPCClientConfig.java b/src/main/java/org/summerboot/jexpress/nio/grpc/GRPCClientConfig.java index d0ba482..f5efaf6 100644 --- a/src/main/java/org/summerboot/jexpress/nio/grpc/GRPCClientConfig.java +++ b/src/main/java/org/summerboot/jexpress/nio/grpc/GRPCClientConfig.java @@ -154,11 +154,7 @@ protected void generateTemplate_truststore(StringBuilder sb) { protected volatile NettyChannelBuilder channelBuilder; @ConfigHeader(title = "4. " + ID + " Channel Settings", - desc = "To see debug info, use JAVA_OPTS=-Djava.util.logging.config.file=logging.properties \n" + - "-Dio.grpc.internal.DnsNameResolverProvider.enable_grpclb=true \n" + - "-Dio.grpc.internal.DnsNameResolverProvider.enable_service_config=true \n" + - "-Dio.grpc.internal.DnsNameResolverProvider.enable_service_config_ttl=true \n" + - "-Dio.grpc.internal.DnsNameResolverProvider.enable_service_config_retries=true \n") + desc = "The following settings are for NettyChannelBuilder, which is used to create a gRPC channel") @Config(key = ID + ".channel.userAgent", desc = "string: default null") protected volatile String userAgent = null; @Config(key = ID + ".channel.maxInboundMessageSize", desc = "int: default 4194304 if not set") diff --git a/src/main/resources/org/summerboot/jexpress/template/log4j2.xml.temp b/src/main/resources/org/summerboot/jexpress/template/log4j2.xml.temp index e0f6d0d..0bff379 100644 --- a/src/main/resources/org/summerboot/jexpress/template/log4j2.xml.temp +++ b/src/main/resources/org/summerboot/jexpress/template/log4j2.xml.temp @@ -76,6 +76,7 @@ + @@ -116,4 +117,4 @@ - \ No newline at end of file + From 65404bf7689339d65976a61a6fad5d1e7fe3b512 Mon Sep 17 00:00:00 2001 From: Summer Boot Framework Date: Wed, 4 Sep 2024 09:37:19 -0400 Subject: [PATCH 19/19] release --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 939ea36..9b7ef2c 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ 4.0.0 org.summerboot jexpress - 2.4.11-SNAPSHOT + 2.4.11 jar Summer Boot jExpress Summer Boot jExpress focuses on solving non-functional and operational maintainability requirements,