2 * jSite2 - FcpMessage.java -
3 * Copyright © 2008 David Roden
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 package net.pterodactylus.util.fcp;
22 import java.io.IOException;
23 import java.io.InputStream;
24 import java.io.OutputStream;
25 import java.util.Collections;
26 import java.util.HashMap;
27 import java.util.Iterator;
29 import java.util.Map.Entry;
31 import net.pterodactylus.util.io.StreamCopier;
34 * An FCP message. FCP messages consist of a name, an arbitrary amount of
35 * “fields” (i.e. key-value pairs), a message end marker, and optional payload
36 * data that follows the marker.
38 * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
41 public class FcpMessage implements Iterable<String> {
43 /** Constant for the linefeed. */
44 private static final String LINEFEED = "\r\n";
46 /** The name of the message. */
47 private final String name;
49 /** The fields of the message. */
50 private final Map<String, String> fields = new HashMap<String, String>();
52 /** The optional payload input stream. */
53 private InputStream payloadInputStream;
56 * Creates a new FCP message with the given name.
59 * The name of the FCP message
61 public FcpMessage(String name) {
66 * Creates a new FCP message with the given name and the given payload input
67 * stream. The payload input stream is not read until the message is sent to
68 * the node using {@link FcpConnection#sendMessage(FcpMessage)}.
71 * The name of the message
72 * @param payloadInputStream
73 * The payload of the message
75 public FcpMessage(String name, InputStream payloadInputStream) {
77 this.payloadInputStream = payloadInputStream;
81 * Returns the name of the message.
83 * @return The name of the message
85 public String getName() {
90 * Sets the field with the given name to the given value. If the field
91 * already exists in this message it is overwritten.
94 * The name of the field
96 * The value of the field
98 public void setField(String field, String value) {
99 if ((field == null) || (value == null)) {
100 throw new NullPointerException(((field == null) ? "field " : "value ") + "must not be null");
102 fields.put(field, value);
106 * Returns the value of the given field.
109 * The name of the field
110 * @return The value of the field, or <code>null</code> if there is no
113 public String getField(String field) {
114 return fields.get(field);
118 * Returns all fields of this message.
120 * @return All fields of this message
122 public Map<String, String> getFields() {
123 return Collections.unmodifiableMap(fields);
129 public Iterator<String> iterator() {
130 return fields.keySet().iterator();
134 * Sets the payload input stream of the message.
136 * @param payloadInputStream
137 * The payload input stream
139 public void setPayloadInputStream(InputStream payloadInputStream) {
140 this.payloadInputStream = payloadInputStream;
144 * Writes this message to the given output stream. If the message has a
145 * payload (i.e. {@link #payloadInputStream} is not <code>null</code>)
146 * the payload is written to the given output stream after the message as
147 * well. That means that this method can only be called once because on the
148 * second invocation the payload input stream could not be read (again).
150 * @param outputStream
151 * The output stream to write the message to
152 * @throws IOException
153 * if an I/O error occurs
155 public void write(OutputStream outputStream) throws IOException {
156 writeLine(outputStream, name);
157 for (Entry<String, String> fieldEntry: fields.entrySet()) {
158 writeLine(outputStream, fieldEntry.getKey() + "=" + fieldEntry.getValue());
160 writeLine(outputStream, "EndMessage");
161 outputStream.flush();
162 if (payloadInputStream != null) {
163 StreamCopier.copy(payloadInputStream, outputStream);
165 outputStream.flush();
173 * Writes the given line (followed by {@link #LINEFEED} to the given output
174 * stream, using UTF-8 as encoding.
176 * @param outputStream
177 * The output stream to write to
180 * @throws IOException
181 * if an I/O error occurs
183 private void writeLine(OutputStream outputStream, String line) throws IOException {
184 outputStream.write((line + LINEFEED).getBytes("UTF-8"));