import net.pterodactylus.util.io.StreamCopier;
/**
- * TODO
+ * An FCP message. FCP messages consist of a name, an arbitrary amount of
+ * “fields” (i.e. key-value pairs), a message end marker, and optional payload
+ * data that follows the marker.
*
* @author David ‘Bombe’ Roden <bombe@freenetproject.org>
* @version $Id$
*/
public class FcpMessage implements Iterable<String> {
+ /** Constant for the linefeed. */
private static final String LINEFEED = "\r\n";
+ /** The name of the message. */
private final String name;
+
+ /** The fields of the message. */
private final Map<String, String> fields = new HashMap<String, String>();
- private InputStream dataInputStream;
+ /** The optional payload input stream. */
+ private InputStream payloadInputStream;
+
+ /**
+ * Creates a new FCP message with the given name.
+ *
+ * @param name
+ * The name of the FCP message
+ */
public FcpMessage(String name) {
this(name, null);
}
- public FcpMessage(String name, InputStream dataInputStream) {
+ /**
+ * Creates a new FCP message with the given name and the given payload input
+ * stream. The payload input stream is not read until the message is sent to
+ * the node using {@link FcpConnection#sendMessage(FcpMessage)}.
+ *
+ * @param name
+ * The name of the message
+ * @param payloadInputStream
+ * The payload of the message
+ */
+ public FcpMessage(String name, InputStream payloadInputStream) {
this.name = name;
- this.dataInputStream = dataInputStream;
+ this.payloadInputStream = payloadInputStream;
}
+ /**
+ * Returns the name of the message.
+ *
+ * @return The name of the message
+ */
public String getName() {
return name;
}
+ /**
+ * Sets the field with the given name to the given value. If the field
+ * already exists in this message it is overwritten.
+ *
+ * @param field
+ * The name of the field
+ * @param value
+ * The value of the field
+ */
public void setField(String field, String value) {
if ((field == null) || (value == null)) {
throw new NullPointerException(((field == null) ? "field " : "value ") + "must not be null");
fields.put(field, value);
}
+ /**
+ * Returns the value of the given field.
+ *
+ * @param field
+ * The name of the field
+ * @return The value of the field, or <code>null</code> if there is no
+ * such field
+ */
public String getField(String field) {
return fields.get(field);
}
+ /**
+ * Returns all fields of this message.
+ *
+ * @return All fields of this message
+ */
public Map<String, String> getFields() {
return Collections.unmodifiableMap(fields);
}
return fields.keySet().iterator();
}
- public void setDataInputStream(InputStream dataInputStream) {
- this.dataInputStream = dataInputStream;
+ /**
+ * Sets the payload input stream of the message.
+ *
+ * @param payloadInputStream
+ * The payload input stream
+ */
+ public void setPayloadInputStream(InputStream payloadInputStream) {
+ this.payloadInputStream = payloadInputStream;
}
+ /**
+ * Writes this message to the given output stream. If the message has a
+ * payload (i.e. {@link #payloadInputStream} is not <code>null</code>)
+ * the payload is written to the given output stream after the message as
+ * well. That means that this method can only be called once because on the
+ * second invocation the payload input stream could not be read (again).
+ *
+ * @param outputStream
+ * The output stream to write the message to
+ * @throws IOException
+ * if an I/O error occurs
+ */
public void write(OutputStream outputStream) throws IOException {
writeLine(outputStream, name);
for (Entry<String, String> fieldEntry: fields.entrySet()) {
}
writeLine(outputStream, "EndMessage");
outputStream.flush();
- if (dataInputStream != null) {
- StreamCopier.copy(dataInputStream, outputStream);
+ if (payloadInputStream != null) {
+ StreamCopier.copy(payloadInputStream, outputStream);
}
outputStream.flush();
}
+ //
+ // PRIVATE METHODS
+ //
+
+ /**
+ * Writes the given line (followed by {@link #LINEFEED} to the given output
+ * stream, using UTF-8 as encoding.
+ *
+ * @param outputStream
+ * The output stream to write to
+ * @param line
+ * The line to write
+ * @throws IOException
+ * if an I/O error occurs
+ */
private void writeLine(OutputStream outputStream, String line) throws IOException {
outputStream.write((line + LINEFEED).getBytes("UTF-8"));
}