tzssangglass commented on code in PR #158: URL: https://github.com/apache/apisix-java-plugin-runner/pull/158#discussion_r913059769
########## runner-starter/src/main/java/org/apache/apisix/plugin/runner/PluginRunnerApplication.java: ########## @@ -17,17 +17,138 @@ package org.apache.apisix.plugin.runner; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.scheduling.annotation.Scheduled; import org.springframework.boot.WebApplicationType; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.context.ApplicationContext; +import org.springframework.scheduling.annotation.EnableScheduling; + +import javax.tools.JavaCompiler; +import javax.tools.ToolProvider; +import java.io.File; +import java.io.IOException; +import java.nio.file.FileSystems; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.WatchEvent; +import java.nio.file.WatchKey; +import java.nio.file.WatchService; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; + +import static java.nio.file.StandardWatchEventKinds.ENTRY_CREATE; +import static java.nio.file.StandardWatchEventKinds.ENTRY_DELETE; +import static java.nio.file.StandardWatchEventKinds.ENTRY_MODIFY; @SpringBootApplication +@EnableScheduling public class PluginRunnerApplication { - + + @Autowired + private YAMLConfig myConfig; + @Autowired + private ApplicationContext ctx; + private static ClassLoader PARENT_CLASS_LOADER; + private static DynamicClassLoader CLASS_LOADER; + public static void main(String[] args) { + PARENT_CLASS_LOADER = DynamicClassLoader.class.getClassLoader(); + CLASS_LOADER = new DynamicClassLoader(PARENT_CLASS_LOADER); + Thread.currentThread().setContextClassLoader(CLASS_LOADER); new SpringApplicationBuilder(PluginRunnerApplication.class) .web(WebApplicationType.NONE) .run(args); } - + + @Scheduled(fixedDelay = Long.MAX_VALUE, initialDelay = 1000) + public void reload() throws ClassNotFoundException, IOException, InterruptedException { + BeanDefinitionRegistry registry = (BeanDefinitionRegistry) ctx.getAutowireCapableBeanFactory(); + WatchService watchService = FileSystems.getDefault().newWatchService(); + + String pathToProject = System.getProperty("user.dir"); + + //get packagename and path to user's filters from YAML file + String packageName = myConfig.getPackageName(); + String absolutePath = myConfig.getPath(); + if (packageName.equals("")) { + packageName = "org.apache.apisix.plugin.runner.filter"; + } + if (absolutePath.equals("")) { + absolutePath = pathToProject + "/runner-plugin/src/main/java/org/apache/apisix/plugin/runner/filter/"; + } + Path path = Paths.get(absolutePath); + + //make /target/classes directory if not already exists, compiled java files are output here + new File(pathToProject + "/target").mkdirs(); + new File(pathToProject + "/target/classes").mkdirs(); + + //detect changes when files in the path are created, modified, or deleted + path.register(watchService, ENTRY_CREATE, ENTRY_MODIFY, ENTRY_DELETE); + boolean poll = true; + while (poll) { + WatchKey key = watchService.take(); + for (WatchEvent<?> event : key.pollEvents()) { + String[] allFilters = new File(absolutePath).list(); + HashSet<String> set = new HashSet<>(); + + for (int i = 0; i < allFilters.length; i++) { + //strangely, watchservice creates a file that ends with ".java~", we ignore this file + if (!allFilters[i].equals("package-info.java") && allFilters[i].charAt(allFilters[i].length() - 1) != '~') { + allFilters[i] = allFilters[i].substring(0, allFilters[i].length() - 5); + set.add(allFilters[i]); + } + } + + for (String filterName : allFilters) { + if ((!filterName.equals("package-info.java")) && filterName.charAt(filterName.length() - 1) != '~') { + //Bean Filter Name necessary because beans always start with lower case letters + String beanFilterName = Character.toLowerCase(filterName.charAt(0)) + filterName.substring(1); + if (registry.containsBeanDefinition(beanFilterName)) { + registry.removeBeanDefinition(beanFilterName); + } + JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); + String[] args = {"-d", pathToProject + "/target/classes", absolutePath + filterName + ".java"}; + compiler.run(null, null, null, args); + + CLASS_LOADER = new DynamicClassLoader(PARENT_CLASS_LOADER); + CLASS_LOADER.setDir(pathToProject + "/target/classes"); + CLASS_LOADER.setFilters(set); + CLASS_LOADER.setPackageName(packageName); + Class myObjectClass = CLASS_LOADER.loadClass(filterName); Review Comment: ```suggestion Class<?> myObjectClass = CLASS_LOADER.loadClass(filterName); ``` -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: notifications-unsubscr...@apisix.apache.org For queries about this service, please contact Infrastructure at: us...@infra.apache.org