Author: toad
Date: 2006-03-10 22:35:51 +0000 (Fri, 10 Mar 2006)
New Revision: 8221

Added:
   trunk/freenet/src/freenet/client/async/ClientRequester.java
   trunk/freenet/src/freenet/node/fcp/ClientPutBase.java
   trunk/freenet/src/freenet/node/fcp/ClientPutDir.java
   trunk/freenet/src/freenet/node/fcp/ClientPutDirMessage.java
   trunk/freenet/src/freenet/node/fcp/ClientPutDiskDirMessage.java
Removed:
   trunk/freenet/src/freenet/client/async/ClientRequest.java
Modified:
   trunk/freenet/src/freenet/client/HighLevelSimpleClientImpl.java
   trunk/freenet/src/freenet/client/async/BaseClientPutter.java
   trunk/freenet/src/freenet/client/async/ClientGetter.java
   trunk/freenet/src/freenet/client/async/ClientRequestScheduler.java
   trunk/freenet/src/freenet/client/async/ManifestElement.java
   trunk/freenet/src/freenet/client/async/SendableRequest.java
   trunk/freenet/src/freenet/client/async/SimpleManifestPutter.java
   trunk/freenet/src/freenet/client/async/SingleBlockInserter.java
   trunk/freenet/src/freenet/client/async/SingleFileFetcher.java
   trunk/freenet/src/freenet/node/RequestStarter.java
   trunk/freenet/src/freenet/node/Version.java
   trunk/freenet/src/freenet/node/fcp/ClientGet.java
   trunk/freenet/src/freenet/node/fcp/ClientPut.java
   trunk/freenet/src/freenet/node/fcp/ClientPutMessage.java
   trunk/freenet/src/freenet/node/fcp/ClientRequest.java
   trunk/freenet/src/freenet/node/fcp/FCPConnectionHandler.java
   trunk/freenet/src/freenet/node/fcp/FCPMessage.java
Log:
522:
New FCP command: ClientPutDiskDir. (persistence not yet supported)
Refactoring relating to FCP - eliminate a large amount of duplicated code and 
modularize.

Modified: trunk/freenet/src/freenet/client/HighLevelSimpleClientImpl.java
===================================================================
--- trunk/freenet/src/freenet/client/HighLevelSimpleClientImpl.java     
2006-03-10 18:33:19 UTC (rev 8220)
+++ trunk/freenet/src/freenet/client/HighLevelSimpleClientImpl.java     
2006-03-10 22:35:51 UTC (rev 8221)
@@ -130,6 +130,7 @@
                PutWaiter pw = new PutWaiter();
                SimpleManifestPutter putter =
                        new SimpleManifestPutter(pw, node.chkPutScheduler, 
node.sskPutScheduler, 
SimpleManifestPutter.bucketsByNameToManifestEntries(bucketsByName), 
priorityClass, insertURI, defaultName, getInserterContext(), false, this);
+               putter.start();
                return pw.waitForCompletion();
        }


Modified: trunk/freenet/src/freenet/client/async/BaseClientPutter.java
===================================================================
--- trunk/freenet/src/freenet/client/async/BaseClientPutter.java        
2006-03-10 18:33:19 UTC (rev 8220)
+++ trunk/freenet/src/freenet/client/async/BaseClientPutter.java        
2006-03-10 22:35:51 UTC (rev 8221)
@@ -1,6 +1,6 @@
 package freenet.client.async;

-public abstract class BaseClientPutter extends ClientRequest {
+public abstract class BaseClientPutter extends ClientRequester {

        protected BaseClientPutter(short priorityClass, ClientRequestScheduler 
chkScheduler, ClientRequestScheduler sskScheduler, Object context) {
                super(priorityClass, chkScheduler, sskScheduler, context);

Modified: trunk/freenet/src/freenet/client/async/ClientGetter.java
===================================================================
--- trunk/freenet/src/freenet/client/async/ClientGetter.java    2006-03-10 
18:33:19 UTC (rev 8220)
+++ trunk/freenet/src/freenet/client/async/ClientGetter.java    2006-03-10 
22:35:51 UTC (rev 8221)
@@ -17,7 +17,7 @@
 /**
  * A high level data request.
  */
-public class ClientGetter extends ClientRequest implements 
GetCompletionCallback {
+public class ClientGetter extends ClientRequester implements 
GetCompletionCallback {

        final ClientCallback client;
        final FreenetURI uri;

Deleted: trunk/freenet/src/freenet/client/async/ClientRequest.java
===================================================================
--- trunk/freenet/src/freenet/client/async/ClientRequest.java   2006-03-10 
18:33:19 UTC (rev 8220)
+++ trunk/freenet/src/freenet/client/async/ClientRequest.java   2006-03-10 
22:35:51 UTC (rev 8221)
@@ -1,118 +0,0 @@
-package freenet.client.async;
-
-import freenet.keys.FreenetURI;
-import freenet.support.Logger;
-
-/** A high level client request. A request (either fetch or put) started
- * by a Client. Has a suitable context and a URI; is fulfilled only when
- * we have followed all the redirects etc, or have an error. Can be 
- * retried.
- */
-public abstract class ClientRequest {
-
-       // FIXME move the priority classes from RequestStarter here
-       protected short priorityClass;
-       protected boolean cancelled;
-       final ClientRequestScheduler chkScheduler;
-       final ClientRequestScheduler sskScheduler;
-       protected final Object client;
-       
-       public short getPriorityClass() {
-               return priorityClass;
-       }
-       
-       protected ClientRequest(short priorityClass, ClientRequestScheduler 
chkScheduler, ClientRequestScheduler sskScheduler, Object client) {
-               this.priorityClass = priorityClass;
-               this.chkScheduler = chkScheduler;
-               this.sskScheduler = sskScheduler;
-               this.client = client;
-       }
-       
-       public void cancel() {
-               cancelled = true;
-       }
-       
-       public boolean isCancelled() {
-               return cancelled;
-       }
-       
-       public abstract FreenetURI getURI();
-       
-       public abstract boolean isFinished();
-       
-       /** Total number of blocks this request has tried to fetch/put. */
-       protected int totalBlocks;
-       /** Number of blocks we have successfully completed a fetch/put for. */
-       protected int successfulBlocks;
-       /** Number of blocks which have failed. */
-       protected int failedBlocks;
-       /** Number of blocks which have failed fatally. */
-       protected int fatallyFailedBlocks;
-       /** Minimum number of blocks required to succeed for success. */
-       protected int minSuccessBlocks;
-       /** Has totalBlocks stopped growing? */
-       protected boolean blockSetFinalized;
-       
-       public void blockSetFinalized() {
-               synchronized(this) {
-                       if(blockSetFinalized) return;
-                       blockSetFinalized = true;
-               }
-               Logger.minor(this, "Finalized set of blocks for "+this, new 
Exception("debug"));
-               notifyClients();
-       }
-       
-       public synchronized void addBlock() {
-               if(blockSetFinalized)
-                       Logger.error(this, "addBlock() but set finalized! on 
"+this, new Exception("error"));
-               totalBlocks++;
-       }
-       
-       public synchronized void addBlocks(int num) {
-               if(blockSetFinalized)
-                       Logger.error(this, "addBlock() but set finalized! on 
"+this, new Exception("error"));
-               totalBlocks+=num;
-       }
-       
-       public void completedBlock(boolean dontNotify) {
-               Logger.minor(this, "Completed block ("+dontNotify+")");
-               synchronized(this) {
-                       successfulBlocks++;
-                       if(dontNotify) return;
-               }
-               notifyClients();
-       }
-       
-       public void failedBlock() {
-               synchronized(this) {
-                       failedBlocks++;
-               }
-               notifyClients();
-       }
-       
-       public void fatallyFailedBlock() {
-               synchronized(this) {
-                       fatallyFailedBlocks++;
-               }
-               notifyClients();
-       }
-       
-       public synchronized void addMustSucceedBlocks(int blocks) {
-               minSuccessBlocks += blocks;
-       }
-       
-       public abstract void notifyClients();
-
-       /** Get client context object */
-       public Object getClient() {
-               return client;
-       }
-
-       public void setPriorityClass(short newPriorityClass) {
-               short oldPriorityClass = priorityClass;
-               this.priorityClass = newPriorityClass;
-               chkScheduler.reregisterAll(this);
-               sskScheduler.reregisterAll(this);
-       }
-
-}

Modified: trunk/freenet/src/freenet/client/async/ClientRequestScheduler.java
===================================================================
--- trunk/freenet/src/freenet/client/async/ClientRequestScheduler.java  
2006-03-10 18:33:19 UTC (rev 8220)
+++ trunk/freenet/src/freenet/client/async/ClientRequestScheduler.java  
2006-03-10 22:35:51 UTC (rev 8221)
@@ -141,7 +141,7 @@
                                        continue;
                                }
                                Logger.minor(this, "removeFirst() returning 
"+req+" ("+rga.getNumber()+")");
-                               ClientRequest cr = req.getClientRequest();
+                               ClientRequester cr = req.getClientRequest();
                                HashSet v = (HashSet) 
allRequestsByClientRequest.get(cr);
                                v.remove(req);
                                if(v.isEmpty())
@@ -153,7 +153,7 @@
                return null;
        }

-       public void reregisterAll(ClientRequest request) {
+       public void reregisterAll(ClientRequester request) {
                synchronized(this) {
                        HashSet h = (HashSet) 
allRequestsByClientRequest.get(request);
                        if(h != null) {

Copied: trunk/freenet/src/freenet/client/async/ClientRequester.java (from rev 
8220, trunk/freenet/src/freenet/client/async/ClientRequest.java)
===================================================================
--- trunk/freenet/src/freenet/client/async/ClientRequest.java   2006-03-10 
18:33:19 UTC (rev 8220)
+++ trunk/freenet/src/freenet/client/async/ClientRequester.java 2006-03-10 
22:35:51 UTC (rev 8221)
@@ -0,0 +1,117 @@
+package freenet.client.async;
+
+import freenet.keys.FreenetURI;
+import freenet.support.Logger;
+
+/** A high level client request. A request (either fetch or put) started
+ * by a Client. Has a suitable context and a URI; is fulfilled only when
+ * we have followed all the redirects etc, or have an error. Can be 
+ * retried.
+ */
+public abstract class ClientRequester {
+
+       // FIXME move the priority classes from RequestStarter here
+       protected short priorityClass;
+       protected boolean cancelled;
+       final ClientRequestScheduler chkScheduler;
+       final ClientRequestScheduler sskScheduler;
+       protected final Object client;
+       
+       public short getPriorityClass() {
+               return priorityClass;
+       }
+       
+       protected ClientRequester(short priorityClass, ClientRequestScheduler 
chkScheduler, ClientRequestScheduler sskScheduler, Object client) {
+               this.priorityClass = priorityClass;
+               this.chkScheduler = chkScheduler;
+               this.sskScheduler = sskScheduler;
+               this.client = client;
+       }
+       
+       public void cancel() {
+               cancelled = true;
+       }
+       
+       public boolean isCancelled() {
+               return cancelled;
+       }
+       
+       public abstract FreenetURI getURI();
+       
+       public abstract boolean isFinished();
+       
+       /** Total number of blocks this request has tried to fetch/put. */
+       protected int totalBlocks;
+       /** Number of blocks we have successfully completed a fetch/put for. */
+       protected int successfulBlocks;
+       /** Number of blocks which have failed. */
+       protected int failedBlocks;
+       /** Number of blocks which have failed fatally. */
+       protected int fatallyFailedBlocks;
+       /** Minimum number of blocks required to succeed for success. */
+       protected int minSuccessBlocks;
+       /** Has totalBlocks stopped growing? */
+       protected boolean blockSetFinalized;
+       
+       public void blockSetFinalized() {
+               synchronized(this) {
+                       if(blockSetFinalized) return;
+                       blockSetFinalized = true;
+               }
+               Logger.minor(this, "Finalized set of blocks for "+this, new 
Exception("debug"));
+               notifyClients();
+       }
+       
+       public synchronized void addBlock() {
+               if(blockSetFinalized)
+                       Logger.error(this, "addBlock() but set finalized! on 
"+this, new Exception("error"));
+               totalBlocks++;
+       }
+       
+       public synchronized void addBlocks(int num) {
+               if(blockSetFinalized)
+                       Logger.error(this, "addBlock() but set finalized! on 
"+this, new Exception("error"));
+               totalBlocks+=num;
+       }
+       
+       public void completedBlock(boolean dontNotify) {
+               Logger.minor(this, "Completed block ("+dontNotify+")");
+               synchronized(this) {
+                       successfulBlocks++;
+                       if(dontNotify) return;
+               }
+               notifyClients();
+       }
+       
+       public void failedBlock() {
+               synchronized(this) {
+                       failedBlocks++;
+               }
+               notifyClients();
+       }
+       
+       public void fatallyFailedBlock() {
+               synchronized(this) {
+                       fatallyFailedBlocks++;
+               }
+               notifyClients();
+       }
+       
+       public synchronized void addMustSucceedBlocks(int blocks) {
+               minSuccessBlocks += blocks;
+       }
+       
+       public abstract void notifyClients();
+
+       /** Get client context object */
+       public Object getClient() {
+               return client;
+       }
+
+       public void setPriorityClass(short newPriorityClass) {
+               this.priorityClass = newPriorityClass;
+               chkScheduler.reregisterAll(this);
+               sskScheduler.reregisterAll(this);
+       }
+
+}

Modified: trunk/freenet/src/freenet/client/async/ManifestElement.java
===================================================================
--- trunk/freenet/src/freenet/client/async/ManifestElement.java 2006-03-10 
18:33:19 UTC (rev 8220)
+++ trunk/freenet/src/freenet/client/async/ManifestElement.java 2006-03-10 
22:35:51 UTC (rev 8221)
@@ -33,4 +33,8 @@
                }
                return false;
        }
+
+       public void freeData() {
+               data.free();
+       }
 }

Modified: trunk/freenet/src/freenet/client/async/SendableRequest.java
===================================================================
--- trunk/freenet/src/freenet/client/async/SendableRequest.java 2006-03-10 
18:33:19 UTC (rev 8220)
+++ trunk/freenet/src/freenet/client/async/SendableRequest.java 2006-03-10 
22:35:51 UTC (rev 8221)
@@ -21,6 +21,6 @@
        public Object getClient();

        /** Get the ClientRequest */
-       public ClientRequest getClientRequest();
+       public ClientRequester getClientRequest();

 }

Modified: trunk/freenet/src/freenet/client/async/SimpleManifestPutter.java
===================================================================
--- trunk/freenet/src/freenet/client/async/SimpleManifestPutter.java    
2006-03-10 18:33:19 UTC (rev 8220)
+++ trunk/freenet/src/freenet/client/async/SimpleManifestPutter.java    
2006-03-10 22:35:51 UTC (rev 8221)
@@ -171,6 +171,9 @@
                putHandlersWaitingForMetadata = new HashSet();
                waitingForBlockSets = new HashSet();
                makePutHandlers(manifestElements, putHandlersByName);
+       }
+
+       public void start() throws InserterException {
                Iterator it = runningPutHandlers.iterator();
                while(it.hasNext()) {
                        PutHandler ph = (PutHandler) it.next();

Modified: trunk/freenet/src/freenet/client/async/SingleBlockInserter.java
===================================================================
--- trunk/freenet/src/freenet/client/async/SingleBlockInserter.java     
2006-03-10 18:33:19 UTC (rev 8220)
+++ trunk/freenet/src/freenet/client/async/SingleBlockInserter.java     
2006-03-10 22:35:51 UTC (rev 8221)
@@ -270,7 +270,7 @@
                return parent.getClient();
        }

-       public ClientRequest getClientRequest() {
+       public ClientRequester getClientRequest() {
                return parent;
        }


Modified: trunk/freenet/src/freenet/client/async/SingleFileFetcher.java
===================================================================
--- trunk/freenet/src/freenet/client/async/SingleFileFetcher.java       
2006-03-10 18:33:19 UTC (rev 8220)
+++ trunk/freenet/src/freenet/client/async/SingleFileFetcher.java       
2006-03-10 22:35:51 UTC (rev 8221)
@@ -571,7 +571,7 @@
                return ctx.ignoreStore;
        }

-       public ClientRequest getClientRequest() {
+       public ClientRequester getClientRequest() {
                return parent;
        }


Modified: trunk/freenet/src/freenet/node/RequestStarter.java
===================================================================
--- trunk/freenet/src/freenet/node/RequestStarter.java  2006-03-10 18:33:19 UTC 
(rev 8220)
+++ trunk/freenet/src/freenet/node/RequestStarter.java  2006-03-10 22:35:51 UTC 
(rev 8221)
@@ -3,7 +3,7 @@
 import java.util.LinkedList;
 import java.util.Vector;

-import freenet.client.async.ClientRequest;
+import freenet.client.async.ClientRequester;
 import freenet.client.async.RequestScheduler;
 import freenet.client.async.SendableRequest;
 import freenet.support.Logger;

Modified: trunk/freenet/src/freenet/node/Version.java
===================================================================
--- trunk/freenet/src/freenet/node/Version.java 2006-03-10 18:33:19 UTC (rev 
8220)
+++ trunk/freenet/src/freenet/node/Version.java 2006-03-10 22:35:51 UTC (rev 
8221)
@@ -20,7 +20,7 @@
        public static final String protocolVersion = "1.0";

        /** The build number of the current revision */
-       private static final int buildNumber = 521;
+       private static final int buildNumber = 522;

        /** Oldest build of Fred we will talk to */
        private static final int lastGoodBuild = 507;

Modified: trunk/freenet/src/freenet/node/fcp/ClientGet.java
===================================================================
--- trunk/freenet/src/freenet/node/fcp/ClientGet.java   2006-03-10 18:33:19 UTC 
(rev 8220)
+++ trunk/freenet/src/freenet/node/fcp/ClientGet.java   2006-03-10 22:35:51 UTC 
(rev 8221)
@@ -13,6 +13,7 @@
 import freenet.client.async.BaseClientPutter;
 import freenet.client.async.ClientCallback;
 import freenet.client.async.ClientGetter;
+import freenet.client.async.ClientRequester;
 import freenet.client.events.ClientEvent;
 import freenet.client.events.ClientEventListener;
 import freenet.client.events.SplitfileProgressEvent;
@@ -33,22 +34,11 @@
  */
 public class ClientGet extends ClientRequest implements ClientCallback, 
ClientEventListener {

-       private final FreenetURI uri;
        private final FetcherContext fctx;
-       private final String identifier;
-       private final int verbosity;
-       /** Original FCPConnectionHandler. Null if persistence != connection */
-       private final FCPConnectionHandler origHandler;
-       private final FCPClient client;
        private final ClientGetter getter;
-       private short priorityClass;
        private final short returnType;
-       private final short persistenceType;
-       /** Has the request finished? */
-       private boolean finished;
        private final File targetFile;
        private final File tempFile;
-       String clientToken;
        /** Bucket passed in to the ClientGetter to return data in. Null unless 
returntype=disk */
        private final Bucket returnBucket;

@@ -74,22 +64,10 @@
        private SimpleProgressMessage progressPending;

        public ClientGet(FCPConnectionHandler handler, ClientGetMessage 
message) throws IdentifierCollisionException {
-               uri = message.uri;
-               clientToken = message.clientToken;
-               // FIXME
-               this.priorityClass = message.priorityClass;
-               this.persistenceType = message.persistenceType;
+               super(message.uri, message.identifier, message.verbosity, 
handler, message.priorityClass,
+                               message.persistenceType, message.clientToken, 
message.global);
                // Create a Fetcher directly in order to get more fine-grained 
control,
                // since the client may override a few context elements.
-               if(persistenceType == PERSIST_CONNECTION)
-                       this.origHandler = handler;
-               else
-                       origHandler = null;
-               if(message.global) {
-                       client = handler.server.globalClient;
-               } else {
-                       client = handler.getClient();
-               }
                fctx = new FetcherContext(client.defaultFetchContext, 
FetcherContext.IDENTICAL_MASK, false);
                fctx.eventProducer.addEventListener(this);
                // ignoreDS
@@ -97,8 +75,6 @@
                fctx.ignoreStore = message.ignoreDS;
                fctx.maxNonSplitfileRetries = message.maxRetries;
                fctx.maxSplitfileBlockRetries = message.maxRetries;
-               this.identifier = message.identifier;
-               this.verbosity = message.verbosity;
                // FIXME do something with verbosity !!
                // Has already been checked
                fctx.maxOutputLength = message.maxSize;
@@ -141,18 +117,9 @@
         * @throws IOException 
         */
        public ClientGet(SimpleFieldSet fs, FCPClient client2) throws 
IOException {
-               uri = new FreenetURI(fs.get("URI"));
-               identifier = fs.get("Identifier");
-               verbosity = Integer.parseInt(fs.get("Verbosity"));
+               super(fs, client2);
                priorityClass = Short.parseShort(fs.get("PriorityClass"));
                returnType = 
ClientGetMessage.parseValidReturnType(fs.get("ReturnType"));
-               persistenceType = 
ClientRequest.parsePersistence(fs.get("Persistence"));
-               if(persistenceType == ClientRequest.PERSIST_CONNECTION)
-                       throw new IllegalArgumentException("Reading persistent 
get with type CONNECTION !!");
-               if(!(persistenceType == ClientRequest.PERSIST_FOREVER || 
persistenceType == ClientRequest.PERSIST_REBOOT))
-                       throw new IllegalArgumentException("Unknown persistence 
type "+ClientRequest.persistenceTypeString(persistenceType));
-               this.client = client2;
-               this.origHandler = null;
                String f = fs.get("Filename");
                if(f != null)
                        targetFile = new File(f);
@@ -163,8 +130,6 @@
                        tempFile = new File(f);
                else
                        tempFile = null;
-               clientToken = fs.get("ClientToken");
-               finished = Fields.stringToBool(fs.get("Finished"), false);
                boolean ignoreDS = Fields.stringToBool(fs.get("IgnoreDS"), 
false);
                boolean dsOnly = Fields.stringToBool(fs.get("DSOnly"), false);
                int maxRetries = Integer.parseInt(fs.get("MaxRetries"));
@@ -349,13 +314,6 @@
                finish();
        }

-       /** Request completed. But we may have to stick around until we are 
acked. */
-       private void finish() {
-               if(persistenceType == ClientRequest.PERSIST_CONNECTION)
-                       origHandler.finishedClientRequest(this);
-               client.finishedClientRequest(this);
-       }
-
        public void onSuccess(BaseClientPutter state) {
                // Ignore
        }
@@ -378,30 +336,6 @@
                trySendProgress(progress, null);
        }

-       public boolean isPersistent() {
-               return persistenceType != ClientRequest.PERSIST_CONNECTION;
-       }
-
-       public void dropped() {
-               cancel();
-               if(allDataPending != null)
-                       allDataPending.bucket.free();
-       }
-
-       public String getIdentifier() {
-               return identifier;
-       }
-
-       public void write(BufferedWriter w) throws IOException {
-               if(persistenceType == ClientRequest.PERSIST_CONNECTION) {
-                       Logger.error(this, "Not persisting as 
persistenceType="+persistenceType);
-                       return;
-               }
-               // Persist the request to disk
-               SimpleFieldSet fs = getFieldSet();
-               fs.writeTo(w);
-       }
-       
        // This is distinct from the ClientGetMessage code, as later on it will 
be radically
        // different (it can store detailed state).
        public synchronized SimpleFieldSet getFieldSet() {
@@ -412,7 +346,7 @@
                fs.put("Verbosity", Integer.toString(verbosity));
                fs.put("PriorityClass", Short.toString(priorityClass));
                fs.put("ReturnType", 
ClientGetMessage.returnTypeString(returnType));
-               fs.put("Persistence", 
ClientRequest.persistenceTypeString(persistenceType));
+               fs.put("Persistence", persistenceTypeString(persistenceType));
                fs.put("ClientName", client.name);
                if(targetFile != null)
                        fs.put("Filename", targetFile.getPath());
@@ -454,21 +388,13 @@
                return fs;
        }

-       public boolean hasFinished() {
-               return finished;
+       protected ClientRequester getClientRequest() {
+               return getter;
        }

-       public boolean isPersistentForever() {
-               return persistenceType == ClientRequest.PERSIST_FOREVER;
+       protected void freeData() {
+               if(returnBucket != null)
+                       returnBucket.free();
        }

-       public void setPriorityClass(short priorityClass) {
-               this.priorityClass = priorityClass;
-               getter.setPriorityClass(priorityClass);
-       }
-
-       public void setClientToken(String clientToken) {
-               this.clientToken = clientToken;
-       }
-
 }

Modified: trunk/freenet/src/freenet/node/fcp/ClientPut.java
===================================================================
--- trunk/freenet/src/freenet/node/fcp/ClientPut.java   2006-03-10 18:33:19 UTC 
(rev 8220)
+++ trunk/freenet/src/freenet/node/fcp/ClientPut.java   2006-03-10 22:35:51 UTC 
(rev 8221)
@@ -1,107 +1,42 @@
 package freenet.node.fcp;

-import java.io.BufferedWriter;
 import java.io.File;
 import java.io.IOException;
-import java.net.MalformedURLException;

 import freenet.client.ClientMetadata;
-import freenet.client.FetchException;
-import freenet.client.FetchResult;
 import freenet.client.InsertBlock;
-import freenet.client.InserterContext;
 import freenet.client.InserterException;
-import freenet.client.async.BaseClientPutter;
-import freenet.client.async.ClientCallback;
-import freenet.client.async.ClientGetter;
 import freenet.client.async.ClientPutter;
-import freenet.client.events.ClientEvent;
-import freenet.client.events.ClientEventListener;
-import freenet.client.events.FinishedCompressionEvent;
-import freenet.client.events.SimpleEventProducer;
-import freenet.client.events.SplitfileProgressEvent;
-import freenet.client.events.StartedCompressionEvent;
-import freenet.keys.FreenetURI;
 import freenet.support.Bucket;
 import freenet.support.Fields;
 import freenet.support.HexUtil;
-import freenet.support.Logger;
 import freenet.support.PaddedEphemerallyEncryptedBucket;
 import freenet.support.SimpleFieldSet;
 import freenet.support.io.FileBucket;

-public class ClientPut extends ClientRequest implements ClientCallback, 
ClientEventListener {
+public class ClientPut extends ClientPutBase {

-       final FreenetURI uri;
        final ClientPutter inserter;
-       final InserterContext ctx;
        final InsertBlock block;
-       /** Original FCP connection handler. Null if persistence != connection. 
*/
-       final FCPConnectionHandler origHandler;
-       /** Client originating this request */
-       final FCPClient client;
-       final String identifier;
-       final boolean getCHKOnly;
-       short priorityClass;
-       private final short persistenceType;
-       final int verbosity;
-       /** Has the request finished? */
-       private boolean finished;
-       /** Client token - opaque string returned to client in PersistentPut */
-       private String clientToken;
        /** Was this from disk? Purely for PersistentPut */
        private final boolean fromDisk;
        /** Original filename if from disk, otherwise null. Purely for 
PersistentPut. */
        private final File origFilename;

-       // Verbosity bitmasks
-       private int VERBOSITY_SPLITFILE_PROGRESS = 1;
-       private int VERBOSITY_COMPRESSION_START_END = 512;
-       
-       // Stuff waiting for reconnection
-       /** Has the request succeeded? */
-       private boolean succeeded;
-       /** If the request failed, how did it fail? PutFailedMessage is the most
-        * convenient way to store this (InserterException has a stack trace!).
-        */
-       private PutFailedMessage putFailedMessage;
-       /** URI generated for the insert. */
-       private FreenetURI generatedURI;
-       // This could be a SimpleProgress, or it could be started/finished 
compression.
-       // Not that important, so not saved on persistence.
-       // Probably saving it would conflict with later changes (full 
persistence at
-       // ClientPutter level).
-       private FCPMessage progressMessage;
-       
        public ClientPut(FCPConnectionHandler handler, ClientPutMessage 
message) throws IdentifierCollisionException {
-               this.verbosity = message.verbosity;
-               this.identifier = message.identifier;
-               this.getCHKOnly = message.getCHKOnly;
-               this.priorityClass = message.priorityClass;
-               this.persistenceType = message.persistenceType;
+               super(message.uri, message.identifier, message.verbosity, 
handler, 
+                               message.priorityClass, message.persistenceType, 
message.clientToken, message.global,
+                               message.getCHKOnly, message.dontCompress, 
message.maxRetries);
                this.fromDisk = message.fromDisk;
                this.origFilename = message.origFilename;
-               if(persistenceType == PERSIST_CONNECTION)
-                       this.origHandler = handler;
-               else
-                       this.origHandler = null;
-               if(message.global) {
-                       client = handler.server.globalClient;
-               } else {
-                       client = handler.getClient();
-               }
-               ctx = new InserterContext(client.defaultInsertContext, new 
SimpleEventProducer());
-               ctx.dontCompress = message.dontCompress;
-               ctx.eventProducer.addEventListener(this);
-               ctx.maxInsertRetries = message.maxRetries;
                // Now go through the fields one at a time
-               uri = message.uri;
                String mimeType = message.contentType;
                clientToken = message.clientToken;
                block = new InsertBlock(message.bucket, new 
ClientMetadata(mimeType), uri);
                if(persistenceType != PERSIST_CONNECTION)
                        client.register(this);
-               inserter = new ClientPutter(this, message.bucket, uri, new 
ClientMetadata(mimeType), ctx, client.node.chkPutScheduler, 
client.node.sskPutScheduler, priorityClass, getCHKOnly, false, client);
+               inserter = new ClientPutter(this, message.bucket, uri, new 
ClientMetadata(mimeType), 
+                               ctx, client.node.chkPutScheduler, 
client.node.sskPutScheduler, priorityClass, getCHKOnly, false, client);
                if(persistenceType != PERSIST_CONNECTION && handler != null)
                        sendPendingMessages(handler.outputHandler, true);
        }
@@ -114,25 +49,9 @@
         * @throws IOException 
         */
        public ClientPut(SimpleFieldSet fs, FCPClient client2) throws 
PersistenceParseException, IOException {
-               uri = new FreenetURI(fs.get("URI"));
-               identifier = fs.get("Identifier");
-               verbosity = Integer.parseInt(fs.get("Verbosity"));
-               priorityClass = Short.parseShort(fs.get("PriorityClass"));
-               persistenceType = 
ClientRequest.parsePersistence(fs.get("Persistence"));
-               if(persistenceType == ClientRequest.PERSIST_CONNECTION
-                               || persistenceType == 
ClientRequest.PERSIST_REBOOT)
-                       throw new IllegalArgumentException("Reading in 
persistent ClientPut, but persistence type = 
"+ClientRequest.persistenceTypeString(persistenceType)+" so shouldn't have been 
saved in the first place");
-               this.client = client2;
-               origHandler = null;
+               super(fs, client2);
                String mimeType = fs.get("Metadata.ContentType");
-               getCHKOnly = Fields.stringToBool(fs.get("CHKOnly"), false);
-               boolean dontCompress = 
Fields.stringToBool(fs.get("DontCompress"), false);
-               int maxRetries = Integer.parseInt(fs.get("MaxRetries"));
-               clientToken = fs.get("ClientToken");
                fromDisk = Fields.stringToBool(fs.get("FromDisk"), false);
-               finished = Fields.stringToBool(fs.get("Finished"), false);
-               //finished = false;
-               succeeded = Fields.stringToBool(fs.get("Succeeded"), false);
                Bucket data;
                if(fromDisk) {
                        origFilename = new File(fs.get("Filename"));
@@ -148,16 +67,7 @@
                                        throw new 
PersistenceParseException("Size of bucket is wrong: "+data.size()+" should be 
"+sz);
                        } else data = null;
                }
-               ctx = new InserterContext(client.defaultInsertContext, new 
SimpleEventProducer());
-               ctx.dontCompress = dontCompress;
-               ctx.eventProducer.addEventListener(this);
-               ctx.maxInsertRetries = maxRetries;
                block = new InsertBlock(data, new ClientMetadata(mimeType), 
uri);
-               String genURI = fs.get("GeneratedURI");
-               if(genURI != null)
-                       generatedURI = new FreenetURI(genURI);
-               if(finished && (!succeeded))
-                       putFailedMessage = new 
PutFailedMessage(fs.subset("PutFailed"), false);
                inserter = new ClientPutter(this, data, uri, new 
ClientMetadata(mimeType), ctx, client.node.chkPutScheduler, 
client.node.sskPutScheduler, priorityClass, getCHKOnly, false, client);
                if(!finished)
                        start();
@@ -171,175 +81,14 @@
                }
        }

-       public void onLostConnection() {
-               if(persistenceType == PERSIST_CONNECTION)
-                       cancel();
-               // otherwise ignore
-       }
-       
-       public void cancel() {
-               inserter.cancel();
-       }
-
-       public void onSuccess(BaseClientPutter state) {
-               synchronized(this) {
-                       progressMessage = null;
-                       succeeded = true;
-                       finished = true;
-               }
-               trySendFinalMessage(null);
+       protected void freeData() {
                block.getData().free();
-               finish();
        }
-
-       public void onFailure(InserterException e, BaseClientPutter state) {
-               synchronized(this) {
-                       finished = true;
-                       putFailedMessage = new PutFailedMessage(e, identifier);
-               }
-               trySendFinalMessage(null);
-               block.getData().free();
-               finish();
-       }
-
-       public void onGeneratedURI(FreenetURI uri, BaseClientPutter state) {
-               synchronized(this) {
-                       if(generatedURI != null && !uri.equals(generatedURI))
-                               Logger.error(this, 
"onGeneratedURI("+uri+","+state+") but already set generatedURI to 
"+generatedURI);
-                       generatedURI = uri;
-               }
-               trySendGeneratedURIMessage(null);
-       }
-
-       public void onSuccess(FetchResult result, ClientGetter state) {
-               // ignore
-       }
-
-       public void onFailure(FetchException e, ClientGetter state) {
-               // ignore
-       }
-
-       public void receive(ClientEvent ce) {
-               if(finished) return;
-               if(ce instanceof SplitfileProgressEvent) {
-                       if((verbosity & VERBOSITY_SPLITFILE_PROGRESS) == 
VERBOSITY_SPLITFILE_PROGRESS) {
-                               SimpleProgressMessage progress = 
-                                       new SimpleProgressMessage(identifier, 
(SplitfileProgressEvent)ce);
-                               trySendProgressMessage(progress, 
VERBOSITY_SPLITFILE_PROGRESS, null);
-                       }
-               } else if(ce instanceof StartedCompressionEvent) {
-                       if((verbosity & VERBOSITY_COMPRESSION_START_END) == 
VERBOSITY_COMPRESSION_START_END) {
-                               StartedCompressionMessage msg =
-                                       new 
StartedCompressionMessage(identifier, ((StartedCompressionEvent)ce).codec);
-                               trySendProgressMessage(msg, 
VERBOSITY_COMPRESSION_START_END, null);
-                       }
-               } else if(ce instanceof FinishedCompressionEvent) {
-                       if((verbosity & VERBOSITY_COMPRESSION_START_END) == 
VERBOSITY_COMPRESSION_START_END) {
-                               FinishedCompressionMessage msg = 
-                                       new 
FinishedCompressionMessage(identifier, (FinishedCompressionEvent)ce);
-                               trySendProgressMessage(msg, 
VERBOSITY_COMPRESSION_START_END, null);
-                       }
-               }
-       }

-       private void trySendFinalMessage(FCPConnectionOutputHandler handler) {
-               
-               FCPMessage msg;
-               
-               if(succeeded) {
-                       msg = new PutSuccessfulMessage(identifier, 
generatedURI);
-               } else {
-                       msg = putFailedMessage;
-               }
-               
-               if(msg == null) {
-                       Logger.error(this, "Trying to send null message on 
"+this, new Exception("error"));
-               } else {
-                       if(handler != null)
-                               handler.queue(msg);
-                       else
-                               client.queueClientRequestMessage(msg, 0);
-               }
-       }
-
-       private void trySendGeneratedURIMessage(FCPConnectionOutputHandler 
handler) {
-               FCPMessage msg = new URIGeneratedMessage(generatedURI, 
identifier);
-               if(handler != null)
-                       handler.queue(msg);
-               else
-                       client.queueClientRequestMessage(msg, 0);
-       }
-
-       private void trySendProgressMessage(FCPMessage msg, int verbosity, 
FCPConnectionOutputHandler handler) {
-               if(persistenceType != PERSIST_CONNECTION)
-                       progressMessage = msg;
-               if(handler != null)
-                       handler.queue(msg);
-               else
-                       client.queueClientRequestMessage(msg, verbosity);
-       }
-       
-       public void sendPendingMessages(FCPConnectionOutputHandler handler, 
boolean includePersistentRequest) {
-               if(persistenceType == PERSIST_CONNECTION) {
-                       Logger.error(this, "WTF? 
persistenceType="+persistenceType, new Exception("error"));
-                       return;
-               }
-               if(includePersistentRequest) {
-                       FCPMessage msg = new PersistentPut(identifier, uri, 
verbosity, priorityClass, fromDisk, persistenceType, origFilename, 
block.clientMetadata.getMIMEType(), client.isGlobalQueue);
-                       handler.queue(msg);
-               }
-               if(generatedURI != null)
-                       trySendGeneratedURIMessage(handler);
-               if(progressMessage != null)
-                       handler.queue(progressMessage);
-               if(finished)
-                       trySendFinalMessage(handler);
-       }
-       
-       /** Request completed. But we may have to stick around until we are 
acked. */
-       private void finish() {
-               if(persistenceType == ClientRequest.PERSIST_CONNECTION)
-                       origHandler.finishedClientRequest(this);
-               client.finishedClientRequest(this);
-       }
-       
-       public boolean isPersistent() {
-               return persistenceType != ClientRequest.PERSIST_CONNECTION;
-       }
-
-       public void dropped() {
-               cancel();
-               block.getData().free();
-       }
-       
-       public String getIdentifier() {
-               return identifier;
-       }
-
-       public void write(BufferedWriter w) throws IOException {
-               if(persistenceType == ClientRequest.PERSIST_CONNECTION) {
-                       Logger.error(this, "Not persisting as 
persistenceType="+persistenceType);
-                       return;
-               }
-               // Persist the request to disk
-               SimpleFieldSet fs = getFieldSet();
-               fs.writeTo(w);
-       }
-       
-       public synchronized SimpleFieldSet getFieldSet() throws IOException {
-               SimpleFieldSet fs = new SimpleFieldSet(true); // we will need 
multi-level later...
-               fs.put("Type", "PUT");
-               fs.put("URI", uri.toString(false));
-               fs.put("Identifier", identifier);
-               fs.put("Verbosity", Integer.toString(verbosity));
-               fs.put("PriorityClass", Short.toString(priorityClass));
-               fs.put("Persistence", 
ClientRequest.persistenceTypeString(persistenceType));
-               fs.put("ClientName", client.name);
+       public synchronized SimpleFieldSet getFieldSet() {
+               SimpleFieldSet fs = super.getFieldSet();
                fs.put("Metadata.ContentType", 
block.clientMetadata.getMIMEType());
                fs.put("GetCHKOnly", Boolean.toString(getCHKOnly));
-               // finished => persistence of completion state, pending messages
-               //fs.put("Finished", Boolean.toString(finished));
-               fs.put("ClientToken", clientToken);
                fs.put("FromDisk", Boolean.toString(fromDisk));
                if(fromDisk) {
                        fs.put("Filename", origFilename.getPath());
@@ -350,34 +99,20 @@
                        fs.put("TempBucket.Filename", 
((FileBucket)(bucket.getUnderlying())).getName());
                        fs.put("TempBucket.Size", Long.toString(bucket.size()));
                }
-               fs.put("DontCompress", Boolean.toString(ctx.dontCompress));
-               fs.put("MaxRetries", Integer.toString(ctx.maxInsertRetries));
-               fs.put("Finished", Boolean.toString(finished));
-               fs.put("Succeeded", Boolean.toString(succeeded));
-               if(generatedURI != null)
-                       fs.put("GeneratedURI", generatedURI.toString(false));
-               if(finished && (!succeeded))
-                       // Should have a putFailedMessage... unless there is a 
race condition.
-                       fs.put("PutFailed", 
putFailedMessage.getFieldSet(false));
-               fs.put("Global", Boolean.toString(client.isGlobalQueue));
                return fs;
        }

-       public boolean hasFinished() {
-               return finished;
+       protected freenet.client.async.ClientRequester getClientRequest() {
+               return inserter;
        }

-       public boolean isPersistentForever() {
-               return persistenceType == ClientRequest.PERSIST_FOREVER;
+       protected FCPMessage persistentTagMessage() {
+               return new PersistentPut(identifier, uri, verbosity, 
priorityClass, fromDisk, persistenceType, origFilename, 
+                               block.clientMetadata.getMIMEType(), 
client.isGlobalQueue);
        }

-       public void setPriorityClass(short priorityClass) {
-               this.priorityClass = priorityClass;
-               inserter.setPriorityClass(priorityClass);
+       protected String getTypeName() {
+               return "PUT";
        }
-
-       public void setClientToken(String clientToken) {
-               this.clientToken = clientToken;
-       }
-
+       
 }

Added: trunk/freenet/src/freenet/node/fcp/ClientPutBase.java
===================================================================
--- trunk/freenet/src/freenet/node/fcp/ClientPutBase.java       2006-03-10 
18:33:19 UTC (rev 8220)
+++ trunk/freenet/src/freenet/node/fcp/ClientPutBase.java       2006-03-10 
22:35:51 UTC (rev 8221)
@@ -0,0 +1,233 @@
+package freenet.node.fcp;
+
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.net.MalformedURLException;
+
+import freenet.client.FetchException;
+import freenet.client.FetchResult;
+import freenet.client.InserterContext;
+import freenet.client.InserterException;
+import freenet.client.async.BaseClientPutter;
+import freenet.client.async.ClientCallback;
+import freenet.client.async.ClientGetter;
+import freenet.client.async.ClientRequester;
+import freenet.client.events.ClientEvent;
+import freenet.client.events.ClientEventListener;
+import freenet.client.events.FinishedCompressionEvent;
+import freenet.client.events.SimpleEventProducer;
+import freenet.client.events.SplitfileProgressEvent;
+import freenet.client.events.StartedCompressionEvent;
+import freenet.keys.FreenetURI;
+import freenet.support.Fields;
+import freenet.support.Logger;
+import freenet.support.SimpleFieldSet;
+
+/**
+ * Base class for ClientPut and ClientPutDir.
+ * Any code which can be shared between the two goes here.
+ */
+public abstract class ClientPutBase extends ClientRequest implements 
ClientCallback, ClientEventListener {
+
+       final InserterContext ctx;
+       final boolean getCHKOnly;
+
+       // Verbosity bitmasks
+       private int VERBOSITY_SPLITFILE_PROGRESS = 1;
+       private int VERBOSITY_COMPRESSION_START_END = 512;
+       
+       // Stuff waiting for reconnection
+       /** Has the request succeeded? */
+       protected boolean succeeded;
+       /** If the request failed, how did it fail? PutFailedMessage is the most
+        * convenient way to store this (InserterException has a stack trace!).
+        */
+       private PutFailedMessage putFailedMessage;
+       /** URI generated for the insert. */
+       private FreenetURI generatedURI;
+       // This could be a SimpleProgress, or it could be started/finished 
compression.
+       // Not that important, so not saved on persistence.
+       // Probably saving it would conflict with later changes (full 
persistence at
+       // ClientPutter level).
+       private FCPMessage progressMessage;
+       
+       public ClientPutBase(FreenetURI uri, String identifier, int verbosity, 
FCPConnectionHandler handler, 
+                       short priorityClass, short persistenceType, String 
clientToken, boolean global, boolean getCHKOnly,
+                       boolean dontCompress, int maxRetries) {
+               super(uri, identifier, verbosity, handler, priorityClass, 
persistenceType, clientToken, global);
+               this.getCHKOnly = getCHKOnly;
+               ctx = new InserterContext(client.defaultInsertContext, new 
SimpleEventProducer());
+               ctx.dontCompress = dontCompress;
+               ctx.eventProducer.addEventListener(this);
+               ctx.maxInsertRetries = maxRetries;
+       }
+
+       public ClientPutBase(SimpleFieldSet fs, FCPClient client2) throws 
MalformedURLException {
+               super(fs, client2);
+               getCHKOnly = Fields.stringToBool(fs.get("CHKOnly"), false);
+               boolean dontCompress = 
Fields.stringToBool(fs.get("DontCompress"), false);
+               int maxRetries = Integer.parseInt(fs.get("MaxRetries"));
+               clientToken = fs.get("ClientToken");
+               finished = Fields.stringToBool(fs.get("Finished"), false);
+               //finished = false;
+               succeeded = Fields.stringToBool(fs.get("Succeeded"), false);
+               ctx = new InserterContext(client.defaultInsertContext, new 
SimpleEventProducer());
+               ctx.dontCompress = dontCompress;
+               ctx.eventProducer.addEventListener(this);
+               ctx.maxInsertRetries = maxRetries;
+               String genURI = fs.get("GeneratedURI");
+               if(genURI != null)
+                       generatedURI = new FreenetURI(genURI);
+               if(finished && (!succeeded))
+                       putFailedMessage = new 
PutFailedMessage(fs.subset("PutFailed"), false);
+       }
+
+       public void onLostConnection() {
+               if(persistenceType == PERSIST_CONNECTION)
+                       cancel();
+               // otherwise ignore
+       }
+       
+       public void onSuccess(BaseClientPutter state) {
+               synchronized(this) {
+                       progressMessage = null;
+                       succeeded = true;
+                       finished = true;
+               }
+               trySendFinalMessage(null);
+               freeData();
+               finish();
+       }
+
+       public void onFailure(InserterException e, BaseClientPutter state) {
+               synchronized(this) {
+                       finished = true;
+                       putFailedMessage = new PutFailedMessage(e, identifier);
+               }
+               trySendFinalMessage(null);
+               freeData();
+               finish();
+       }
+
+       public void onGeneratedURI(FreenetURI uri, BaseClientPutter state) {
+               synchronized(this) {
+                       if(generatedURI != null && !uri.equals(generatedURI))
+                               Logger.error(this, 
"onGeneratedURI("+uri+","+state+") but already set generatedURI to 
"+generatedURI);
+                       generatedURI = uri;
+               }
+               trySendGeneratedURIMessage(null);
+       }
+
+       public void onSuccess(FetchResult result, ClientGetter state) {
+               // ignore
+       }
+
+       public void onFailure(FetchException e, ClientGetter state) {
+               // ignore
+       }
+
+       public void receive(ClientEvent ce) {
+               if(finished) return;
+               if(ce instanceof SplitfileProgressEvent) {
+                       if((verbosity & VERBOSITY_SPLITFILE_PROGRESS) == 
VERBOSITY_SPLITFILE_PROGRESS) {
+                               SimpleProgressMessage progress = 
+                                       new SimpleProgressMessage(identifier, 
(SplitfileProgressEvent)ce);
+                               trySendProgressMessage(progress, 
VERBOSITY_SPLITFILE_PROGRESS, null);
+                       }
+               } else if(ce instanceof StartedCompressionEvent) {
+                       if((verbosity & VERBOSITY_COMPRESSION_START_END) == 
VERBOSITY_COMPRESSION_START_END) {
+                               StartedCompressionMessage msg =
+                                       new 
StartedCompressionMessage(identifier, ((StartedCompressionEvent)ce).codec);
+                               trySendProgressMessage(msg, 
VERBOSITY_COMPRESSION_START_END, null);
+                       }
+               } else if(ce instanceof FinishedCompressionEvent) {
+                       if((verbosity & VERBOSITY_COMPRESSION_START_END) == 
VERBOSITY_COMPRESSION_START_END) {
+                               FinishedCompressionMessage msg = 
+                                       new 
FinishedCompressionMessage(identifier, (FinishedCompressionEvent)ce);
+                               trySendProgressMessage(msg, 
VERBOSITY_COMPRESSION_START_END, null);
+                       }
+               }
+       }
+       
+       private void trySendFinalMessage(FCPConnectionOutputHandler handler) {
+               
+               FCPMessage msg;
+               
+               if(succeeded) {
+                       msg = new PutSuccessfulMessage(identifier, 
generatedURI);
+               } else {
+                       msg = putFailedMessage;
+               }
+               
+               if(msg == null) {
+                       Logger.error(this, "Trying to send null message on 
"+this, new Exception("error"));
+               } else {
+                       if(handler != null)
+                               handler.queue(msg);
+                       else
+                               client.queueClientRequestMessage(msg, 0);
+               }
+       }
+
+       private void trySendGeneratedURIMessage(FCPConnectionOutputHandler 
handler) {
+               FCPMessage msg = new URIGeneratedMessage(generatedURI, 
identifier);
+               if(handler != null)
+                       handler.queue(msg);
+               else
+                       client.queueClientRequestMessage(msg, 0);
+       }
+
+       private void trySendProgressMessage(FCPMessage msg, int verbosity, 
FCPConnectionOutputHandler handler) {
+               if(persistenceType != PERSIST_CONNECTION)
+                       progressMessage = msg;
+               if(handler != null)
+                       handler.queue(msg);
+               else
+                       client.queueClientRequestMessage(msg, verbosity);
+       }
+       
+       public void sendPendingMessages(FCPConnectionOutputHandler handler, 
boolean includePersistentRequest) {
+               if(persistenceType == PERSIST_CONNECTION) {
+                       Logger.error(this, "WTF? 
persistenceType="+persistenceType, new Exception("error"));
+                       return;
+               }
+               if(includePersistentRequest) {
+                       FCPMessage msg = persistentTagMessage();
+                       handler.queue(msg);
+               }
+               if(generatedURI != null)
+                       trySendGeneratedURIMessage(handler);
+               if(progressMessage != null)
+                       handler.queue(progressMessage);
+               if(finished)
+                       trySendFinalMessage(handler);
+       }
+
+       protected abstract FCPMessage persistentTagMessage();
+       
+       public SimpleFieldSet getFieldSet() {
+               SimpleFieldSet fs = new SimpleFieldSet(true); // we will need 
multi-level later...
+               fs.put("Type", getTypeName());
+               fs.put("URI", uri.toString(false));
+               fs.put("Identifier", identifier);
+               fs.put("Verbosity", Integer.toString(verbosity));
+               fs.put("PriorityClass", Short.toString(priorityClass));
+               fs.put("Persistence", 
ClientRequest.persistenceTypeString(persistenceType));
+               fs.put("ClientName", client.name);
+               fs.put("ClientToken", clientToken);
+               fs.put("DontCompress", Boolean.toString(ctx.dontCompress));
+               fs.put("MaxRetries", Integer.toString(ctx.maxInsertRetries));
+               fs.put("Finished", Boolean.toString(finished));
+               fs.put("Succeeded", Boolean.toString(succeeded));
+               if(generatedURI != null)
+                       fs.put("GeneratedURI", generatedURI.toString(false));
+               if(finished && (!succeeded))
+                       // Should have a putFailedMessage... unless there is a 
race condition.
+                       fs.put("PutFailed", 
putFailedMessage.getFieldSet(false));
+               fs.put("Global", Boolean.toString(client.isGlobalQueue));
+               return fs;
+       }
+       
+       protected abstract String getTypeName();
+
+}

Added: trunk/freenet/src/freenet/node/fcp/ClientPutDir.java
===================================================================
--- trunk/freenet/src/freenet/node/fcp/ClientPutDir.java        2006-03-10 
18:33:19 UTC (rev 8220)
+++ trunk/freenet/src/freenet/node/fcp/ClientPutDir.java        2006-03-10 
22:35:51 UTC (rev 8221)
@@ -0,0 +1,97 @@
+package freenet.node.fcp;
+
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Iterator;
+
+import freenet.client.FetchException;
+import freenet.client.FetchResult;
+import freenet.client.InserterContext;
+import freenet.client.InserterException;
+import freenet.client.async.BaseClientPutter;
+import freenet.client.async.ClientCallback;
+import freenet.client.async.ClientGetter;
+import freenet.client.async.ClientRequester;
+import freenet.client.async.ManifestElement;
+import freenet.client.async.SimpleManifestPutter;
+import freenet.client.events.ClientEvent;
+import freenet.client.events.ClientEventListener;
+import freenet.client.events.SimpleEventProducer;
+import freenet.keys.FreenetURI;
+import freenet.support.SimpleFieldSet;
+
+public class ClientPutDir extends ClientPutBase implements 
ClientEventListener, ClientCallback {
+
+       private HashMap manifestElements;
+       private SimpleManifestPutter putter;
+       private InserterContext ctx;
+       
+       public ClientPutDir(FCPConnectionHandler handler, ClientPutDirMessage 
message, 
+                       HashMap manifestElements) throws 
IdentifierCollisionException {
+               super(message.uri, message.identifier, message.verbosity, 
handler,
+                               message.priorityClass, message.persistenceType, 
message.clientToken, message.global,
+                               message.getCHKOnly, message.dontCompress, 
message.maxRetries);
+               this.manifestElements = manifestElements;
+               ctx = new InserterContext(client.defaultInsertContext, new 
SimpleEventProducer());
+               ctx.dontCompress = message.dontCompress;
+               ctx.eventProducer.addEventListener(this);
+               ctx.maxInsertRetries = message.maxRetries;
+               try {
+                       putter = new SimpleManifestPutter(this, 
client.node.chkPutScheduler, client.node.sskPutScheduler,
+                                       manifestElements, priorityClass, uri, 
message.defaultName, ctx, message.getCHKOnly, client);
+               } catch (InserterException e) {
+                       onFailure(e, null);
+               } 
+               if(persistenceType != PERSIST_CONNECTION)
+                       client.register(this);
+       }
+
+       public void start() {
+               try {
+                       putter.start();
+               } catch (InserterException e) {
+                       onFailure(e, null);
+               }
+       }
+       
+       public void onLostConnection() {
+               if(persistenceType == PERSIST_CONNECTION)
+                       cancel();
+               // otherwise ignore
+       }
+       
+       protected void freeData() {
+               freeData(manifestElements);
+       }
+       
+       private void freeData(HashMap manifestElements) {
+               Iterator i = manifestElements.values().iterator();
+               while(i.hasNext()) {
+                       Object o = i.next();
+                       if(o instanceof HashMap)
+                               freeData((HashMap)o);
+                       else {
+                               ManifestElement e = (ManifestElement) o;
+                               e.freeData();
+                       }
+               }
+       }
+
+       protected ClientRequester getClientRequest() {
+               return putter;
+       }
+
+       public SimpleFieldSet getFieldSet() {
+               throw new UnsupportedOperationException();
+       }
+
+       protected FCPMessage persistentTagMessage() {
+               throw new UnsupportedOperationException();
+       }
+
+       protected String getTypeName() {
+               return "PUTDIR";
+       }
+
+}

Added: trunk/freenet/src/freenet/node/fcp/ClientPutDirMessage.java
===================================================================
--- trunk/freenet/src/freenet/node/fcp/ClientPutDirMessage.java 2006-03-10 
18:33:19 UTC (rev 8220)
+++ trunk/freenet/src/freenet/node/fcp/ClientPutDirMessage.java 2006-03-10 
22:35:51 UTC (rev 8221)
@@ -0,0 +1,124 @@
+package freenet.node.fcp;
+
+import java.net.MalformedURLException;
+
+import freenet.keys.FreenetURI;
+import freenet.node.RequestStarter;
+import freenet.support.Fields;
+import freenet.support.SimpleFieldSet;
+
+/**
+ * Put a directory, rather than a file.
+ * Base class.
+ * 
+ * Two forms: ClientPutDiskDir and ClientPutComplexDir
+ *
+ * Both share:
+ * Identifier=<identifier>
+ * Verbosity=<verbosity as ClientPut>
+ * MaxRetries=<max retries as ClientPut>
+ * PriorityClass=<priority class>
+ * URI=<target URI>
+ * GetCHKOnly=<GetCHKOnly as ClientPut>
+ * DontCompress=<DontCompress as ClientPut>
+ * ClientToken=<ClientToken as ClientPut>
+ * Persistence=<Persistence as ClientPut>
+ * Global=<Global as ClientPut>
+ */
+public abstract class ClientPutDirMessage extends FCPMessage {
+
+       final String identifier;
+       final FreenetURI uri;
+       final int verbosity;
+       final int maxRetries;
+       final boolean getCHKOnly;
+       final short priorityClass;
+       final short persistenceType;
+       final boolean dontCompress;
+       final String clientToken;
+       final boolean global;
+       final String defaultName;
+       
+       public ClientPutDirMessage(SimpleFieldSet fs) throws 
MessageInvalidException {
+               identifier = fs.get("Identifier");
+               defaultName = fs.get("DefaultName");
+               if(identifier == null)
+                       throw new 
MessageInvalidException(ProtocolErrorMessage.MISSING_FIELD, "No Identifier", 
null);
+               try {
+                       String u = fs.get("URI");
+                       if(u == null)
+                               throw new 
MessageInvalidException(ProtocolErrorMessage.MISSING_FIELD, "No URI", 
identifier);
+                       uri = new FreenetURI(fs.get("URI"));
+               } catch (MalformedURLException e) {
+                       throw new 
MessageInvalidException(ProtocolErrorMessage.URI_PARSE_ERROR, e.getMessage(), 
identifier);
+               }
+               global = Fields.stringToBool(fs.get("Global"), false);
+               String verbosityString = fs.get("Verbosity");
+               if(verbosityString == null)
+                       verbosity = 0;
+               else {
+                       try {
+                               verbosity = Integer.parseInt(verbosityString, 
10);
+                       } catch (NumberFormatException e) {
+                               throw new 
MessageInvalidException(ProtocolErrorMessage.ERROR_PARSING_NUMBER, "Error 
parsing Verbosity field: "+e.getMessage(), identifier);
+                       }
+               }
+               String maxRetriesString = fs.get("MaxRetries");
+               if(maxRetriesString == null)
+                       // default to 0
+                       maxRetries = 0;
+               else {
+                       try {
+                               maxRetries = Integer.parseInt(maxRetriesString, 
10);
+                       } catch (NumberFormatException e) {
+                               throw new 
MessageInvalidException(ProtocolErrorMessage.ERROR_PARSING_NUMBER, "Error 
parsing MaxSize field: "+e.getMessage(), identifier);
+                       }
+               }
+               getCHKOnly = Fields.stringToBool(fs.get("GetCHKOnly"), false);
+               String priorityString = fs.get("PriorityClass");
+               if(priorityString == null) {
+                       // defaults to the one just below fproxy
+                       priorityClass = 
RequestStarter.IMMEDIATE_SPLITFILE_PRIORITY_CLASS;
+               } else {
+                       try {
+                               priorityClass = 
Short.parseShort(priorityString, 10);
+                               if(priorityClass < 
RequestStarter.MAXIMUM_PRIORITY_CLASS || priorityClass > 
RequestStarter.MINIMUM_PRIORITY_CLASS)
+                                       throw new 
MessageInvalidException(ProtocolErrorMessage.INVALID_FIELD, "Valid priorities 
are from "+RequestStarter.MAXIMUM_PRIORITY_CLASS+" to 
"+RequestStarter.MINIMUM_PRIORITY_CLASS, identifier);
+                       } catch (NumberFormatException e) {
+                               throw new 
MessageInvalidException(ProtocolErrorMessage.ERROR_PARSING_NUMBER, "Error 
parsing PriorityClass field: "+e.getMessage(), identifier);
+                       }
+               }
+               dontCompress = Fields.stringToBool(fs.get("DontCompress"), 
false);
+               String persistenceString = fs.get("Persistence");
+               if(persistenceString == null || 
persistenceString.equalsIgnoreCase("connection")) {
+                       // Default: persists until connection loss.
+                       persistenceType = ClientRequest.PERSIST_CONNECTION;
+               } else if(persistenceString.equalsIgnoreCase("reboot")) {
+                       // Reports to client by name; persists over connection 
loss.
+                       // Not saved to disk, so dies on reboot.
+                       persistenceType = ClientRequest.PERSIST_REBOOT;
+               } else if(persistenceString.equalsIgnoreCase("forever")) {
+                       // Same as reboot but saved to disk, persists forever.
+                       persistenceType = ClientRequest.PERSIST_FOREVER;
+               } else {
+                       throw new 
MessageInvalidException(ProtocolErrorMessage.ERROR_PARSING_NUMBER, "Error 
parsing Persistence field: "+persistenceString, identifier);
+               }
+               clientToken = fs.get("ClientToken");
+       }
+
+       public SimpleFieldSet getFieldSet() {
+               SimpleFieldSet sfs = new SimpleFieldSet(false);
+               sfs.put("URI", uri.toString());
+               sfs.put("Identifier", identifier);
+               sfs.put("Verbosity", Integer.toString(verbosity));
+               sfs.put("MaxRetries", Integer.toString(maxRetries));
+               sfs.put("ClientToken", clientToken);
+               sfs.put("GetCHKOnly", Boolean.toString(getCHKOnly));
+               sfs.put("PriorityClass", Short.toString(priorityClass));
+               sfs.put("PersistenceType", 
ClientRequest.persistenceTypeString(persistenceType));
+               sfs.put("DontCompress", Boolean.toString(dontCompress));
+               sfs.put("Global", Boolean.toString(global));
+               return sfs;
+       }
+
+}

Added: trunk/freenet/src/freenet/node/fcp/ClientPutDiskDirMessage.java
===================================================================
--- trunk/freenet/src/freenet/node/fcp/ClientPutDiskDirMessage.java     
2006-03-10 18:33:19 UTC (rev 8220)
+++ trunk/freenet/src/freenet/node/fcp/ClientPutDiskDirMessage.java     
2006-03-10 22:35:51 UTC (rev 8221)
@@ -0,0 +1,87 @@
+package freenet.node.fcp;
+
+import java.io.File;
+import java.util.HashMap;
+
+import freenet.client.async.ManifestElement;
+import freenet.node.Node;
+import freenet.support.Fields;
+import freenet.support.Logger;
+import freenet.support.SimpleFieldSet;
+import freenet.support.io.FileBucket;
+
+/**
+ * Insert a directory from disk as a manifest.
+ * 
+ * ClientPutDiskDirMessage
+ * < generic fields from ClientPutDirMessage >
+ * Filename=<filename>
+ * AllowUnreadableFiles=<unless true, any unreadable files cause the whole 
request to fail>
+ * End
+ */
+public class ClientPutDiskDirMessage extends ClientPutDirMessage {
+
+       public static String name = "ClientPutDiskDir";
+       
+       final File dirname;
+       final boolean allowUnreadableFiles;
+
+       public ClientPutDiskDirMessage(SimpleFieldSet fs) throws 
MessageInvalidException {
+               super(fs);
+               allowUnreadableFiles = 
Fields.stringToBool(fs.get("AllowUnreadableFiles"), false);
+               String fnam = fs.get("Filename");
+               if(fnam == null)
+                       throw new 
MessageInvalidException(ProtocolErrorMessage.MISSING_FIELD, "Filename missing", 
identifier);
+               dirname = new File(fnam);
+       }
+
+       public String getName() {
+               return name;
+       }
+
+       public void run(FCPConnectionHandler handler, Node node)
+                       throws MessageInvalidException {
+               // Create a directory listing of Buckets of data, mapped to 
ManifestElement's.
+               // Directories are sub-HashMap's.
+               HashMap buckets = makeBucketsByName(dirname);
+               handler.startClientPutDir(this, buckets);
+       }
+
+    /**
+     * Create a map of String -> Bucket for every file in a directory
+     * and its subdirs.
+     * @throws MessageInvalidException 
+     */
+    private HashMap makeBucketsByName(File thisdir) throws 
MessageInvalidException {
+       
+       Logger.minor(this, "Listing directory: "+thisdir);
+       
+       HashMap ret = new HashMap();
+       
+       File filelist[] = thisdir.listFiles();
+       if(filelist == null)
+               throw new IllegalArgumentException("No such directory");
+       for(int i = 0 ; i < filelist.length ; i++) {
+                //   Skip unreadable files and dirs
+               //   Skip files nonexistant (dangling symlinks) - check last 
+               if (filelist[i].canRead() && filelist[i].exists()) {
+                       if (filelist[i].isFile()) {
+                               File f = filelist[i];
+                               
+                               FileBucket bucket = new FileBucket(f, true, 
false, false, false);
+                               
+                               ret.put(f.getName(), new 
ManifestElement(f.getName(), bucket, null));
+                       } else if(filelist[i].isDirectory()) {
+                               HashMap subdir = makeBucketsByName(new 
File(thisdir, filelist[i].getName()));
+                               ret.put(filelist[i].getName(), subdir);
+                       } else if(!allowUnreadableFiles) {
+                               throw new 
MessageInvalidException(ProtocolErrorMessage.FILE_NOT_FOUND, "Not directory and 
not file: "+filelist[i], identifier);
+                       }
+               } else {
+                       throw new 
MessageInvalidException(ProtocolErrorMessage.FILE_NOT_FOUND, "Not readable or 
doesn't exist: "+filelist[i], identifier);
+               }
+       }
+       return ret;
+       }
+
+}

Modified: trunk/freenet/src/freenet/node/fcp/ClientPutMessage.java
===================================================================
--- trunk/freenet/src/freenet/node/fcp/ClientPutMessage.java    2006-03-10 
18:33:19 UTC (rev 8220)
+++ trunk/freenet/src/freenet/node/fcp/ClientPutMessage.java    2006-03-10 
22:35:51 UTC (rev 8221)
@@ -147,10 +147,22 @@
                SimpleFieldSet sfs = new SimpleFieldSet(false);
                sfs.put("URI", uri.toString());
                sfs.put("Identifier", identifier);
-               sfs.put("DataLength", Long.toString(dataLength));
                sfs.put("Verbosity", Integer.toString(verbosity));
                sfs.put("MaxRetries", Integer.toString(maxRetries));
                sfs.put("Metadata.ContentType", contentType);
+               sfs.put("ClientToken", clientToken);
+               if(fromDisk) {
+                       sfs.put("UploadFrom", "disk");
+                       sfs.put("Filename", origFilename.getAbsolutePath());
+               } else {
+                       sfs.put("UploadFrom", "direct");
+                       sfs.put("DataLength", Long.toString(dataLength));
+               }
+               sfs.put("GetCHKOnly", Boolean.toString(getCHKOnly));
+               sfs.put("PriorityClass", Short.toString(priorityClass));
+               sfs.put("PersistenceType", 
ClientRequest.persistenceTypeString(persistenceType));
+               sfs.put("DontCompress", Boolean.toString(dontCompress));
+               sfs.put("Global", Boolean.toString(global));
                return sfs;
        }


Modified: trunk/freenet/src/freenet/node/fcp/ClientRequest.java
===================================================================
--- trunk/freenet/src/freenet/node/fcp/ClientRequest.java       2006-03-10 
18:33:19 UTC (rev 8220)
+++ trunk/freenet/src/freenet/node/fcp/ClientRequest.java       2006-03-10 
22:35:51 UTC (rev 8221)
@@ -3,7 +3,10 @@
 import java.io.BufferedReader;
 import java.io.BufferedWriter;
 import java.io.IOException;
+import java.net.MalformedURLException;

+import freenet.client.async.ClientRequester;
+import freenet.keys.FreenetURI;
 import freenet.support.Fields;
 import freenet.support.Logger;
 import freenet.support.SimpleFieldSet;
@@ -14,17 +17,68 @@
  */
 public abstract class ClientRequest {

-       /** Lost connection */
-       public abstract void onLostConnection();
+       /** URI to fetch, or target URI to insert to */
+       protected final FreenetURI uri;
+       /** Unique request identifier */
+       protected final String identifier;
+       /** Verbosity level. Relevant to all ClientRequests, although they 
interpret it
+        * differently. */
+       protected final int verbosity;
+       /** Original FCPConnectionHandler. Null if persistence != connection */
+       protected final FCPConnectionHandler origHandler;
+       /** Client */
+       protected final FCPClient client;
+       /** Priority class */
+       protected short priorityClass;
+       /** Persistence type */
+       protected final short persistenceType;
+       /** Has the request finished? */
+       protected boolean finished;
+       /** Client token (string to feed back to the client on a Persistent* 
when he does a
+        * ListPersistentRequests). */
+       protected String clientToken;
+       /** Is the request on the global queue? */
+       protected final boolean global;

-       /** Is the request persistent? False = we can drop the request if we 
lose the connection */
-       public abstract boolean isPersistent();
+       public ClientRequest(FreenetURI uri2, String identifier2, int 
verbosity2, FCPConnectionHandler handler, 
+                       short priorityClass2, short persistenceType2, String 
clientToken2, boolean global) {
+               this.uri = uri2;
+               this.identifier = identifier2;
+               this.verbosity = verbosity2;
+               this.finished = false;
+               this.priorityClass = priorityClass2;
+               this.persistenceType = persistenceType2;
+               this.clientToken = clientToken2;
+               this.global = global;
+               if(persistenceType == PERSIST_CONNECTION)
+                       this.origHandler = handler;
+               else
+                       origHandler = null;
+               if(global) {
+                       client = handler.server.globalClient;
+               } else {
+                       client = handler.getClient();
+               }
+       }

-       /** Completed request dropped off the end without being acknowledged */
-       public abstract void dropped();
+       public ClientRequest(SimpleFieldSet fs, FCPClient client2) throws 
MalformedURLException {
+               uri = new FreenetURI(fs.get("URI"));
+               identifier = fs.get("Identifier");
+               verbosity = Integer.parseInt(fs.get("Verbosity"));
+               persistenceType = 
ClientRequest.parsePersistence(fs.get("Persistence"));
+               if(persistenceType == ClientRequest.PERSIST_CONNECTION)
+                       throw new IllegalArgumentException("Reading persistent 
get with type CONNECTION !!");
+               if(!(persistenceType == ClientRequest.PERSIST_FOREVER || 
persistenceType == ClientRequest.PERSIST_REBOOT))
+                       throw new IllegalArgumentException("Unknown persistence 
type "+ClientRequest.persistenceTypeString(persistenceType));
+               this.client = client2;
+               this.origHandler = null;
+               clientToken = fs.get("ClientToken");
+               finished = Fields.stringToBool(fs.get("Finished"), false);
+               global = Fields.stringToBool(fs.get("Global"), false);
+       }

-       /** Get identifier string for request */
-       public abstract String getIdentifier();
+       /** Lost connection */
+       public abstract void onLostConnection();

        /** Send any pending messages for a persistent request e.g. after 
reconnecting */
        public abstract void sendPendingMessages(FCPConnectionOutputHandler 
handler, boolean includePersistentRequest);
@@ -58,12 +112,6 @@
                return Short.parseShort(string);
        }

-       /**
-        * Write a persistent request to disk.
-        * @throws IOException 
-        */
-       public abstract void write(BufferedWriter w) throws IOException;
-
        public static ClientRequest readAndRegister(BufferedReader br, 
FCPServer server) throws IOException {
                SimpleFieldSet fs = new SimpleFieldSet(br, true);
                String clientName = fs.get("ClientName");
@@ -93,14 +141,71 @@
                }
        }

-       public abstract boolean hasFinished();
-       
-       public abstract boolean isPersistentForever();
+       public void cancel() {
+               getClientRequest().cancel();
+       }

-       public abstract void cancel();
+       public boolean isPersistentForever() {
+               return persistenceType == ClientRequest.PERSIST_FOREVER;
+       }

-       public abstract void setPriorityClass(short priorityClass);
+       /** Is the request persistent? False = we can drop the request if we 
lose the connection */
+       public boolean isPersistent() {
+               return persistenceType != ClientRequest.PERSIST_CONNECTION;
+       }

-       public abstract void setClientToken(String clientToken);
+       public boolean hasFinished() {
+               return finished;
+       }

+       /** Get identifier string for request */
+       public String getIdentifier() {
+               return identifier;
+       }
+
+       public void setPriorityClass(short priorityClass) {
+               this.priorityClass = priorityClass;
+               getClientRequest().setPriorityClass(priorityClass);
+       }
+
+       public void setClientToken(String clientToken) {
+               this.clientToken = clientToken;
+       }
+
+       protected abstract ClientRequester getClientRequest();
+       
+       /** Completed request dropped off the end without being acknowledged */
+       public void dropped() {
+               cancel();
+               freeData();
+       }
+
+       /** Free cached data bucket(s) */
+       protected abstract void freeData(); 
+
+       /** Request completed. But we may have to stick around until we are 
acked. */
+       protected void finish() {
+               if(persistenceType == ClientRequest.PERSIST_CONNECTION)
+                       origHandler.finishedClientRequest(this);
+               client.finishedClientRequest(this);
+       }
+       
+       /**
+        * Write a persistent request to disk.
+        * @throws IOException 
+        */
+       public void write(BufferedWriter w) throws IOException {
+               if(persistenceType == ClientRequest.PERSIST_CONNECTION) {
+                       Logger.error(this, "Not persisting as 
persistenceType="+persistenceType);
+                       return;
+               }
+               // Persist the request to disk
+               SimpleFieldSet fs = getFieldSet();
+               fs.writeTo(w);
+       }
+       
+       /**
+        * Get a SimpleFieldSet representing this request.
+        */
+       public abstract SimpleFieldSet getFieldSet() throws IOException;
 }

Modified: trunk/freenet/src/freenet/node/fcp/FCPConnectionHandler.java
===================================================================
--- trunk/freenet/src/freenet/node/fcp/FCPConnectionHandler.java        
2006-03-10 18:33:19 UTC (rev 8220)
+++ trunk/freenet/src/freenet/node/fcp/FCPConnectionHandler.java        
2006-03-10 22:35:51 UTC (rev 8221)
@@ -174,6 +174,44 @@
                }
        }

+       public void startClientPutDir(ClientPutDiskDirMessage message, HashMap 
buckets) {
+               String id = message.identifier;
+               ClientPutDir cp = null;
+               boolean success;
+               boolean persistent = message.persistenceType != 
ClientGet.PERSIST_CONNECTION;
+               synchronized(this) {
+                       if(isClosed) return;
+                       // We need to track non-persistent requests anyway, so 
we may as well check
+                       if(persistent)
+                               success = true;
+                       else
+                               success = !requestsByIdentifier.containsKey(id);
+                       if(success) {
+                               try {
+                                       cp = new ClientPutDir(this, message, 
buckets);
+                               } catch (IdentifierCollisionException e) {
+                                       success = false;
+                               }
+                               if(!persistent)
+                                       requestsByIdentifier.put(id, cp);
+                       }
+               }
+               if(!success) {
+                       Logger.normal(this, "Identifier collision on "+this);
+                       FCPMessage msg = new IdentifierCollisionMessage(id);
+                       outputHandler.queue(msg);
+                       return;
+               } else {
+                       // Register before starting, because it may complete 
immediately, and if it does,
+                       // we may end up with it not being removable because it 
wasn't registered!
+                       if(cp.isPersistent()) {
+                               if(cp.isPersistentForever())
+                                       server.forceStorePersistentRequests();
+                       }
+                       cp.start();
+               }
+       }
+       
        public FCPClient getClient() {
                return client;
        }
@@ -183,5 +221,5 @@
                        requestsByIdentifier.remove(get.getIdentifier());
                }
        }
-       
+
 }

Modified: trunk/freenet/src/freenet/node/fcp/FCPMessage.java
===================================================================
--- trunk/freenet/src/freenet/node/fcp/FCPMessage.java  2006-03-10 18:33:19 UTC 
(rev 8220)
+++ trunk/freenet/src/freenet/node/fcp/FCPMessage.java  2006-03-10 22:35:51 UTC 
(rev 8221)
@@ -41,6 +41,8 @@
                        return new WatchGlobal(fs);
                if(name.equals(ModifyPersistentRequest.name))
                        return new ModifyPersistentRequest(fs);
+               if(name.equals(ClientPutDiskDirMessage.name))
+                       return new ClientPutDiskDirMessage(fs);
                if(name.equals("Void"))
                        return null;
                throw new 
MessageInvalidException(ProtocolErrorMessage.INVALID_MESSAGE, "Unknown message 
name "+name, null);


Reply via email to