Author: cyberdo
Date: 2006-02-18 16:46:38 +0000 (Sat, 18 Feb 2006)
New Revision: 8059
Added:
trunk/freenet/src/pluginmanager/
trunk/freenet/src/pluginmanager/FredPlugin.java
trunk/freenet/src/pluginmanager/PluginHandler.java
trunk/freenet/src/pluginmanager/PluginInfoWrapper.java
trunk/freenet/src/pluginmanager/PluginManager.java
trunk/freenet/src/pluginmanager/PluginNotFoundException.java
trunk/freenet/src/pluginmanager/PluginRespirator.java
trunk/freenet/src/pluginmanager/TestPlugin.java
Modified:
trunk/freenet/src/freenet/node/Node.java
trunk/freenet/src/freenet/node/TextModeClientInterface.java
trunk/freenet/src/freenet/node/Version.java
Log:
449:
First version of the plugin manager!
3 basic sommands added. Example plugin in src/pluginmanager/TestPlugin.java
(PLUGLOAD:pluginmanager.TestPlugin).
should workfine for now. Only FCP-support ATM. No sandboxing.
Modified: trunk/freenet/src/freenet/node/Node.java
===================================================================
--- trunk/freenet/src/freenet/node/Node.java 2006-02-18 14:43:37 UTC (rev
8058)
+++ trunk/freenet/src/freenet/node/Node.java 2006-02-18 16:46:38 UTC (rev
8059)
@@ -25,6 +25,9 @@
import java.util.HashSet;
import java.util.Iterator;
+import pluginmanager.PluginManager;
+import pluginmanager.PluginRespirator;
+
import snmplib.SNMPAgent;
import snmplib.SNMPStarter;
@@ -199,6 +202,9 @@
public final ClientRequestScheduler fetchScheduler;
public final ClientRequestScheduler putScheduler;
+ // Things that's needed to keep track of
+ public final PluginManager pluginManager;
+
// Client stuff that needs to be configged - FIXME
static final int MAX_ARCHIVE_HANDLERS = 200; // don't take up much RAM...
FIXME
static final long MAX_CACHED_ARCHIVE_DATA = 32*1024*1024; // make a fixed
fraction of the store by default? FIXME
@@ -485,6 +491,19 @@
testnetHandler.start();
if(statusUploader != null)
statusUploader.start();
+
+ // And finally, Initialize the plugin manager
+ PluginManager pm = null;
+ try {
+ HighLevelSimpleClient hlsc = new
HighLevelSimpleClientImpl(this,
+ archiveManager, tempBucketFactory,
random, false, (short)0);
+ PluginRespirator pluginRespirator = new
PluginRespirator(hlsc);
+ pm = new PluginManager(pluginRespirator);
+ } catch (Throwable e) {
+ e.printStackTrace();
+ System.err.println("THIS SHOULDN'T OCCUR!!!! (plugin
system now disabled)");
+ }
+ pluginManager = pm;
System.err.println("Created Node on port "+port);
}
Modified: trunk/freenet/src/freenet/node/TextModeClientInterface.java
===================================================================
--- trunk/freenet/src/freenet/node/TextModeClientInterface.java 2006-02-18
14:43:37 UTC (rev 8058)
+++ trunk/freenet/src/freenet/node/TextModeClientInterface.java 2006-02-18
16:46:38 UTC (rev 8059)
@@ -98,6 +98,9 @@
System.out.println("MAKESSK - Create an SSK keypair.");
System.out.println("PUTSSK:<insert uri>;<url to redirect to> - Insert
an SSK redirect to a file already inserted.");
System.out.println("PUTSSKDIR:<insert uri>#<path>[#<defaultfile>] -
Insert an entire directory to an SSK.");
+ System.out.println("PLUGLOAD: <pkg.classname>[@file:<jarfile.jar>] -
Load plugin.");
+ System.out.println("PLUGLIST - List all loaded plugins.");
+ System.out.println("PLUGKILL: <pluginID> - Unload the plugin with the
given ID (see PLUGLIST).");
// System.out.println("PUBLISH:<name> - create a publish/subscribe
stream called <name>");
// System.out.println("PUSH:<name>:<text> - publish a single line of
text to the stream named");
// System.out.println("SUBSCRIBE:<key> - subscribe to a
publish/subscribe stream by key");
@@ -500,6 +503,13 @@
} else if(uline.startsWith("DISCONNECT:")) {
String ipAndPort = line.substring("DISCONNECT:".length());
disconnect(ipAndPort.trim());
+
+ } else if(uline.startsWith("PLUGLOAD:")) {
+
n.pluginManager.startPlugin(line.substring("PLUGLOAD:".length()).trim());
+ } else if(uline.startsWith("PLUGLIST")) {
+ n.pluginManager.dumpPlugins();
+ } else if(uline.startsWith("PLUGKILL:")) {
+
n.pluginManager.killPlugin(line.substring("PLUGKILL:".length()).trim());
} else {
if(uline.length() > 0)
printHeader();
Modified: trunk/freenet/src/freenet/node/Version.java
===================================================================
--- trunk/freenet/src/freenet/node/Version.java 2006-02-18 14:43:37 UTC (rev
8058)
+++ trunk/freenet/src/freenet/node/Version.java 2006-02-18 16:46:38 UTC (rev
8059)
@@ -20,7 +20,7 @@
public static final String protocolVersion = "1.0";
/** The build number of the current revision */
- private static final int buildNumber = 448;
+ private static final int buildNumber = 449;
/** Oldest build of Fred we will talk to */
private static final int lastGoodBuild = 403;
Added: trunk/freenet/src/pluginmanager/FredPlugin.java
===================================================================
--- trunk/freenet/src/pluginmanager/FredPlugin.java 2006-02-18 14:43:37 UTC
(rev 8058)
+++ trunk/freenet/src/pluginmanager/FredPlugin.java 2006-02-18 16:46:38 UTC
(rev 8059)
@@ -0,0 +1,6 @@
+package pluginmanager;
+
+public interface FredPlugin {
+ public void terminate();
+ public void runPlugin(PluginRespirator pr);
+}
Added: trunk/freenet/src/pluginmanager/PluginHandler.java
===================================================================
--- trunk/freenet/src/pluginmanager/PluginHandler.java 2006-02-18 14:43:37 UTC
(rev 8058)
+++ trunk/freenet/src/pluginmanager/PluginHandler.java 2006-02-18 16:46:38 UTC
(rev 8059)
@@ -0,0 +1,64 @@
+package pluginmanager;
+
+/**
+ * Methods to handle a specific plugin (= set it up and start it)
+ *
+ * @author cyberdo
+ */
+public class PluginHandler {
+
+ /**
+ * Will get all needed info from the plugin, put it into the Wrapper.
Then
+ * the Pluginstarter will be greated, and the plugin fedto it, starting
the
+ * plugin.
+ *
+ * the pluginInfoWrapper will then be returned
+ *
+ * @param plug
+ */
+ public static PluginInfoWrapper startPlugin(PluginManager pm,
FredPlugin plug, PluginRespirator pr) {
+ PluginStarter ps = new PluginStarter(pr);
+ PluginInfoWrapper pi = new PluginInfoWrapper();
+ pi.putPluginThread(plug, ps);
+ ps.setPlugin(pm, plug);
+ ps.start();
+ return pi;
+ }
+
+ private static class PluginStarter extends Thread {
+ private Object plugin = null;
+ private PluginRespirator pr;
+ private PluginManager pm = null;
+
+ public PluginStarter(PluginRespirator pr) {
+ this.pr = pr;
+ }
+
+ public void setPlugin(PluginManager pm, Object plugin) {
+ this.plugin = plugin;
+ this.pm = pm;
+ }
+
+ public void run() {
+ int seconds = 120; // give up after 2 min
+ while (plugin == null) {
+ // 1s polling
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException e) {
+ }
+ if (seconds-- <= 0)
+ return;
+ }
+
+ if (plugin instanceof FredPlugin)
+ ((FredPlugin)plugin).runPlugin(pr);
+
+ // If not FredPlugin, then the whole thing is aborted,
+ // and then this method will return, killing the thread
+
+ pm.removePlugin(this);
+ }
+
+ }
+}
Added: trunk/freenet/src/pluginmanager/PluginInfoWrapper.java
===================================================================
--- trunk/freenet/src/pluginmanager/PluginInfoWrapper.java 2006-02-18
14:43:37 UTC (rev 8058)
+++ trunk/freenet/src/pluginmanager/PluginInfoWrapper.java 2006-02-18
16:46:38 UTC (rev 8059)
@@ -0,0 +1,50 @@
+package pluginmanager;
+
+import java.util.Date;
+
+public class PluginInfoWrapper {
+ // Parameters to make the object OTP
+ private boolean fedPluginThread = false;
+ // Public since only PluginHandler will know about it
+ private String className;
+ private Thread thread;
+ private long start;
+ private String threadName;
+ private FredPlugin plug;
+ //public String
+
+ public void putPluginThread(FredPlugin plug, Thread ps) {
+ if (fedPluginThread) return;
+
+ className = plug.getClass().toString();
+ thread = ps;
+ this.plug = plug;
+ threadName = "p" + className.replaceAll("^class ", "") + "_" +
ps.hashCode();
+ start = System.currentTimeMillis();
+ ps.setName(threadName);
+
+ fedPluginThread = true;
+ }
+
+ public String toString() {
+ return "ID: \"" +threadName + "\", Name: "+ className +"
Started: " + (new Date(start)).toString();
+ }
+
+ public String getThreadName() {
+ return threadName;
+ }
+
+/* public FredPlugin getPlugin(){
+ return plug;
+ }
+ */
+ public void stopPlugin() {
+ plug.terminate();
+ //thread.interrupt();
+ }
+
+ public boolean sameThread(Thread t){
+ return (t == thread);
+ }
+
+}
Added: trunk/freenet/src/pluginmanager/PluginManager.java
===================================================================
--- trunk/freenet/src/pluginmanager/PluginManager.java 2006-02-18 14:43:37 UTC
(rev 8058)
+++ trunk/freenet/src/pluginmanager/PluginManager.java 2006-02-18 16:46:38 UTC
(rev 8059)
@@ -0,0 +1,143 @@
+package pluginmanager;
+
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Iterator;
+
+import freenet.client.HighLevelSimpleClient;
+
+public class PluginManager {
+
+ /*
+ *
+ * TODO: Synchronize
+ * TODO: Synchronize
+ * TODO: Synchronize
+ * TODO: Synchronize
+ * TODO: Synchronize
+ *
+ */
+
+
+ private static HashMap pluginInfo;
+ private static PluginManager pluginManager = null;
+ private PluginRespirator pluginRespirator = null;
+
+ public PluginManager(PluginRespirator pluginRespirator) {
+ pluginInfo = new HashMap();
+
+ this.pluginRespirator = pluginRespirator;
+ //StartPlugin("misc at file:plugin.jar");
+
+ // Needed to include plugin in jar-files
+ if (new Date().equals(null))
+ System.err.println(new TestPlugin());
+ }
+
+ public void startPlugin(String filename) {
+ FredPlugin plug;
+ try {
+ plug = LoadPlugin(filename);
+ PluginInfoWrapper pi = PluginHandler.startPlugin(this,
plug, pluginRespirator);
+ pluginInfo.put(pi.getThreadName(), pi);
+ } catch (PluginNotFoundException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public void removePlugin(Thread t) {
+ Object removeKey = null;
+ {
+ Iterator it = pluginInfo.keySet().iterator();
+ while (it.hasNext()) {
+ Object key = it.next();
+ PluginInfoWrapper pi = (PluginInfoWrapper)
pluginInfo.get(key);
+ if (pi.sameThread(t))
+ removeKey = key;
+ }
+ }
+ if (removeKey != null)
+ pluginInfo.remove(removeKey);
+ }
+
+ public void dumpPlugins() {
+ Iterator it = pluginInfo.keySet().iterator();
+ while (it.hasNext()) {
+ PluginInfoWrapper pi = (PluginInfoWrapper)
pluginInfo.get(it.next());
+ System.out.println(pi);
+ }
+ }
+
+ public void killPlugin(String name) {
+ Iterator it = pluginInfo.keySet().iterator();
+ while (it.hasNext()) {
+ PluginInfoWrapper pi = (PluginInfoWrapper)
pluginInfo.get(it.next());
+ if (pi.getThreadName().equals(name))
+ {
+ pi.stopPlugin();
+ }
+ }
+ }
+
+
+ /**
+ * Method to load a plugin from the given path and return is as an
object.
+ * Will accept filename to be of one of the following forms:
+ * "classname" to load a class from the current classpath
+ * "classame at file:/path/to/jarfile.jar" to load class from an other
jarfile.
+ *
+ * @param filename The filename to load from
+ * @return An instanciated object of the plugin
+ * @throws PluginNotFoundException If anything goes wrong.
+ */
+ private FredPlugin LoadPlugin(String filename) throws
PluginNotFoundException {
+ Class cls = null;
+
+ if (filename.indexOf("@file:") >= 0) {
+ // Open from extern file
+ try {
+ // Load the jar-file
+ String[] parts = filename.split("@file:");
+ if (parts.length != 2) {
+ throw new PluginNotFoundException("Could not split at
\"@file:\".");
+ }
+
+ // Load the class inside file
+ URL[] serverURLs = new URL[]{new URL("file:" + parts[1])};
+ ClassLoader cl = new URLClassLoader(serverURLs);
+ cls = cl.loadClass(parts[0]);
+ } catch (Exception e) {
+ throw new PluginNotFoundException("Initialization error:"
+ + filename, e);
+ }
+ } else {
+ // Load class
+ try {
+ cls = Class.forName(filename);
+ } catch (ClassNotFoundException e) {
+ throw new PluginNotFoundException(filename);
+ }
+ }
+
+ if(cls == null)
+ throw new PluginNotFoundException("Unknown error");
+
+ // Class loaded... Objectize it!
+ Object o = null;
+ try {
+ o = cls.newInstance();
+ } catch (Exception e) {
+ throw new PluginNotFoundException("Could not re-create plugin:"
+
+ filename, e);
+ }
+
+ // See if we have the right type
+ if (!(o instanceof FredPlugin)) {
+ throw new PluginNotFoundException("Not a plugin: " + filename);
+ }
+
+ return (FredPlugin)o;
+ }
+}
Added: trunk/freenet/src/pluginmanager/PluginNotFoundException.java
===================================================================
--- trunk/freenet/src/pluginmanager/PluginNotFoundException.java
2006-02-18 14:43:37 UTC (rev 8058)
+++ trunk/freenet/src/pluginmanager/PluginNotFoundException.java
2006-02-18 16:46:38 UTC (rev 8059)
@@ -0,0 +1,25 @@
+package pluginmanager;
+
+public class PluginNotFoundException extends Exception {
+
+ public PluginNotFoundException() {
+ super();
+ // TODO Auto-generated constructor stub
+ }
+
+ public PluginNotFoundException(String arg0) {
+ super(arg0);
+ // TODO Auto-generated constructor stub
+ }
+
+ public PluginNotFoundException(String arg0, Throwable arg1) {
+ super(arg0, arg1);
+ // TODO Auto-generated constructor stub
+ }
+
+ public PluginNotFoundException(Throwable arg0) {
+ super(arg0);
+ // TODO Auto-generated constructor stub
+ }
+
+}
Added: trunk/freenet/src/pluginmanager/PluginRespirator.java
===================================================================
--- trunk/freenet/src/pluginmanager/PluginRespirator.java 2006-02-18
14:43:37 UTC (rev 8058)
+++ trunk/freenet/src/pluginmanager/PluginRespirator.java 2006-02-18
16:46:38 UTC (rev 8059)
@@ -0,0 +1,17 @@
+package pluginmanager;
+
+import freenet.client.HighLevelSimpleClient;
+import freenet.client.HighLevelSimpleClientImpl;
+import freenet.node.Node;
+
+public class PluginRespirator {
+ private HighLevelSimpleClient hlsc = null;
+
+ public PluginRespirator(HighLevelSimpleClient hlsc) {
+ this.hlsc = hlsc;
+ }
+
+ public HighLevelSimpleClient getHLSimpleClient() {
+ return hlsc;
+ }
+}
Added: trunk/freenet/src/pluginmanager/TestPlugin.java
===================================================================
--- trunk/freenet/src/pluginmanager/TestPlugin.java 2006-02-18 14:43:37 UTC
(rev 8058)
+++ trunk/freenet/src/pluginmanager/TestPlugin.java 2006-02-18 16:46:38 UTC
(rev 8059)
@@ -0,0 +1,38 @@
+package pluginmanager;
+
+import java.net.MalformedURLException;
+import java.util.Date;
+
+import freenet.client.FetchException;
+import freenet.client.FetchResult;
+import freenet.keys.FreenetURI;
+
+public class TestPlugin implements FredPlugin {
+ boolean goon = true;
+ public void terminate() {
+ goon = false;
+ }
+
+ public void runPlugin(PluginRespirator pr) {
+ int i = (int)System.currentTimeMillis()%1000;
+ while(goon) {
+ System.err.println("This is a threaded test-plugin (" +
+ i + "). " +
+ "Time is now: " + (new Date()));
+ FetchResult fr;
+ try {
+ fr = pr.getHLSimpleClient().fetch(new
FreenetURI("freenet:CHK at
j-v1zc0cuN3wlaCpxlKd6vT6c1jAnT9KiscVjfzLu54,q9FIlJSh8M1I1ymRBz~A0fsIcGkvUYZahZb5j7uepLA,AAEA--8"));
+ System.err.println(" Got data from key, length
= " + fr.size() + " Message: "
+ + new
String(fr.asByteArray()).trim());
+ } catch (Exception e) {
+ }
+ try {
+ Thread.sleep(10000);
+ } catch (InterruptedException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+ }
+
+}