Commit 154e95a9 authored by akwizgran's avatar akwizgran
Browse files

Merge branch 'client-helper' into 'master'

Helper class to reduce client boilerplate

* Renamed BdfReader methods for consistency with BdfList/BdfDictionary
* Added readList() and readDictionary() methods to BdfReader
* Added ClientHelper to reduce boilerplate when converting messages and metadata to and from BDF
* Moved PrivateGroupFactory to the same package as ClientHelper


See merge request !114
parents 75d53598 34d34a75
package org.briarproject.api.clients;
import org.briarproject.api.FormatException;
import org.briarproject.api.data.BdfDictionary;
import org.briarproject.api.data.BdfList;
import org.briarproject.api.db.DbException;
import org.briarproject.api.db.Transaction;
import org.briarproject.api.sync.GroupId;
import org.briarproject.api.sync.Message;
import org.briarproject.api.sync.MessageId;
import java.util.Map;
public interface ClientHelper {
Message createMessage(GroupId g, long timestamp, BdfDictionary body)
throws FormatException;
Message createMessage(GroupId g, long timestamp, BdfList body)
throws FormatException;
BdfDictionary getMessageAsDictionary(MessageId m) throws DbException,
FormatException;
BdfDictionary getMessageAsDictionary(Transaction txn, MessageId m)
throws DbException, FormatException;
BdfList getMessageAsList(MessageId m) throws DbException, FormatException;
BdfList getMessageAsList(Transaction txn, MessageId m) throws DbException,
FormatException;
BdfDictionary getGroupMetadataAsDictionary(GroupId g) throws DbException,
FormatException;
BdfDictionary getGroupMetadataAsDictionary(Transaction txn, GroupId g)
throws DbException, FormatException;
BdfDictionary getMessageMetadataAsDictionary(MessageId m) throws DbException,
FormatException;
BdfDictionary getMessageMetadataAsDictionary(Transaction txn, MessageId m)
throws DbException, FormatException;
Map<MessageId, BdfDictionary> getMessageMetatataAsDictionary(GroupId g)
throws DbException, FormatException;
Map<MessageId, BdfDictionary> getMessageMetadataAsDictionary(
Transaction txn, GroupId g) throws DbException, FormatException;
void mergeGroupMetadata(GroupId g, BdfDictionary metadata)
throws DbException, FormatException;
void mergeGroupMetadata(Transaction txn, GroupId g, BdfDictionary metadata)
throws DbException, FormatException;
void mergeMessageMetadata(MessageId m, BdfDictionary metadata)
throws DbException, FormatException;
void mergeMessageMetadata(Transaction txn, MessageId m,
BdfDictionary metadata) throws DbException, FormatException;
}
package org.briarproject.api.sync;
package org.briarproject.api.clients;
import org.briarproject.api.contact.Contact;
import org.briarproject.api.sync.ClientId;
import org.briarproject.api.sync.Group;
public interface PrivateGroupFactory {
......
......@@ -15,13 +15,13 @@ public interface BdfReader {
boolean readBoolean() throws IOException;
void skipBoolean() throws IOException;
boolean hasInteger() throws IOException;
long readInteger() throws IOException;
void skipInteger() throws IOException;
boolean hasLong() throws IOException;
long readLong() throws IOException;
void skipLong() throws IOException;
boolean hasFloat() throws IOException;
double readFloat() throws IOException;
void skipFloat() throws IOException;
boolean hasDouble() throws IOException;
double readDouble() throws IOException;
void skipDouble() throws IOException;
boolean hasString() throws IOException;
String readString(int maxLength) throws IOException;
......@@ -32,12 +32,14 @@ public interface BdfReader {
void skipRaw() throws IOException;
boolean hasList() throws IOException;
BdfList readList() throws IOException;
void readListStart() throws IOException;
boolean hasListEnd() throws IOException;
void readListEnd() throws IOException;
void skipList() throws IOException;
boolean hasDictionary() throws IOException;
BdfDictionary readDictionary() throws IOException;
void readDictionaryStart() throws IOException;
boolean hasDictionaryEnd() throws IOException;
void readDictionaryEnd() throws IOException;
......
......@@ -11,8 +11,8 @@ public interface BdfWriter {
void writeNull() throws IOException;
void writeBoolean(boolean b) throws IOException;
void writeInteger(long l) throws IOException;
void writeFloat(double d) throws IOException;
void writeLong(long l) throws IOException;
void writeDouble(double d) throws IOException;
void writeString(String s) throws IOException;
void writeRaw(byte[] b) throws IOException;
......
package org.briarproject.clients;
import com.google.inject.Inject;
import org.briarproject.api.FormatException;
import org.briarproject.api.clients.ClientHelper;
import org.briarproject.api.data.BdfDictionary;
import org.briarproject.api.data.BdfList;
import org.briarproject.api.data.BdfReader;
import org.briarproject.api.data.BdfReaderFactory;
import org.briarproject.api.data.BdfWriter;
import org.briarproject.api.data.BdfWriterFactory;
import org.briarproject.api.data.MetadataEncoder;
import org.briarproject.api.data.MetadataParser;
import org.briarproject.api.db.DatabaseComponent;
import org.briarproject.api.db.DbException;
import org.briarproject.api.db.Metadata;
import org.briarproject.api.db.Transaction;
import org.briarproject.api.sync.GroupId;
import org.briarproject.api.sync.Message;
import org.briarproject.api.sync.MessageFactory;
import org.briarproject.api.sync.MessageId;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
class ClientHelperImpl implements ClientHelper {
private final DatabaseComponent db;
private final MessageFactory messageFactory;
private final BdfReaderFactory bdfReaderFactory;
private final BdfWriterFactory bdfWriterFactory;
private final MetadataParser metadataParser;
private final MetadataEncoder metadataEncoder;
@Inject
ClientHelperImpl(DatabaseComponent db, MessageFactory messageFactory,
BdfReaderFactory bdfReaderFactory,
BdfWriterFactory bdfWriterFactory, MetadataParser metadataParser,
MetadataEncoder metadataEncoder) {
this.db = db;
this.messageFactory = messageFactory;
this.bdfReaderFactory = bdfReaderFactory;
this.bdfWriterFactory = bdfWriterFactory;
this.metadataParser = metadataParser;
this.metadataEncoder = metadataEncoder;
}
@Override
public Message createMessage(GroupId g, long timestamp, BdfDictionary body)
throws FormatException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
BdfWriter writer = bdfWriterFactory.createWriter(out);
try {
writer.writeDictionary(body);
} catch (FormatException e) {
throw e;
} catch (IOException e) {
// Shouldn't happen with ByteArrayOutputStream
throw new RuntimeException(e);
}
byte[] raw = out.toByteArray();
return messageFactory.createMessage(g, timestamp, raw);
}
@Override
public Message createMessage(GroupId g, long timestamp, BdfList body)
throws FormatException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
BdfWriter writer = bdfWriterFactory.createWriter(out);
try {
writer.writeList(body);
} catch (FormatException e) {
throw e;
} catch (IOException e) {
// Shouldn't happen with ByteArrayOutputStream
throw new RuntimeException(e);
}
byte[] raw = out.toByteArray();
return messageFactory.createMessage(g, timestamp, raw);
}
@Override
public BdfDictionary getMessageAsDictionary(MessageId m) throws DbException,
FormatException {
BdfDictionary dictionary;
Transaction txn = db.startTransaction();
try {
dictionary = getMessageAsDictionary(txn, m);
txn.setComplete();
} finally {
db.endTransaction(txn);
}
return dictionary;
}
@Override
public BdfDictionary getMessageAsDictionary(Transaction txn, MessageId m)
throws DbException, FormatException {
byte[] raw = db.getRawMessage(txn, m);
if (raw == null) return null;
ByteArrayInputStream in = new ByteArrayInputStream(raw);
BdfReader reader = bdfReaderFactory.createReader(in);
BdfDictionary dictionary;
try {
dictionary = reader.readDictionary();
if (!reader.eof()) throw new FormatException();
} catch (FormatException e) {
throw e;
} catch (IOException e) {
// Shouldn't happen with ByteArrayInputStream
throw new RuntimeException(e);
}
return dictionary;
}
@Override
public BdfList getMessageAsList(MessageId m) throws DbException,
FormatException {
BdfList list;
Transaction txn = db.startTransaction();
try {
list = getMessageAsList(txn, m);
txn.setComplete();
} finally {
db.endTransaction(txn);
}
return list;
}
@Override
public BdfList getMessageAsList(Transaction txn, MessageId m)
throws DbException, FormatException {
byte[] raw = db.getRawMessage(txn, m);
if (raw == null) return null;
ByteArrayInputStream in = new ByteArrayInputStream(raw);
BdfReader reader = bdfReaderFactory.createReader(in);
BdfList list;
try {
list = reader.readList();
if (!reader.eof()) throw new FormatException();
} catch (FormatException e) {
throw e;
} catch (IOException e) {
// Shouldn't happen with ByteArrayInputStream
throw new RuntimeException(e);
}
return list;
}
@Override
public BdfDictionary getGroupMetadataAsDictionary(GroupId g)
throws DbException, FormatException {
BdfDictionary dictionary;
Transaction txn = db.startTransaction();
try {
dictionary = getGroupMetadataAsDictionary(txn, g);
txn.setComplete();
} finally {
db.endTransaction(txn);
}
return dictionary;
}
@Override
public BdfDictionary getGroupMetadataAsDictionary(Transaction txn,
GroupId g) throws DbException, FormatException {
Metadata metadata = db.getGroupMetadata(txn, g);
return metadataParser.parse(metadata);
}
@Override
public BdfDictionary getMessageMetadataAsDictionary(MessageId m)
throws DbException, FormatException {
BdfDictionary dictionary;
Transaction txn = db.startTransaction();
try {
dictionary = getMessageMetadataAsDictionary(txn, m);
txn.setComplete();
} finally {
db.endTransaction(txn);
}
return dictionary;
}
@Override
public BdfDictionary getMessageMetadataAsDictionary(Transaction txn,
MessageId m) throws DbException, FormatException {
Metadata metadata = db.getMessageMetadata(txn, m);
return metadataParser.parse(metadata);
}
@Override
public Map<MessageId, BdfDictionary> getMessageMetatataAsDictionary(
GroupId g) throws DbException, FormatException {
Map<MessageId, BdfDictionary> map;
Transaction txn = db.startTransaction();
try {
map = getMessageMetadataAsDictionary(txn, g);
txn.setComplete();
} finally {
db.endTransaction(txn);
}
return map;
}
@Override
public Map<MessageId, BdfDictionary> getMessageMetadataAsDictionary(
Transaction txn, GroupId g) throws DbException, FormatException {
Map<MessageId, Metadata> raw = db.getMessageMetadata(txn, g);
Map<MessageId, BdfDictionary> parsed =
new HashMap<MessageId, BdfDictionary>(raw.size());
for (Entry<MessageId, Metadata> e : raw.entrySet())
parsed.put(e.getKey(), metadataParser.parse(e.getValue()));
return Collections.unmodifiableMap(parsed);
}
@Override
public void mergeGroupMetadata(GroupId g, BdfDictionary metadata)
throws DbException, FormatException {
Transaction txn = db.startTransaction();
try {
mergeGroupMetadata(txn, g, metadata);
txn.setComplete();
} finally {
db.endTransaction(txn);
}
}
@Override
public void mergeGroupMetadata(Transaction txn, GroupId g,
BdfDictionary metadata) throws DbException, FormatException {
db.mergeGroupMetadata(txn, g, metadataEncoder.encode(metadata));
}
@Override
public void mergeMessageMetadata(MessageId m, BdfDictionary metadata)
throws DbException, FormatException {
Transaction txn = db.startTransaction();
try {
mergeMessageMetadata(txn, m, metadata);
txn.setComplete();
} finally {
db.endTransaction(txn);
}
}
@Override
public void mergeMessageMetadata(Transaction txn, MessageId m,
BdfDictionary metadata) throws DbException, FormatException {
db.mergeMessageMetadata(txn, m, metadataEncoder.encode(metadata));
}
}
package org.briarproject.clients;
import com.google.inject.AbstractModule;
import org.briarproject.api.clients.ClientHelper;
import org.briarproject.api.clients.PrivateGroupFactory;
public class ClientsModule extends AbstractModule {
@Override
protected void configure() {
bind(ClientHelper.class).to(ClientHelperImpl.class);
bind(PrivateGroupFactory.class).to(PrivateGroupFactoryImpl.class);
}
}
package org.briarproject.sync;
package org.briarproject.clients;
import com.google.inject.Inject;
import org.briarproject.api.Bytes;
import org.briarproject.api.clients.PrivateGroupFactory;
import org.briarproject.api.contact.Contact;
import org.briarproject.api.data.BdfWriter;
import org.briarproject.api.data.BdfWriterFactory;
......@@ -10,7 +11,6 @@ import org.briarproject.api.identity.AuthorId;
import org.briarproject.api.sync.ClientId;
import org.briarproject.api.sync.Group;
import org.briarproject.api.sync.GroupFactory;
import org.briarproject.api.sync.PrivateGroupFactory;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
......
package org.briarproject.data;
import org.briarproject.api.FormatException;
import org.briarproject.api.data.BdfDictionary;
import org.briarproject.api.data.BdfList;
import org.briarproject.api.data.BdfReader;
import java.io.IOException;
import java.io.InputStream;
import static org.briarproject.api.data.BdfDictionary.NULL_VALUE;
import static org.briarproject.data.Types.DICTIONARY;
import static org.briarproject.data.Types.END;
import static org.briarproject.data.Types.FALSE;
......@@ -74,11 +77,26 @@ class BdfReaderImpl implements BdfReader {
}
}
private Object readObject() throws IOException {
if (hasNull()) {
readNull();
return NULL_VALUE;
}
if (hasBoolean()) return readBoolean();
if (hasLong()) return readLong();
if (hasDouble()) return readDouble();
if (hasString()) return readString(Integer.MAX_VALUE);
if (hasRaw()) return readRaw(Integer.MAX_VALUE);
if (hasList()) return readList();
if (hasDictionary()) return readDictionary();
throw new FormatException();
}
private void skipObject() throws IOException {
if (hasNull()) skipNull();
else if (hasBoolean()) skipBoolean();
else if (hasInteger()) skipInteger();
else if (hasFloat()) skipFloat();
else if (hasLong()) skipLong();
else if (hasDouble()) skipDouble();
else if (hasString()) skipString();
else if (hasRaw()) skipRaw();
else if (hasList()) skipList();
......@@ -129,15 +147,15 @@ class BdfReaderImpl implements BdfReader {
hasLookahead = false;
}
public boolean hasInteger() throws IOException {
public boolean hasLong() throws IOException {
if (!hasLookahead) readLookahead();
if (eof) return false;
return next == INT_8 || next == INT_16 || next == INT_32 ||
next == INT_64;
}
public long readInteger() throws IOException {
if (!hasInteger()) throw new FormatException();
public long readLong() throws IOException {
if (!hasLong()) throw new FormatException();
hasLookahead = false;
if (next == INT_8) return readInt8();
if (next == INT_16) return readInt16();
......@@ -169,8 +187,8 @@ class BdfReaderImpl implements BdfReader {
return value;
}
public void skipInteger() throws IOException {
if (!hasInteger()) throw new FormatException();
public void skipLong() throws IOException {
if (!hasLong()) throw new FormatException();
if (next == INT_8) skip(1);
else if (next == INT_16) skip(2);
else if (next == INT_32) skip(4);
......@@ -178,14 +196,14 @@ class BdfReaderImpl implements BdfReader {
hasLookahead = false;
}
public boolean hasFloat() throws IOException {
public boolean hasDouble() throws IOException {
if (!hasLookahead) readLookahead();
if (eof) return false;
return next == FLOAT_64;
}
public double readFloat() throws IOException {
if (!hasFloat()) throw new FormatException();
public double readDouble() throws IOException {
if (!hasDouble()) throw new FormatException();
hasLookahead = false;
readIntoBuffer(8);
long value = 0;
......@@ -193,8 +211,8 @@ class BdfReaderImpl implements BdfReader {
return Double.longBitsToDouble(value);
}
public void skipFloat() throws IOException {
if (!hasFloat()) throw new FormatException();
public void skipDouble() throws IOException {
if (!hasDouble()) throw new FormatException();
skip(8);
hasLookahead = false;
}
......@@ -268,6 +286,15 @@ class BdfReaderImpl implements BdfReader {
return next == LIST;
}
public BdfList readList() throws IOException {
if (!hasList()) throw new FormatException();
BdfList list = new BdfList();
readListStart();
while (!hasListEnd()) list.add(readObject());
readListEnd();
return list;
}
public void readListStart() throws IOException {
if (!hasList()) throw new FormatException();
hasLookahead = false;
......@@ -305,6 +332,16 @@ class BdfReaderImpl implements BdfReader {
return next == DICTIONARY;
}
public BdfDictionary readDictionary() throws IOException {
if (!hasDictionary()) throw new FormatException();
BdfDictionary dictionary = new BdfDictionary();
readDictionaryStart();
while (!hasDictionaryEnd())
dictionary.put(readString(Integer.MAX_VALUE), readObject());
readDictionaryEnd();
return dictionary;
}
public void readDictionaryStart() throws IOException {
if (!hasDictionary()) throw new FormatException();
hasLookahead = false;
......
......@@ -11,6 +11,7 @@ import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import static org.briarproject.api.data.BdfDictionary.NULL_VALUE;
import static org.briarproject.data.Types.DICTIONARY;
import static org.briarproject.data.Types.END;
import static org.briarproject.data.Types.FALSE;
......@@ -55,7 +56,7 @@ class BdfWriterImpl implements BdfWriter {
else out.write(FALSE);
}
public void writeInteger(long i) throws IOException {
public void writeLong(long i) throws IOException {
if (i >= Byte.MIN_VALUE && i <= Byte.MAX_VALUE) {
out.write(INT_8);
out.write((byte) i);
......@@ -94,7 +95,7 @@ class BdfWriterImpl implements BdfWriter {
out.write((byte) ((i << 56) >> 56));
}
public void writeFloat(double d) throws IOException {
public void writeDouble(double d) throws IOException {
out.write(FLOAT_64);
writeInt64(Double.doubleToRawLongBits(d));
}
......@@ -135,14 +136,14 @@ class BdfWriterImpl implements BdfWriter {
}
private void writeObject(Object o) throws IOException {
if (o == null) writeNull();
if (o == null || o == NULL_VALUE) writeNull();
else if (o instanceof Boolean) writeBoolean((Boolean) o);
else if (o instanceof Byte) writeInteger((Byte) o);
else if (o instanceof Short) writeInteger((Short) o);
else if (o instanceof Integer) writeInteger((Integer) o);
else if (o instanceof Long) writeInteger((Long) o);