PDA

View Full Version : [Java] Simple Plugin System



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.

Lord Pain
June 18th, 2010, 23:31
thanks, i sorta understand this not much into java i mostly code C++ Or D3D so nice Job :)

Pie`
June 20th, 2010, 16:19
this is like an eventmanager

only bad and doesn't work properly

EDIT:


public IPlugin getPlugin(String name) {
IPlugin plugin = null;
for (String s : loadedPlugins.keySet()) {
if (s.equalsIgnoreCase(name)) {
plugin = loadedPlugins.get(s);
}
}
return plugin;
}

????? whats wrong with


public IPlugin getPlugin(String name) {
return loadedPlugins.get(name);
}

it achieves exactly the same.

Anthony
June 20th, 2010, 22:08
this is like an eventmanager

only bad and doesn't work properly

EDIT:


public IPlugin getPlugin(String name) {
IPlugin plugin = null;
for (String s : loadedPlugins.keySet()) {
if (s.equalsIgnoreCase(name)) {
plugin = loadedPlugins.get(s);
}
}
return plugin;
}

????? whats wrong with


public IPlugin getPlugin(String name) {
return loadedPlugins.get(name);
}

it achieves exactly the same.

explain this doesnt work properly theory and i though get(Object) only checked references unless I'm being retarded.

Trey
June 21st, 2010, 03:08
explain this doesnt work properly theory and i though get(Object) only checked references unless I'm being retarded.

Map's get method uses the equals method.


Returns the value to which the specified key is mapped, or null if this map contains no mapping for the key.
More formally, if this map contains a mapping from a key k to a value v such that (key==null ? k==null : key.equals(k)), then this method returns v; otherwise it returns null. (There can be at most one such mapping.)

A return value of null does not necessarily indicate that the map contains no mapping for the key; it's also possible that the map explicitly maps the key to null. The containsKey operation may be used to distinguish these two cases.


I can't think of any collection that compares references instead of using the equals method.

Peter
June 21st, 2010, 03:56
Thanks, I'm about to give it a try, Its better then meh other one...

Anthony
June 21st, 2010, 07:03
Map's get method uses the equals method.


I can't think of any collection that compares references instead of using the equals method.
Actually HashMap's check the hashcode of a class, hence the name.

Trey
June 21st, 2010, 13:12
Actually HashMap's check the hashcode of a class, hence the name.

Hashing and object references are completely different things. You should override hashCode whenever you override equals, because any objects that are equal in terms of the equals method should have the same hashCode result. hashCode only deals with addresses by default, and if you're storing an object in a collection you should have a proper equals method, so in turn you should have a proper hashCode method.

roystonparera
June 22nd, 2010, 06:17
I think that this information given by you is really nice, I really wanted to try this class loader for overwrite one class in another.

nmanpure
June 25th, 2010, 18:39
Hate to break it to you Peter but "Void Coding" would be spelled "Void Codeing" Unless you spelled it that way on purpose.

Trey
June 25th, 2010, 18:48
Hate to break it to you Peter but "Void Coding" would be spelled "Void Codeing" Unless you spelled it that way on purpose.

Hate to break it to you nmanpure but you're wrong.

nmanpure
August 22nd, 2010, 21:29
=] ......
______
Tht last comment wasnt me it was someone else on my computer -_-