Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.summerboot.jexpress.boot.SummerApplication Maven / Gradle / Ivy
/*
* 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 com.google.inject.Inject;
import com.google.inject.Module;
import io.grpc.BindableService;
import io.grpc.ServerBuilder;
import io.grpc.ServerInterceptor;
import io.grpc.ServerServiceDefinition;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.core.Appender;
import org.apache.logging.log4j.core.Filter;
import org.apache.logging.log4j.core.appender.ConsoleAppender;
import org.apache.logging.log4j.core.filter.LevelRangeFilter;
import org.quartz.SchedulerException;
import org.summerboot.jexpress.boot.config.ConfigUtil;
import org.summerboot.jexpress.boot.event.AppLifecycleListener;
import org.summerboot.jexpress.boot.instrumentation.HealthMonitor;
import org.summerboot.jexpress.boot.instrumentation.NIOStatusListener;
import org.summerboot.jexpress.boot.instrumentation.Timeout;
import org.summerboot.jexpress.boot.instrumentation.jmx.InstrumentationMgr;
import org.summerboot.jexpress.i18n.I18n;
import org.summerboot.jexpress.integration.quartz.QuartzUtil;
import org.summerboot.jexpress.integration.smtp.PostOffice;
import org.summerboot.jexpress.nio.grpc.GRPCServer;
import org.summerboot.jexpress.nio.grpc.GRPCServerConfig;
import org.summerboot.jexpress.nio.grpc.StatusReporter;
import org.summerboot.jexpress.nio.server.NioChannelInitializer;
import org.summerboot.jexpress.nio.server.NioConfig;
import org.summerboot.jexpress.nio.server.NioServer;
import org.summerboot.jexpress.util.ApplicationUtil;
import java.io.File;
import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* In Code We Trust
*
* @author Changski Tie Zheng Zhang 张铁铮, 魏泽北, 杜旺财, 杜富贵
*/
abstract public class SummerApplication extends SummerBigBang {
@Inject
protected InstrumentationMgr instrumentationMgr;
protected NioServer httpServer;
protected List gRPCServerList = new ArrayList();
@Inject
protected PostOffice postOffice;
@Inject
protected AppLifecycleListener appLifecycleListener;
protected boolean memoLogged = false;
private SummerApplication(Class callerClass, Module userOverrideModule, String... args) {
super(callerClass, userOverrideModule, args);
}
/**
* Might not work on Non HotSpot VM implementations.
*
* @param
* @return
*/
public static T run() {
Module userOverrideModule = null;
return run(userOverrideModule);
}
/**
* @param callerClass
* @param args
*/
public static void run(Class callerClass, String[] args) {
Module userOverrideModule = null;
run(callerClass, userOverrideModule, args);
}
/**
* Might not work on Non Hotspot VM implementations.
*
* @param
* @param userOverrideModule
* @return
*/
public static T run(Module userOverrideModule) {
String[] mainCommand = ApplicationUtil.getApplicationArgs();
int size = mainCommand.length;
String[] args = size > 0 ? new String[size - 1] : ApplicationUtil.EMPTY_ARGS;
String mainClassName = mainCommand[0];
System.arraycopy(mainCommand, 1, args, 0, size - 1);
Class callerClass = null;
StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
for (StackTraceElement stackTraceElement : stackTrace) {
if ("main".equals(stackTraceElement.getMethodName())) {
try {
callerClass = Class.forName(stackTraceElement.getClassName());
break;
} catch (ClassNotFoundException ex) {
}
}
}
if (callerClass == null) {
try {
callerClass = Class.forName(mainClassName);
} catch (ClassNotFoundException ex) {
}
}
if (callerClass == null) {
throw new RuntimeException("Failed to find the caller class");
}
return run(callerClass, userOverrideModule, args);
}
/**
* @param
* @param args
* @return
*/
public static T run(String[] args) {
Module userOverrideModule = null;
return run(userOverrideModule, args);
}
/**
* @param
* @param args
* @param userOverrideModule
* @return
*/
public static T run(Module userOverrideModule, String[] args) {
Class callerClass = null;
StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
for (StackTraceElement stackTraceElement : stackTrace) {
if ("main".equals(stackTraceElement.getMethodName())) {
try {
callerClass = Class.forName(stackTraceElement.getClassName());
break;
} catch (ClassNotFoundException ex) {
}
}
}
if (callerClass == null) {
throw new RuntimeException("Failed to find the caller class");
}
return run(callerClass, userOverrideModule, args);
}
/**
* @param
* @param callerClass
* @param userOverrideModule
* @param argsStr
* @return
*/
public static T run(Class callerClass, Module userOverrideModule, String argsStr) {
String[] args = argsStr.split(" ");
return run(callerClass, userOverrideModule, args);
}
/**
* @param
* @param callerClass
* @param userOverrideModule
* @param args
* @return
*/
public static T run(Class callerClass, Module userOverrideModule, String[] args) {
SummerApplication app = new SummerApplication(callerClass, userOverrideModule, args) {
};
app.start();
return (T) app;
}
/**
* @param
* @param callerClass
* @param userOverrideModule
* @param argsStr
* @return
*/
public static T unittest(Class callerClass, Module userOverrideModule, String argsStr) {
String[] args = argsStr.split(" ");
return unittest(callerClass, userOverrideModule, args);
}
/**
* @param
* @param callerClass
* @param userOverrideModule
* @param args
* @return
*/
public static T unittest(Class callerClass, Module userOverrideModule, String... args) {
SummerApplication app = new SummerApplication(callerClass, userOverrideModule, args) {
};
app.traceConfig();
return (T) app;
}
public List getgRPCServers() {
return gRPCServerList;
}
@Override
protected Class getAddtionalI18n() {
return null;
}
protected void traceConfig() {
log.trace("");
if (!memoLogged) {
memo.append(BootConstant.BR).append("\t- sys.prop.").append(BootConstant.SYS_PROP_LOGID).append(" = ").append(System.getProperty(BootConstant.SYS_PROP_LOGID));
memo.append(BootConstant.BR).append("\t- sys.prop.").append(BootConstant.SYS_PROP_LOGFILEPATH).append(" = ").append(System.getProperty(BootConstant.SYS_PROP_LOGFILEPATH));
memo.append(BootConstant.BR).append("\t- sys.prop.").append(BootConstant.SYS_PROP_LOGFILENAME).append(" = ").append(System.getProperty(BootConstant.SYS_PROP_LOGFILENAME));
memo.append(BootConstant.BR).append("\t- sys.prop.").append(BootConstant.SYS_PROP_SERVER_NAME).append(" = ").append(System.getProperty(BootConstant.SYS_PROP_SERVER_NAME));
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: ConfigChangeListener=").append(configChangeListener.getClass().getName());
memo.append(BootConstant.BR).append("\t- start: InstrumentationMgr=").append(instrumentationMgr.getClass().getName());
memoLogged = true;
}
log.trace(() -> memo.toString());
}
/**
* run application with ping enabled, URI as webApiContextRoot +
* loadBalancerHealthCheckPath
*/
public void start() {
log.trace("");
traceConfig();
if (appLifecycleListener != null) {
ConfigUtil.setConfigChangeListener(appLifecycleListener);
}
//1. init email
log.trace("1. init email");
if (postOffice != null) {
postOffice.setAppVersion(super.appVersion);
//gracefully shutdown
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
if (appLifecycleListener != null) {
appLifecycleListener.onApplicationStop(super.appVersion);
}
}, "ShutdownHook.BootApp")
);
}
if (appLifecycleListener != null) {
HealthMonitor.setAppLifecycleListener(appLifecycleListener);
}
try {
// 2. initialize JMX instrumentation
log.trace("2. initialize JMX instrumentation");
if (instrumentationMgr != null/* && isJMXRequired()*/) {
instrumentationMgr.start(BootConstant.VERSION);
}
// 3a. runner.run
log.trace("3a. runner.run");
SummerRunner.RunnerContext context = new SummerRunner.RunnerContext(cli, userSpecifiedConfigDir, guiceInjector, postOffice);
for (SummerRunner summerRunner : summerRunners) {
summerRunner.run(context);
}
// 3b. start scheduler
log.trace("3b. start scheduler");
if (schedulerTriggers > 0) {
scheduler.start();
StringBuilder sb = new StringBuilder();
sb.append("Scheduled jobs next fire time by ").append(schedulerTriggers).append(" triggers: ");
QuartzUtil.getNextFireTimes(scheduler, sb);
log.info(() -> sb.toString());
}
// 4. health inspection
log.trace("4. health inspection");
String serviceStatus = HealthMonitor.start(true, guiceInjector);
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);
log.trace("5a. start server: gRPC hasGRPCImpl.ssd={}", gRPCServerServiceDefinitionImplClasses);
ServerInterceptor serverInterceptor = super.guiceInjector.getInstance(ServerInterceptor.class);
//2. init gRPC server
GRPCServerConfig gRPCCfg = GRPCServerConfig.cfg;
List bindingAddresses = gRPCCfg.getBindingAddresses();
NIOStatusListener nioListener = super.guiceInjector.getInstance(NIOStatusListener.class);
for (InetSocketAddress bindingAddress : bindingAddresses) {
String host = bindingAddress.getAddress().getHostAddress();
int port = bindingAddress.getPort();
log.trace("5a. binding gRPC on {}:{}", host, port);
try (var a = Timeout.watch("starting gRPCServer at " + host + ":" + port, timeoutMs).withDesc(timeoutDesc)) {
GRPCServer gRPCServer = new GRPCServer(host, port, gRPCCfg.getKmf(), gRPCCfg.getTmf(), serverInterceptor, gRPCCfg.getTpe(), nioListener);
ServerBuilder serverBuilder = gRPCServer.getServerBuilder();
for (Class extends BindableService> c : gRPCBindableServiceImplClasses) {
BindableService impl = guiceInjector.getInstance(c);
serverBuilder.addService(impl);
if (impl instanceof StatusReporter) {
((StatusReporter) impl).setCounter(gRPCServer.getServiceCounter());
}
}
for (Class c : gRPCServerServiceDefinitionImplClasses) {
ServerServiceDefinition impl = guiceInjector.getInstance(c);
serverBuilder.addService(impl);
}
if (gRPCCfg.isAutoStart()) {
gRPCServer.start(startingMemo);
}
gRPCServerList.add(gRPCServer);
}
}
}
// 5b. start server: HTTP
log.trace("5b. start server: HTTP hasControllers={}", hasControllers);
if (hasControllers && NioConfig.cfg.isAutoStart()) {
try (var a = Timeout.watch("starting Web Server", timeoutMs).withDesc(timeoutDesc)) {
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, 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, startingMemo.toString());
}
} catch (java.net.BindException ex) {// from NioServer
log.fatal(ex + BootConstant.BR + BackOffice.agent.getPortInUseAlertMessage());
System.exit(1);
} catch (Throwable ex) {
Throwable cause = ExceptionUtils.getRootCause(ex);
if (cause instanceof java.net.BindException) {// from gRPC server
log.fatal(ex + BootConstant.BR + BackOffice.agent.getPortInUseAlertMessage());
} else {
log.fatal(I18n.info.unlaunched.format(userSpecifiedResourceBundle), ex);
}
System.exit(1);
} finally {
// show prompt only with default log4j2.xml in case user is not familiar with log4j2.xml (only one ConsoleAppender with maxLevel is NOT "ALL"), no prompt if user modify the default log4j2.xml due to user knows what he/she is doing
String prompt = null;
try {
org.apache.logging.log4j.core.Logger c = (org.apache.logging.log4j.core.Logger) log;
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);
}
}
}
public void shutdown() {
log.trace("");
if (gRPCServerList != null && !gRPCServerList.isEmpty()) {
for (GRPCServer gRPCServer : gRPCServerList) {
gRPCServer.shutdown();
}
}
if (httpServer != null) {
httpServer.shutdown();
}
if (instrumentationMgr != null) {
instrumentationMgr.shutdown();
}
if (scheduler != null) {
try {
scheduler.shutdown();
} catch (SchedulerException ex) {
log.warn("Failed to shoutdown scheduler", ex);
}
}
}
}