meerkat-java/meerkat-common/src/main/java/meerkat/util/BulletinBoardUtils.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();
}
}