First implementation of simple BB Client
parent
b6b234891a
commit
a31d88bd12
|
@ -0,0 +1,163 @@
|
|||
package meerkat.bulletinboard;
|
||||
|
||||
import com.google.protobuf.ByteString;
|
||||
import meerkat.comm.CommunicationException;
|
||||
import meerkat.crypto.Digest;
|
||||
import meerkat.crypto.concrete.SHA256Digest;
|
||||
import meerkat.protobuf.BulletinBoardAPI.*;
|
||||
import meerkat.rest.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.ws.rs.client.Client;
|
||||
import javax.ws.rs.client.ClientBuilder;
|
||||
import javax.ws.rs.client.Entity;
|
||||
import javax.ws.rs.client.WebTarget;
|
||||
import javax.ws.rs.core.Response;
|
||||
|
||||
/**
|
||||
* Created by Arbel Deutsch Peled on 05-Dec-15.
|
||||
*/
|
||||
public class SimpleBulletinBoardClient implements BulletinBoardClient {
|
||||
|
||||
//TODO: Make this general
|
||||
private static String SQL_SERVER_POST = "sqlserver/postmessage";
|
||||
private static String SQL_SERVER_GET = "sqlserver/readmessages";
|
||||
|
||||
private List<String> meerkatDBs;
|
||||
|
||||
private Client client;
|
||||
|
||||
private Digest digest;
|
||||
|
||||
/**
|
||||
* Stores database locations and initializes the web Client
|
||||
* @param meerkatDBs is the list of database locations
|
||||
*/
|
||||
@Override
|
||||
public void init(List<String> meerkatDBs) {
|
||||
|
||||
this.meerkatDBs = meerkatDBs;
|
||||
|
||||
client = ClientBuilder.newClient();
|
||||
client.register(ProtobufMessageBodyReader.class);
|
||||
client.register(ProtobufMessageBodyWriter.class);
|
||||
|
||||
digest = new SHA256Digest();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Post message to all DBs
|
||||
* Make only one try per DB.
|
||||
* @param msg is the message,
|
||||
* @return the message ID for later retrieval
|
||||
* @throws CommunicationException
|
||||
*/
|
||||
@Override
|
||||
public MessageID postMessage(BulletinBoardMessage msg) throws CommunicationException {
|
||||
|
||||
WebTarget webTarget;
|
||||
Response response;
|
||||
|
||||
// Post message to all databases
|
||||
try {
|
||||
for (String db : meerkatDBs) {
|
||||
webTarget = client.target(db).path(SQL_SERVER_POST);
|
||||
response = webTarget.request(Constants.MEDIATYPE_PROTOBUF).post(Entity.entity(msg, Constants.MEDIATYPE_PROTOBUF));
|
||||
|
||||
// Only consider valid responses
|
||||
if (response.getStatusInfo() == Response.Status.OK
|
||||
|| response.getStatusInfo() == Response.Status.CREATED) {
|
||||
response.readEntity(BoolMsg.class).getValue();
|
||||
}
|
||||
}
|
||||
} catch (Exception e) { // Occurs only when server replies with valid status but invalid data
|
||||
throw new CommunicationException("Error accessing database: " + e.getMessage());
|
||||
}
|
||||
|
||||
// Calculate the correct message ID and return it
|
||||
digest.reset();
|
||||
digest.update(msg.getMsg());
|
||||
return MessageID.newBuilder().setID(ByteString.copyFrom(digest.digest())).build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Access each database and search for a given message ID
|
||||
* Return the number of databases in which the message was found
|
||||
* Only try once per DB
|
||||
* Ignore communication exceptions in specific databases
|
||||
* @param id is the requested message ID
|
||||
* @return the number of DBs in which retrieval was successful
|
||||
*/
|
||||
@Override
|
||||
public float getRedundancy(MessageID id) {
|
||||
WebTarget webTarget;
|
||||
Response response;
|
||||
|
||||
MessageFilterList filterList = MessageFilterList.newBuilder()
|
||||
.addFilter(MessageFilter.newBuilder()
|
||||
.setType(FilterType.MSG_ID)
|
||||
.setId(id.getID())
|
||||
.build())
|
||||
.build();
|
||||
|
||||
int count = 0;
|
||||
|
||||
for (String db : meerkatDBs) {
|
||||
try {
|
||||
webTarget = client.target(db).path(SQL_SERVER_GET);
|
||||
|
||||
response = webTarget.request(Constants.MEDIATYPE_PROTOBUF).post(Entity.entity(filterList, Constants.MEDIATYPE_PROTOBUF));
|
||||
|
||||
if (response.readEntity(BulletinBoardMessageList.class).getMessageCount() > 0){
|
||||
count++;
|
||||
}
|
||||
|
||||
} catch (Exception e) {}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Go through the DBs and try to retrieve messages according to the specified filter
|
||||
* If at the operation is successful for some DB: return the results and stop iterating
|
||||
* If no operation is successful: return null (NOT blank list)
|
||||
* @param filterList return only messages that match the filters (null means no filtering).
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public List<BulletinBoardMessage> readMessages(MessageFilterList filterList) {
|
||||
WebTarget webTarget;
|
||||
Response response;
|
||||
BulletinBoardMessageList messageList;
|
||||
|
||||
// Replace null filter list with blank one.
|
||||
if (filterList == null){
|
||||
filterList = MessageFilterList.newBuilder().build();
|
||||
}
|
||||
|
||||
for (String db : meerkatDBs) {
|
||||
try {
|
||||
webTarget = client.target(db).path(SQL_SERVER_GET);
|
||||
|
||||
response = webTarget.request(Constants.MEDIATYPE_PROTOBUF).post(Entity.entity(filterList, Constants.MEDIATYPE_PROTOBUF));
|
||||
|
||||
messageList =response.readEntity(BulletinBoardMessageList.class);
|
||||
|
||||
if (messageList != null){
|
||||
return messageList.getMessageList();
|
||||
}
|
||||
|
||||
} catch (Exception e) {}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerNewMessageCallback(MessageCallback callback, MessageFilterList filterList) {
|
||||
callback.handleNewMessage(readMessages(filterList));
|
||||
}
|
||||
}
|
|
@ -8,7 +8,14 @@ import java.util.List;
|
|||
/**
|
||||
* Created by talm on 24/10/15.
|
||||
*/
|
||||
public interface BulletinBoard {
|
||||
public interface BulletinBoardClient {
|
||||
|
||||
/**
|
||||
* Initialize the client to use some specified servers
|
||||
* @param meerkatDBs is the list of database locations
|
||||
*/
|
||||
void init(List<String> meerkatDBs);
|
||||
|
||||
/**
|
||||
* Post a message to the bulletin board
|
||||
* @param msg
|
||||
|
@ -27,22 +34,21 @@ public interface BulletinBoard {
|
|||
* Note that if messages haven't been "fully posted", this might return a different
|
||||
* set of messages in different calls. However, messages that are fully posted
|
||||
* are guaranteed to be included.
|
||||
* @param filter return only messages that match the filter (null means no filtering).
|
||||
* @param max maximum number of messages to return (0=no limit)
|
||||
* @param filterList return only messages that match the filters (null means no filtering).
|
||||
* @return
|
||||
*/
|
||||
List<BulletinBoardMessage> readMessages(MessageFilter filter, int max);
|
||||
List<BulletinBoardMessage> readMessages(MessageFilterList filterList);
|
||||
|
||||
interface MessageCallback {
|
||||
void handleNewMessage(BulletinBoardMessage msg);
|
||||
void handleNewMessage(List<BulletinBoardMessage> msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a callback that will be called with each new message that is posted.
|
||||
* The callback will be called only once for each message.
|
||||
* @param callback
|
||||
* @param filter only call back for messages that match the filter.
|
||||
* @param filterList only call back for messages that match the filter.
|
||||
*/
|
||||
void registerNewMessageCallback(MessageCallback callback, MessageFilter filter);
|
||||
void registerNewMessageCallback(MessageCallback callback, MessageFilterList filterList);
|
||||
|
||||
}
|
|
@ -3,3 +3,5 @@ include 'voting-booth'
|
|||
include 'bulletin-board-server'
|
||||
include 'polling-station'
|
||||
include 'restful-api-common'
|
||||
include 'bulletin-board-client'
|
||||
|
||||
|
|
Loading…
Reference in New Issue