getBootErrorCodeMapping() {
@Config(key = "naming.cli.decrypt", defaultValue = "decrypt")
private String cliName_decrypt = "decrypt";
+ @Config(key = "naming.cli.psv", defaultValue = "psv")
+ private String cliName_psv = "psv";
+
@Config(key = "naming.memo.delimiter", defaultValue = ": ")
private String memoDelimiter = ": ";
@@ -361,6 +370,14 @@ public String getgRPCConfigFileName() {
return gRPCConfigFileName;
}
+ public String getPauseLockCodeViaFile() {
+ return pauseLockCodeViaFile;
+ }
+
+ public String getPauseLockCodeViaWeb() {
+ return pauseLockCodeViaWeb;
+ }
+
public String getLog4J2LogId() {
return log4j2LogId;
}
@@ -437,6 +454,10 @@ public String getCliName_decrypt() {
return cliName_decrypt;
}
+ public String getCliName_psv() {
+ return cliName_psv;
+ }
+
public String getMemoDelimiter() {
return memoDelimiter;
}
diff --git a/src/main/java/org/summerboot/jexpress/boot/BootConstant.java b/src/main/java/org/summerboot/jexpress/boot/BootConstant.java
index 6329bd53..33533342 100644
--- a/src/main/java/org/summerboot/jexpress/boot/BootConstant.java
+++ b/src/main/java/org/summerboot/jexpress/boot/BootConstant.java
@@ -1,95 +1,116 @@
-/*
- * Copyright 2005-2022 Du Law Office - The Summer Boot Framework Project
- *
- * The Summer Boot Project licenses this file to you under the Apache License, version 2.0 (the
- * "License"); you may not use this file except in compliance with the License and you have no
- * policy prohibiting employee contributions back to this file (unless the contributor to this
- * file is your current or retired employee). You may obtain a copy of the License at:
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-package org.summerboot.jexpress.boot;
+
+
+
+
+
+
+
+
+
+
+
+
+
-import java.util.Random;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-/**
- * @author Changski Tie Zheng Zhang 张铁铮, 魏泽北, 杜旺财, 杜富贵
- */
-public interface BootConstant {
- String APP_ID = String.format("%06d", new Random().nextInt(999999));
+
+
+
+
+
- //version
- String VERSION = "SummerBoot.jExpress 2.4.9";
- String JEXPRESS_PACKAGE_NAME = "org.summerboot.jexpress";
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
- String DEFAULT_ADMIN_MM = "changeit";
-
- /*
- * Runtime info
- */
- int CPU_CORE = Runtime.getRuntime().availableProcessors();
- String PID = java.lang.management.ManagementFactory.getRuntimeMXBean().getName();
- String BR = System.lineSeparator();
-
- //logging metadata
- String LOG4J2_KEY = "log4j.configurationFile";
- String LOG4J2_JDKADAPTER_KEY = "java.util.logging.manager";
- String LOG4J2_JDKADAPTER_VALUE = "org.apache.logging.log4j.jul.LogManager";
-
- /**
- * 3. jExpress Default Settings
- */
- boolean CFG_ERROR_CODE_AS_INT = BackOffice.agent.isErrorCodeAsInt();
- int CFG_CHANGE_MONITOR_INTERVAL_SEC = BackOffice.agent.getCfgChangeMonitorIntervalSec();
- int PACKAGE_LEVEL = BackOffice.agent.getReflectionPackageLevel();
- long WEB_RESOURCE_TTL_MS = BackOffice.agent.getWebResourceCacheTtlSec() * 1000;
- String DIR_STANDALONE = BackOffice.agent.getDomainFolderPrefix();
- String DIR_CONFIGURATION = BackOffice.agent.getConfigFolderName();
- String DIR_PLUGIN = BackOffice.agent.getPluginFolderName();
- String DIR_LOG = BackOffice.agent.getLogFolderName();
-
- String FILE_CFG_AUTH = BackOffice.agent.getAuthConfigFileName();
- String FILE_CFG_SMTP = BackOffice.agent.getSmtpConfigFileName();
- String FILE_CFG_NIO = BackOffice.agent.getNioConfigFileName();
- String FILE_CFG_GRPC = BackOffice.agent.getgRPCConfigFileName();
-
- /*
- * 4. jExpress Default CLI Name
- */
- String CLI_USAGE = BackOffice.agent.getCliName_usage();
- String CLI_VERSION = BackOffice.agent.getCliName_version();
- String CLI_CONFIG_DOMAIN = BackOffice.agent.getCliName_domain();
- String CLI_CONFIG_DIR = BackOffice.agent.getCliName_cfgdir();
- String CLI_CONFIG_MONITOR_INTERVAL = BackOffice.agent.getCliName_monitorInterval();
- String CLI_I8N = BackOffice.agent.getCliName_i18n();
- String CLI_USE_IMPL = BackOffice.agent.getCliName_use();//To specify which implementation will be used via @Component.checkImplTagUsed
- String CLI_CONFIG_DEMO = BackOffice.agent.getCliName_cfgdemo();
- String CLI_LIST_UNIQUE = BackOffice.agent.getCliName_list();
- String CLI_ADMIN_PWD_FILE = BackOffice.agent.getCliName_authfile();
- String CLI_ADMIN_PWD = BackOffice.agent.getCliName_auth();
- String CLI_JWT = BackOffice.agent.getCliName_jwt();
- String CLI_ENCRYPT = BackOffice.agent.getCliName_encrypt();
- String CLI_DECRYPT = BackOffice.agent.getCliName_decrypt();
- String MEMO_DELIMITER = BackOffice.agent.getMemoDelimiter();
-
- /*
- * 5. Log4j2.xml variables
- *
- * Pass by System.setProperty() instead of making them public static, any better idea?
- * ‘java.lang.System.getProperty()’ API underlyingly uses ‘java.util.Hashtable.get()’ API.
- * Please be advised that ‘java.util.Hashtable.get()’ is a synchronized API.
- * It means only one thread can invoke the ‘java.util.Hashtable.get()’ method at any given time.
- */
- String SYS_PROP_LOGID = BackOffice.agent.getLog4J2LogId();// "logid" // used by log4j2.xml ${sys:logid}
- String SYS_PROP_LOGFILEPATH = BackOffice.agent.getLog4j2LogFilePath();//"logPath"; // used by log4j2.xml ${sys:loggingPath}
- String SYS_PROP_LOGFILENAME = BackOffice.agent.getLog4j2LogFileName();//"appName"; // used by log4j2.xml ${sys:appappName} as log file name
- String SYS_PROP_SERVER_NAME = BackOffice.agent.getLog4j2ServerName();//"serverName"; // used by log4j2.xml ${hostName}
- String SYS_PROP_APP_PACKAGE_NAME = BackOffice.agent.getLog4j2AppPackageName();//"appPackageName"; // used by both log4j2.xml ${sys:appPackage} and JPAHibernateConfig to scan @Entity
-
-}
+
+
+
+
+
+
+
diff --git a/src/main/java/org/summerboot/jexpress/boot/BootGuiceModule.java b/src/main/java/org/summerboot/jexpress/boot/BootGuiceModule.java
index c036a5a3..7fd6f1b8 100644
--- a/src/main/java/org/summerboot/jexpress/boot/BootGuiceModule.java
+++ b/src/main/java/org/summerboot/jexpress/boot/BootGuiceModule.java
@@ -24,15 +24,14 @@
import org.apache.commons.lang3.StringUtils;
import org.quartz.Scheduler;
import org.summerboot.jexpress.boot.annotation.Controller;
+import org.summerboot.jexpress.boot.annotation.Inspector;
import org.summerboot.jexpress.boot.event.AppLifecycleHandler;
import org.summerboot.jexpress.boot.event.AppLifecycleListener;
import org.summerboot.jexpress.boot.event.HttpExceptionHandler;
import org.summerboot.jexpress.boot.event.HttpExceptionListener;
import org.summerboot.jexpress.boot.event.HttpLifecycleHandler;
import org.summerboot.jexpress.boot.event.HttpLifecycleListener;
-import org.summerboot.jexpress.boot.instrumentation.BootHealthInspectorImpl;
import org.summerboot.jexpress.boot.instrumentation.HTTPClientStatusListener;
-import org.summerboot.jexpress.boot.instrumentation.HealthInspector;
import org.summerboot.jexpress.boot.instrumentation.NIOStatusListener;
import org.summerboot.jexpress.boot.instrumentation.jmx.InstrumentationMgr;
import org.summerboot.jexpress.boot.instrumentation.jmx.InstrumentationMgrImpl;
@@ -107,9 +106,6 @@ public void configure() {
memo.append(INFO).append(ChannelHandler.class.getName()).append(BIND_TO).append(BootHttpPingHandler.class.getSimpleName()).append(", named=").append(BootHttpPingHandler.class.getSimpleName());
// 4. @Services
- bind(HealthInspector.class).to(BootHealthInspectorImpl.class);
- memo.append(INFO).append(HealthInspector.class.getName()).append(BIND_TO).append(BootHealthInspectorImpl.class.getName());
-
bind(AuthTokenCache.class).to(AuthTokenCacheLocalImpl.class);
memo.append(INFO).append(AuthTokenCache.class.getName()).append(BIND_TO).append(AuthTokenCacheLocalImpl.class.getName());
@@ -134,8 +130,9 @@ public void configure() {
bind(ChannelHandler.class).annotatedWith(Names.named(BootHttpRequestHandler.class.getSimpleName())).to(BootHttpRequestHandler.class);
memo.append(INFO).append(ChannelHandler.class.getName()).append(BIND_TO).append(BootHttpRequestHandler.class.getSimpleName()).append(", named=").append(BootHttpRequestHandler.class.getSimpleName());
- // 5. Controllers
+ // 5. get instances
scanAnnotation_BindInstance(binder(), Controller.class, callerRootPackageName);
+ scanAnnotation_BindInstance(binder(), Inspector.class, callerRootPackageName);
// 6. caller's Main class (App.Main)
if (caller != null) {
@@ -149,7 +146,8 @@ public void configure() {
/**
* This method will be called by
*
- * Guice.createInjector(...) from SummerBigBang.genesis(...) to trigger SummerBigBang.onGuiceInjectorCreated_ControllersInjected(@Controller {@code Map} controllers)
+ * Guice.createInjector(...) from SummerBigBang.genesis(...)
+ * it will trigger SummerBigBang.onGuiceInjectorCreated_ControllersInjected(@Controller {@code Map} controllers)
*
*
* @param binder
@@ -167,16 +165,19 @@ protected void scanAnnotation_BindInstance(Binder binder, Class extends Annota
Set> classes = ReflectionUtil.getAllImplementationsByAnnotation(annotation, false, rootPackageNames);
//classesAll.addAll(classes);
for (Class c : classes) {
- Controller a = (Controller) c.getAnnotation(annotation);
- String implTag = a.implTag();
- if (StringUtils.isNotBlank(implTag) && !isCliUseImplTag(implTag)) {
- continue;
- }
-
+ //
+ Annotation a = c.getAnnotation(annotation);
int mod = c.getModifiers();
if (Modifier.isAbstract(mod) || Modifier.isInterface(mod)) {
continue;
}
+ if (a instanceof Controller) {
+ Controller ca = (Controller) a;
+ String implTag = ca.implTag();
+ if (StringUtils.isNotBlank(implTag) && !isCliUseImplTag(implTag)) {
+ continue;
+ }
+ }
classesAll.add(c);
}
//}
diff --git a/src/main/java/org/summerboot/jexpress/boot/SummerApplication.java b/src/main/java/org/summerboot/jexpress/boot/SummerApplication.java
index 570da48a..2c5bb1d4 100644
--- a/src/main/java/org/summerboot/jexpress/boot/SummerApplication.java
+++ b/src/main/java/org/summerboot/jexpress/boot/SummerApplication.java
@@ -25,7 +25,6 @@
import org.quartz.SchedulerException;
import org.summerboot.jexpress.boot.config.ConfigUtil;
import org.summerboot.jexpress.boot.event.AppLifecycleListener;
-import org.summerboot.jexpress.boot.instrumentation.HealthInspector;
import org.summerboot.jexpress.boot.instrumentation.HealthMonitor;
import org.summerboot.jexpress.boot.instrumentation.NIOStatusListener;
import org.summerboot.jexpress.boot.instrumentation.Timeout;
@@ -40,7 +39,6 @@
import org.summerboot.jexpress.nio.server.NioConfig;
import org.summerboot.jexpress.nio.server.NioServer;
import org.summerboot.jexpress.util.ApplicationUtil;
-import org.summerboot.jexpress.util.BeanUtil;
import java.net.InetSocketAddress;
import java.util.ArrayList;
@@ -53,11 +51,8 @@
*/
abstract public class SummerApplication extends SummerBigBang {
-
@Inject
protected InstrumentationMgr instrumentationMgr;
- @Inject
- protected HealthInspector healthInspector;
protected NioServer httpServer;
protected List gRPCServerList = new ArrayList();
@Inject
@@ -231,7 +226,6 @@ protected void traceConfig() {
memo.append(BootConstant.BR).append("\t- sys.prop.").append(BootConstant.SYS_PROP_APP_PACKAGE_NAME).append(" = ").append(System.getProperty(BootConstant.SYS_PROP_APP_PACKAGE_NAME));
memo.append(BootConstant.BR).append("\t- start: PostOffice=").append(postOffice.getClass().getName());
- memo.append(BootConstant.BR).append("\t- start: HealthInspector=").append(healthInspector.getClass().getName());
//memo.append(BootConstant.BR).append("\t- start: ConfigChangeListener=").append(configChangeListener.getClass().getName());
memo.append(BootConstant.BR).append("\t- start: InstrumentationMgr=").append(instrumentationMgr.getClass().getName());
memoLogged = true;
@@ -274,7 +268,7 @@ public void start() {
// 3a. runner.run
log.trace("3a. runner.run");
- SummerRunner.RunnerContext context = new SummerRunner.RunnerContext(cli, userSpecifiedConfigDir, guiceInjector, healthInspector, postOffice);
+ SummerRunner.RunnerContext context = new SummerRunner.RunnerContext(cli, userSpecifiedConfigDir, guiceInjector, postOffice);
for (SummerRunner summerRunner : summerRunners) {
summerRunner.run(context);
}
@@ -292,29 +286,7 @@ public void start() {
String timeoutDesc = BackOffice.agent.getProcessTimeoutAlertMessage();
// 4. health inspection
log.trace("4. health inspection");
- StringBuilder sb = new StringBuilder();
- sb.append(BootConstant.BR).append(HealthMonitor.PROMPT);
- if (healthInspector != null) {
- try (var a = Timeout.watch(healthInspector.getClass().getName() + ".ping()", timeoutMs).withDesc(timeoutDesc)) {
- List errors = healthInspector.ping(log);
- if (errors == null || errors.isEmpty()) {
- sb.append("passed");
- log.info(sb);
- } else {
- String inspectionReport;
- try {
- inspectionReport = BeanUtil.toJson(errors, true, true);
- } catch (Throwable ex) {
- inspectionReport = "total " + errors.size();
- }
- sb.append(inspectionReport);
- HealthMonitor.setHealthStatus(false, sb.toString(), healthInspector);
- }
- }
- } else {
- sb.append("skipped");
- log.warn(sb);
- }
+ String serviceStatus = HealthMonitor.start(true);
// 5a. start server: gRPC
if (hasGRPCImpl) {
@@ -363,11 +335,9 @@ public void start() {
}
// 6. announcement
- log.info(() -> I18n.info.launched.format(userSpecifiedResourceBundle, appVersion + " pid#" + BootConstant.PID));
-
- String fullConfigInfo = sb.toString();
+ log.info(() -> BootConstant.BR + BootConstant.BR + I18n.info.launched.format(userSpecifiedResourceBundle, appVersion + " pid#" + BootConstant.PID) + serviceStatus);
if (appLifecycleListener != null) {
- appLifecycleListener.onApplicationStart(super.appVersion, fullConfigInfo);
+ appLifecycleListener.onApplicationStart(super.appVersion, serviceStatus);
}
} catch (java.net.BindException ex) {// from NioServer
log.fatal(ex + BootConstant.BR + BackOffice.agent.getPortInUseAlertMessage());
@@ -383,6 +353,8 @@ public void start() {
}
}
+ 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/SummerBigBang.java b/src/main/java/org/summerboot/jexpress/boot/SummerBigBang.java
index e9bf126b..6e4488e5 100644
--- a/src/main/java/org/summerboot/jexpress/boot/SummerBigBang.java
+++ b/src/main/java/org/summerboot/jexpress/boot/SummerBigBang.java
@@ -26,13 +26,17 @@
import org.apache.commons.cli.DefaultParser;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.ParseException;
+import org.apache.commons.lang3.exception.ExceptionUtils;
+import org.apache.commons.lang3.tuple.ImmutablePair;
import org.quartz.Job;
import org.quartz.Scheduler;
import org.summerboot.jexpress.boot.annotation.Controller;
+import org.summerboot.jexpress.boot.annotation.Inspector;
import org.summerboot.jexpress.boot.annotation.Order;
import org.summerboot.jexpress.boot.config.BootConfig;
import org.summerboot.jexpress.boot.config.ConfigUtil;
import org.summerboot.jexpress.boot.config.JExpressConfig;
+import org.summerboot.jexpress.boot.instrumentation.HealthMonitor;
import org.summerboot.jexpress.i18n.I18n;
import org.summerboot.jexpress.integration.quartz.QuartzUtil;
import org.summerboot.jexpress.nio.server.ws.rs.JaxRsRequestProcessorManager;
@@ -40,8 +44,10 @@
import org.summerboot.jexpress.security.JwtUtil;
import org.summerboot.jexpress.security.SecurityUtil;
import org.summerboot.jexpress.util.FormatterUtil;
+import org.summerboot.jexpress.util.PropertiesFile;
import org.summerboot.jexpress.util.ReflectionUtil;
+import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
@@ -219,6 +225,13 @@ protected void bigBang_LetThereBeCLI(String[] args) {
.build();
cliOptions.addOption(arg);
+ arg = Option.builder(BootConstant.CLI_PSV)
+ .hasArg().argName("envId")
+ .desc("Generate configuration list in PSV format with the specified environment id"
+ + BootConstant.BR + BootConstant.BR + "\t -" + BootConstant.CLI_PSV + " -" + BootConstant.CLI_CONFIG_DOMAIN + " ")
+ .build();
+ cliOptions.addOption(arg);
+
arg = Option.builder(BootConstant.CLI_DECRYPT)
.desc("Decrypt config file content with all \"ENC(encrypted text)\" using password:"
+ BootConstant.BR + BootConstant.BR + BootConstant.BR + "\t -" + BootConstant.CLI_DECRYPT + " -" + BootConstant.CLI_CONFIG_DOMAIN + " -" + BootConstant.CLI_ADMIN_PWD + " ")
@@ -284,12 +297,12 @@ protected List scanImplementation_SummerInitializer() {
protected boolean runCLI_Utils() {
log.trace("");
boolean continueCLI = true;
- //usage
+ // usage
if (cli.hasOption(BootConstant.CLI_USAGE)) {
continueCLI = false;
cliHelpFormatter.printHelp(appVersion, cliOptions);
}
- //callerVersion
+ // callerVersion
if (cli.hasOption(BootConstant.CLI_VERSION)) {
continueCLI = false;
System.out.println(appVersion);
@@ -302,7 +315,7 @@ protected boolean runCLI_Utils() {
String jwt = JwtUtil.buildSigningKey(signatureAlgorithm);
System.out.println(jwt);
}
- //check unique
+ // check unique
if (cli.hasOption(BootConstant.CLI_LIST_UNIQUE)) {
continueCLI = false;
String tag = cli.getOptionValue(BootConstant.CLI_LIST_UNIQUE);
@@ -389,6 +402,41 @@ protected void bigBang_AndThereWasCLI() {
System.exit(0);
}
+ /*
+ * [generate configurations list in PSV format]
+ */
+ if (cli.hasOption(BootConstant.CLI_PSV)) {
+ String envId = cli.getOptionValue(BootConstant.CLI_PSV);
+ StringBuilder sb = new StringBuilder();
+ //File path = Paths.get(userSpecifiedConfigDir.getAbsolutePath(), BootConstant.DIR_CONFIGURATION).toFile();
+ System.out.println("loading from " + userSpecifiedConfigDir.getAbsolutePath());
+ for (final File configFile : userSpecifiedConfigDir.listFiles()) {
+ if (!configFile.isFile()) {
+ continue;
+ }
+ String fileName = configFile.getName();
+ if (!fileName.endsWith(".properties")) {
+ continue; //skip non-properties file
+ }
+
+ System.out.println("loading " + configFile.getAbsolutePath());
+ try {
+ PropertiesFile propertiesFile = new PropertiesFile();
+ List> pairs = propertiesFile.load(configFile);
+ for (ImmutablePair pair : pairs) {
+ String key = pair.getKey();
+ String value = pair.getValue();
+ sb.append(key).append("|").append(value).append("|").append(envId).append("|").append(fileName).append(BootConstant.BR);
+ }
+ } catch (IOException ex) {
+ sb.append("Failed to generate configurations list in PSV format: " + configFile.getAbsolutePath()).append(BootConstant.BR);
+ sb.append(ExceptionUtils.getRootCauseMessage(ex)).append(BootConstant.BR);
+ }
+ }
+ System.out.println("\n\n" + sb);
+ System.exit(0);
+ }
+
/*
* [IoC] - set user selected implementations to override the default
* should be invoked before genesis was initialezed to avoid caller invoks LogManager.static{}
@@ -556,7 +604,12 @@ protected void onGuiceInjectorCreated_ControllersInjected(@Controller Map defaultHealthInspectors) {
+ log.trace("");
+ HealthMonitor.registerDefaultHealthInspectors(defaultHealthInspectors, memo);
}
protected void scanImplementation_SummerRunner(Injector injector) {
diff --git a/src/main/java/org/summerboot/jexpress/boot/SummerRunner.java b/src/main/java/org/summerboot/jexpress/boot/SummerRunner.java
index 67e1f775..e0a5d7e0 100644
--- a/src/main/java/org/summerboot/jexpress/boot/SummerRunner.java
+++ b/src/main/java/org/summerboot/jexpress/boot/SummerRunner.java
@@ -17,7 +17,6 @@
import com.google.inject.Injector;
import org.apache.commons.cli.CommandLine;
-import org.summerboot.jexpress.boot.instrumentation.HealthInspector;
import org.summerboot.jexpress.integration.smtp.PostOffice;
import java.io.File;
@@ -32,14 +31,12 @@ class RunnerContext {
protected final CommandLine cli;
protected final File configDir;
protected final Injector guiceInjector;
- protected final HealthInspector healthInspector;
protected final PostOffice postOffice;
- public RunnerContext(CommandLine cli, File configDir, Injector guiceInjector, HealthInspector healthInspector, PostOffice postOffice) {
+ public RunnerContext(CommandLine cli, File configDir, Injector guiceInjector, PostOffice postOffice) {
this.cli = cli;
this.configDir = configDir;
this.guiceInjector = guiceInjector;
- this.healthInspector = healthInspector;
this.postOffice = postOffice;
}
@@ -55,10 +52,6 @@ public Injector getGuiceInjector() {
return guiceInjector;
}
- public HealthInspector getHealthInspector() {
- return healthInspector;
- }
-
public PostOffice getPostOffice() {
return postOffice;
}
diff --git a/src/main/java/org/summerboot/jexpress/boot/annotation/Controller.java b/src/main/java/org/summerboot/jexpress/boot/annotation/Controller.java
index 7d929796..84e6ce39 100644
--- a/src/main/java/org/summerboot/jexpress/boot/annotation/Controller.java
+++ b/src/main/java/org/summerboot/jexpress/boot/annotation/Controller.java
@@ -16,6 +16,7 @@
package org.summerboot.jexpress.boot.annotation;
import com.google.inject.BindingAnnotation;
+import org.summerboot.jexpress.boot.BootConstant;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
@@ -36,7 +37,7 @@
String implTag() default NOT_TAGGED;
- String responseHeader_ServerTs() default "X-ServerTs";
+ String responseHeader_ServerTs() default BootConstant.RESPONSE_HEADER_KEY_TS;
- String responseHeader_Reference() default "X-Reference";
+ String responseHeader_Reference() default BootConstant.RESPONSE_HEADER_KEY_REF;
}
diff --git a/src/main/java/org/summerboot/jexpress/boot/instrumentation/BootHealthInspectorImpl.java b/src/main/java/org/summerboot/jexpress/boot/annotation/Inspector.java
similarity index 52%
rename from src/main/java/org/summerboot/jexpress/boot/instrumentation/BootHealthInspectorImpl.java
rename to src/main/java/org/summerboot/jexpress/boot/annotation/Inspector.java
index 3210b070..8ad3a460 100644
--- a/src/main/java/org/summerboot/jexpress/boot/instrumentation/BootHealthInspectorImpl.java
+++ b/src/main/java/org/summerboot/jexpress/boot/annotation/Inspector.java
@@ -13,35 +13,24 @@
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
-package org.summerboot.jexpress.boot.instrumentation;
+package org.summerboot.jexpress.boot.annotation;
-import com.google.inject.Singleton;
-import jakarta.annotation.Nonnull;
-import org.summerboot.jexpress.boot.BootConstant;
-import org.summerboot.jexpress.nio.server.domain.Err;
-import org.summerboot.jexpress.nio.server.domain.ServiceError;
+import com.google.inject.BindingAnnotation;
-import java.util.List;
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
/**
* @author Changski Tie Zheng Zhang 张铁铮, 魏泽北, 杜旺财, 杜富贵
*/
-@Singleton
-public class BootHealthInspectorImpl implements HealthInspector {
-
- /**
- * @param args Logger, Boolean
- * @return
- */
- @Override
- public List ping(Object... args) {
- ServiceError error = new ServiceError(BootConstant.APP_ID + "- ping");
- healthCheck(error, args);
- List errors = error.getErrors();
- return errors;
- }
-
- protected void healthCheck(@Nonnull ServiceError error, Object... args) {
- }
+@Target(value = {ElementType.TYPE, ElementType.PARAMETER, ElementType.METHOD})
+@Retention(value = RetentionPolicy.RUNTIME)
+@Documented
+@BindingAnnotation
+public @interface Inspector {
+ String[] poi() default {};
}
diff --git a/src/main/java/org/summerboot/jexpress/boot/config/BootConfig.java b/src/main/java/org/summerboot/jexpress/boot/config/BootConfig.java
index 0a845be9..9a8f7565 100644
--- a/src/main/java/org/summerboot/jexpress/boot/config/BootConfig.java
+++ b/src/main/java/org/summerboot/jexpress/boot/config/BootConfig.java
@@ -26,6 +26,7 @@
import org.apache.logging.log4j.Logger;
import org.summerboot.jexpress.boot.config.annotation.Config;
import org.summerboot.jexpress.boot.config.annotation.ConfigHeader;
+import org.summerboot.jexpress.boot.config.annotation.ImportResource;
import org.summerboot.jexpress.security.SecurityUtil;
import org.summerboot.jexpress.util.ApplicationUtil;
import org.summerboot.jexpress.util.BeanUtil;
@@ -380,6 +381,15 @@ public static String generateTemplate(Class configClass) {
}
}
+ String namespace = "";
+ ImportResource ir = (ImportResource) configClass.getAnnotation(ImportResource.class);
+ if (ir != null) {
+ namespace = ir.namespace();
+ }
+ if (!namespace.isBlank()) {
+ namespace += ".";
+ }
+
List configItems = ReflectionUtil.getDeclaredAndSuperClassesFields(configClass, true);
boolean hasConfig = false;
StringBuilder sb = new StringBuilder();
@@ -501,7 +511,7 @@ public static String generateTemplate(Class configClass) {
if (!hasPredefinedValue && !isRequired || hasDefaultValue) {
sb.append("#");
}
- String key = cfg.key();
+ String key = namespace + cfg.key();
sb.append(key).append("=");
if (isEncrypted) {
sb.append("DEC(");
diff --git a/src/main/java/org/summerboot/jexpress/boot/config/ConfigurationMonitor.java b/src/main/java/org/summerboot/jexpress/boot/config/ConfigurationMonitor.java
index 86bd8938..28864330 100644
--- a/src/main/java/org/summerboot/jexpress/boot/config/ConfigurationMonitor.java
+++ b/src/main/java/org/summerboot/jexpress/boot/config/ConfigurationMonitor.java
@@ -20,6 +20,7 @@
import org.apache.commons.io.monitor.FileAlterationObserver;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
+import org.summerboot.jexpress.boot.BootConstant;
import org.summerboot.jexpress.boot.instrumentation.HealthMonitor;
import java.io.File;
@@ -46,9 +47,18 @@ public class ConfigurationMonitor implements FileAlterationListener {
protected ConfigurationMonitor() {
}
+ private static final String PAUSE_LOCK_CODE = BootConstant.PAUSE_LOCK_CODE_VIAFILE;
+
public void start(File folder, int intervalSec, Map cfgUpdateTasks) throws Exception {
File pauseFile = Paths.get(folder.getAbsolutePath(), APUSE_FILE_NAME).toFile();
- HealthMonitor.setPauseStatus(pauseFile.exists(), "by file detection " + pauseFile.getAbsolutePath());
+ boolean pause = pauseFile.exists();
+ String cause;
+ if (pause) {
+ cause = "File detected: " + pauseFile.getAbsolutePath();
+ } else {
+ cause = "File not detected: " + pauseFile.getAbsolutePath();
+ }
+ HealthMonitor.pauseService(pause, PAUSE_LOCK_CODE, cause);
if (running) {
return;
}
@@ -110,12 +120,27 @@ public void onDirectoryDelete(File file) {
@Override
public void onFileCreate(File file) {
+ if (!isPauseFile(file)) {
+ return;
+ }
log.info(() -> "new " + file.getAbsoluteFile());
- HealthMonitor.setPauseStatus(true, "file created " + file.getAbsolutePath());
+ HealthMonitor.pauseService(true, PAUSE_LOCK_CODE, "file created " + file.getAbsolutePath());
+ }
+
+ @Override
+ public void onFileDelete(File file) {
+ if (!isPauseFile(file)) {
+ return;
+ }
+ log.info(() -> "del " + file.getAbsoluteFile());
+ HealthMonitor.pauseService(false, PAUSE_LOCK_CODE, "file deleted " + file.getAbsolutePath());
}
@Override
public void onFileChange(File file) {
+ if (isPauseFile(file)) {
+ return;
+ }
log.info(() -> "mod " + file.getAbsoluteFile());
// decouple business logic from framework logic
// bad example: if(file.equals(AppConstant.CFG_PATH_EMAIL)){...}
@@ -125,10 +150,7 @@ public void onFileChange(File file) {
}
}
- @Override
- public void onFileDelete(File file) {
- log.info(() -> "del " + file.getAbsoluteFile());
- HealthMonitor.setPauseStatus(false, "file deleted " + file.getAbsolutePath());
+ private boolean isPauseFile(File file) {
+ return APUSE_FILE_NAME.equals(file.getName());
}
-
}
diff --git a/src/main/java/org/summerboot/jexpress/boot/config/annotation/ImportResource.java b/src/main/java/org/summerboot/jexpress/boot/config/annotation/ImportResource.java
index 0f99de7b..fb056f80 100644
--- a/src/main/java/org/summerboot/jexpress/boot/config/annotation/ImportResource.java
+++ b/src/main/java/org/summerboot/jexpress/boot/config/annotation/ImportResource.java
@@ -37,4 +37,6 @@
String checkImplTagUsed() default "";
boolean loadWhenImplTagUsed() default false;
+
+ String namespace() default "";
}
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 f25ba15c..9d337921 100644
--- a/src/main/java/org/summerboot/jexpress/boot/event/AppLifecycleHandler.java
+++ b/src/main/java/org/summerboot/jexpress/boot/event/AppLifecycleHandler.java
@@ -17,10 +17,10 @@
import com.google.inject.Inject;
import com.google.inject.Singleton;
-import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
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;
@@ -66,18 +66,18 @@ public void onApplicationStop(String appVersion) {
public void onApplicationStatusUpdated(boolean healthOk, boolean paused, boolean serviceStatusChanged, String reason) {
if (serviceStatusChanged) {
boolean serviceAvaliable = healthOk && !paused;
- String content = "\n\t server status changed: paused=" + paused + ", OK=" + healthOk + ", serviceAvaliable=" + serviceAvaliable + "\n\t reason: " + reason;
- log.log(healthOk ? Level.WARN : Level.FATAL, content);
+ String content = HealthMonitor.buildMessage();
if (postOffice != null) {
- postOffice.sendAlertAsync(SMTPClientConfig.cfg.getEmailToAppSupport(), "Service Status Changed", content, null, false);
+ postOffice.sendAlertAsync(SMTPClientConfig.cfg.getEmailToAppSupport(), "Service Status Changed at " + OffsetDateTime.now(), content, null, false);
}
}
}
@Override
- public void onHealthInspectionFailed(int retryIndex, String reason, int nextInspectionIntervalSeconds) {
+ public void onHealthInspectionFailed(boolean healthOk, boolean paused, long retryIndex, int nextInspectionIntervalSeconds) {
if (postOffice != null) {
- postOffice.sendAlertAsync(SMTPClientConfig.cfg.getEmailToAppSupport(), "Health Inspection Failed", reason, null, true);
+ String content = HealthMonitor.buildMessage();
+ postOffice.sendAlertAsync(SMTPClientConfig.cfg.getEmailToAppSupport(), "Health Inspection Failed", content, null, true);
}
}
diff --git a/src/main/java/org/summerboot/jexpress/boot/event/AppLifecycleListener.java b/src/main/java/org/summerboot/jexpress/boot/event/AppLifecycleListener.java
index 39d95988..4d08f82e 100644
--- a/src/main/java/org/summerboot/jexpress/boot/event/AppLifecycleListener.java
+++ b/src/main/java/org/summerboot/jexpress/boot/event/AppLifecycleListener.java
@@ -37,7 +37,7 @@ public interface AppLifecycleListener {
*/
void onApplicationStatusUpdated(boolean healthOk, boolean paused, boolean serviceStatusChanged, String reason);
- void onHealthInspectionFailed(int retryIndex, String reason, int nextInspectionIntervalSeconds);
+ void onHealthInspectionFailed(boolean healthOk, boolean paused, long retryIndex, int nextInspectionIntervalSeconds);
void onConfigChangeBefore(File configFile, JExpressConfig cfg);
diff --git a/src/main/java/org/summerboot/jexpress/boot/event/HttpExceptionHandler.java b/src/main/java/org/summerboot/jexpress/boot/event/HttpExceptionHandler.java
index a07fa93d..111f7cf7 100644
--- a/src/main/java/org/summerboot/jexpress/boot/event/HttpExceptionHandler.java
+++ b/src/main/java/org/summerboot/jexpress/boot/event/HttpExceptionHandler.java
@@ -25,7 +25,6 @@
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.logging.log4j.Level;
import org.summerboot.jexpress.boot.BootErrorCode;
-import org.summerboot.jexpress.boot.instrumentation.HealthInspector;
import org.summerboot.jexpress.boot.instrumentation.HealthMonitor;
import org.summerboot.jexpress.integration.smtp.PostOffice;
import org.summerboot.jexpress.integration.smtp.SMTPClientConfig;
@@ -50,9 +49,6 @@
@Singleton
public class HttpExceptionHandler implements HttpExceptionListener {
- @Inject
- protected HealthInspector healthInspector;
-
@Inject
protected PostOffice po;
@@ -73,7 +69,7 @@ public void onNamingException(NamingException ex, HttpMethod httptMethod, String
cause = ex;
}
if (cause instanceof IOException) {// java.net.UnknownHostException
- HealthMonitor.setHealthStatus(false, ex.toString(), healthInspector);
+ HealthMonitor.inspect();
nakFatal(context, HttpResponseStatus.BAD_GATEWAY, BootErrorCode.NETWORK_ERROR, "LDAP " + cause.getClass().getSimpleName(), ex, SMTPClientConfig.cfg.getEmailToAppSupport(), httptMethod + " " + httpRequestPath);
} else {
onNamingException(ex, cause, httptMethod, httpRequestPath, context);
@@ -83,7 +79,7 @@ public void onNamingException(NamingException ex, HttpMethod httptMethod, String
protected void onNamingException(NamingException ex, Throwable cause, HttpMethod httptMethod, String httpRequestPath, ServiceContext context) {
Err e = new Err(BootErrorCode.ACCESS_ERROR_LDAP, null, null, ex, cause.toString());
- context.error(e).status(HttpResponseStatus.BAD_GATEWAY);
+ context.error(e).status(HttpResponseStatus.INTERNAL_SERVER_ERROR);
}
@Override
@@ -93,20 +89,21 @@ public void onPersistenceException(PersistenceException ex, HttpMethod httptMeth
cause = ex;
}
if (cause instanceof IOException) {// java.net.ConnectException
- HealthMonitor.setHealthStatus(false, ex.toString(), healthInspector);
- nakFatal(context, HttpResponseStatus.SERVICE_UNAVAILABLE, BootErrorCode.ACCESS_ERROR_DATABASE, "DB " + cause.getClass().getSimpleName(), ex, SMTPClientConfig.cfg.getEmailToAppSupport(), httptMethod + " " + httpRequestPath);
+ HealthMonitor.inspect();
+ nakFatal(context, HttpResponseStatus.BAD_GATEWAY, BootErrorCode.ACCESS_ERROR_DATABASE, "DB " + cause.getClass().getSimpleName(), ex, SMTPClientConfig.cfg.getEmailToAppSupport(), httptMethod + " " + httpRequestPath);
} else {
onPersistenceException(ex, cause, httptMethod, httpRequestPath, context);
}
}
- public void onPersistenceException(PersistenceException ex, Throwable cause, HttpMethod httptMethod, String httpRequestPath, ServiceContext context) {
+ protected void onPersistenceException(PersistenceException ex, Throwable cause, HttpMethod httptMethod, String httpRequestPath, ServiceContext context) {
Err e = new Err(BootErrorCode.ACCESS_ERROR_DATABASE, null, null, ex, cause.toString());
context.error(e).status(HttpResponseStatus.INTERNAL_SERVER_ERROR);
}
@Override
public void onHttpConnectTimeoutException(HttpConnectTimeoutException ex, HttpMethod httptMethod, String httpRequestPath, ServiceContext context) {
+ HealthMonitor.inspect();
context.status(HttpResponseStatus.GATEWAY_TIMEOUT)
.level(Level.WARN)
.error(new Err(BootErrorCode.HTTP_CONNECTION_TIMEOUT, null, null, ex, "Http Connect Timeout: " + ex.getMessage()));
@@ -128,15 +125,14 @@ public void onRejectedExecutionException(Throwable ex, HttpMethod httptMethod, S
@Override
public void onConnectException(Throwable ex, HttpMethod httptMethod, String httpRequestPath, ServiceContext context) {
- HealthMonitor.setHealthStatus(false, ex.toString(), healthInspector);
+ HealthMonitor.inspect();
nakFatal(context, HttpResponseStatus.BAD_GATEWAY, BootErrorCode.IO_BASE, "Failed to connect: " + ex.getClass().getSimpleName(), ex, SMTPClientConfig.cfg.getEmailToAppSupport(), httptMethod + " " + httpRequestPath);
}
@Override
public void onIOException(Throwable ex, HttpMethod httptMethod, String httpRequestPath, ServiceContext context) {
- HealthMonitor.setHealthStatus(false, ex.toString(), healthInspector);
- nakFatal(context, HttpResponseStatus.SERVICE_UNAVAILABLE, BootErrorCode.IO_BASE, "IO issue: " + ex.getClass().getSimpleName(), ex, SMTPClientConfig.cfg.getEmailToAppSupport(), httptMethod + " " + httpRequestPath);
-
+ HealthMonitor.inspect();
+ nakFatal(context, HttpResponseStatus.BAD_GATEWAY, BootErrorCode.IO_BASE, "IO issue: " + ex.getClass().getSimpleName(), ex, SMTPClientConfig.cfg.getEmailToAppSupport(), httptMethod + " " + httpRequestPath);
}
@Override
diff --git a/src/main/java/org/summerboot/jexpress/boot/instrumentation/HealthInspector.java b/src/main/java/org/summerboot/jexpress/boot/instrumentation/HealthInspector.java
index 1ebf6b2b..3cbb77da 100644
--- a/src/main/java/org/summerboot/jexpress/boot/instrumentation/HealthInspector.java
+++ b/src/main/java/org/summerboot/jexpress/boot/instrumentation/HealthInspector.java
@@ -15,6 +15,7 @@
*/
package org.summerboot.jexpress.boot.instrumentation;
+import org.apache.logging.log4j.Level;
import org.summerboot.jexpress.nio.server.domain.Err;
import java.util.List;
@@ -24,9 +25,33 @@
* @param parameter
* @author Changski Tie Zheng Zhang 张铁铮, 魏泽北, 杜旺财, 杜富贵
*/
-public interface HealthInspector {
+public interface HealthInspector extends Comparable