Ghetto module+lib loading

This commit is contained in:
Erik Bročko 2018-10-01 23:53:38 +02:00
parent e97a43c9e2
commit 29b7a3cee7
3 changed files with 136 additions and 19 deletions

View File

@ -2,6 +2,11 @@ package cz.marwland.mc.core;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.Path;
import java.util.HashMap;
import java.util.Map;
@ -18,6 +23,7 @@ import cz.marwland.mc.core.storage.StorageCredentials;
import cz.marwland.mc.core.storage.impl.MariaDbConnectionFactory;
import cz.marwland.mc.core.storage.impl.MySqlConnectionFactory;
import cz.marwland.mc.core.util.ConfigUtil;
import cz.marwland.mc.core.util.FileUtil;
public class MarwCore extends JavaPlugin {
@ -25,28 +31,32 @@ public class MarwCore extends JavaPlugin {
private HashMap<String, Feature> features = new HashMap<>();
private static MarwCore INSTANCE = null;
private File modulesFolder = null;
private File libsFolder = null;
private ModuleClassLoader moduleClassLoader;
private SQLStorage sqlStorage;
@Override
public void onEnable() {
INSTANCE = this;
this.getCommand("marw").setExecutor(new MarwCommandExecutor());
modulesFolder = this.getModulesFolderPath().toFile();
modulesFolder.mkdirs();
libsFolder = this.getLibsFolderPath().toFile();
libsFolder.mkdir();
configManager = new ConfigManager(this);
configManager.registerConfig("config.yml");
configManager.loadConfig("config.yml");
this.loadModulesAndLibs();
this.loadDatabase();
modulesFolder = this.getModulesFolderPath().toFile();
modulesFolder.mkdirs();
this.loadAndEnableModules();
this.getCommand("marw").setExecutor(new MarwCommandExecutor());
this.enableModules();
}
@Override
public void onDisable() {
this.features.forEach((k, v) -> v.onDisable());
this.configManager.save();
if (sqlStorage != null)
this.sqlStorage.shutdown();
}
@ -56,13 +66,14 @@ public class MarwCore extends JavaPlugin {
}
public void reload() {
this.reloadConfig();
this.features.forEach((k, v) -> v.onDisable());
this.reloadConfig();
this.loadModulesAndLibs();
this.loadDatabase();
this.loadAndEnableModules();
this.enableModules();
}
public void loadModules() {
public void loadModulesAndLibs() {
if (moduleClassLoader != null) {
try {
moduleClassLoader.close();
@ -71,10 +82,17 @@ public class MarwCore extends JavaPlugin {
}
}
moduleClassLoader = new ModuleClassLoader();
URLClassLoader pluginClassLoader = (URLClassLoader) this.getClassLoader();
FileUtil.addFromDirectory(pluginClassLoader, libsFolder);
//FileUtil.addFromDirectory(pluginClassLoader, modulesFolder);
moduleClassLoader = new ModuleClassLoader(pluginClassLoader);
//moduleClassLoader.addFromDirectory(libsFolder);
moduleClassLoader.addFromDirectory(modulesFolder);
}
public void enableModules() {
for (String modClass : configManager.getConfig("config.yml").getStringList("modules")) {
//Feature f = FileUtil.doConstructor((URLClassLoader) this.getClassLoader(), modClass, this);
Feature f = moduleClassLoader.doConstructor(modClass, this);
if (f == null)
continue;
@ -82,10 +100,6 @@ public class MarwCore extends JavaPlugin {
this.addFeature(f);
this.getLogger().log(Level.INFO, "Loaded " + f.getName() + " @ " + modClass);
}
}
public void loadAndEnableModules() {
this.loadModules();
configManager.load();
this.features.forEach((k, v) -> v.onEnable());
}
@ -114,6 +128,10 @@ public class MarwCore extends JavaPlugin {
return this.getDataFolder().toPath().resolve("modules");
}
public Path getLibsFolderPath() {
return this.getDataFolder().toPath().resolve("libs");
}
public ModuleClassLoader getModuleClassLoader() {
return this.moduleClassLoader;
}
@ -141,7 +159,7 @@ public class MarwCore extends JavaPlugin {
props
);
String method = cfg.getString("method");
String method = cfg.getString("dataSource.method");
if (method.equalsIgnoreCase("mariadb")) {
this.sqlStorage = new SQLStorage(new MariaDbConnectionFactory(creds));
} else if (method.equalsIgnoreCase("mysql")) {

View File

@ -15,8 +15,8 @@ public class ModuleClassLoader extends URLClassLoader {
private ArrayList<JarFile> jars = new ArrayList<>();
public ModuleClassLoader() {
super(new URL[] { }, ModuleClassLoader.class.getClassLoader());
public ModuleClassLoader(ClassLoader parent) {
super(new URL[] { }, parent);
}
public void addFile(File file) throws IOException {

View File

@ -0,0 +1,99 @@
package cz.marwland.mc.core.util;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.charset.StandardCharsets;
import java.util.logging.Level;
import org.bukkit.plugin.java.JavaPlugin;
import cz.marwland.mc.core.features.Feature;
public class FileUtil {
public static String readFileFromJAR(Class<?> parent, String path) throws IOException {
InputStream in = parent.getResourceAsStream(path);
if (in == null) {
System.err.println("Invalid path: " + path);
return null;
}
ByteArrayOutputStream result = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int length;
while ((length = in.read(buffer)) != -1) {
result.write(buffer, 0, length);
}
String ret = result.toString(StandardCharsets.UTF_8.name() );
in.close();
return ret;
}
public static void addFromDirectory(URLClassLoader cl, File modDir) {
if (!modDir.isDirectory())
throw new IllegalArgumentException("Provided 'modDir' argument is not a directory: " + modDir.getPath());
for (File mod : modDir.listFiles()) {
if (mod.isDirectory())
continue;
int lastdot = mod.getName().lastIndexOf('.');
if (lastdot < 0)
continue;
if (!mod.getName().substring(lastdot + 1).equalsIgnoreCase("jar"))
continue;
try {
Method method = URLClassLoader.class.getDeclaredMethod("addURL", new Class[]{ URL.class });
method.setAccessible(true);
method.invoke(cl, new Object[]{ mod.toURI().toURL() });
} catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | MalformedURLException e) {
e.printStackTrace();
}
System.out.println(">>> Loaded: " + mod.getAbsolutePath());
}
}
public static Feature doConstructor(ClassLoader cl, String classPath)
throws ClassNotFoundException, ClassCastException, IllegalAccessException, InstantiationException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException {
Class<?> jarClass;
jarClass = Class.forName(classPath, true, cl);
Class<? extends Feature> pluginClass;
pluginClass = jarClass.asSubclass(Feature.class);
return pluginClass.getDeclaredConstructor().newInstance();
}
public static Feature doConstructor(ClassLoader cl, String classPath, JavaPlugin plugin) {
try {
return doConstructor(cl, classPath);
} catch (ClassNotFoundException e) {
plugin.getLogger().log(Level.SEVERE, "Cannot find class '" + classPath + "'!");
} catch (ClassCastException e) {
plugin.getLogger().log(Level.SEVERE, "Class '" + classPath + "' does not extend Feature!");
} catch (IllegalAccessException e) {
plugin.getLogger().log(Level.SEVERE, "No public constructor in '" + classPath + "'!");
} catch (InstantiationException e) {
plugin.getLogger().log(Level.SEVERE, "Cannot instantiate '" + classPath + "'!");
} catch (IllegalArgumentException e) {
plugin.getLogger().log(Level.SEVERE, "Illegal arguments to the constructor of '" + classPath + "'!");
} catch (InvocationTargetException e) {
plugin.getLogger().log(Level.SEVERE, "Error occured whilst initializing '" + classPath + "'!");
e.printStackTrace();
} catch (NoSuchMethodException e) {
plugin.getLogger().log(Level.SEVERE, "Class '" + classPath + "' does not have a public constructor!");
} catch (SecurityException e) {
plugin.getLogger().log(Level.SEVERE, "SecurityException occured whilst initializing '" + classPath + "'!");
e.printStackTrace();
}
return null;
}
}