Anthony
June 17th, 2010, 19:36
A simple plugin system, uses a custom class loader so that it can load classes on another class loader and overwrite the currently loaded plugin if needed.
/**
* Copyright (C) 2010 Anthony Snavely
*
* This program is free software. It comes without any warranty, to
* the extent permitted by applicable law. You can redistribute it
* and/or modify it under the terms of the Do What The Fuck You Want
* To Public License, Version 2, as published by Sam Hocevar. See
* Only the registered members can see the link. for more details.
*/
package com.anthony.mscp.sps;
/**
* @author anthony
*
*/
public interface IPlugin {
public void execute();
public String getName();
}
/**
* Copyright (C) 2010 Anthony Snavely
*
* This program is free software. It comes without any warranty, to
* the extent permitted by applicable law. You can redistribute it
* and/or modify it under the terms of the Do What The Fuck You Want
* To Public License, Version 2, as published by Sam Hocevar. See
* Only the registered members can see the link. for more details.
*/
package com.anthony.mscp.sps;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
/**
* @author anthony A simple plugin system that loads plugins dynamically then
* allows the reloading of them.
*/
public class SimplePluginSystem {
private Map<String, IPlugin> loadedPlugins = new HashMap<String, IPlugin>();
private PluginClassLoader curLoader;
public void reloadPlugins() {
File pluginDir = new File("./bin/com/anthony/mscp/sps/impl/");
loadedPlugins.clear();
curLoader = new PluginClassLoader("./bin/");
if (pluginDir.isDirectory()) {
for (File i : pluginDir.listFiles()) {
String name = i.getName();
if (name.contains(".class")) {
try {
curLoader.addPlugin("com.anthony.mscp.sps.impl."
+ name.replace(".class", ""));
Class<IPlugin> c = curLoader.loadClass(
"com.anthony.mscp.sps.impl."
+ name.replace(".class", ""), true);
if (IPlugin.class.isAssignableFrom(c)) {
IPlugin plugin = c.newInstance();
loadedPlugins.put(plugin.getName(), plugin);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
}
public IPlugin getPlugin(String name) {
return loadedPlugins.get(name);
}
// Just random testing shit.
public static void main(String[] args) {
while (true) {
SimplePluginSystem shit = new SimplePluginSystem();
shit.reloadPlugins();
shit.getPlugin("test1").execute();
shit.getPlugin("test2").execute();
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
//**
* Copyright (C) 2010 Anthony Snavely
*
* This program is free software. It comes without any warranty, to
* the extent permitted by applicable law. You can redistribute it
* and/or modify it under the terms of the Do What The Fuck You Want
* To Public License, Version 2, as published by Sam Hocevar. See
* Only the registered members can see the link. for more details.
*/
package com.anthony.mscp.sps;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
/**
* @author anthony
* A simple class loader impl so we can load plugins.
*/
public class PluginClassLoader extends ClassLoader {
private String root;
private ArrayList<String> pluginNames = new ArrayList<String>();
public PluginClassLoader(String rootDir) {
if (rootDir == null)
throw new IllegalArgumentException("Null root directory");
root = rootDir;
}
public void addPlugin(String s) {
pluginNames.add(s);
}
public boolean allowedPlugin(String s) {
boolean found = false;
for(String plg : pluginNames) {
if(plg.equalsIgnoreCase(s)) {
found = true;
}
}
return found;
}
@SuppressWarnings("unchecked")
public Class<IPlugin> loadClass(String classname, boolean resolve)
throws ClassNotFoundException {
if (allowedPlugin(classname)) {
Class<IPlugin> c = null;
String filename = classname.replace('.', File.separatorChar) + ".class";
try {
byte[] buffer = grabClassBytes(filename);
c = (Class<IPlugin>) defineClass(classname, buffer, 0, buffer.length);
} catch (IOException e) {
throw new ClassNotFoundException("cannot read file: "
+ filename);
}
if (resolve) {
resolveClass(c);
}
return c;
}
return (Class<IPlugin>) super.loadClass(classname, resolve);
}
private byte[] grabClassBytes(String name) throws IOException {
File classFile = new File(root, name);
int bufsize = (int) classFile.length();
byte buffer[] = new byte[bufsize];
FileInputStream fis = new FileInputStream(classFile);
DataInputStream dis = new DataInputStream(fis);
dis.readFully(buffer);
dis.close();
return buffer;
}
}
If you have any criticism feel free to post it here, do note this isn't production ready it's just an example of how you could write something like this.
/**
* Copyright (C) 2010 Anthony Snavely
*
* This program is free software. It comes without any warranty, to
* the extent permitted by applicable law. You can redistribute it
* and/or modify it under the terms of the Do What The Fuck You Want
* To Public License, Version 2, as published by Sam Hocevar. See
* Only the registered members can see the link. for more details.
*/
package com.anthony.mscp.sps;
/**
* @author anthony
*
*/
public interface IPlugin {
public void execute();
public String getName();
}
/**
* Copyright (C) 2010 Anthony Snavely
*
* This program is free software. It comes without any warranty, to
* the extent permitted by applicable law. You can redistribute it
* and/or modify it under the terms of the Do What The Fuck You Want
* To Public License, Version 2, as published by Sam Hocevar. See
* Only the registered members can see the link. for more details.
*/
package com.anthony.mscp.sps;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
/**
* @author anthony A simple plugin system that loads plugins dynamically then
* allows the reloading of them.
*/
public class SimplePluginSystem {
private Map<String, IPlugin> loadedPlugins = new HashMap<String, IPlugin>();
private PluginClassLoader curLoader;
public void reloadPlugins() {
File pluginDir = new File("./bin/com/anthony/mscp/sps/impl/");
loadedPlugins.clear();
curLoader = new PluginClassLoader("./bin/");
if (pluginDir.isDirectory()) {
for (File i : pluginDir.listFiles()) {
String name = i.getName();
if (name.contains(".class")) {
try {
curLoader.addPlugin("com.anthony.mscp.sps.impl."
+ name.replace(".class", ""));
Class<IPlugin> c = curLoader.loadClass(
"com.anthony.mscp.sps.impl."
+ name.replace(".class", ""), true);
if (IPlugin.class.isAssignableFrom(c)) {
IPlugin plugin = c.newInstance();
loadedPlugins.put(plugin.getName(), plugin);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
}
public IPlugin getPlugin(String name) {
return loadedPlugins.get(name);
}
// Just random testing shit.
public static void main(String[] args) {
while (true) {
SimplePluginSystem shit = new SimplePluginSystem();
shit.reloadPlugins();
shit.getPlugin("test1").execute();
shit.getPlugin("test2").execute();
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
//**
* Copyright (C) 2010 Anthony Snavely
*
* This program is free software. It comes without any warranty, to
* the extent permitted by applicable law. You can redistribute it
* and/or modify it under the terms of the Do What The Fuck You Want
* To Public License, Version 2, as published by Sam Hocevar. See
* Only the registered members can see the link. for more details.
*/
package com.anthony.mscp.sps;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
/**
* @author anthony
* A simple class loader impl so we can load plugins.
*/
public class PluginClassLoader extends ClassLoader {
private String root;
private ArrayList<String> pluginNames = new ArrayList<String>();
public PluginClassLoader(String rootDir) {
if (rootDir == null)
throw new IllegalArgumentException("Null root directory");
root = rootDir;
}
public void addPlugin(String s) {
pluginNames.add(s);
}
public boolean allowedPlugin(String s) {
boolean found = false;
for(String plg : pluginNames) {
if(plg.equalsIgnoreCase(s)) {
found = true;
}
}
return found;
}
@SuppressWarnings("unchecked")
public Class<IPlugin> loadClass(String classname, boolean resolve)
throws ClassNotFoundException {
if (allowedPlugin(classname)) {
Class<IPlugin> c = null;
String filename = classname.replace('.', File.separatorChar) + ".class";
try {
byte[] buffer = grabClassBytes(filename);
c = (Class<IPlugin>) defineClass(classname, buffer, 0, buffer.length);
} catch (IOException e) {
throw new ClassNotFoundException("cannot read file: "
+ filename);
}
if (resolve) {
resolveClass(c);
}
return c;
}
return (Class<IPlugin>) super.loadClass(classname, resolve);
}
private byte[] grabClassBytes(String name) throws IOException {
File classFile = new File(root, name);
int bufsize = (int) classFile.length();
byte buffer[] = new byte[bufsize];
FileInputStream fis = new FileInputStream(classFile);
DataInputStream dis = new DataInputStream(fis);
dis.readFully(buffer);
dis.close();
return buffer;
}
}
If you have any criticism feel free to post it here, do note this isn't production ready it's just an example of how you could write something like this.