236 lines
7.5 KiB
Java
236 lines
7.5 KiB
Java
package meerkat.util;
|
|
|
|
import com.google.protobuf.ByteString;
|
|
import com.google.protobuf.Int64Value;
|
|
import meerkat.protobuf.BulletinBoardAPI.*;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.LinkedList;
|
|
import java.util.List;
|
|
|
|
/**
|
|
* Created by Arbel Deutsch Peled on 16-Feb-16.
|
|
*/
|
|
public class BulletinBoardUtils {
|
|
|
|
/**
|
|
* Searches the tags in the message for one that begins with given prefix
|
|
* @param message is the message to search
|
|
* @param prefix is the given prefix
|
|
* @return the tag without the prefix, if found, or null if not found
|
|
*/
|
|
public static String findTagWithPrefix(BulletinBoardMessage message, String prefix) {
|
|
|
|
for (String tag : message.getMsg().getTagList()){
|
|
if (tag.startsWith(prefix)) {
|
|
return tag.substring(prefix.length());
|
|
}
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
/**
|
|
* Searches the tags in a message for tags that do not contain a given list of prefixes
|
|
* @param message is the message to search
|
|
* @param prefixes is the list of prefixes
|
|
* @return a list of the tags that do *not* contain any of the given prefixes
|
|
*/
|
|
public static List<String> removePrefixTags(BulletinBoardMessage message, Iterable<String> prefixes) {
|
|
|
|
if (prefixes == null)
|
|
return message.getMsg().getTagList();
|
|
|
|
List<String> result = new LinkedList<>();
|
|
|
|
for (String tag : message.getMsg().getTagList()){
|
|
|
|
boolean found = false;
|
|
|
|
for (String prefix : prefixes){
|
|
if (tag.startsWith(prefix)){
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!found) {
|
|
result.add(tag);
|
|
}
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
/**
|
|
* This method creates a Timestamp Protobuf from a time specification
|
|
* @param timeInMillis is the time to encode since the Epoch time in milliseconds
|
|
* @return a Timestamp Protobuf encoding of the given time
|
|
*/
|
|
public static com.google.protobuf.Timestamp toTimestampProto(long timeInMillis) {
|
|
|
|
return com.google.protobuf.Timestamp.newBuilder()
|
|
.setSeconds(timeInMillis / 1000)
|
|
.setNanos((int) ((timeInMillis % 1000) * 1000000))
|
|
.build();
|
|
|
|
}
|
|
|
|
/**
|
|
* This method creates a Timestamp Protobuf from the current system time
|
|
* @return a Timestamp Protobuf encoding of the current system time
|
|
*/
|
|
public static com.google.protobuf.Timestamp getCurrentTimestampProto() {
|
|
|
|
return toTimestampProto(System.currentTimeMillis());
|
|
|
|
}
|
|
|
|
/**
|
|
* This method converts an SQL Timestamp object into a Protobuf Timestamp object
|
|
* @param sqlTimestamp is the SQL Timestamp
|
|
* @return an equivalent Protobuf Timestamp
|
|
*/
|
|
public static com.google.protobuf.Timestamp toTimestampProto(java.sql.Timestamp sqlTimestamp) {
|
|
return toTimestampProto(sqlTimestamp.getTime());
|
|
}
|
|
|
|
/**
|
|
* This method converts a Protobuf Timestamp object into an SQL Timestamp object
|
|
* @param protoTimestamp is the Protobuf Timestamp
|
|
* @return an equivalent SQL Timestamp
|
|
*/
|
|
public static java.sql.Timestamp toSQLTimestamp(com.google.protobuf.Timestamp protoTimestamp) {
|
|
return new java.sql.Timestamp(protoTimestamp.getSeconds() * 1000 + protoTimestamp.getNanos() / 1000000);
|
|
}
|
|
|
|
/**
|
|
* Breaks up a bulletin board message into chunks
|
|
* @param msg is the complete message
|
|
* @return a list of BatchChunks that contains the raw message data
|
|
*/
|
|
public static List<BatchChunk> breakToBatch(BulletinBoardMessage msg, int chunkSize) {
|
|
|
|
byte[] data = msg.getMsg().getData().toByteArray();
|
|
|
|
int chunkNum = data.length / chunkSize;
|
|
if (data.length % chunkSize != 0)
|
|
chunkNum++;
|
|
|
|
List<BatchChunk> chunkList = new ArrayList<>(chunkNum);
|
|
|
|
int location = 0;
|
|
|
|
for (int i=0 ; i < chunkNum ; i++) {
|
|
|
|
int chunkLength;
|
|
|
|
if (i == chunkNum - 1){
|
|
chunkLength = data.length % chunkSize;
|
|
if (chunkLength == 0){
|
|
chunkLength = chunkSize;
|
|
}
|
|
} else{
|
|
chunkLength = chunkSize;
|
|
}
|
|
|
|
chunkList.add(BatchChunk.newBuilder()
|
|
.setData(ByteString.copyFrom(data, location, chunkLength))
|
|
.build());
|
|
|
|
location += chunkLength;
|
|
|
|
}
|
|
|
|
return chunkList;
|
|
|
|
}
|
|
|
|
/**
|
|
* Removes concrete data from the message and turns it into a stub
|
|
* Note that the stub does not contain the message ID
|
|
* Therefore, it cannot be used to retrieve the message from a server
|
|
* @param msg is the original message
|
|
* @return the message stub
|
|
*/
|
|
public static BulletinBoardMessage makeStub(BulletinBoardMessage msg) {
|
|
|
|
return BulletinBoardMessage.newBuilder()
|
|
.mergeFrom(msg)
|
|
.setMsg(UnsignedBulletinBoardMessage.newBuilder()
|
|
.mergeFrom(msg.getMsg())
|
|
.clearDataType()
|
|
.clearData()
|
|
.build())
|
|
.build();
|
|
|
|
}
|
|
|
|
/**
|
|
* Merges a batch chunk list back into a message stub to create a complete Bulletin Board message
|
|
* @param msgStub is a message stub
|
|
* @param chunkList contains the (ordered) data of the batch message
|
|
* @return a complete message containing both data and metadata
|
|
*/
|
|
public static BulletinBoardMessage gatherBatch(BulletinBoardMessage msgStub, List<BatchChunk> chunkList) {
|
|
|
|
List<ByteString> dataList = new LinkedList<>();
|
|
|
|
for (BatchChunk chunk : chunkList){
|
|
dataList.add(chunk.getData());
|
|
}
|
|
|
|
return BulletinBoardMessage.newBuilder()
|
|
.mergeFrom(msgStub)
|
|
.setMsg(UnsignedBulletinBoardMessage.newBuilder()
|
|
.mergeFrom(msgStub.getMsg())
|
|
.setData(ByteString.copyFrom(dataList))
|
|
.build())
|
|
.build();
|
|
|
|
}
|
|
|
|
/**
|
|
* Gerenates a BeginBatchMessage Protobuf which is used to begin uploading a message as a batch
|
|
* @param msg is the Bulletin Board message to be uploaded, which can be a stub or a complete message
|
|
* @return the required BeginBatchMessage
|
|
*/
|
|
public static BeginBatchMessage generateBeginBatchMessage(BulletinBoardMessage msg) {
|
|
|
|
if (msg.getSigCount() <= 0){
|
|
throw new IllegalArgumentException("No signatures found");
|
|
}
|
|
|
|
return BeginBatchMessage.newBuilder()
|
|
.addAllTag(msg.getMsg().getTagList())
|
|
.build();
|
|
|
|
}
|
|
|
|
/**
|
|
* Gerenates a CloseBatchMessage Protobuf which is used to finalize a batch message
|
|
* @param batchId is the temporary identifier for the message
|
|
* @param batchLength is the number of chunks in the batch
|
|
* @param msg is the Bulletin Board message that was uploaded (and can also be a stub of said message)
|
|
* @throws IllegalArgumentException if the message contains no signatures
|
|
*/
|
|
public static CloseBatchMessage generateCloseBatchMessage(Int64Value batchId, int batchLength, BulletinBoardMessage msg) {
|
|
|
|
if (msg.getSigCount() <= 0){
|
|
throw new IllegalArgumentException("No signatures found");
|
|
}
|
|
|
|
return CloseBatchMessage.newBuilder()
|
|
.setTimestamp(msg.getMsg().getTimestamp())
|
|
.setBatchLength(batchLength)
|
|
.setBatchId(batchId.getValue())
|
|
.addAllSig(msg.getSigList())
|
|
.build();
|
|
|
|
}
|
|
|
|
}
|