Skip to content

Commit

Permalink
fixes networknt#2055 add plugin configuration as part of the module r…
Browse files Browse the repository at this point in the history
…eload (networknt#2060)
  • Loading branch information
stevehu authored Dec 19, 2023
1 parent ca3ba4b commit aa93134
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 37 deletions.
4 changes: 4 additions & 0 deletions config-reload/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@
<groupId>com.networknt</groupId>
<artifactId>body</artifactId>
</dependency>
<dependency>
<groupId>com.networknt</groupId>
<artifactId>rule-loader</artifactId>
</dependency>
<dependency>
<groupId>com.networknt</groupId>
<artifactId>handler</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
import com.networknt.consul.ConsulRegistry;
import com.networknt.handler.LightHttpHandler;
import com.networknt.httpstring.AttachmentConstants;
import com.networknt.rule.IAction;
import com.networknt.rule.RuleLoaderStartupHook;
import com.networknt.server.DefaultConfigLoader;
import com.networknt.server.IConfigLoader;
import com.networknt.status.HttpStatus;
Expand Down Expand Up @@ -47,37 +49,37 @@ public ConfigReloadHandler() {

@Override
public void handleRequest(final HttpServerExchange exchange) throws Exception {
List<String> modules = (List)exchange.getAttachment(AttachmentConstants.REQUEST_BODY);
List<String> reloads = new ArrayList<>();
if (config.isEnabled()) {
// this modulePlugins list contains both modules and plugins.
List<String> modulePlugins = (List)exchange.getAttachment(AttachmentConstants.REQUEST_BODY);
// the list that contains all the reloaded modules.
List<String> reloaded = new ArrayList<>();
// reload the config values.yml from the config server or local filesystem.
reLoadConfigs();
if (modules==null || modules.isEmpty() || modules.contains(MODULE_DEFAULT)) {
if (modules==null) modules = new ArrayList<>();
if (!modules.isEmpty()) modules.clear();

Map<String, Object> modulesRegistry = ModuleRegistry.getModuleRegistry();
for (Map.Entry<String, Object> entry: modulesRegistry.entrySet()) {
String key = entry.getKey();
if (key.contains(":")) {
key = key.substring(key.indexOf(":") + 1);
}
modules.add(key);
}
if (modulePlugins==null || modulePlugins.isEmpty() || modulePlugins.contains(MODULE_DEFAULT)) {
if (modulePlugins == null) modulePlugins = new ArrayList<>();
if (!modulePlugins.isEmpty()) modulePlugins.clear();
modulePlugins.addAll(ModuleRegistry.getModuleClasses());
modulePlugins.addAll(ModuleRegistry.getPluginClasses());
}

for (String module: modules) {
try {
Class handler = Class.forName(module);
if (processReloadMethod(handler)) reloads.add(handler.getName());
} catch (ClassNotFoundException e) {
throw new RuntimeException("Handler class: " + module + " has not been found");
for (String module: modulePlugins) {
if (ModuleRegistry.getModuleClasses().contains(module)) {
String s = reloadModule(module);
if(s != null) reloaded.add(s);
} else if (ModuleRegistry.getPluginClasses().contains(module)) {
String s = reloadPlugin(module);
if(s != null) reloaded.add(s);
} else {
logger.error("Module or plugin " + module + " is not found in the registry");
}
}
exchange.getResponseHeaders().add(new HttpString("Content-Type"), "application/json");
exchange.setStatusCode(HttpStatus.OK.value());
exchange.getResponseSender().send(mapper.writeValueAsString(reloads));
exchange.getResponseSender().send(mapper.writeValueAsString(reloaded));
} else {
logger.error("Config reload is disabled in configreload.yml");
logger.error("Config reload is disabled in configReload.yml");
setExchangeStatus(exchange, STATUS_CONFIG_RELOAD_DISABLED);
}
}
Expand All @@ -100,6 +102,35 @@ private boolean processReloadMethod(Class<?> handler) {
return false;
}

private String reloadModule(String module) {
try {
Class handler = Class.forName(module);
if (processReloadMethod(handler)) {
logger.info("Reload module " + module);
return module;
}
} catch (ClassNotFoundException e) {
throw new RuntimeException("Handler class: " + module + " has not been found");
}
return null;
}

private String reloadPlugin(String plugin) {
// remove from the RuleLoaderStartupHook.ruleEngine.actionClassCache
Object object = RuleLoaderStartupHook.ruleEngine.actionClassCache.remove(plugin);
if (object != null) {
// recreate the module and put it into the cache.
try {
IAction ia = (IAction)Class.forName(plugin).getDeclaredConstructor().newInstance();
RuleLoaderStartupHook.ruleEngine.actionClassCache.put(plugin, ia);
} catch (Exception e) {
throw new RuntimeException("Handler class: " + plugin + " has not been found");
}
logger.info("Reload plugin " + plugin);
return plugin;
}
return null;
}

private void reLoadConfigs(){
IConfigLoader configLoader;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
* This is an admin endpoint used to load the list of Registry moduels
Expand All @@ -31,28 +30,19 @@ public ModuleRegistryGetHandler() {

@Override
public void handleRequest(final HttpServerExchange exchange) throws Exception {


ConfigReloadConfig config = (ConfigReloadConfig) Config.getInstance().getJsonObjectConfig(ConfigReloadConfig.CONFIG_NAME, ConfigReloadConfig.class);

if (config.isEnabled()) {
List<String> modules = new ArrayList<>();
Map<String, Object> modulesRegistry = ModuleRegistry.getModuleRegistry();
for (Map.Entry<String, Object> entry : modulesRegistry.entrySet()) {
String key = entry.getKey();
if (key.contains(":")) {
key = key.substring(key.indexOf(":") + 1);
}
modules.add(key);
}
List<String> modulePlugins = new ArrayList<>();
modulePlugins.addAll(ModuleRegistry.getModuleClasses());
modulePlugins.addAll(ModuleRegistry.getPluginClasses());

exchange.getResponseHeaders().add(new HttpString("Content-Type"), "application/json");
exchange.setStatusCode(HttpStatus.OK.value());
exchange.getResponseSender().send(mapper.writeValueAsString(modules));

exchange.getResponseSender().send(mapper.writeValueAsString(modulePlugins));
} else {
logger.error("Config reload is disabled in configreload.yml");
logger.error("Config reload is disabled in configReload.yml");
setExchangeStatus(exchange, STATUS_CONFIG_RELOAD_DISABLED);
}

}
}
19 changes: 19 additions & 0 deletions utility/src/main/java/com/networknt/utility/ModuleRegistry.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@ public class ModuleRegistry {
private static final Map<String, Object> pluginRegistry = new HashMap<>();
private static final List<Map<String, Object>> plugins = new ArrayList<>();

// cache for the module classes
private static final List<String> moduleClasses = new ArrayList<>();
// cache for the plugin classes
private static final List<String> pluginClasses = new ArrayList<>();

public static void registerModule(String configName, String moduleClass, Map<String, Object> config, List<String> masks) {
// use module name as key for the config map will make api-certification parses this object easily.
if(config != null) {
Expand All @@ -46,6 +51,9 @@ public static void registerModule(String configName, String moduleClass, Map<Str
// we don't have any module without config, but we cannot guarantee user created modules
moduleRegistry.put(configName + ":" + moduleClass, new HashMap<String, Object>());
}
if(!moduleClasses.contains(moduleClass)) {
moduleClasses.add(moduleClass);
}
}
public static Map<String, Object> getModuleRegistry() {
return moduleRegistry;
Expand Down Expand Up @@ -75,11 +83,22 @@ public static void registerPlugin(String pluginName, String pluginVersion, Strin
plugin.put("pluginClass", pluginClass);
plugin.put("pluginVersion", pluginVersion);
plugins.add(plugin);
if(!pluginClasses.contains(pluginClass)) {
pluginClasses.add(pluginClass);
}
}

public static Map<String, Object> getPluginRegistry() { return pluginRegistry; }
public static List<Map<String, Object>> getPlugins() { return plugins; }

public static List<String> getModuleClasses() {
return moduleClasses;
}

public static List<String> getPluginClasses() {
return pluginClasses;
}

@SuppressWarnings("unchecked")
private static void maskNode(Map<String, Object> map, String mask) {
for (Map.Entry<String, Object> entry : map.entrySet()) {
Expand Down

0 comments on commit aa93134

Please sign in to comment.