--- /dev/null
+/**
+ * © 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);
+ }
+
+}
}
/**
+ * @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)
*/
/**
* Notifies all listeners that a “TestDDAReply” message was received.
*
+ * @see FcpListener#receivedTestDDAReply(FcpConnection, TestDDAReply)
* @param testDDAReply
* The “TestDDAReply” message
*/
/**
* Notifies all listeners that a “TestDDAComplete” message was received.
*
+ * @see FcpListener#receivedTestDDAComplete(FcpConnection, TestDDAComplete)
* @param testDDAComplete
* The “TestDDAComplete” message
*/
}
/**
+ * 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
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)) {
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
--- /dev/null
+/**
+ * © 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;
+
+}
--- /dev/null
+/**
+ * © 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"));
+ }
+
+}
--- /dev/null
+/**
+ * © 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());
+ }
+
+}
--- /dev/null
+/**
+ * © 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;
+
+}
--- /dev/null
+/**
+ * © 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;
+ }
+ }
+
+}