add ClientPut and PersistentPut
authorDavid ‘Bombe’ Roden <bombe@pterodactylus.net>
Thu, 10 Apr 2008 10:39:21 +0000 (10:39 +0000)
committerDavid ‘Bombe’ Roden <bombe@pterodactylus.net>
Thu, 10 Apr 2008 10:39:21 +0000 (10:39 +0000)
git-svn-id: http://trooper/svn/projects/jSite/trunk@688 c3eda9e8-030b-0410-8277-bc7414b0a119

src/net/pterodactylus/util/fcp/ClientPut.java [new file with mode: 0644]
src/net/pterodactylus/util/fcp/FcpAdapter.java
src/net/pterodactylus/util/fcp/FcpConnection.java
src/net/pterodactylus/util/fcp/FcpListener.java
src/net/pterodactylus/util/fcp/Persistence.java [new file with mode: 0644]
src/net/pterodactylus/util/fcp/PersistentPut.java [new file with mode: 0644]
src/net/pterodactylus/util/fcp/Priority.java [new file with mode: 0644]
src/net/pterodactylus/util/fcp/UploadFrom.java [new file with mode: 0644]
src/net/pterodactylus/util/fcp/Verbosity.java [new file with mode: 0644]

diff --git a/src/net/pterodactylus/util/fcp/ClientPut.java b/src/net/pterodactylus/util/fcp/ClientPut.java
new file mode 100644 (file)
index 0000000..bfbe210
--- /dev/null
@@ -0,0 +1,222 @@
+/**
+ * © 2008 INA Service GmbH
+ */
+package net.pterodactylus.util.fcp;
+
+/**
+ * A “ClientPut” requests inserts a single file into freenet, either uploading
+ * it directly with this messge ({@link UploadFrom#direct}), uploading it from
+ * disk ({@link UploadFrom#disk}) or by creating a redirect to another URI ({@link UploadFrom#redirect}).
+ * 
+ * @author <a href="mailto:dr@ina-germany.de">David Roden</a>
+ * @version $Id$
+ */
+public class ClientPut extends FcpMessage {
+
+       /**
+        * Creates a new “ClientPut” message that inserts a file to the given URI.
+        * The file data <em>has</em> to be supplied to this message using
+        * {@link #setPayloadInputStream(java.io.InputStream)}!
+        * 
+        * Using this constructor is the same as using
+        * {@link #ClientPut(String, String, UploadFrom)} with
+        * {@link UploadFrom#direct} as third parameter.
+        * 
+        * @param uri
+        *            The URI to insert the file to
+        * @param identifier
+        *            The identifier of the request
+        */
+       public ClientPut(String uri, String identifier) {
+               this(uri, identifier, UploadFrom.direct);
+       }
+
+       /**
+        * Creates a new “ClientPut” message that inserts a file to the given URI.
+        * Depending on <code>uploadFrom</code> the file data has to be supplied
+        * in different ways:
+        * 
+        * If <code>uploadFrom</code> is {@link UploadFrom#direct}, use
+        * {@link #setPayloadInputStream(java.io.InputStream)} to supply the input
+        * data.
+        * 
+        * If <code>uploadFrom</code> is {@link UploadFrom#disk}, use
+        * {@link #setFilename(String)} to supply the file to upload. You have to
+        * test your direct-disk access (see {@link TestDDARequest},
+        * {@link TestDDAReply}, {@link TestDDAResponse}, {@link TestDDAComplete})
+        * before using this option!
+        * 
+        * If <code>uploadFrom</code> is {@link UploadFrom#redirect}, use
+        * {@link #setTargetURI(String)} to set the target URI of the redirect.
+        * 
+        * @param uri
+        *            The URI to insert to
+        * @param identifier
+        *            The identifier of the insert
+        * @param uploadFrom
+        *            The source of the upload
+        */
+       public ClientPut(String uri, String identifier, UploadFrom uploadFrom) {
+               super("ClientPut");
+               setField("URI", uri);
+               setField("Identifier", identifier);
+               setField("UploadFrom", String.valueOf(uploadFrom));
+       }
+
+       /**
+        * The MIME type of the content.
+        * 
+        * @param metadataContentType
+        *            The MIME type of the content
+        */
+       public void setMetadataContentType(String metadataContentType) {
+               setField("Metadata.ContentType", metadataContentType);
+       }
+
+       /**
+        * The verbosity of the request. Depending on this parameter you will
+        * received only the bare minimum of messages for the request (i.e. “it
+        * completed”) or a whole lot more.
+        * 
+        * @see Verbosity
+        * @param verbosity
+        *            The verbosity of the request
+        */
+       public void setVerbosity(Verbosity verbosity) {
+               setField("Verbosity", String.valueOf(verbosity));
+       }
+
+       /**
+        * The number of retries for a request if the initial try failed.
+        * 
+        * @param maxRetries
+        *            The maximum number of retries after failure, or
+        *            <code>-1</code> to retry forever.
+        */
+       public void setMaxRetries(int maxRetries) {
+               setField("MaxRetries", String.valueOf(maxRetries));
+       }
+
+       /**
+        * Sets the priority of the request.
+        * 
+        * @param priority
+        *            The priority of the request
+        */
+       public void setPriority(Priority priority) {
+               setField("Priority", String.valueOf(priority));
+       }
+
+       /**
+        * Determines whether the node should really insert the data or generate the
+        * final CHK only.
+        * 
+        * @param getCHKOnly
+        *            <code>true</code> to generate the final CHK only,
+        *            <code>false</code> to really insert the data
+        */
+       public void setGetCHKOnly(boolean getCHKOnly) {
+               setField("GetCHKOnly", String.valueOf(getCHKOnly));
+       }
+
+       /**
+        * Determines whether this request appears on the global queue.
+        * 
+        * @param global
+        *            <code>true</code> to put the request on the global queue,
+        *            <code>false</code> for the client-local queue.
+        */
+       public void setGlobal(boolean global) {
+               setField("Global", String.valueOf(global));
+       }
+
+       /**
+        * Determines whether the node should skip compression because the file has
+        * already been compressed.
+        * 
+        * @param dontCompress
+        *            <code>true</code> to skip compression of the data in the
+        *            node, <code>false</code> to allow compression
+        */
+       public void setDontCompress(boolean dontCompress) {
+               setField("DontCompress", String.valueOf(dontCompress));
+       }
+
+       /**
+        * Sets an optional client token. This client token is mentioned in progress
+        * and other request-related messages and can be used to identify this
+        * request.
+        * 
+        * @param clientToken
+        *            The client token
+        */
+       public void setClientToken(String clientToken) {
+               setField("ClientToken", clientToken);
+       }
+
+       /**
+        * Sets the persistence of this request.
+        * 
+        * @param persistence
+        *            The persistence of this request
+        */
+       public void setPersistence(Persistence persistence) {
+               setField("Persistence", String.valueOf(persistence));
+       }
+
+       /**
+        * Sets the target filename of the inserted file. This value is ignored for
+        * all inserts that do not have “CHK@” as a target.
+        * 
+        * @param targetFilename
+        *            The filename of the target
+        */
+       public void setTargetFilename(String targetFilename) {
+               setField("TargetFilename", targetFilename);
+       }
+
+       /**
+        * Determines whether to encode the complete file early in the life of the
+        * request.
+        * 
+        * @param earlyEncode
+        *            <code>true</code> to generate the final key long before the
+        *            file is completely fetchable
+        */
+       public void setEarlyEncode(boolean earlyEncode) {
+               setField("EarlyEncode", String.valueOf(earlyEncode));
+       }
+
+       /**
+        * Sets the length of the data that will be transferred after this message
+        * if <code>uploadFrom</code> is {@link UploadFrom#direct} is used.
+        * 
+        * @param dataLength
+        *            The length of the data
+        */
+       public void setDataLength(long dataLength) {
+               setField("DataLength", String.valueOf(dataLength));
+       }
+
+       /**
+        * Sets the name of the file to upload the data from.
+        * 
+        * @param filename
+        *            The filename to upload
+        */
+       public void setFilename(String filename) {
+               setField("Filename", filename);
+       }
+
+       /**
+        * If <code>uploadFrom</code> is {@link UploadFrom#redirect}, use this
+        * method to determine that target of the redirect.
+        * 
+        * @param targetURI
+        *            The target URI to redirect to
+        */
+       public void setTargetURI(String targetURI) {
+               setField("TargetURI", targetURI);
+       }
+
+}
index 6ec19e3..a1bec35 100644 (file)
@@ -104,6 +104,14 @@ public class FcpAdapter implements FcpListener {
        }
 
        /**
+        * @see net.pterodactylus.util.fcp.FcpListener#receivedPersistentPut(net.pterodactylus.util.fcp.FcpConnection,
+        *      net.pterodactylus.util.fcp.PersistentPut)
+        */
+       public void receivedPersistentPut(FcpConnection fcpConnection, PersistentPut persistentPut) {
+               /* empty. */
+       }
+
+       /**
         * @see net.pterodactylus.util.fcp.FcpListener#receivedProtocolError(net.pterodactylus.util.fcp.FcpConnection,
         *      net.pterodactylus.util.fcp.ProtocolError)
         */
index dabb542..157093a 100644 (file)
@@ -261,6 +261,7 @@ public class FcpConnection {
        /**
         * Notifies all listeners that a “TestDDAReply” message was received.
         * 
+        * @see FcpListener#receivedTestDDAReply(FcpConnection, TestDDAReply)
         * @param testDDAReply
         *            The “TestDDAReply” message
         */
@@ -273,6 +274,7 @@ public class FcpConnection {
        /**
         * Notifies all listeners that a “TestDDAComplete” message was received.
         * 
+        * @see FcpListener#receivedTestDDAComplete(FcpConnection, TestDDAComplete)
         * @param testDDAComplete
         *            The “TestDDAComplete” message
         */
@@ -283,6 +285,19 @@ public class FcpConnection {
        }
 
        /**
+        * Notifies all listeners that a “PersistentPut” message was received.
+        * 
+        * @see FcpListener#receivedPersistentPut(FcpConnection, PersistentPut)
+        * @param persistentPut
+        *            The “PersistentPut” message
+        */
+       private void fireReceivedPersistentPut(PersistentPut persistentPut) {
+               for (FcpListener fcpListener: fcpListeners) {
+                       fcpListener.receivedPersistentPut(this, persistentPut);
+               }
+       }
+
+       /**
         * Notifies all listeners that a “ProtocolError” message was received.
         * 
         * @param protocolError
@@ -370,6 +385,8 @@ public class FcpConnection {
                String messageName = fcpMessage.getName();
                if ("ProtocolError".equals(messageName)) {
                        fireReceivedProtocolError(new ProtocolError(fcpMessage));
+               } else if ("PersistentPut".equals(messageName)) {
+                       fireReceivedPersistentPut(new PersistentPut(fcpMessage));
                } else if ("Peer".equals(messageName)) {
                        fireReceivedPeer(new Peer(fcpMessage));
                } else if ("PeerNote".equals(messageName)) {
index f17cdd3..928cdc9 100644 (file)
@@ -141,6 +141,16 @@ public interface FcpListener extends EventListener {
        public void receivedTestDDAComplete(FcpConnection fcpConnection, TestDDAComplete testDDAComplete);
 
        /**
+        * Notifies a listener that a “PersistentPut” was received.
+        * 
+        * @param fcpConnection
+        *            The connection that received the message
+        * @param persistentPut
+        *            The “PersistentPut” message
+        */
+       public void receivedPersistentPut(FcpConnection fcpConnection, PersistentPut persistentPut);
+
+       /**
         * Notifies a listener that a “ProtocolError” was received.
         * 
         * @param fcpConnection
diff --git a/src/net/pterodactylus/util/fcp/Persistence.java b/src/net/pterodactylus/util/fcp/Persistence.java
new file mode 100644 (file)
index 0000000..5266ca2
--- /dev/null
@@ -0,0 +1,29 @@
+/**
+ * © 2008 INA Service GmbH
+ */
+package net.pterodactylus.util.fcp;
+
+/**
+ * Convenience class for persistence values.
+ * 
+ * @author <a href="mailto:dr@ina-germany.de">David Roden</a>
+ * @version $Id$
+ */
+public enum Persistence {
+
+       /**
+        * Connection persistence. A request with this persistence will die as soon
+        * as the connection goes down.
+        */
+       connection,
+
+       /**
+        * Reboot persistence. A request with this persistence will live until the
+        * node is restarted.
+        */
+       reboot,
+
+       /** Forever persistence. A request with this persistence will live forever. */
+       forever;
+
+}
diff --git a/src/net/pterodactylus/util/fcp/PersistentPut.java b/src/net/pterodactylus/util/fcp/PersistentPut.java
new file mode 100644 (file)
index 0000000..4c7eb36
--- /dev/null
@@ -0,0 +1,162 @@
+/**
+ * © 2008 INA Service GmbH
+ */
+package net.pterodactylus.util.fcp;
+
+/**
+ * A “PersistentPut” message notifies a client about a persistent
+ * {@link ClientPut} request.
+ * 
+ * @author <a href="mailto:dr@ina-germany.de">David Roden</a>
+ * @version $Id$
+ */
+public class PersistentPut extends BaseMessage {
+
+       /**
+        * Creates a new “PersistentPut” message that wraps the received message.
+        * 
+        * @param receivedMessage
+        *            The received message
+        */
+       public PersistentPut(FcpMessage receivedMessage) {
+               super(receivedMessage);
+       }
+
+       /**
+        * Returns the client token of the request.
+        * 
+        * @return The client token of the request
+        */
+       public String getClientToken() {
+               return getField("ClientToken");
+       }
+
+       /**
+        * Returns the data length of the request.
+        * 
+        * @return The data length of the request, or <code>-1</code> if the
+        *         length could not be parsed
+        */
+       public long getDataLength() {
+               try {
+                       return Long.valueOf(getField("DataLength"));
+               } catch (NumberFormatException nfe1) {
+                       return -1;
+               }
+       }
+
+       /**
+        * Returns whether the request is on the global queue.
+        * 
+        * @return <code>true</code> if the request is on the global queue,
+        *         <code>false</code> otherwise
+        */
+       public boolean isGlobal() {
+               return Boolean.valueOf(getField("Global"));
+       }
+
+       /**
+        * Returns the identifier of the request.
+        * 
+        * @return The identifier of the request
+        */
+       public String getIdentifier() {
+               return getField("Identifier");
+       }
+
+       /**
+        * Returns the maximum number of retries for failed blocks. When
+        * <code>-1</code> is returned each block is tried forever.
+        * 
+        * @return The maximum number of retries for failed blocks, or
+        *         <code>-1</code> for unlimited retries, or <code>-2</code> if
+        *         the number of retries could not be parsed
+        */
+       public int getMaxRetries() {
+               try {
+                       return Integer.valueOf(getField("MaxRetries"));
+               } catch (NumberFormatException nfe1) {
+                       /* we need to return -2 here as -1 is also a valid value. */
+                       return -2;
+               }
+       }
+
+       /**
+        * Returns the content type of the data.
+        * 
+        * @return The content type
+        */
+       public String getMetadataContentType() {
+               return getField("Metadata.ContentType");
+       }
+
+       /**
+        * Returns the persistence of the request.
+        * 
+        * @return The persistence of the request
+        */
+       public Persistence getPersistence() {
+               return Persistence.valueOf(getField("Persistence"));
+       }
+
+       /**
+        * Returns the priority of the request.
+        * 
+        * @return The priority of the request, or {@link Priority#unknown} if the
+        *         priority could not be parsed
+        */
+       public Priority getPriority() {
+               try {
+                       return Priority.values()[Integer.valueOf(getField("Priority"))];
+               } catch (NumberFormatException nfe1) {
+                       return Priority.unknown;
+               }
+       }
+
+       /**
+        * Returns whether this request has started.
+        * 
+        * @return <code>true</code> if the request has started,
+        *         <code>false</code> otherwise
+        */
+       public boolean isStarted() {
+               return Boolean.valueOf(getField("Started"));
+       }
+
+       /**
+        * Returns the target filename of the request.
+        * 
+        * @return The target filename of the request
+        */
+       public String getTargetFilename() {
+               return getField("TargetFilename");
+       }
+
+       /**
+        * Returns the upload source of the request.
+        * 
+        * @return The upload source of the request
+        */
+       public UploadFrom getUploadFrom() {
+               return UploadFrom.valueOf(getField("UploadFrom"));
+       }
+
+       /**
+        * Returns the target URI of the request.
+        * 
+        * @return The target URI of the request
+        */
+       public String getURI() {
+               return getField("URI");
+       }
+
+       /**
+        * Returns the verbosity of the request.
+        * 
+        * @return The verbosity of the request
+        */
+       public Verbosity getVerbosity() {
+               return Verbosity.valueOf(getField("Verbosity"));
+       }
+
+}
diff --git a/src/net/pterodactylus/util/fcp/Priority.java b/src/net/pterodactylus/util/fcp/Priority.java
new file mode 100644 (file)
index 0000000..9e6a2ec
--- /dev/null
@@ -0,0 +1,46 @@
+/**
+ * © 2008 INA Service GmbH
+ */
+package net.pterodactylus.util.fcp;
+
+/**
+ * The priority classes used by the Freenet node.
+ * 
+ * @author <a href="mailto:dr@ina-germany.de">David Roden</a>
+ * @version $Id$
+ */
+public enum Priority {
+
+       /** Maximum priority. */
+       maximum,
+
+       /** Priority for interactive request, i.e. FProxy. */
+       interactive,
+
+       /** Priority for splitfile manifests. */
+       immediateSplitfile,
+
+       /** Priority for USK searches. */
+       update,
+
+       /** Priority for splitfile blocks. */
+       bulkSplitfile,
+
+       /** Priority for prefetching blocks. */
+       prefetch,
+
+       /** Minimum priority. */
+       minimum,
+
+       /** Unknown priority. */
+       unknown;
+
+       /**
+        * @see java.lang.Enum#toString()
+        */
+       @Override
+       public String toString() {
+               return String.valueOf(ordinal());
+       }
+
+}
diff --git a/src/net/pterodactylus/util/fcp/UploadFrom.java b/src/net/pterodactylus/util/fcp/UploadFrom.java
new file mode 100644 (file)
index 0000000..81736d5
--- /dev/null
@@ -0,0 +1,24 @@
+/**
+ * © 2008 INA Service GmbH
+ */
+package net.pterodactylus.util.fcp;
+
+/**
+ * Enumeration for the different values for the “UploadFrom” field in
+ * {@link ClientPut} and {@link ClientGet} requests.
+ * 
+ * @author <a href="mailto:dr@ina-germany.de">David Roden</a>
+ * @version $Id$
+ */
+public enum UploadFrom {
+
+       /** Request data follows the request. */
+       direct,
+
+       /** Request data is written to or read from disk. */
+       disk,
+
+       /** Request data is just a redirect. */
+       redirect;
+
+}
diff --git a/src/net/pterodactylus/util/fcp/Verbosity.java b/src/net/pterodactylus/util/fcp/Verbosity.java
new file mode 100644 (file)
index 0000000..831a8cd
--- /dev/null
@@ -0,0 +1,89 @@
+/**
+ * © 2008 INA Service GmbH
+ */
+package net.pterodactylus.util.fcp;
+
+/**
+ * Convenicence class for verbosity handling. This might come in handy with the
+ * {@link ClientPut} and {@link ClientGet} requests.
+ * 
+ * The verbosity is a bit-mask that can be composed of several bits.
+ * {@link #PROGRESS} and {@link #COMPRESSION} are single bits in that mask and
+ * can be combined into a new verbosity using {@link #add(Verbosity)}.
+ * 
+ * @author <a href="mailto:dr@ina-germany.de">David Roden</a>
+ * @version $Id$
+ */
+public class Verbosity {
+
+       /** Constant for no verbosity at all. */
+       public static final Verbosity NONE = new Verbosity(0);
+
+       /** Constant for progress message verbosity. */
+       public static final Verbosity PROGRESS = new Verbosity(1);
+
+       /** Constant for compression message verbosity. */
+       public static final Verbosity COMPRESSION = new Verbosity(512);
+
+       /** The verbosity level. */
+       private final int level;
+
+       /**
+        * Creates a new verbosity with the given level.
+        * 
+        * @param level
+        *            The verbosity level
+        */
+       private Verbosity(int level) {
+               this.level = level;
+       }
+
+       /**
+        * Adds the given verbosity to this verbosity and returns a verbosity with
+        * the new value. The value of this verbosity is not changed.
+        * 
+        * @param verbosity
+        *            The verbosity to add to this verbosity
+        * @return The verbosity with the new level.
+        */
+       public Verbosity add(Verbosity verbosity) {
+               return new Verbosity(level | verbosity.level);
+       }
+
+       /**
+        * Checks whether this Verbosity contains all bits of the given Verbosity.
+        * 
+        * @param verbosity
+        *            The verbosity to check for in this Verbosity
+        * @return <code>true</code> if and only if all set bits in the given
+        *         Verbosity are also set in this Verbosity
+        */
+       public boolean contains(Verbosity verbosity) {
+               return (level & verbosity.level) == verbosity.level;
+       }
+
+       /**
+        * @see java.lang.Object#toString()
+        */
+       @Override
+       public String toString() {
+               return String.valueOf(level);
+       }
+
+       /**
+        * Parses the given string and creates a Verbosity with the given level.
+        * 
+        * @param s
+        *            The string to parse
+        * @return The parsed verbosity, or {@link #NONE} if the string could not be
+        *         parsed
+        */
+       public static Verbosity valueOf(String s) {
+               try {
+                       return new Verbosity(Integer.valueOf(s));
+               } catch (NumberFormatException nfe1) {
+                       return NONE;
+               }
+       }
+
+}