Author: cyberdo
Date: 2006-03-11 00:26:13 +0000 (Sat, 11 Mar 2006)
New Revision: 8223
Added:
trunk/freenet/src/freenet/clients/http/SymlinkerToadlet.java
trunk/freenet/src/freenet/pluginmanager/FredPluginThreadless.java
Modified:
trunk/freenet/src/freenet/node/Node.java
trunk/freenet/src/freenet/node/Version.java
trunk/freenet/src/freenet/pluginmanager/PluginHandler.java
trunk/freenet/src/freenet/pluginmanager/PluginInfoWrapper.java
trunk/freenet/src/freenet/pluginmanager/PluginManager.java
Log:
524: Plugins may now "implement" FredPluginThreadless, which makes the thread
never being started. This saves resources.
Introducing SymlinkerToadlet, to make aliases. No front end yet. Hard-coded
links:
/sl/search/ => /plugins/plugins.Librarian/
/sl/gallery/ => /plugins/plugins.TestGallery/
Added: trunk/freenet/src/freenet/clients/http/SymlinkerToadlet.java
===================================================================
--- trunk/freenet/src/freenet/clients/http/SymlinkerToadlet.java
2006-03-11 00:11:20 UTC (rev 8222)
+++ trunk/freenet/src/freenet/clients/http/SymlinkerToadlet.java
2006-03-11 00:26:13 UTC (rev 8223)
@@ -0,0 +1,164 @@
+package freenet.clients.http;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Iterator;
+
+import freenet.client.HighLevelSimpleClient;
+import freenet.clients.http.Toadlet;
+import freenet.clients.http.ToadletContext;
+import freenet.clients.http.ToadletContextClosedException;
+import freenet.node.Node;
+import freenet.pluginmanager.HTTPRequest;
+import freenet.pluginmanager.PluginHTTPException;
+import freenet.pluginmanager.PluginInfoWrapper;
+import freenet.pluginmanager.PluginManager;
+import freenet.support.Logger;
+import freenet.support.MultiValueTable;
+import freenet.client.HighLevelSimpleClient;
+import freenet.config.InvalidConfigValueException;
+import freenet.config.StringArrCallback;
+import freenet.config.StringArrOption;
+import freenet.config.SubConfig;
+
+public class SymlinkerToadlet extends Toadlet {
+
+ private final HashMap linkMap = new HashMap();
+ private final Node node;
+ SubConfig tslconfig;
+
+ public SymlinkerToadlet(HighLevelSimpleClient client, String CSSName,
Node node) {
+ super(client, CSSName);
+ this.node = node;
+ tslconfig = new SubConfig("toadletsymlinker", node.config);
+ tslconfig.register("symlinks", null, 9, true, "Symlinks in
ToadletServer",
+ "A list of \"alias#target\"'s that forms a
bunch of symlinks",
+ new StringArrCallback() {
+ public String get() {
+ return getConfigLoadString();
+ }
+ public void set(String val) throws
InvalidConfigValueException {
+ //if(storeDir.equals(new File(val))) return;
+ // FIXME
+ throw new InvalidConfigValueException("Cannot
set the plugins that's loaded.");
+ }
+ });
+
+ String fns[] = tslconfig.getStringArr("symlinks");
+ if (fns != null)
+ for (int i = 0 ; i < fns.length ; i++) {
+ String tuple[] =
StringArrOption.decode(fns[i]).split("#");
+ if (tuple.length == 2)
+ System.err.println("Adding link: " +
tuple[0] + " => " + tuple[1]);
+ }
+
+ if (fns != null)
+ for (int i = 0 ; i < fns.length ; i++) {
+ //System.err.println("Load: " +
StringArrOption.decode(fns[i]));
+ String tuple[] =
StringArrOption.decode(fns[i]).split("#");
+ if (tuple.length == 2)
+ addLink(tuple[0], tuple[1]);
+ }
+ tslconfig.finishedInitialization();
+
+ fns = tslconfig.getStringArr("symlinks");
+ if (fns != null)
+ for (int i = 0 ; i < fns.length ; i++) {
+ String tuple[] =
StringArrOption.decode(fns[i]).split("#");
+ if (tuple.length == 2)
+ Logger.normal(this, "Added link: " +
tuple[0] + " => " + tuple[1]);
+ }
+ addLink("/sl/search/", "/plugins/plugins.Librarian/");
+ addLink("/sl/gallery/", "/plugins/plugins.TestGallery/");
+ }
+
+ public boolean addLink(String alias, String target) {
+ synchronized (linkMap) {
+ if (linkMap.put(alias, target) == alias) {
+ Logger.normal(this, "Adding link: " + alias + "
=> " + target);
+ node.config.store();
+ return true;
+ } else {
+ Logger.error(this, "Adding link: " + alias + "
=> " + target);
+ return false;
+ }
+ }
+ }
+
+ public boolean removeLink(String alias) {
+ synchronized (linkMap) {
+ Object o;
+ if ((o = linkMap.remove(alias))!= null) {
+ Logger.normal(this, "Removing link: " + alias +
" => " + o);
+ node.config.store();
+ return true;
+ } else {
+ Logger.error(this, "Adding link: " + alias + "
=> " + o);
+ return false;
+ }
+ }
+ }
+
+ private String getConfigLoadString() {
+ String retarr[] = new String[linkMap.size()];
+ synchronized (linkMap) {
+ Iterator it = linkMap.keySet().iterator();
+ int i = 0;
+ while(it.hasNext()) {
+ String key = (String)it.next();
+ retarr[i++] = key + "#" + linkMap.get(key);
+ }
+ }
+ return StringArrOption.arrayToString(retarr);
+ }
+
+ public String supportedMethods() {
+ return "GET";
+ }
+
+ public void handleGet(URI uri, ToadletContext ctx)
+ throws ToadletContextClosedException, IOException, RedirectException {
+ String path = uri.getPath();
+ String foundkey = null;
+ String foundtarget = null;
+ synchronized (linkMap) {
+ Iterator it = linkMap.keySet().iterator();
+ while (it.hasNext()) {
+ String key = (String)it.next();
+ if (path.startsWith(key)) {
+ foundkey = key;
+ foundtarget = (String)linkMap.get(key);
+ }
+ }
+ }
+
+ // TODO redirect to errorpage
+ if ((foundtarget == null) || (foundkey == null)) {
+ writeReply(ctx, 404, "text/html", "Path not found",
"Page not found");
+ return;
+ }
+
+ path = foundtarget + path.substring(foundkey.length());
+ URI outuri = null;
+ try {
+ outuri = new URI(null, null,
+ path, uri.getQuery(), uri.getFragment());
+ } catch (URISyntaxException e) {
+ // TODO Handle error somehow
+ writeReply(ctx, 200, "text/html", "OK", e.getMessage());
+ return;
+ }
+
+ uri.getRawQuery();
+
+ RedirectException re = new RedirectException();
+ re.newuri = outuri;
+ throw re;
+ }
+
+}
Modified: trunk/freenet/src/freenet/node/Node.java
===================================================================
--- trunk/freenet/src/freenet/node/Node.java 2006-03-11 00:11:20 UTC (rev
8222)
+++ trunk/freenet/src/freenet/node/Node.java 2006-03-11 00:26:13 UTC (rev
8223)
@@ -31,6 +31,7 @@
import freenet.client.async.ClientRequestScheduler;
import freenet.clients.http.FproxyToadlet;
import freenet.clients.http.SimpleToadletServer;
+import freenet.clients.http.SymlinkerToadlet;
import freenet.config.Config;
import freenet.config.FilePersistentConfig;
import freenet.config.IntCallback;
@@ -253,6 +254,7 @@
TextModeClientInterface tmci;
FCPServer fcpServer;
FproxyToadlet fproxyServlet;
+ private SymlinkerToadlet symlinkerToadlet;
SimpleToadletServer toadletContainer;
// Persistent temporary buckets
@@ -908,6 +910,9 @@
e.printStackTrace();
throw new
NodeInitException(EXIT_COULD_NOT_START_FPROXY, "Could not start fproxy: "+e);
}
+
+ symlinkerToadlet = new
SymlinkerToadlet(makeClient(RequestStarter.INTERACTIVE_PRIORITY_CLASS),"",
this);
+ toadletContainer.register(symlinkerToadlet, "/sl/", true);
/*
SimpleToadletServer server = new SimpleToadletServer(port+2000);
FproxyToadlet fproxy = new
FproxyToadlet(n.makeClient(RequestStarter.INTERACTIVE_PRIORITY_CLASS));
@@ -2076,4 +2081,8 @@
public void setFCPServer(FCPServer fcp) {
this.fcpServer = fcp;
}
+
+ public SymlinkerToadlet getSymlinkerToadlet() {
+ return symlinkerToadlet;
+ }
}
Modified: trunk/freenet/src/freenet/node/Version.java
===================================================================
--- trunk/freenet/src/freenet/node/Version.java 2006-03-11 00:11:20 UTC (rev
8222)
+++ trunk/freenet/src/freenet/node/Version.java 2006-03-11 00:26:13 UTC (rev
8223)
@@ -20,7 +20,7 @@
public static final String protocolVersion = "1.0";
/** The build number of the current revision */
- private static final int buildNumber = 523;
+ private static final int buildNumber = 524;
/** Oldest build of Fred we will talk to */
private static final int lastGoodBuild = 507;
Added: trunk/freenet/src/freenet/pluginmanager/FredPluginThreadless.java
===================================================================
--- trunk/freenet/src/freenet/pluginmanager/FredPluginThreadless.java
2006-03-11 00:11:20 UTC (rev 8222)
+++ trunk/freenet/src/freenet/pluginmanager/FredPluginThreadless.java
2006-03-11 00:26:13 UTC (rev 8223)
@@ -0,0 +1,10 @@
+package freenet.pluginmanager;
+
+public interface FredPluginThreadless {
+
+ // Let them return null if unhandled
+
+ public String handleHTTPGet(HTTPRequest request) throws
PluginHTTPException;
+ public String handleHTTPPut(HTTPRequest request) throws
PluginHTTPException;
+ public String handleHTTPPost(HTTPRequest request) throws
PluginHTTPException;
+}
Modified: trunk/freenet/src/freenet/pluginmanager/PluginHandler.java
===================================================================
--- trunk/freenet/src/freenet/pluginmanager/PluginHandler.java 2006-03-11
00:11:20 UTC (rev 8222)
+++ trunk/freenet/src/freenet/pluginmanager/PluginHandler.java 2006-03-11
00:26:13 UTC (rev 8223)
@@ -19,8 +19,13 @@
public static PluginInfoWrapper startPlugin(PluginManager pm, String
filename, FredPlugin plug, PluginRespirator pr) {
PluginStarter ps = new PluginStarter(pr);
PluginInfoWrapper pi = new PluginInfoWrapper(plug, ps,
filename);
+
+ // This is an ugly trick... sorry ;o)
+ // The thread still exists as an identifier, but is never
started if the
+ // plugin doesn't require it
ps.setPlugin(pm, plug);
- ps.start();
+ if (!pi.isThreadlessPlugin())
+ ps.start();
return pi;
}
Modified: trunk/freenet/src/freenet/pluginmanager/PluginInfoWrapper.java
===================================================================
--- trunk/freenet/src/freenet/pluginmanager/PluginInfoWrapper.java
2006-03-11 00:11:20 UTC (rev 8222)
+++ trunk/freenet/src/freenet/pluginmanager/PluginInfoWrapper.java
2006-03-11 00:26:13 UTC (rev 8223)
@@ -1,6 +1,8 @@
package freenet.pluginmanager;
import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
public class PluginInfoWrapper {
// Parameters to make the object OTP
@@ -12,7 +14,9 @@
private String threadName;
private FredPlugin plug;
private boolean isPproxyPlugin;
+ private boolean isThreadlessPlugin;
private String filename;
+ private HashSet toadletLinks=new HashSet();
//public String
public PluginInfoWrapper(FredPlugin plug, Thread ps, String filename) {
@@ -26,6 +30,7 @@
ps.setName(threadName);
fedPluginThread = true;
isPproxyPlugin = (plug instanceof FredPluginHTTP);
+ isThreadlessPlugin = (plug instanceof FredPluginThreadless);
}
public String toString() {
@@ -43,7 +48,29 @@
public String getPluginClassName(){
return plug.getClass().getName().toString();
}
-
+
+ public String[] getPluginToadletSymlinks(){
+ synchronized (toadletLinks) {
+ return (String[])toadletLinks.toArray();
+ }
+ }
+
+ public boolean addPluginToadletSymlink(String linkfrom){
+ synchronized (toadletLinks) {
+ if (toadletLinks.size() < 1)
+ toadletLinks = new HashSet();
+ return toadletLinks.add(linkfrom);
+ }
+ }
+
+ public boolean removePluginToadletSymlink(String linkfrom){
+ synchronized (toadletLinks) {
+ if (toadletLinks.size() < 1)
+ return false;
+ return toadletLinks.remove(linkfrom);
+ }
+ }
+
public void stopPlugin() {
plug.terminate();
thread.interrupt();
@@ -60,5 +87,13 @@
public String getFilename() {
return filename;
}
+
+ public boolean isThreadlessPlugin() {
+ return isThreadlessPlugin;
+ }
+
+ public Thread getThread() {
+ return thread;
+ }
}
Modified: trunk/freenet/src/freenet/pluginmanager/PluginManager.java
===================================================================
--- trunk/freenet/src/freenet/pluginmanager/PluginManager.java 2006-03-11
00:11:20 UTC (rev 8222)
+++ trunk/freenet/src/freenet/pluginmanager/PluginManager.java 2006-03-11
00:26:13 UTC (rev 8223)
@@ -158,6 +158,7 @@
Logger.normal(this,
"Removed HTTP handler for /plugins/"+
pi.getPluginClassName()+"/");
} catch (Throwable ex) {
+ Logger.error(this,
"removing Plugin", ex);
}
}
}
@@ -168,6 +169,47 @@
}
saveConfig();
}
+
+ public void addToadletSymlinks(PluginInfoWrapper pi) {
+ synchronized (toadletList) {
+ try {
+ String targets[] =
pi.getPluginToadletSymlinks();
+ if (targets == null)
+ return;
+
+ for (int i = 0 ; i < targets.length ; i++) {
+ toadletList.remove(targets[i]);
+ Logger.normal(this, "Removed HTTP
symlink: " + targets[i] +
+ " =>
/plugins/"+pi.getPluginClassName()+"/");
+ }
+ } catch (Throwable ex) {
+ Logger.error(this, "removing Toadlet-link", ex);
+ }
+ }
+ saveConfig();
+ }
+
+ public void removeToadletSymlinks(PluginInfoWrapper pi) {
+ synchronized (toadletList) {
+ String rm = null;
+ try {
+ String targets[] =
pi.getPluginToadletSymlinks();
+ if (targets == null)
+ return;
+
+ for (int i = 0 ; i < targets.length ; i++) {
+ rm = targets[i];
+ toadletList.remove(targets[i]);
+
pi.removePluginToadletSymlink(targets[i]);
+ Logger.normal(this, "Removed HTTP
symlink: " + targets[i] +
+ " =>
/plugins/"+pi.getPluginClassName()+"/");
+ }
+ } catch (Throwable ex) {
+ Logger.error(this, "removing Toadlet-link: " +
rm, ex);
+ }
+ }
+ saveConfig();
+ }
public String dumpPlugins() {
StringBuffer out= new StringBuffer();
@@ -213,16 +255,21 @@
}
public void killPlugin(String name) {
+ PluginInfoWrapper pi = null;
+ boolean found = false;
synchronized (pluginInfo) {
Iterator it = pluginInfo.keySet().iterator();
- while (it.hasNext()) {
- PluginInfoWrapper pi = (PluginInfoWrapper)
pluginInfo.get(it.next());
+ while (it.hasNext() && !found) {
+ pi = (PluginInfoWrapper)
pluginInfo.get(it.next());
if (pi.getThreadName().equals(name))
- {
- pi.stopPlugin();
- }
+ found = true;
}
}
+ if (found)
+ if (pi.isThreadlessPlugin())
+ removePlugin(pi.getThread());
+ else
+ pi.stopPlugin();
}