X-Git-Url: https://git.pterodactylus.net/?a=blobdiff_plain;f=src%2Fnet%2Fpterodactylus%2Futil%2Ffcp%2FFcpMessage.java;h=67828689ed17d9a42a5338e42e247f59115bc68b;hb=ebd531bc775036dd66a7e20abebbcb480af35491;hp=6ff4ec6493225a1017d07d937af00305061b052f;hpb=90f3a1c8e0c85f19c82130e49d7a605cb9e55286;p=jSite2.git diff --git a/src/net/pterodactylus/util/fcp/FcpMessage.java b/src/net/pterodactylus/util/fcp/FcpMessage.java index 6ff4ec6..6782868 100644 --- a/src/net/pterodactylus/util/fcp/FcpMessage.java +++ b/src/net/pterodactylus/util/fcp/FcpMessage.java @@ -31,55 +31,139 @@ import java.util.Map.Entry; 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 { + /** 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 fields = new HashMap(); - 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; } - + + /** + * Checks whether this message has a field with the given name. + * + * @param field + * The name of the field to check for + * @return true if the message has a field with the given + * name, false otherwise + */ + public boolean hasField(String field) { + return fields.containsKey(field); + } + + /** + * 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 null 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 getFields() { return Collections.unmodifiableMap(fields); } - + /** * {@inheritDoc} */ public Iterator iterator() { 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 null) + * 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 fieldEntry: fields.entrySet()) { @@ -87,12 +171,27 @@ public class FcpMessage implements Iterable { } 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")); }