diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/client/BdfMessageValidator.java b/bramble-api/src/main/java/org/briarproject/bramble/api/client/BdfMessageValidator.java index 468c64126..8688aeea9 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/client/BdfMessageValidator.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/client/BdfMessageValidator.java @@ -31,6 +31,12 @@ public abstract class BdfMessageValidator implements MessageValidator { protected final Clock clock; protected final boolean canonical; + /** + * Transitional alternative to + * {@link #BdfMessageValidator(ClientHelper, MetadataEncoder, Clock)} that + * accepts messages in non-canonical form, for backward compatibility. + */ + @Deprecated protected BdfMessageValidator(ClientHelper clientHelper, MetadataEncoder metadataEncoder, Clock clock, boolean canonical) { this.clientHelper = clientHelper; diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/client/ClientHelper.java b/bramble-api/src/main/java/org/briarproject/bramble/api/client/ClientHelper.java index ff8ee773c..423fa37ba 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/client/ClientHelper.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/client/ClientHelper.java @@ -49,6 +49,15 @@ public interface ClientHelper { BdfList getMessageAsList(Transaction txn, MessageId m) throws DbException, FormatException; + /** + * Transitional alternative to + * {@link #getMessageAsList(Transaction, MessageId)} that allows the + * message to be in non-canonical form, for backward compatibility. + * + * @param canonical True if the message must be in canonical form (a + * {@link FormatException} will be thrown if it's not. + */ + @Deprecated BdfList getMessageAsList(Transaction txn, MessageId m, boolean canonical) throws DbException, FormatException; @@ -109,6 +118,14 @@ public interface ClientHelper { BdfList toList(Message m) throws FormatException; + /** + * Transitional alternative to {@link #toList(Message)} that allows the + * message to be in non-canonical form, for backward compatibility. + * + * @param canonical True if the message must be in canonical form (a + * {@link FormatException} will be thrown if it's not. + */ + @Deprecated BdfList toList(Message m, boolean canonical) throws FormatException; BdfList toList(Author a); diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/data/BdfDictionary.java b/bramble-api/src/main/java/org/briarproject/bramble/api/data/BdfDictionary.java index 11d6f8a08..2124cd14e 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/data/BdfDictionary.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/data/BdfDictionary.java @@ -10,6 +10,27 @@ import java.util.TreeMap; import javax.annotation.Nullable; import javax.annotation.concurrent.NotThreadSafe; +/** + * A BDF dictionary contains zero or more key-value pairs, where the keys + * are strings and the values are BDF objects, which may be primitive types + * (null, boolean, integer, float, string, raw) or nested containers (list, + * dictionary). + *

+ * Note that a BDF integer has the same range as a Java long, while a BDF + * float has the same range as a Java double. Method names in this class + * correspond to the Java types. + *

+ * The getX() methods throw {@link FormatException} if the specified key is + * absent, the value is null, or the value does not have the requested type. + *

+ * The getOptionalX() methods return null if the specified key is absent or + * the value is null, or throw {@link FormatException} if the value does not + * have the requested type. + *

+ * The getX() methods that take a default value return the default value if + * the specified key is absent or the value is null, or throw + * {@link FormatException} if the value does not have the requested type. + */ @NotThreadSafe public final class BdfDictionary extends TreeMap { @@ -80,12 +101,33 @@ public final class BdfDictionary extends TreeMap { return value == null ? defaultValue : value; } + /** + * Returns the integer with the specified key. + *

+ * This method should be used in preference to + * getLong(key).intValue() as it checks for + * overflow/underflow. + * + * @throws FormatException if there is no value at the specified key, + * or if the value is null or cannot be represented as a Java int. + */ public Integer getInt(String key) throws FormatException { Integer value = getOptionalInt(key); if (value == null) throw new FormatException(); return value; } + /** + * Returns the integer with the specified key, or null if the key is + * absent or the value is null. + *

+ * This method should be used in preference to + * getOptionalLong(key).intValue() as it checks for + * overflow/underflow. + * + * @throws FormatException if the value at the specified key is not null + * and cannot be represented as a Java int. + */ @Nullable public Integer getOptionalInt(String key) throws FormatException { Long value = getOptionalLong(key); @@ -96,6 +138,17 @@ public final class BdfDictionary extends TreeMap { return value.intValue(); } + /** + * Returns the integer with the specified key, or the given default + * value if the key is absent or the value is null. + *

+ * This method should be used in preference to + * getLong(key, defaultValue).intValue() as it checks for + * overflow/underflow. + * + * @throws FormatException if the value at the specified key is not null + * and cannot be represented as a Java int. + */ public Integer getInt(String key, Integer defaultValue) throws FormatException { Integer value = getOptionalInt(key); diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/data/BdfEntry.java b/bramble-api/src/main/java/org/briarproject/bramble/api/data/BdfEntry.java index 3fb4b2678..42b52fc2e 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/data/BdfEntry.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/data/BdfEntry.java @@ -6,6 +6,11 @@ import java.util.Map.Entry; import javax.annotation.concurrent.Immutable; +/** + * A convenience class for building {@link BdfDictionary BdfDictionaries} + * via the {@link BdfDictionary#of(Entry[]) factory method}. Entries in + * BdfDictionaries do not have to be BdfEntries. + */ @Immutable @NotNullByDefault public class BdfEntry implements Entry, Comparable { diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/data/BdfList.java b/bramble-api/src/main/java/org/briarproject/bramble/api/data/BdfList.java index 6ba6747cc..bce11b079 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/data/BdfList.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/data/BdfList.java @@ -12,6 +12,29 @@ import javax.annotation.concurrent.NotThreadSafe; import static org.briarproject.bramble.api.data.BdfDictionary.NULL_VALUE; +/** + * A BDF list contains zero or more BDF objects, which may be primitive types + * (null, boolean, integer, float, string, raw) or nested containers (list, + * dictionary). + *

+ * Note that a BDF integer has the same range as a Java long, while a BDF + * float has the same range as a Java double. Method names in this class + * correspond to the Java types. + *

+ * The getX() methods throw {@link FormatException} if the object at the + * specified index is null or does not have the requested type. + *

+ * The getOptionalX() methods return null if the object at the specified + * index is null, or throw {@link FormatException} if the object does not + * have the requested type. + *

+ * The getX() methods that take a default value return the default value if + * the object at the specified index is null, or throw + * {@link FormatException} if the object does not have the requested type. + *

+ * All of the getters throw {@link FormatException} if the specified index is + * out of range. + */ @NotThreadSafe public final class BdfList extends ArrayList { @@ -82,12 +105,34 @@ public final class BdfList extends ArrayList { return value == null ? defaultValue : value; } + /** + * Returns the integer at the specified index. + *

+ * This method should be used in preference to + * getLong(index).intValue() as it checks for + * overflow/underflow. + * + * @throws FormatException if the index is out of range, or if the + * value at the specified index is null or cannot be represented as a + * Java int. + */ public Integer getInt(int index) throws FormatException { Integer value = getOptionalInt(index); if (value == null) throw new FormatException(); return value; } + /** + * Returns the integer at the specified index, or null if the object at + * the specified index is null. + *

+ * This method should be used in preference to + * getOptionalLong(index).intValue() as it checks for + * overflow/underflow. + * + * @throws FormatException if the index is out of range, or if the value + * at the specified index cannot be represented as a Java int. + */ @Nullable public Integer getOptionalInt(int index) throws FormatException { Long value = getOptionalLong(index); @@ -98,6 +143,17 @@ public final class BdfList extends ArrayList { return value.intValue(); } + /** + * Returns the integer at the specified index, or the given default value + * if the object at the specified index is null. + *

+ * This method should be used in preference to + * getLong(index, defaultValue).intValue() as it checks for + * overflow/underflow. + * + * @throws FormatException if the index is out of range, or if the value + * at the specified index cannot be represented as a Java int. + */ public Integer getInt(int index, Integer defaultValue) throws FormatException { Integer value = getOptionalInt(index); diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/data/BdfReader.java b/bramble-api/src/main/java/org/briarproject/bramble/api/data/BdfReader.java index fe710becd..f134d2614 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/data/BdfReader.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/data/BdfReader.java @@ -1,70 +1,178 @@ package org.briarproject.bramble.api.data; +import org.briarproject.bramble.api.FormatException; import org.briarproject.nullsafety.NotNullByDefault; import java.io.IOException; +/** + * An interface for reading BDF objects from an input stream. + *

+ * The readX() methods throw {@link FormatException} if the data is not in + * canonical form, but the hasX() and skipX() methods do not check for + * canonical form. + */ @NotNullByDefault public interface BdfReader { int DEFAULT_NESTED_LIMIT = 5; int DEFAULT_MAX_BUFFER_SIZE = 64 * 1024; + /** + * Returns true if the reader has reached the end of its input stream. + */ boolean eof() throws IOException; + /** + * Closes the reader's input stream. + */ void close() throws IOException; + /** + * Returns true if the next object in the input is a BDF null. + */ boolean hasNull() throws IOException; + /** + * Reads a BDF null from the input. + */ void readNull() throws IOException; + /** + * Skips over a BDF null. + */ void skipNull() throws IOException; + /** + * Returns true if the next object in the input is a BDF boolean. + */ boolean hasBoolean() throws IOException; + /** + * Reads a BDF boolean from the input and returns it. + */ boolean readBoolean() throws IOException; + /** + * Skips over a BDF boolean. + */ void skipBoolean() throws IOException; + /** + * Returns true if the next object in the input is a BDF integer, which + * has the same range as a Java long. + */ boolean hasLong() throws IOException; + /** + * Reads a BDF integer from the input and returns it as a Java long. + */ long readLong() throws IOException; + /** + * Skips over a BDF integer. + */ void skipLong() throws IOException; + /** + * Returns true if the next object in the input is a BDF integer and the + * value would fit within the range of a Java int. + */ boolean hasInt() throws IOException; + /** + * Reads a BDF integer from the input and returns it as a Java int. + * + * @throws FormatException if the value exceeds the range of a Java int. + */ int readInt() throws IOException; + /** + * Skips over a BDF integer. + * + * @throws FormatException if the value exceeds the range of a Java int. + */ void skipInt() throws IOException; + /** + * Returns true if the next object in the input is a BDF float, which has + * the same range as a Java double. + */ boolean hasDouble() throws IOException; + /** + * Reads a BDF float from the input and returns it as a Java double. + */ double readDouble() throws IOException; + /** + * Skips over a BDF float. + */ void skipDouble() throws IOException; + /** + * Returns true if the next object in the input is a BDF string. + */ boolean hasString() throws IOException; + /** + * Reads a BDF string from the input. + * + * @throws IOException If the string is not valid UTF-8. + */ String readString() throws IOException; + /** + * Skips over a BDF string without checking whether it is valid UTF-8. + */ void skipString() throws IOException; + /** + * Returns true if the next object in the input is a BDF raw. + */ boolean hasRaw() throws IOException; + /** + * Reads a BDF raw from the input and returns it as a byte array. + */ byte[] readRaw() throws IOException; + /** + * Skips over a BDF raw. + */ void skipRaw() throws IOException; + /** + * Returns true if the next object in the input is a BDF list. + */ boolean hasList() throws IOException; + /** + * Reads a BDF list from the input and returns it. The list's contents + * are parsed and validated. + */ BdfList readList() throws IOException; + /** + * Skips over a BDF list. The list's contents are parsed (to determine + * their length) but not validated. + */ void skipList() throws IOException; + /** + * Returns true if the next object in the input is a BDF dictionary. + */ boolean hasDictionary() throws IOException; + /** + * Reads a BDF dictionary from the input and returns it. The dictionary's + * contents are parsed and validated. + */ BdfDictionary readDictionary() throws IOException; + /** + * Skips over a BDF dictionary. The dictionary's contents are parsed + * (to determine their length) but not validated. + */ void skipDictionary() throws IOException; } diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/data/BdfReaderFactory.java b/bramble-api/src/main/java/org/briarproject/bramble/api/data/BdfReaderFactory.java index 5ff95dfa1..1a132434d 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/data/BdfReaderFactory.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/data/BdfReaderFactory.java @@ -9,6 +9,12 @@ public interface BdfReaderFactory { BdfReader createReader(InputStream in); + /** + * Transitional alternative to {@link #createReader(InputStream)} that + * can create a reader that accepts non-canonical input, for backward + * compatibility. + */ + @Deprecated BdfReader createReader(InputStream in, boolean canonical); BdfReader createReader(InputStream in, int nestedLimit, diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/data/BdfWriter.java b/bramble-api/src/main/java/org/briarproject/bramble/api/data/BdfWriter.java index 1427859a6..63f3a4357 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/data/BdfWriter.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/data/BdfWriter.java @@ -1,28 +1,74 @@ package org.briarproject.bramble.api.data; +import org.briarproject.bramble.api.FormatException; + import java.io.IOException; import java.util.Collection; import java.util.Map; +/** + * An interface for writing BDF objects to an output stream. The BDF output + * is in canonical form, ie integers and length fields are represented using + * the minimum number of bytes and dictionary keys are unique and sorted in + * lexicographic order. + */ public interface BdfWriter { + /** + * Flushes the writer's output stream. + */ void flush() throws IOException; + /** + * Closes the writer's output stream. + */ void close() throws IOException; + /** + * Writes a BDF null to the output stream. + */ void writeNull() throws IOException; + /** + * Writes a BDF boolean to the output stream. + */ void writeBoolean(boolean b) throws IOException; + /** + * Writes a BDF integer (which has the same range as a Java long) to the + * output stream. + */ void writeLong(long l) throws IOException; + /** + * Writes a BDF float (which has the same range as a Java double) to the + * output stream. + */ void writeDouble(double d) throws IOException; + /** + * Writes a BDF string (which uses UTF-8 encoding) to the output stream. + */ void writeString(String s) throws IOException; + /** + * Writes a BDF raw to the output stream. + */ void writeRaw(byte[] b) throws IOException; + /** + * Writes a BDF list to the output stream. + * + * @throws FormatException if the contents of the given collection cannot + * be represented as (nested) BDF objects. + */ void writeList(Collection c) throws IOException; + /** + * Writes a BDF dictionary to the output stream. + * + * @throws FormatException if the contents of the given map cannot be + * represented as (nested) BDF objects. + */ void writeDictionary(Map m) throws IOException; } diff --git a/bramble-core/src/main/java/org/briarproject/bramble/properties/TransportPropertyManagerImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/properties/TransportPropertyManagerImpl.java index e1641d6e9..229ff1a23 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/properties/TransportPropertyManagerImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/properties/TransportPropertyManagerImpl.java @@ -311,6 +311,7 @@ class TransportPropertyManagerImpl implements TransportPropertyManager, if (latest == null) { merged = new TransportProperties(p); Iterator it = merged.values().iterator(); + //noinspection Java8CollectionRemoveIf while (it.hasNext()) { if (isNullOrEmpty(it.next())) it.remove(); }