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.SummerSingularity 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 io.grpc.BindableService;
import io.grpc.ServerServiceDefinition;
import io.netty.channel.ChannelHandler;
import jakarta.annotation.security.DeclareRoles;
import jakarta.annotation.security.RolesAllowed;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Options;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.summerboot.jexpress.boot.annotation.Controller;
import org.summerboot.jexpress.boot.annotation.GrpcService;
import org.summerboot.jexpress.boot.annotation.Service;
import org.summerboot.jexpress.boot.annotation.Service.ChannelHandlerType;
import org.summerboot.jexpress.boot.annotation.Unique;
import org.summerboot.jexpress.boot.annotation.Version;
import org.summerboot.jexpress.boot.config.ConfigUtil;
import org.summerboot.jexpress.boot.config.JExpressConfig;
import org.summerboot.jexpress.boot.config.annotation.ImportResource;
import org.summerboot.jexpress.i18n.I18n;
import org.summerboot.jexpress.integration.smtp.SMTPClientConfig;
import org.summerboot.jexpress.nio.grpc.GRPCServerConfig;
import org.summerboot.jexpress.nio.server.NioConfig;
import org.summerboot.jexpress.security.auth.AuthConfig;
import org.summerboot.jexpress.util.ApplicationUtil;
import org.summerboot.jexpress.util.BeanUtil;
import org.summerboot.jexpress.util.FormatterUtil;
import org.summerboot.jexpress.util.ReflectionUtil;
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.stream.Collectors;
/**
* In Code We Trust
*
* @author Changski Tie Zheng Zhang 张铁铮, 魏泽北, 杜旺财, 杜富贵
*/
abstract public class SummerSingularity {
public static final String HOST = jExpressInit();
protected static String jExpressInit() {
String FILE_CFG_SYSTEM = "boot.conf";
File currentDir = new File("etc").getAbsoluteFile();
if (!currentDir.exists()) {
currentDir.mkdirs();
}
File systemConfigFile = Paths.get(currentDir.getAbsolutePath(), FILE_CFG_SYSTEM).toFile();
try {
if (!systemConfigFile.exists()) {
ConfigUtil.createConfigFile(BackOffice.class, currentDir, FILE_CFG_SYSTEM, false);
}
BackOffice.agent.load(systemConfigFile, false);// isReal:false = do not init logging
} catch (IOException ex) {
System.err.println("Failed to init " + systemConfigFile + ", caused by " + ex);
System.exit(1);
}
return ApplicationUtil.getServerName(true);
}
protected static Logger log;
protected static final File DEFAULT_CFG_DIR = new File(BootConstant.DIR_CONFIGURATION).getAbsoluteFile();
protected static final File CURRENT_DIR = new File("").getAbsoluteFile();
protected File userSpecifiedConfigDir;
protected File pluginDir;
protected final StringBuilder memo = new StringBuilder();
protected final Class primaryClass;
/*
* CLI utils
*/
protected CommandLine cli;
protected final Options cliOptions = new Options();
protected final HelpFormatter cliHelpFormatter = new HelpFormatter();
/*
* CLI results
*/
protected Locale userSpecifiedResourceBundle;
protected int userSpecifiedCfgMonitorIntervalSec;
protected final Set userSpecifiedImplTags = new HashSet<>();
/*
* Scan Results
*/
protected String jvmStartCommand;
protected boolean jmxRequired;
protected String[] callerRootPackageNames;//also used by JPAHibernateConfig access to scan @Entity
protected String appVersion = BootConstant.VERSION;
protected String logFileName = BootConstant.VERSION;
/*
* Annotation scan results as CLI inputs
*/
protected final List availableUniqueTagOptions = new ArrayList();
protected final Map scanedJExpressConfigs = new LinkedHashMap<>();
protected final Set availableImplTagOptions = new HashSet();
protected final Set> gRPCBindableServiceImplClasses = new HashSet();
protected final Set> gRPCServerServiceDefinitionImplClasses = new HashSet();
protected boolean hasControllers = false;
protected boolean hasGRPCImpl = false;
protected boolean hasAuthImpl = false;
/*
* Annotation scan results as BootGuiceModule input
* Format: bindingClass <--> {key=(ImplTag+named) <--> [@Service impl classes list]}
*/
protected final Map>> scanedServiceBindingMap = new HashMap();
protected final Map> channelHandlerNames = new HashMap();
protected SummerSingularity(Class callerClass, String... args) {
System.out.println("jExpress loading from " + HOST);
System.setProperty(BootConstant.SYS_PROP_SERVER_NAME, HOST);// used by log4j2.xml
primaryClass = callerClass == null
? this.getClass()
: callerClass;
singularity();
bigBang(args);
}
protected void singularity() {
if (BackOffice.agent.isTraceWithSystemOut()) {
System.out.println("jExpress init.0");
}
memo.setLength(0);
userSpecifiedConfigDir = null;
pluginDir = null;
System.getProperties().remove(BootConstant.LOG4J2_KEY);
System.getProperties().remove(BootConstant.LOG4J2_JDKADAPTER_KEY);
System.getProperties().remove(BootConstant.SYS_PROP_APP_PACKAGE_NAME, "");// used by log4j2.xml
System.getProperties().remove(BootConstant.SYS_PROP_LOGFILENAME, "");// used by log4j2.xml
System.setProperty(BootConstant.LOG4J2_KEY, "");
// CLI
userSpecifiedResourceBundle = null;
userSpecifiedCfgMonitorIntervalSec = BootConstant.CFG_CHANGE_MONITOR_INTERVAL_SEC;
userSpecifiedImplTags.clear();
// reset Scan Results
jvmStartCommand = null;
jmxRequired = false;
callerRootPackageNames = null;
appVersion = BootConstant.VERSION;
logFileName = BootConstant.VERSION;
//reset Annotation scan results as CLI inputs
availableUniqueTagOptions.clear();
scanedJExpressConfigs.clear();
availableImplTagOptions.clear();
gRPCBindableServiceImplClasses.clear();
gRPCServerServiceDefinitionImplClasses.clear();
hasControllers = false;
hasGRPCImpl = false;
hasAuthImpl = false;
}
protected T bigBang(String[] args) {
if (BackOffice.agent.isTraceWithSystemOut()) {
System.out.println("jExpress init.1");
}
memo.append(BootConstant.BR).append("\t- deployee callerClass=").append(primaryClass.getName());
Set packageSet = new HashSet();
Set configuredPackageSet = BackOffice.agent.getRootPackageNames();
if (configuredPackageSet != null && !configuredPackageSet.isEmpty()) {
packageSet.addAll(configuredPackageSet);
}
String rootPackageName = ReflectionUtil.getRootPackageName(primaryClass, BootConstant.PACKAGE_LEVEL);
packageSet.add(rootPackageName);
BackOffice.agent.setRootPackageNames(packageSet);
callerRootPackageNames = packageSet.toArray(String[]::new);
memo.append(BootConstant.BR).append("\t- callerRootPackageName=").append(packageSet);
if (BackOffice.agent.isTraceWithSystemOut()) {
System.out.println("jExpress init.2");
}
StringBuilder sb = new StringBuilder();
jmxRequired = ApplicationUtil.scanJVM_StartCommand(sb);
jvmStartCommand = sb.toString();
if (BackOffice.agent.isTraceWithSystemOut()) {
System.out.println("jExpress init.3");
}
scanAnnotation_Version(primaryClass);
System.setProperty(BootConstant.SYS_PROP_LOGFILENAME, logFileName);// used by log4j2.xml as log file name
System.setProperty(BootConstant.SYS_PROP_APP_PACKAGE_NAME, rootPackageName);// used by log4j2.xml
BackOffice.agent.setVersion(appVersion);
scanArgsToInitializeLogging(args);
/*
* load external modules
*/
try {
scanPluginJars(pluginDir, true);// depends -domain or -cfgdir
} catch (IOException ex) {
System.out.println(ex + BootConstant.BR + "\tFailed to load plugin jar files from " + pluginDir);
ex.printStackTrace();
System.exit(1);
}
String error = scanAnnotation_Unique(callerRootPackageNames, memo);
if (error != null) {
System.out.println(error);
System.exit(1);
}
String[] packages = FormatterUtil.arrayAdd(callerRootPackageNames, BootConstant.JEXPRESS_PACKAGE_NAME);
scanImplementation_gRPC(callerRootPackageNames);
scanAnnotation_Controller(callerRootPackageNames);
scanAnnotation_Service(callerRootPackageNames);
scanAnnotation_DeclareRoles(callerRootPackageNames);
scanAnnotation_JExpressConfigImportResource(packages);
return (T) this;
}
protected void scanAnnotation_Version(Class callerClass) {
if (BackOffice.agent.isTraceWithSystemOut()) {
System.out.println("jExpress scanning version");
}
Version version = (Version) callerClass.getAnnotation(Version.class);
if (version != null) {
String logManager = version.LogManager();
if (StringUtils.isNotBlank(logManager)) {
System.setProperty(BootConstant.LOG4J2_JDKADAPTER_KEY, logManager);// https://logging.apache.org/log4j/log4j-2.3.2/log4j-jul/index.html
}
logFileName = version.logFileName();
if (StringUtils.isBlank(logFileName)) {
logFileName = version.value()[0];
}
appVersion = version.value()[0];
BackOffice.agent.setVersionShort(appVersion);
int versionCount = version.value().length;
if (versionCount > 1) {
appVersion = appVersion + " (";
for (int i = 1; i < versionCount; i++) {
appVersion = appVersion + version.value()[i] + " ";
}
appVersion = appVersion + ")";
}
} else {
logFileName = "app";
}
memo.append(BootConstant.BR).append("\t- callerVersion=").append(appVersion);
}
protected void scanArgsToInitializeLogging(String[] args) {
if (BackOffice.agent.isTraceWithSystemOut()) {
System.out.println("jExpress initLogger.1");
}
/*
* [Config File] Location - determine the configuration path: userSpecifiedConfigDir
*/
userSpecifiedConfigDir = null;//to clear the state
if (args != null) {
for (int i = 0; i < args.length; i++) {
String cli = args[i];
if (("-" + BootConstant.CLI_CONFIG_DIR).equals(cli)) {
String cfgDir = args[++i];
userSpecifiedConfigDir = new File(cfgDir).getAbsoluteFile();
break;
} else if (("-" + BootConstant.CLI_CONFIG_DOMAIN).equals(cli)) {
String envTag = args[++i];
String cfgDir = /*unittestWorkingDir +*/ BootConstant.DIR_STANDALONE + "_" + envTag + File.separator + BootConstant.DIR_CONFIGURATION;
userSpecifiedConfigDir = new File(cfgDir).getAbsoluteFile();
System.setProperty("domainName", envTag);
break;
}
}
}
if (BackOffice.agent.isTraceWithSystemOut()) {
System.out.println("jExpress initLogger.2");
}
if (userSpecifiedConfigDir == null) {
userSpecifiedConfigDir = DEFAULT_CFG_DIR;
}
if (!userSpecifiedConfigDir.exists()) {
userSpecifiedConfigDir.mkdirs();
}
if (BackOffice.agent.isTraceWithSystemOut()) {
System.out.println("jExpress initLogger.3");
}
// if (userSpecifiedConfigDir.getAbsolutePath().equals(CURRENT_DIR.getAbsolutePath())) {
// //set log folder inside user specified config folder
// System.setProperty(SYS_PROP_LOGFILEPATH, userSpecifiedConfigDir.getAbsolutePath());//used by log4j2.xml
// pluginDir = new File(userSpecifiedConfigDir.getAbsolutePath(), BootConstant.DIR_PLUGIN).getAbsoluteFile();
// } else {
if (!userSpecifiedConfigDir.exists() || !userSpecifiedConfigDir.isDirectory() || !userSpecifiedConfigDir.canRead()) {
System.out.println("Could access configuration path as a folder: " + userSpecifiedConfigDir);
System.exit(1);
}
//set log folder outside user specified config folder
// this will convert any number sequence into 6 character.
System.setProperty(BootConstant.SYS_PROP_LOGID, BootConstant.APP_ID);
System.setProperty(BootConstant.SYS_PROP_LOGFILEPATH, userSpecifiedConfigDir.getParent() + File.separator + BootConstant.DIR_LOG);//used by log4j2.xml
pluginDir = new File(userSpecifiedConfigDir.getParentFile(), BootConstant.DIR_PLUGIN).getAbsoluteFile();
// }
/*
* [Config File] Log4J - init
*/
if (BackOffice.agent.isTraceWithSystemOut()) {
System.out.println("jExpress initLogger.4");
}
String location = userSpecifiedConfigDir.getAbsolutePath();
ClassLoader classLoader = this.getClass().getClassLoader();
Path logFilePath = ApplicationUtil.createIfNotExist(location, classLoader, "log4j2.xml.temp", "log4j2.xml");
String log4j2ConfigFile = logFilePath.toString();
System.setProperty(BootConstant.LOG4J2_KEY, log4j2ConfigFile);
log = LogManager.getLogger(SummerApplication.class);// init log
log.info("Logging initialized from {}", userSpecifiedConfigDir);
Locale userSpecifiedResourceBundle = null;
memo.append(BootConstant.BR).append("\t- ").append(I18n.info.launchingLog.format(userSpecifiedResourceBundle, System.getProperty(BootConstant.LOG4J2_KEY)));
}
protected void scanPluginJars(File pluginDir, boolean failOnUndefinedClasses) throws IOException {
log.trace("{}, {}", pluginDir, failOnUndefinedClasses);
pluginDir.mkdirs();
if (!pluginDir.canRead() || !pluginDir.isDirectory()) {
memo.append(BootConstant.BR).append("\t- loadPluginJars: invalid dir ").append(pluginDir);
return;
}
FileFilter fileFilter = file -> !file.isDirectory() && file.getName().endsWith(".jar");
File[] jarFiles = pluginDir.listFiles(fileFilter);
if (jarFiles == null || jarFiles.length < 1) {
memo.append(BootConstant.BR).append("\t- loadPluginJars: no jar files found at ").append(pluginDir);
return;
}
Set> pluginClasses = new HashSet<>();
for (File jarFile : jarFiles) {
memo.append(BootConstant.BR).append("\t- loadPluginJars: loading jar file ").append(jarFile.getAbsolutePath());
Set> classes = ApplicationUtil.loadClassFromJarFile(jarFile, failOnUndefinedClasses);
memo.append(BootConstant.BR).append("\t- loadPluginJars: loaded ").append(classes.size()).append(" classes from jar file ").append(jarFile.getAbsolutePath());
pluginClasses.addAll(classes);
}
ReflectionUtil.setPluginClasses(pluginClasses);
memo.append(BootConstant.BR).append("\t- loadPluginJars: loaded ").append(pluginClasses.size()).append(" classes from ").append(jarFiles.length).append(" jar files in ").append(pluginDir);
}
/**
* @param rootPackageNames
* @param sb
* @param displayByTags
* @return error message
*/
protected String scanAnnotation_Unique(String[] rootPackageNames, StringBuilder sb, String... displayByTags) {
log.trace("");
StringBuilder errors = new StringBuilder();
boolean error = false;
Set> classes = ReflectionUtil.getAllImplementationsByAnnotation(Unique.class, false, rootPackageNames);
for (Class classWithUniqueValues : classes) {
if (!classWithUniqueValues.isInterface()) {
error = true;
errors.append(BootConstant.BR).append("\t @Unique can only apply on interfaces, ").append(classWithUniqueValues).append(" is not an interface");
continue;
}
Unique u = (Unique) classWithUniqueValues.getAnnotation(Unique.class);
String tag = u.name();
availableUniqueTagOptions.add(tag);
Class uniqueType = u.type();
List tags = List.of(displayByTags);
try {
Map> duplicated = ApplicationUtil.checkDuplicateFields(classWithUniqueValues, uniqueType);
if (!duplicated.isEmpty()) {
String report = BeanUtil.toJson(duplicated, true, false);
return "Duplicated " + uniqueType.getSimpleName() + " values in " + classWithUniqueValues.getSimpleName() + " " + report;
} else if (tags.contains(tag)) {
Map results = new HashMap();
ReflectionUtil.loadFields(classWithUniqueValues, uniqueType, results, false);
Map sorted = results
.entrySet()
.stream()
.sorted(Map.Entry.comparingByValue())
.collect(Collectors.toMap(Map.Entry::getValue, Map.Entry::getKey, (e1, e2) -> e1, LinkedHashMap::new));
String json = BeanUtil.toJson(sorted, true, false);
sb.append(BootConstant.BR).append(tag).append("=").append(json);
}
} catch (Throwable ex) {
throw new RuntimeException("check unique failed on " + classWithUniqueValues.getName(), ex);
}
}
if (error) {
throw new RuntimeException(errors.toString());
}
return null;
}
protected void scanAnnotation_JExpressConfigImportResource(String... rootPackageNames) {
log.trace("");
Set pakcages = Set.copyOf(List.of(rootPackageNames));
//Set> classesAll = new HashSet();//to remove duplicated
//for (String rootPackageName : pakcages) {
Set> jExpressConfigClasses = ReflectionUtil.getAllImplementationsByInterface(JExpressConfig.class, pakcages);
// classesAll.addAll(jExpressConfigClasses);
//}
for (Class jExpressConfigClass : jExpressConfigClasses) {
int mod = jExpressConfigClass.getModifiers();
if (mod == 0 || Modifier.isAbstract(mod) || Modifier.isInterface(mod)) {
continue;
}
String key = jExpressConfigClass.getSimpleName();
if (scanedJExpressConfigs.containsKey(key)) {
continue;
}
String configFileName = null;
String checkImplTagUsed = "";
boolean loadWhenImplTagUsed = false;
ImportResource ir = (ImportResource) jExpressConfigClass.getAnnotation(ImportResource.class);
if (ir != null) {
configFileName = ir.value();
checkImplTagUsed = ir.checkImplTagUsed();
loadWhenImplTagUsed = ir.loadWhenImplTagUsed();
} else if (/*hasAuthImpl && */jExpressConfigClass.equals(AuthConfig.class)) {
configFileName = BootConstant.FILE_CFG_AUTH;
} else if (hasControllers && jExpressConfigClass.equals(NioConfig.class)) {
configFileName = BootConstant.FILE_CFG_NIO;
} else if (hasGRPCImpl && jExpressConfigClass.equals(GRPCServerConfig.class)) {
configFileName = BootConstant.FILE_CFG_GRPC;
} else if (jExpressConfigClass.equals(SMTPClientConfig.class)) {
configFileName = BootConstant.FILE_CFG_SMTP;
} else {
continue;
}
ConfigMetadata metadata = new ConfigMetadata(configFileName, jExpressConfigClass, null, checkImplTagUsed, loadWhenImplTagUsed);
//availableAppConfigs.add(rc);
scanedJExpressConfigs.put(key, metadata);
memo.append(BootConstant.BR).append("\t- scan.JExpressConfig.ImportResource:").append(key).append("=").append(metadata);
memo.append(BootConstant.BR).append("\t- cfg.scaned=").append(jExpressConfigClass.getName()).append(", file=").append(configFileName);
}
}
protected void scanImplementation_gRPC(String... pakcages) {
log.trace("");
//gRPCBindableServiceImplClasses.addAll(ReflectionUtil.getAllImplementationsByInterface(BindableService.class, callerRootPackageNames));
//for (String rootPackageName : pakcages) {
Set> gRPCServerClasses = ReflectionUtil.getAllImplementationsByAnnotation(GrpcService.class, false, pakcages);
for (Class gRPCServerClass : gRPCServerClasses) {
if (BindableService.class.isAssignableFrom(gRPCServerClass)) {
gRPCBindableServiceImplClasses.add(gRPCServerClass);
} else if (ServerServiceDefinition.class.equals(gRPCServerClass)) {
gRPCServerServiceDefinitionImplClasses.add(gRPCServerClass);
}
}
//}
hasGRPCImpl = !gRPCServerServiceDefinitionImplClasses.isEmpty() || !gRPCBindableServiceImplClasses.isEmpty();
}
protected void scanAnnotation_Controller(String... rootPackageNames) {
log.trace("");
//Set> classesAll = new HashSet();//to remove duplicated
//for (String rootPackageName : rootPackageNames) {
Set> classes = ReflectionUtil.getAllImplementationsByAnnotation(Controller.class, false, rootPackageNames);
//classesAll.addAll(classes);
//}
List tags = new ArrayList();
for (Class c : classes) {
Controller a = (Controller) c.getAnnotation(Controller.class);
if (a == null) {
continue;
}
String implTag = a.implTag();
tags.add(implTag);
}
List serviceImplTags = tags.stream()
.distinct()
.collect(Collectors.toList());
serviceImplTags.removeAll(Collections.singleton(null));
serviceImplTags.removeAll(Collections.singleton(""));
serviceImplTags.removeAll(Collections.singleton(Controller.NOT_TAGGED));
availableImplTagOptions.addAll(serviceImplTags);
}
protected List scanAnnotation_Service(String... rootPackageNames) {
log.trace("");
//Set> classesAll = new HashSet();//to remove duplicated
//for (String rootPackageName : rootPackageNames) {
Set> classes = ReflectionUtil.getAllImplementationsByAnnotation(Service.class, false, rootPackageNames);
//classesAll.addAll(classes);
//}
return scanAnnotation_Service(classes);
}
protected List scanAnnotation_Service(Set> classesAll) {
log.trace("");
List tags = new ArrayList();
StringBuilder sb = new StringBuilder();
for (Class serviceImplClass : classesAll) {
Service serviceAnnotation = (Service) serviceImplClass.getAnnotation(Service.class);
if (serviceAnnotation == null) {
continue;
}
String named = serviceAnnotation.named().trim();
String implTag = serviceAnnotation.implTag().trim();
tags.add(implTag);
String uniqueKey = "named=" + named + ", implTag=" + implTag;
Class[] bindingClasses = serviceAnnotation.binding();
Service.ChannelHandlerType ChannelHandlerType = serviceAnnotation.type();
if (bindingClasses != null && bindingClasses.length > 0) {//developer specified
for (Class bindingClass : bindingClasses) {
if (!bindingClass.isAssignableFrom(serviceImplClass)) {
List interfaces = ReflectionUtil.getAllInterfaces(serviceImplClass, true);
List superclasses = ReflectionUtil.getAllSuperClasses(serviceImplClass);
interfaces.addAll(superclasses);
interfaces.remove(Object.class);
sb.append(BootConstant.BR).append("\t").append(serviceImplClass).append(" specifies @").append(Service.class.getSimpleName()).append("(binding=").append(bindingClass.getSimpleName()).append(".class), which is not in its Interfaces:").append(interfaces);
continue;
}
scanAnnotation_Service_Add2BindingMap(bindingClass, uniqueKey, new ServiceMetadata(serviceImplClass, named, implTag, ChannelHandlerType), sb);
}
} else {//bindingClass not specified by developer, use its declaired interfaces by default
List declaredInterfaces = ReflectionUtil.getAllInterfaces(serviceImplClass, false);
if (declaredInterfaces.isEmpty()) {
List superInterfaces = ReflectionUtil.getAllInterfaces(serviceImplClass.getSuperclass(), true);
if (superInterfaces.isEmpty()) {
sb.append(BootConstant.BR).append("\t").append(serviceImplClass).append(" does not implement any interfaces.");
} /*else if (superInterfaces.size() == 1) {
Class bindingClass = superInterfaces.get(0);
scanAnnotation_Service_Add2BindingMap(bindingClass, uniqueKey, serviceImplClass, named);
} */ else {
sb.append(BootConstant.BR).append("\t").append(serviceImplClass).append(" needs to specify the binding interface @").append(Service.class.getSimpleName()).append("(binding=TheMissingInterface.class), which implemented by supper class: ").append(superInterfaces);
}
continue;
}
for (Class bindingClass : declaredInterfaces) {
scanAnnotation_Service_Add2BindingMap(bindingClass, uniqueKey, new ServiceMetadata(serviceImplClass, named, implTag, ChannelHandlerType), sb);
}
}
}
scanAnnotation_Service_ValidateBindingMap(sb);
//Java 17if (!sb.isEmpty()) {
String error = sb.toString();
if (!error.isBlank()) {
System.out.println("IOC Code error:" + sb);
System.exit(1);
}
List serviceImplTags = tags.stream()
.distinct()
.collect(Collectors.toList());
serviceImplTags.removeAll(Collections.singleton(null));
serviceImplTags.removeAll(Collections.singleton(""));
serviceImplTags.removeAll(Collections.singleton(Service.NOT_TAGGED));
availableImplTagOptions.addAll(serviceImplTags);
return serviceImplTags;
}
protected void scanAnnotation_Service_Add2BindingMap(Class bindingClass, String uniqueKey, ServiceMetadata service, StringBuilder sb) {
log.trace("");
memo.append(BootConstant.BR).append("\t- scan.taggedservice.add to guiceModule.bind(").append(bindingClass.getName()).append(").to(").append(service).append("), uniqueKey=").append(uniqueKey);
Map> taggeServicedMap = scanedServiceBindingMap.get(bindingClass);
if (taggeServicedMap == null) {
taggeServicedMap = new HashMap();
scanedServiceBindingMap.put(bindingClass, taggeServicedMap);
}
List serviceImplList = taggeServicedMap.get(uniqueKey);
if (serviceImplList == null) {
serviceImplList = new ArrayList();
taggeServicedMap.put(uniqueKey, serviceImplList);
}
if (bindingClass.equals(ChannelHandler.class)) {
ChannelHandlerType channelHandlerType = service.getChannelHandlerType();
if (channelHandlerType == null || channelHandlerType == ChannelHandlerType.nptspecified) {
sb.append(BootConstant.BR).append("\t").append(service.getServiceImplClass()).append(" needs to specify type @").append(Service.class.getSimpleName()).append("(binding=ChannelHandler.class, type=?), when binding=ChannelHandler.class");
}
}
serviceImplList.add(service);
}
protected void scanAnnotation_Service_ValidateBindingMap(StringBuilder sb) {
log.trace("");
for (Class keyBindingClass : scanedServiceBindingMap.keySet()) {
Map> taggeServicedMap = scanedServiceBindingMap.get(keyBindingClass);
for (String keyImplTag : taggeServicedMap.keySet()) {
List serviceImplList = taggeServicedMap.get(keyImplTag);
int size = serviceImplList.size();
if (size != 1) {
sb.append(BootConstant.BR).append("IOC ").append(keyBindingClass).append(" required a single bean, but ").append(size).append(" were found with the same named+implTag(").append(keyImplTag).append("): ").append(serviceImplList);
}
}
}
}
protected void scanAnnotation_DeclareRoles(String... rootPackageNames) {
log.trace("");
Set declareRoles = new TreeSet();
//Set> classesAll = new HashSet();//to remove duplicated
//for (String rootPackageName : rootPackageNames) {
Set> classes = ReflectionUtil.getAllImplementationsByAnnotation(Controller.class, false, rootPackageNames);
// classesAll.addAll(classes);
//}
hasControllers = !classes.isEmpty();
// @DeclareRoles
for (Class c : classes) {
DeclareRoles drs = (DeclareRoles) c.getAnnotation(DeclareRoles.class);
if (drs != null) {
String[] roles = drs.value();
declareRoles.addAll(Arrays.asList(roles));
}
// @RolesAllowed
List methods = ReflectionUtil.getDeclaredAndSuperClassesMethods(c, true);
for (Method javaMethod : methods) {
RolesAllowed ra = javaMethod.getAnnotation(RolesAllowed.class);
if (ra == null) {
continue;
}
String[] roles = ra.value();
declareRoles.addAll(Arrays.asList(roles));
}
}
final AuthConfig authCfg = AuthConfig.cfg;
authCfg.addDeclareRoles(declareRoles);
memo.append(BootConstant.BR).append("\t- scan.DeclareRoles=").append(declareRoles);
//2. check is there any declared roles so that the auth config should be used
hasAuthImpl = !authCfg.getDeclareRoles().isEmpty();
}
protected static class ConfigMetadata {
final Class cfgClass;
final String configFileName;
final JExpressConfig instance;
final String checkImplTagUsed;
final boolean loadWhenImplTagUsed;
ConfigMetadata(String configFileName, Class cfgClass, JExpressConfig instance, String checkImplTagUsed, boolean loadWhenImplTagUsed) {
this.configFileName = configFileName;
this.cfgClass = cfgClass;
this.instance = instance;
this.checkImplTagUsed = checkImplTagUsed;
this.loadWhenImplTagUsed = loadWhenImplTagUsed;
}
@Override
public String toString() {
return "ConfigMetadata{" + "cfgClass=" + cfgClass.getName() + ", configFileName=" + configFileName + ", instance=" + instance + ", checkImplTagUsed=" + checkImplTagUsed + ", loadWhenImplTagUsed=" + loadWhenImplTagUsed + '}';
}
}
public static class ServiceMetadata {
final Class serviceImplClass;
final String named;
final String implTag;
final ChannelHandlerType channelHandlerType;
public ServiceMetadata(Class serviceImplClass, String named, String implTag, ChannelHandlerType channelHandlerType) {
this.serviceImplClass = serviceImplClass;
this.named = named;
this.implTag = implTag;
this.channelHandlerType = channelHandlerType;
}
@Override
public String toString() {
return "ServiceImpl{" + serviceImplClass.getName() + ", named=" + named + ", implTag=" + implTag + '}';
}
public Class getServiceImplClass() {
return serviceImplClass;
}
public String getNamed() {
return named;
}
public String getImplTag() {
return implTag;
}
public ChannelHandlerType getChannelHandlerType() {
return channelHandlerType;
}
}
}