Made SQL Servers generic.
Added MySQL Server and test. Added partial H2 Server code.Bulletin-Board-Client-phase_1
parent
3f21f30f35
commit
76c5e6681f
|
@ -45,7 +45,11 @@ dependencies {
|
||||||
|
|
||||||
// Jersey for RESTful API
|
// Jersey for RESTful API
|
||||||
compile 'org.glassfish.jersey.containers:jersey-container-servlet:2.22.+'
|
compile 'org.glassfish.jersey.containers:jersey-container-servlet:2.22.+'
|
||||||
|
|
||||||
|
// JDBC connections
|
||||||
compile 'org.xerial:sqlite-jdbc:3.7.+'
|
compile 'org.xerial:sqlite-jdbc:3.7.+'
|
||||||
|
compile 'mysql:mysql-connector-java:5.1.+'
|
||||||
|
compile 'com.h2database:h2:1.0.+'
|
||||||
|
|
||||||
// Servlets
|
// Servlets
|
||||||
compile 'javax.servlet:javax.servlet-api:3.0.+'
|
compile 'javax.servlet:javax.servlet-api:3.0.+'
|
||||||
|
|
|
@ -1,103 +0,0 @@
|
||||||
package meerkat.bulletinboard.httpserver;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import javax.servlet.ServletConfig;
|
|
||||||
import javax.servlet.ServletException;
|
|
||||||
import javax.servlet.http.HttpServlet;
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
|
||||||
|
|
||||||
import meerkat.bulletinboard.BulletinBoardServer;
|
|
||||||
import meerkat.bulletinboard.sqlserver.SQLiteBulletinBoardServer;
|
|
||||||
import meerkat.comm.CommunicationException;
|
|
||||||
import meerkat.protobuf.BulletinBoardAPI.*;
|
|
||||||
|
|
||||||
public class BulletinBoardHttpServer extends HttpServlet {
|
|
||||||
|
|
||||||
public final static String DEFAULT_MEERKAT_DB = "local-instances/meerkat.db";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Auto-generated UID.
|
|
||||||
*/
|
|
||||||
private static final long serialVersionUID = -1263665607729456165L;
|
|
||||||
|
|
||||||
BulletinBoardServer bbs;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void init(ServletConfig config) throws ServletException {
|
|
||||||
//TODO: Make this generic
|
|
||||||
bbs = new SQLiteBulletinBoardServer();
|
|
||||||
|
|
||||||
try {
|
|
||||||
bbs.init(DEFAULT_MEERKAT_DB);
|
|
||||||
} catch (CommunicationException e) {
|
|
||||||
// TODO Log error
|
|
||||||
throw new ServletException("Servlet failed to initialize: " + e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This procedure handles (POST) requests to post messages to the Bulletin Board.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected void doPost( HttpServletRequest request, HttpServletResponse response)
|
|
||||||
throws ServletException, IOException {
|
|
||||||
|
|
||||||
BulletinBoardMessage message;
|
|
||||||
|
|
||||||
try{
|
|
||||||
message = BulletinBoardMessage.newBuilder()
|
|
||||||
.mergeFrom(request.getInputStream())
|
|
||||||
.build();
|
|
||||||
} catch(Exception e){
|
|
||||||
//TODO: Log invalid request
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
bbs.postMessage(message);
|
|
||||||
} catch (CommunicationException e) {
|
|
||||||
// TODO Log DB communication error
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This procedure handles (GET) requests which request data from the Bulletin Board.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected void doGet( HttpServletRequest request, HttpServletResponse response)
|
|
||||||
throws ServletException, IOException {
|
|
||||||
|
|
||||||
BulletinBoardMessage message;
|
|
||||||
|
|
||||||
try{
|
|
||||||
message = BulletinBoardMessage.newBuilder()
|
|
||||||
.mergeFrom(request.getInputStream())
|
|
||||||
.build();
|
|
||||||
} catch(Exception e){
|
|
||||||
//TODO: Log invalid request
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
bbs.postMessage(message);
|
|
||||||
} catch (CommunicationException e) {
|
|
||||||
// TODO Log DB communication error
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void destroy() {
|
|
||||||
|
|
||||||
try {
|
|
||||||
bbs.close();
|
|
||||||
} catch (CommunicationException e) {
|
|
||||||
// TODO Log DB communication error
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,16 +1,11 @@
|
||||||
package meerkat.bulletinboard.sqlserver;
|
package meerkat.bulletinboard.sqlserver;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.sql.*;
|
||||||
import java.util.List;
|
import java.util.*;
|
||||||
|
|
||||||
|
import com.google.protobuf.InvalidProtocolBufferException;
|
||||||
import com.google.protobuf.ProtocolStringList;
|
import com.google.protobuf.ProtocolStringList;
|
||||||
|
|
||||||
import java.sql.Connection;
|
|
||||||
import java.sql.PreparedStatement;
|
|
||||||
import java.sql.ResultSet;
|
|
||||||
import java.sql.SQLException;
|
|
||||||
import java.sql.Statement;
|
|
||||||
|
|
||||||
import meerkat.bulletinboard.BulletinBoardServer;
|
import meerkat.bulletinboard.BulletinBoardServer;
|
||||||
import meerkat.comm.CommunicationException;
|
import meerkat.comm.CommunicationException;
|
||||||
import meerkat.protobuf.BulletinBoardAPI.*;
|
import meerkat.protobuf.BulletinBoardAPI.*;
|
||||||
|
@ -19,8 +14,77 @@ import meerkat.protobuf.Crypto.SignatureVerificationKey;
|
||||||
import meerkat.crypto.Digest;
|
import meerkat.crypto.Digest;
|
||||||
import meerkat.crypto.concrete.SHA256Digest;
|
import meerkat.crypto.concrete.SHA256Digest;
|
||||||
|
|
||||||
public abstract class BulletinBoardSQLServer implements BulletinBoardServer{
|
/**
|
||||||
|
* This is a generic SQL implementation of the BulletinBoardServer API.
|
||||||
|
*/
|
||||||
|
public class BulletinBoardSQLServer implements BulletinBoardServer{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This interface provides the required implementation-specific data to enable an access to an actual SQL server.
|
||||||
|
* It accounts for differences in languages between SQL DB types and for the different addresses needed to access them.
|
||||||
|
*/
|
||||||
|
public interface SQLQueryProvider {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allowed query types.
|
||||||
|
* Note that each query returned has to comply with the placeholder ("?") requirements written in its comment.
|
||||||
|
*/
|
||||||
|
public static enum QueryType {
|
||||||
|
FIND_MSG_ID, // Placeholders for: MsgId
|
||||||
|
INSERT_MSG, // Placeholders for: MsgId, Msg
|
||||||
|
INSERT_NEW_TAG, // Placeholders for: Tag
|
||||||
|
CONNECT_TAG, // Placeholders for: EntryNum, Tag
|
||||||
|
ADD_SIGNATURE, // Placeholders for: EntryNum, SignerId, Signature
|
||||||
|
GET_SIGNATURES, // Placeholders for: EntryNum
|
||||||
|
GET_MESSAGES // Placeholders for: N/A
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function translates a QueryType into an actual SQL query.
|
||||||
|
* @param queryType is the type of query requested
|
||||||
|
* @return a string representation of the query for the specific type of SQL database implemented.
|
||||||
|
*/
|
||||||
|
public String getSQLString(QueryType queryType) throws IllegalArgumentException;
|
||||||
|
|
||||||
|
public String getCondition(FilterType filterType) throws IllegalArgumentException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the string needed in order to connect to the DB.
|
||||||
|
*/
|
||||||
|
public String getConnectionString();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is used to get a list of queries that together create the schema needed for the DB.
|
||||||
|
* Note that these queries should not assume anything about the current state of the DB.
|
||||||
|
* In particular: they should not erase any existing tables and/or entries.
|
||||||
|
* @return The list of queries.
|
||||||
|
*/
|
||||||
|
public List<String> getSchemaCreationCommands();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is used to get a list of queries that together delete the schema needed for the DB.
|
||||||
|
* This is useful primarily for tests, in which we want to make sure we start with a clean DB.
|
||||||
|
* @return The list of queries.
|
||||||
|
*/
|
||||||
|
public List<String> getSchemaDeletionCommands();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class implements a comparator for the MessageFilter class
|
||||||
|
* The comparison is done solely by comparing the type of the filter
|
||||||
|
* This is used to sort the filters by type
|
||||||
|
*/
|
||||||
|
public class FilterTypeComparator implements Comparator<MessageFilter> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compare(MessageFilter filter1, MessageFilter filter2) {
|
||||||
|
return filter1.getTypeValue() - filter2.getTypeValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected SQLQueryProvider sqlQueryProvider;
|
||||||
|
|
||||||
protected Connection connection;
|
protected Connection connection;
|
||||||
|
|
||||||
protected Digest digest;
|
protected Digest digest;
|
||||||
|
@ -30,18 +94,52 @@ public abstract class BulletinBoardSQLServer implements BulletinBoardServer{
|
||||||
|
|
||||||
protected List<List<SignatureVerificationKey>> pollingCommitteeSignatureVerificationKeyArray;
|
protected List<List<SignatureVerificationKey>> pollingCommitteeSignatureVerificationKeyArray;
|
||||||
protected int minCommiteeSignatures;
|
protected int minCommiteeSignatures;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method initializes the signatures but does not implement the DB connection.
|
* This constructor sets the type of SQL language in use.
|
||||||
* Any full (non-abstract) extension of this class should
|
* @param sqlQueryProvider is the provider of the SQL query strings required for actual operation of the server.
|
||||||
* 1. Establish a DB connection, and
|
*/
|
||||||
* 2. Call this procedure
|
public BulletinBoardSQLServer(SQLQueryProvider sqlQueryProvider) {
|
||||||
|
this.sqlQueryProvider = sqlQueryProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createSchema() throws SQLException {
|
||||||
|
|
||||||
|
final int TIMEOUT = 20;
|
||||||
|
|
||||||
|
Statement statement = connection.createStatement();
|
||||||
|
statement.setQueryTimeout(TIMEOUT);
|
||||||
|
|
||||||
|
for (String command : sqlQueryProvider.getSchemaCreationCommands()) {
|
||||||
|
statement.executeUpdate(command);
|
||||||
|
}
|
||||||
|
|
||||||
|
statement.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method initializes the signatures, connects to the DB and creates the schema (if required).
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void init(String meerkatDB) throws CommunicationException {
|
public void init(String meerkatDB) throws CommunicationException {
|
||||||
// TODO write signature reading part.
|
// TODO write signature reading part.
|
||||||
|
|
||||||
digest = new SHA256Digest();
|
digest = new SHA256Digest();
|
||||||
|
|
||||||
|
try{
|
||||||
|
|
||||||
|
String dbString = sqlQueryProvider.getConnectionString();
|
||||||
|
connection = DriverManager.getConnection(dbString);
|
||||||
|
} catch (SQLException e) {
|
||||||
|
throw new CommunicationException("Couldn't form a connection with the database " + e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
createSchema();
|
||||||
|
} catch (SQLException e) {
|
||||||
|
throw new CommunicationException("Couldn't create schema " + e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -61,7 +159,29 @@ public abstract class BulletinBoardSQLServer implements BulletinBoardServer{
|
||||||
* This procedure makes sure that all tags in the given list have an entry in the tags table.
|
* This procedure makes sure that all tags in the given list have an entry in the tags table.
|
||||||
* @param tags
|
* @param tags
|
||||||
*/
|
*/
|
||||||
protected abstract void insertNewTags(String[] tags) throws SQLException;
|
protected void insertNewTags(String[] tags) throws SQLException {
|
||||||
|
|
||||||
|
PreparedStatement pstmt;
|
||||||
|
String sql;
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
sql = sqlQueryProvider.getSQLString(SQLQueryProvider.QueryType.INSERT_NEW_TAG);
|
||||||
|
pstmt = connection.prepareStatement(sql);
|
||||||
|
|
||||||
|
for (String tag : tags){
|
||||||
|
pstmt.setString(1, tag);
|
||||||
|
pstmt.addBatch();
|
||||||
|
}
|
||||||
|
|
||||||
|
pstmt.executeBatch();
|
||||||
|
pstmt.close();
|
||||||
|
|
||||||
|
} catch (SQLException e){
|
||||||
|
throw new SQLException("Error adding new tags to table: " + e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This procedure is used to convert a boolean to a BoolMsg.
|
* This procedure is used to convert a boolean to a BoolMsg.
|
||||||
|
@ -73,7 +193,7 @@ public abstract class BulletinBoardSQLServer implements BulletinBoardServer{
|
||||||
.setValue(b)
|
.setValue(b)
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BoolMsg postMessage(BulletinBoardMessage msg) throws CommunicationException {
|
public BoolMsg postMessage(BulletinBoardMessage msg) throws CommunicationException {
|
||||||
|
|
||||||
|
@ -104,7 +224,7 @@ public abstract class BulletinBoardSQLServer implements BulletinBoardServer{
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
sql = "SELECT EntryNum From MsgTable WHERE MsgId = ?";
|
sql = sqlQueryProvider.getSQLString(SQLQueryProvider.QueryType.FIND_MSG_ID);
|
||||||
pstmt = connection.prepareStatement(sql);
|
pstmt = connection.prepareStatement(sql);
|
||||||
pstmt.setBytes(1, msgID);
|
pstmt.setBytes(1, msgID);
|
||||||
rs = pstmt.executeQuery();
|
rs = pstmt.executeQuery();
|
||||||
|
@ -115,8 +235,8 @@ public abstract class BulletinBoardSQLServer implements BulletinBoardServer{
|
||||||
|
|
||||||
} else{
|
} else{
|
||||||
|
|
||||||
sql = "INSERT INTO MsgTable (MsgId, Msg) VALUES(?,?)";
|
sql = sqlQueryProvider.getSQLString(SQLQueryProvider.QueryType.INSERT_MSG);
|
||||||
pstmt = connection.prepareStatement(sql);
|
pstmt = connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
|
||||||
pstmt.setBytes(1, msgID);
|
pstmt.setBytes(1, msgID);
|
||||||
pstmt.setBytes(2, msg.getMsg().toByteArray());
|
pstmt.setBytes(2, msg.getMsg().toByteArray());
|
||||||
pstmt.executeUpdate();
|
pstmt.executeUpdate();
|
||||||
|
@ -150,7 +270,7 @@ public abstract class BulletinBoardSQLServer implements BulletinBoardServer{
|
||||||
// Connect message to tags.
|
// Connect message to tags.
|
||||||
|
|
||||||
try{
|
try{
|
||||||
sql = "INSERT OR IGNORE INTO MsgTagTable (TagId, EntryNum) SELECT TagTable.TagId, ? AS EntryNum FROM TagTable WHERE Tag = ?";
|
sql = sqlQueryProvider.getSQLString(SQLQueryProvider.QueryType.CONNECT_TAG);
|
||||||
pstmt = connection.prepareStatement(sql);
|
pstmt = connection.prepareStatement(sql);
|
||||||
|
|
||||||
pstmt.setLong(1, entryNum);
|
pstmt.setLong(1, entryNum);
|
||||||
|
@ -176,7 +296,7 @@ public abstract class BulletinBoardSQLServer implements BulletinBoardServer{
|
||||||
// Connect message to signatures.
|
// Connect message to signatures.
|
||||||
|
|
||||||
try{
|
try{
|
||||||
sql = "INSERT OR IGNORE INTO SignatureTable (EntryNum, SignerId, Signature) VALUES (?,?,?)";
|
sql = sqlQueryProvider.getSQLString(SQLQueryProvider.QueryType.ADD_SIGNATURE);
|
||||||
pstmt = connection.prepareStatement(sql);
|
pstmt = connection.prepareStatement(sql);
|
||||||
|
|
||||||
pstmt.setLong(1, entryNum);
|
pstmt.setLong(1, entryNum);
|
||||||
|
@ -197,41 +317,147 @@ public abstract class BulletinBoardSQLServer implements BulletinBoardServer{
|
||||||
|
|
||||||
return boolToBoolMsg(true);
|
return boolToBoolMsg(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String testPrint(){
|
@Override
|
||||||
|
public BulletinBoardMessageList readMessages(MessageFilterList filterList) throws CommunicationException {
|
||||||
String s = "";
|
PreparedStatement pstmt;
|
||||||
|
ResultSet messages, signatures;
|
||||||
try {
|
|
||||||
|
long entryNum;
|
||||||
Statement statement = connection.createStatement();
|
BulletinBoardMessageList.Builder resultListBuilder = BulletinBoardMessageList.newBuilder();
|
||||||
ResultSet rs = statement.executeQuery("select * from MsgTable");
|
BulletinBoardMessage.Builder messageBuilder;
|
||||||
while (rs.next()) {
|
|
||||||
// read the result set
|
String sql;
|
||||||
s += "entry = " + rs.getInt("EntryNum") + " \n";
|
|
||||||
s += "id = " + Arrays.toString(rs.getBytes("MsgId")) + " \n";
|
List<MessageFilter> filters = new ArrayList<MessageFilter>(filterList.getFilterList());
|
||||||
s += "msg = " + Arrays.toString(rs.getBytes("Msg")) + " \n";
|
int i;
|
||||||
s += "signer ID = " + Arrays.toString(rs.getBytes("SignerId")) + "\t\n<BR>";
|
|
||||||
|
boolean tagsRequired = false;
|
||||||
|
boolean signaturesRequired = false;
|
||||||
|
|
||||||
|
boolean isFirstFilter = true;
|
||||||
|
|
||||||
|
Collections.sort(filters, new FilterTypeComparator());
|
||||||
|
|
||||||
|
// Check if Tag/Signature tables are required for filtering purposes.
|
||||||
|
|
||||||
|
sql = sqlQueryProvider.getSQLString(SQLQueryProvider.QueryType.GET_MESSAGES);
|
||||||
|
|
||||||
|
// Add conditions.
|
||||||
|
|
||||||
|
if (!filters.isEmpty()){
|
||||||
|
sql += " WHERE ";
|
||||||
|
|
||||||
|
for (MessageFilter filter : filters){
|
||||||
|
|
||||||
|
if (filter.getType().getNumber() != FilterType.MAX_MESSAGES_VALUE){
|
||||||
|
if (isFirstFilter){
|
||||||
|
isFirstFilter = false;
|
||||||
|
} else{
|
||||||
|
sql += " AND ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sql += sqlQueryProvider.getCondition(filter.getType());
|
||||||
}
|
}
|
||||||
|
|
||||||
rs = statement.executeQuery("select * from TagTable");
|
|
||||||
while (rs.next()) {
|
|
||||||
// read the result set
|
|
||||||
s += "Tag = " + rs.getString("Tag") + " \n";
|
|
||||||
s += "TagId = " + rs.getInt("TagId") + "\t\n<BR>";
|
|
||||||
}
|
|
||||||
|
|
||||||
rs = statement.executeQuery("select * from MsgTagTable");
|
|
||||||
while (rs.next()) {
|
|
||||||
// read the result set
|
|
||||||
s += "MsgId = " + Arrays.toString(rs.getBytes("MsgId")) + " \n";
|
|
||||||
s += "TagId = " + rs.getInt("TagId") + "\t\n<BR>";
|
|
||||||
}
|
|
||||||
} catch(SQLException e){
|
|
||||||
s += "Error reading from DB";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return s;
|
// Make query.
|
||||||
|
|
||||||
|
try {
|
||||||
|
pstmt = connection.prepareStatement(sql);
|
||||||
|
|
||||||
|
// Specify values for filters.
|
||||||
|
|
||||||
|
i = 1;
|
||||||
|
for (MessageFilter filter : filters){
|
||||||
|
|
||||||
|
switch (filter.getType().getNumber()){
|
||||||
|
|
||||||
|
case FilterType.EXACT_ENTRY_VALUE: // Go through.
|
||||||
|
case FilterType.MAX_ENTRY_VALUE:
|
||||||
|
pstmt.setLong(i, filter.getEntry());
|
||||||
|
i++;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FilterType.MSG_ID_VALUE: // Go through.
|
||||||
|
case FilterType.SIGNER_ID_VALUE:
|
||||||
|
pstmt.setBytes(i, filter.getId().toByteArray());
|
||||||
|
i++;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FilterType.TAG_VALUE:
|
||||||
|
pstmt.setString(i, filter.getTag());
|
||||||
|
i++;
|
||||||
|
break;
|
||||||
|
|
||||||
|
// The max-messages condition is applied as a suffix. Therefore, it is treated differently.
|
||||||
|
case FilterType.MAX_MESSAGES_VALUE:
|
||||||
|
pstmt.setLong(filters.size(), filter.getMaxMessages());
|
||||||
|
i++;
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run query.
|
||||||
|
|
||||||
|
messages = pstmt.executeQuery();
|
||||||
|
|
||||||
|
// Compile list of messages.
|
||||||
|
|
||||||
|
sql = sqlQueryProvider.getSQLString(SQLQueryProvider.QueryType.GET_SIGNATURES);
|
||||||
|
pstmt = connection.prepareStatement(sql);
|
||||||
|
|
||||||
|
while (messages.next()){
|
||||||
|
|
||||||
|
// Get entry number and retrieve signatures.
|
||||||
|
|
||||||
|
entryNum = messages.getLong(1);
|
||||||
|
pstmt.setLong(1, entryNum);
|
||||||
|
signatures = pstmt.executeQuery();
|
||||||
|
|
||||||
|
// Create message and append signatures.
|
||||||
|
|
||||||
|
messageBuilder = BulletinBoardMessage.newBuilder()
|
||||||
|
.setEntryNum(entryNum)
|
||||||
|
.setMsg(UnsignedBulletinBoardMessage.parseFrom(messages.getBytes(2)));
|
||||||
|
|
||||||
|
while (signatures.next()){
|
||||||
|
messageBuilder.addSig(Signature.parseFrom(signatures.getBytes(1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finalize message and add to message list.
|
||||||
|
|
||||||
|
resultListBuilder.addMessage(messageBuilder.build());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
pstmt.close();
|
||||||
|
|
||||||
|
} catch (SQLException e){
|
||||||
|
throw new CommunicationException("Error reading messages from DB: " + e.getMessage());
|
||||||
|
} catch (InvalidProtocolBufferException e) {
|
||||||
|
throw new CommunicationException("Invalid data from DB: " + e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
//Combine results and return.
|
||||||
|
|
||||||
|
return resultListBuilder.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() throws CommunicationException {
|
||||||
|
|
||||||
|
try{
|
||||||
|
connection.close();
|
||||||
|
} catch (SQLException e) {
|
||||||
|
|
||||||
|
throw new CommunicationException("Couldn't close connection to the database");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,190 +0,0 @@
|
||||||
package meerkat.bulletinboard.sqlserver;
|
|
||||||
|
|
||||||
import com.google.protobuf.InvalidProtocolBufferException;
|
|
||||||
import meerkat.comm.CommunicationException;
|
|
||||||
import meerkat.protobuf.BulletinBoardAPI;
|
|
||||||
import meerkat.protobuf.BulletinBoardAPI.*;
|
|
||||||
import meerkat.protobuf.Crypto.*;
|
|
||||||
|
|
||||||
import java.sql.PreparedStatement;
|
|
||||||
import java.sql.ResultSet;
|
|
||||||
import java.sql.SQLException;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Comparator;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by Arbel Deutsch Peled on 07-Dec-15.
|
|
||||||
* This server version allows for reading of messages with several tags and/or signatures
|
|
||||||
* The superclass only allows one constraint per type.
|
|
||||||
*/
|
|
||||||
public class EnhancedSQLiteBulletinBoardServer extends SQLiteBulletinBoardServer {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class implements a comparator for the MessageFilter class
|
|
||||||
* The comparison is done solely by comparing the type of the filter
|
|
||||||
* This is used to sort the filters by type
|
|
||||||
*/
|
|
||||||
public class FilterTypeComparator implements Comparator<MessageFilter>{
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int compare(MessageFilter filter1, MessageFilter filter2) {
|
|
||||||
return filter1.getTypeValue() - filter2.getTypeValue();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public BulletinBoardMessageList readMessages(MessageFilterList filterList) throws CommunicationException {
|
|
||||||
|
|
||||||
PreparedStatement pstmt;
|
|
||||||
ResultSet messages, signatures;
|
|
||||||
|
|
||||||
long entryNum;
|
|
||||||
BulletinBoardMessageList.Builder resultListBuilder = BulletinBoardMessageList.newBuilder();
|
|
||||||
BulletinBoardMessage.Builder messageBuilder;
|
|
||||||
|
|
||||||
String sql;
|
|
||||||
String sqlSuffix = "";
|
|
||||||
|
|
||||||
List<MessageFilter> filters = new ArrayList<MessageFilter>(filterList.getFilterList());
|
|
||||||
int i;
|
|
||||||
|
|
||||||
boolean tagsRequired = false;
|
|
||||||
boolean signaturesRequired = false;
|
|
||||||
|
|
||||||
boolean isFirstFilter = true;
|
|
||||||
|
|
||||||
Collections.sort(filters, new FilterTypeComparator());
|
|
||||||
|
|
||||||
// Check if Tag/Signature tables are required for filtering purposes.
|
|
||||||
|
|
||||||
sql = "SELECT MsgTable.EntryNum, MsgTable.Msg FROM MsgTable";
|
|
||||||
|
|
||||||
// Add conditions.
|
|
||||||
|
|
||||||
if (!filters.isEmpty()){
|
|
||||||
sql += " WHERE";
|
|
||||||
|
|
||||||
for (MessageFilter filter : filters){
|
|
||||||
|
|
||||||
if (filter.getType().getNumber() != FilterType.MAX_MESSAGES_VALUE){
|
|
||||||
if (isFirstFilter){
|
|
||||||
isFirstFilter = false;
|
|
||||||
} else{
|
|
||||||
sql += " AND";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (filter.getType().getNumber()){
|
|
||||||
case FilterType.EXACT_ENTRY_VALUE:
|
|
||||||
sql += " MsgTable.EntryNum = ?";
|
|
||||||
break;
|
|
||||||
case FilterType.MAX_ENTRY_VALUE:
|
|
||||||
sql += " MsgTable.EntryNum <= ?";
|
|
||||||
break;
|
|
||||||
case FilterType.MAX_MESSAGES_VALUE:
|
|
||||||
sqlSuffix += " LIMIT = ?";
|
|
||||||
break;
|
|
||||||
case FilterType.MSG_ID_VALUE:
|
|
||||||
sql += " MsgTable.MsgId = ?";
|
|
||||||
break;
|
|
||||||
case FilterType.SIGNER_ID_VALUE:
|
|
||||||
sql += " EXISTS (SELECT 1 FROM SignatureTable"
|
|
||||||
+ " WHERE SignatureTable.SignerId = ? AND SignatureTable.EntryNum = MsgTable.EntryNum)";
|
|
||||||
break;
|
|
||||||
case FilterType.TAG_VALUE:
|
|
||||||
sql += " EXISTS (SELECT 1 FROM TagTable"
|
|
||||||
+ " INNER JOIN MsgTagTable ON TagTable.TagId = MsgTagTable.TagId"
|
|
||||||
+ " WHERE TagTable.Tag = ? AND MsgTagTable.EntryNum = MsgTable.EntryNum)";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sql += sqlSuffix;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make query.
|
|
||||||
|
|
||||||
try {
|
|
||||||
pstmt = connection.prepareStatement(sql);
|
|
||||||
|
|
||||||
// Specify values for filters.
|
|
||||||
|
|
||||||
i = 1;
|
|
||||||
for (MessageFilter filter : filters){
|
|
||||||
|
|
||||||
switch (filter.getType().getNumber()){
|
|
||||||
|
|
||||||
case FilterType.EXACT_ENTRY_VALUE: // Go through.
|
|
||||||
case FilterType.MAX_ENTRY_VALUE:
|
|
||||||
pstmt.setLong(i, filter.getEntry());
|
|
||||||
i++;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FilterType.MSG_ID_VALUE: // Go through.
|
|
||||||
case FilterType.SIGNER_ID_VALUE:
|
|
||||||
pstmt.setBytes(i, filter.getId().toByteArray());
|
|
||||||
i++;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FilterType.TAG_VALUE:
|
|
||||||
pstmt.setString(i, filter.getTag());
|
|
||||||
i++;
|
|
||||||
break;
|
|
||||||
|
|
||||||
// The max-messages condition is applied as a suffix. Therefore, it is treated differently.
|
|
||||||
case FilterType.MAX_MESSAGES_VALUE:
|
|
||||||
pstmt.setLong(filters.size(), filter.getMaxMessages());
|
|
||||||
i++;
|
|
||||||
break;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Run query.
|
|
||||||
|
|
||||||
messages = pstmt.executeQuery();
|
|
||||||
|
|
||||||
// Compile list of messages.
|
|
||||||
|
|
||||||
sql = "SELECT Signature FROM SignatureTable WHERE EntryNum = ?";
|
|
||||||
pstmt = connection.prepareStatement(sql);
|
|
||||||
|
|
||||||
while (messages.next()){
|
|
||||||
|
|
||||||
// Get entry number and retrieve signatures.
|
|
||||||
|
|
||||||
entryNum = messages.getLong(1);
|
|
||||||
pstmt.setLong(1, entryNum);
|
|
||||||
signatures = pstmt.executeQuery();
|
|
||||||
|
|
||||||
// Create message and append signatures.
|
|
||||||
|
|
||||||
messageBuilder = BulletinBoardMessage.newBuilder()
|
|
||||||
.setEntryNum(entryNum)
|
|
||||||
.setMsg(UnsignedBulletinBoardMessage.parseFrom(messages.getBytes(2)));
|
|
||||||
|
|
||||||
while (signatures.next()){
|
|
||||||
messageBuilder.addSig(Signature.parseFrom(signatures.getBytes(1)));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Finalize message and add to message list.
|
|
||||||
|
|
||||||
resultListBuilder.addMessage(messageBuilder.build());
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
pstmt.close();
|
|
||||||
|
|
||||||
} catch (SQLException e){
|
|
||||||
throw new CommunicationException("Error reading messages from DB: " + e.getMessage());
|
|
||||||
} catch (InvalidProtocolBufferException e) {
|
|
||||||
throw new CommunicationException("Invalid data from DB: " + e.getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
//Combine results and return.
|
|
||||||
|
|
||||||
return resultListBuilder.build();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,111 @@
|
||||||
|
package meerkat.bulletinboard.sqlserver;
|
||||||
|
|
||||||
|
import meerkat.protobuf.BulletinBoardAPI.FilterType;
|
||||||
|
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Arbel Deutsch Peled on 09-Dec-15.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class H2QueryProvider implements BulletinBoardSQLServer.SQLQueryProvider {
|
||||||
|
|
||||||
|
private String dbConnectionString;
|
||||||
|
|
||||||
|
public H2QueryProvider(String dbAddress) {
|
||||||
|
dbConnectionString = "jdbc:h2:" + dbAddress + ";MODE=MYSQL";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getSQLString(QueryType queryType) throws IllegalArgumentException{
|
||||||
|
|
||||||
|
switch(queryType) {
|
||||||
|
case ADD_SIGNATURE:
|
||||||
|
return "INSERT IGNORE INTO SignatureTable (EntryNum, SignerId, Signature) VALUES (?,?,?)";
|
||||||
|
case CONNECT_TAG:
|
||||||
|
return "INSERT IGNORE INTO MsgTagTable (TagId, EntryNum)"
|
||||||
|
+ " SELECT TagTable.TagId, ? AS EntryNum FROM TagTable WHERE Tag = ?";
|
||||||
|
case FIND_MSG_ID:
|
||||||
|
return "SELECT EntryNum From MsgTable WHERE MsgId = ?";
|
||||||
|
case GET_MESSAGES:
|
||||||
|
return "SELECT MsgTable.EntryNum, MsgTable.Msg FROM MsgTable";
|
||||||
|
case GET_SIGNATURES:
|
||||||
|
return "SELECT Signature FROM SignatureTable WHERE EntryNum = ?";
|
||||||
|
case INSERT_MSG:
|
||||||
|
return "INSERT INTO MsgTable (MsgId, Msg) VALUES(?,?)";
|
||||||
|
case INSERT_NEW_TAG:
|
||||||
|
return "INSERT IGNORE INTO TagTable(Tag) VALUES (?)";
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException("Cannot serve a query of type " + queryType);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getCondition(FilterType filterType) throws IllegalArgumentException {
|
||||||
|
|
||||||
|
switch(filterType) {
|
||||||
|
case EXACT_ENTRY:
|
||||||
|
return "MsgTable.EntryNum = ?";
|
||||||
|
case MAX_ENTRY:
|
||||||
|
return "MsgTable.EntryNum <= ?";
|
||||||
|
case MAX_MESSAGES:
|
||||||
|
return "LIMIT ?";
|
||||||
|
case MSG_ID:
|
||||||
|
return "MsgTable.MsgId = ?";
|
||||||
|
case SIGNER_ID:
|
||||||
|
return "EXISTS (SELECT 1 FROM SignatureTable"
|
||||||
|
+ " WHERE SignatureTable.SignerId = ? AND SignatureTable.EntryNum = MsgTable.EntryNum)";
|
||||||
|
case TAG:
|
||||||
|
return "EXISTS (SELECT 1 FROM TagTable"
|
||||||
|
+ " INNER JOIN MsgTagTable ON TagTable.TagId = MsgTagTable.TagId"
|
||||||
|
+ " WHERE TagTable.Tag = ? AND MsgTagTable.EntryNum = MsgTable.EntryNum)";
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException("Cannot serve a filter of type " + filterType);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getConnectionString() {
|
||||||
|
return dbConnectionString;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> getSchemaCreationCommands() {
|
||||||
|
List<String> list = new LinkedList<String>();
|
||||||
|
|
||||||
|
list.add("CREATE TABLE IF NOT EXISTS MsgTable (EntryNum INT NOT NULL AUTO_INCREMENT PRIMARY KEY, MsgId TINYBLOB UNIQUE, Msg BLOB)");
|
||||||
|
|
||||||
|
list.add("CREATE TABLE IF NOT EXISTS TagTable (TagId INT NOT NULL AUTO_INCREMENT PRIMARY KEY, Tag varchar(50) UNIQUE)");
|
||||||
|
|
||||||
|
list.add("CREATE TABLE IF NOT EXISTS MsgTagTable (EntryNum INT, TagId INT,"
|
||||||
|
+ " FOREIGN KEY (EntryNum) REFERENCES MsgTable(EntryNum),"
|
||||||
|
+ " FOREIGN KEY (TagId) REFERENCES TagTable(TagId),"
|
||||||
|
+ " UNIQUE (EntryNum, TagID))");
|
||||||
|
|
||||||
|
list.add("CREATE TABLE IF NOT EXISTS SignatureTable (EntryNum INT, SignerId TINYBLOB, Signature TINYBLOB UNIQUE,"
|
||||||
|
+ " FOREIGN KEY (EntryNum) REFERENCES MsgTable(EntryNum))");
|
||||||
|
|
||||||
|
list.add("CREATE UNIQUE INDEX IF NOT EXISTS SignerIdIndex ON SignatureTable(SignerId)");
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> getSchemaDeletionCommands() {
|
||||||
|
List<String> list = new LinkedList<String>();
|
||||||
|
|
||||||
|
list.add("DROP INDEX IF EXISTS SignerIdIndex");
|
||||||
|
list.add("DROP TABLE IF EXISTS MsgTagTable");
|
||||||
|
list.add("DROP TABLE IF EXISTS SignatureTable");
|
||||||
|
list.add("DROP TABLE IF EXISTS TagTable");
|
||||||
|
list.add("DROP TABLE IF EXISTS MsgTable");
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,106 @@
|
||||||
|
package meerkat.bulletinboard.sqlserver;
|
||||||
|
|
||||||
|
import meerkat.protobuf.BulletinBoardAPI.FilterType;
|
||||||
|
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Arbel Deutsch Peled on 09-Dec-15.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class MySQLQueryProvider implements BulletinBoardSQLServer.SQLQueryProvider {
|
||||||
|
|
||||||
|
String dbConnectionString;
|
||||||
|
|
||||||
|
public MySQLQueryProvider(String dbAddress, String username, String password) {
|
||||||
|
dbConnectionString = "jdbc:mysql:" + dbAddress + "?user=" + username + "&password=" + password;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getSQLString(QueryType queryType) throws IllegalArgumentException{
|
||||||
|
|
||||||
|
switch(queryType) {
|
||||||
|
case ADD_SIGNATURE:
|
||||||
|
return "INSERT IGNORE INTO SignatureTable (EntryNum, SignerId, Signature) VALUES (?,?,?)";
|
||||||
|
case CONNECT_TAG:
|
||||||
|
return "INSERT IGNORE INTO MsgTagTable (TagId, EntryNum)"
|
||||||
|
+ " SELECT TagTable.TagId, ? AS EntryNum FROM TagTable WHERE Tag = ?";
|
||||||
|
case FIND_MSG_ID:
|
||||||
|
return "SELECT EntryNum From MsgTable WHERE MsgId = ?";
|
||||||
|
case GET_MESSAGES:
|
||||||
|
return "SELECT MsgTable.EntryNum, MsgTable.Msg FROM MsgTable";
|
||||||
|
case GET_SIGNATURES:
|
||||||
|
return "SELECT Signature FROM SignatureTable WHERE EntryNum = ?";
|
||||||
|
case INSERT_MSG:
|
||||||
|
return "INSERT INTO MsgTable (MsgId, Msg) VALUES(?,?)";
|
||||||
|
case INSERT_NEW_TAG:
|
||||||
|
return "INSERT IGNORE INTO TagTable(Tag) VALUES (?)";
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException("Cannot serve a query of type " + queryType);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getCondition(FilterType filterType) throws IllegalArgumentException {
|
||||||
|
|
||||||
|
switch(filterType) {
|
||||||
|
case EXACT_ENTRY:
|
||||||
|
return "MsgTable.EntryNum = ?";
|
||||||
|
case MAX_ENTRY:
|
||||||
|
return "MsgTable.EntryNum <= ?";
|
||||||
|
case MAX_MESSAGES:
|
||||||
|
return "LIMIT ?";
|
||||||
|
case MSG_ID:
|
||||||
|
return "MsgTable.MsgId = ?";
|
||||||
|
case SIGNER_ID:
|
||||||
|
return "EXISTS (SELECT 1 FROM SignatureTable"
|
||||||
|
+ " WHERE SignatureTable.SignerId = ? AND SignatureTable.EntryNum = MsgTable.EntryNum)";
|
||||||
|
case TAG:
|
||||||
|
return "EXISTS (SELECT 1 FROM TagTable"
|
||||||
|
+ " INNER JOIN MsgTagTable ON TagTable.TagId = MsgTagTable.TagId"
|
||||||
|
+ " WHERE TagTable.Tag = ? AND MsgTagTable.EntryNum = MsgTable.EntryNum)";
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException("Cannot serve a filter of type " + filterType);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getConnectionString() {
|
||||||
|
return dbConnectionString;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> getSchemaCreationCommands() {
|
||||||
|
List<String> list = new LinkedList<String>();
|
||||||
|
|
||||||
|
list.add("CREATE TABLE IF NOT EXISTS MsgTable (EntryNum INT NOT NULL AUTO_INCREMENT PRIMARY KEY, MsgId TINYBLOB, Msg BLOB, UNIQUE(MsgId(50)))");
|
||||||
|
|
||||||
|
list.add("CREATE TABLE IF NOT EXISTS TagTable (TagId INT NOT NULL AUTO_INCREMENT PRIMARY KEY, Tag varchar(50), UNIQUE(Tag))");
|
||||||
|
|
||||||
|
list.add("CREATE TABLE IF NOT EXISTS MsgTagTable (EntryNum INT, TagId INT,"
|
||||||
|
+ " CONSTRAINT FOREIGN KEY (EntryNum) REFERENCES MsgTable(EntryNum),"
|
||||||
|
+ " CONSTRAINT FOREIGN KEY (TagId) REFERENCES TagTable(TagId),"
|
||||||
|
+ " CONSTRAINT UNIQUE (EntryNum, TagID))");
|
||||||
|
|
||||||
|
list.add("CREATE TABLE IF NOT EXISTS SignatureTable (EntryNum INT, SignerId TINYBLOB, Signature TINYBLOB, UNIQUE(Signature(150)),"
|
||||||
|
+ " INDEX(SignerId(50)), CONSTRAINT FOREIGN KEY (EntryNum) REFERENCES MsgTable(EntryNum))");
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> getSchemaDeletionCommands() {
|
||||||
|
List<String> list = new LinkedList<String>();
|
||||||
|
|
||||||
|
list.add("DROP TABLE IF EXISTS MsgTagTable");
|
||||||
|
list.add("DROP TABLE IF EXISTS SignatureTable");
|
||||||
|
list.add("DROP TABLE IF EXISTS TagTable");
|
||||||
|
list.add("DROP TABLE IF EXISTS MsgTable");
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,266 +0,0 @@
|
||||||
package meerkat.bulletinboard.sqlserver;
|
|
||||||
|
|
||||||
import java.sql.DriverManager;
|
|
||||||
import java.sql.PreparedStatement;
|
|
||||||
import java.sql.ResultSet;
|
|
||||||
import java.sql.SQLException;
|
|
||||||
import java.sql.Statement;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import com.google.protobuf.InvalidProtocolBufferException;
|
|
||||||
|
|
||||||
import meerkat.protobuf.BulletinBoardAPI.*;
|
|
||||||
import meerkat.protobuf.Crypto.Signature;
|
|
||||||
import meerkat.bulletinboard.sqlserver.BulletinBoardSQLServer;
|
|
||||||
import meerkat.comm.CommunicationException;
|
|
||||||
|
|
||||||
public class SQLiteBulletinBoardServer extends BulletinBoardSQLServer {
|
|
||||||
|
|
||||||
protected static final int TIMEOUT = 20;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This procedure initializes:
|
|
||||||
* 1. The database connection
|
|
||||||
* 2. The database tables (if they do not yet exist).
|
|
||||||
*/
|
|
||||||
|
|
||||||
private void createSchema() throws SQLException {
|
|
||||||
Statement statement = connection.createStatement();
|
|
||||||
statement.setQueryTimeout(TIMEOUT);
|
|
||||||
|
|
||||||
statement.executeUpdate("CREATE TABLE IF NOT EXISTS MsgTable (EntryNum INTEGER PRIMARY KEY, MsgId BLOB UNIQUE, Msg BLOB)");
|
|
||||||
|
|
||||||
statement.executeUpdate("CREATE TABLE IF NOT EXISTS TagTable (TagId INTEGER PRIMARY KEY, Tag varchar(50) UNIQUE)");
|
|
||||||
statement.executeUpdate("CREATE TABLE IF NOT EXISTS MsgTagTable (EntryNum BLOB, TagId INTEGER, FOREIGN KEY (EntryNum) REFERENCES MsgTable(EntryNum), FOREIGN KEY (TagId) REFERENCES TagTable(TagId), UNIQUE (EntryNum, TagID))");
|
|
||||||
|
|
||||||
statement.executeUpdate("CREATE TABLE IF NOT EXISTS SignatureTable (EntryNum BLOB, SignerId BLOB, Signature BLOB UNIQUE, FOREIGN KEY (EntryNum) REFERENCES MsgTable(EntryNum))");
|
|
||||||
statement.executeUpdate("CREATE INDEX IF NOT EXISTS SignerIndex ON SignatureTable(SignerId)");
|
|
||||||
|
|
||||||
statement.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void init(String meerkatDB) throws CommunicationException {
|
|
||||||
|
|
||||||
try{
|
|
||||||
String dbString = "jdbc:sqlite:" + meerkatDB;
|
|
||||||
connection = DriverManager.getConnection(dbString);
|
|
||||||
createSchema();
|
|
||||||
|
|
||||||
super.init(meerkatDB);
|
|
||||||
|
|
||||||
} catch (SQLException e) {
|
|
||||||
|
|
||||||
throw new CommunicationException("Couldn't form a connection with the database" + e.getMessage());
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public void close() throws CommunicationException{
|
|
||||||
|
|
||||||
try{
|
|
||||||
connection.close();
|
|
||||||
} catch (SQLException e) {
|
|
||||||
|
|
||||||
throw new CommunicationException("Couldn't close connection to the database");
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void insertNewTags(String[] tags) throws SQLException {
|
|
||||||
|
|
||||||
PreparedStatement pstmt;
|
|
||||||
String sql;
|
|
||||||
|
|
||||||
try {
|
|
||||||
|
|
||||||
sql = "INSERT OR IGNORE INTO TagTable(Tag) VALUES (?)";
|
|
||||||
pstmt = connection.prepareStatement(sql);
|
|
||||||
|
|
||||||
for (String tag : tags){
|
|
||||||
pstmt.setString(1, tag);
|
|
||||||
pstmt.addBatch();
|
|
||||||
}
|
|
||||||
|
|
||||||
pstmt.executeBatch();
|
|
||||||
pstmt.close();
|
|
||||||
|
|
||||||
} catch (SQLException e){
|
|
||||||
throw new SQLException("Error adding new tags to table: " + e.getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public BoolMsg postMessage(BulletinBoardMessage msg) throws CommunicationException {
|
|
||||||
return super.postMessage(msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public BulletinBoardMessageList readMessages(MessageFilterList filterList) throws CommunicationException{
|
|
||||||
|
|
||||||
PreparedStatement pstmt;
|
|
||||||
ResultSet messages, signatures;
|
|
||||||
|
|
||||||
long entryNum;
|
|
||||||
BulletinBoardMessageList.Builder resultListBuilder = BulletinBoardMessageList.newBuilder();
|
|
||||||
BulletinBoardMessage.Builder messageBuilder;
|
|
||||||
|
|
||||||
String sql;
|
|
||||||
String sqlSuffix = "";
|
|
||||||
|
|
||||||
List<MessageFilter> filters = filterList.getFilterList();
|
|
||||||
int i;
|
|
||||||
|
|
||||||
boolean tagsRequired = false;
|
|
||||||
boolean signaturesRequired = false;
|
|
||||||
|
|
||||||
boolean isFirstFilter = true;
|
|
||||||
|
|
||||||
// Check if Tag/Signature tables are required for filtering purposes.
|
|
||||||
|
|
||||||
for (MessageFilter filter : filters){
|
|
||||||
if (filter.getType() == FilterType.TAG){
|
|
||||||
tagsRequired = true;
|
|
||||||
} else if (filter.getType() == FilterType.SIGNER_ID){
|
|
||||||
signaturesRequired = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sql = "SELECT MsgTable.EntryNum, MsgTable.Msg FROM MsgTable";
|
|
||||||
|
|
||||||
if (tagsRequired){
|
|
||||||
sql += " INNER JOIN MsgTagTable ON MsgTable.EntryNum = MsgTagTable.EntryNum";
|
|
||||||
sql += " INNER JOIN TagTable ON TagTable.TagId = MsgTagTable.TagId";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (signaturesRequired){
|
|
||||||
sql += " INNER JOIN SignatureTable ON SignatureTable.EntryNum = MsgTable.EntryNum";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add conditions.
|
|
||||||
|
|
||||||
if (!filters.isEmpty()){
|
|
||||||
sql += " WHERE";
|
|
||||||
|
|
||||||
for (MessageFilter filter : filters){
|
|
||||||
|
|
||||||
if (filter.getType().getNumber() != FilterType.MAX_MESSAGES_VALUE){
|
|
||||||
if (isFirstFilter){
|
|
||||||
isFirstFilter = false;
|
|
||||||
} else{
|
|
||||||
sql += " AND";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (filter.getType().getNumber()){
|
|
||||||
case FilterType.EXACT_ENTRY_VALUE:
|
|
||||||
sql += " MsgTable.EntryNum = ?";
|
|
||||||
break;
|
|
||||||
case FilterType.MAX_ENTRY_VALUE:
|
|
||||||
sql += " MsgTable.EntryNum <= ?";
|
|
||||||
break;
|
|
||||||
case FilterType.MAX_MESSAGES_VALUE:
|
|
||||||
sqlSuffix += " LIMIT = ?";
|
|
||||||
break;
|
|
||||||
case FilterType.MSG_ID_VALUE:
|
|
||||||
sql += " MsgTable.MsgId = ?";
|
|
||||||
break;
|
|
||||||
case FilterType.SIGNER_ID_VALUE:
|
|
||||||
sql += " SignatureTable.SignerId = ?";
|
|
||||||
break;
|
|
||||||
case FilterType.TAG_VALUE:
|
|
||||||
sql += " TagTable.Tag = ?";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sql += sqlSuffix;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make query.
|
|
||||||
|
|
||||||
try {
|
|
||||||
pstmt = connection.prepareStatement(sql);
|
|
||||||
|
|
||||||
// Specify values for filters.
|
|
||||||
|
|
||||||
i = 1;
|
|
||||||
for (MessageFilter filter : filters){
|
|
||||||
|
|
||||||
switch (filter.getType().getNumber()){
|
|
||||||
|
|
||||||
case FilterType.EXACT_ENTRY_VALUE: // Go through.
|
|
||||||
case FilterType.MAX_ENTRY_VALUE:
|
|
||||||
pstmt.setLong(i, filter.getEntry());
|
|
||||||
i++;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FilterType.MSG_ID_VALUE: // Go through.
|
|
||||||
case FilterType.SIGNER_ID_VALUE:
|
|
||||||
pstmt.setBytes(i, filter.getId().toByteArray());
|
|
||||||
i++;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case FilterType.TAG_VALUE:
|
|
||||||
pstmt.setString(i, filter.getTag());
|
|
||||||
break;
|
|
||||||
|
|
||||||
// The max-messages condition is applied as a suffix. Therefore, it is treated differently.
|
|
||||||
case FilterType.MAX_MESSAGES_VALUE:
|
|
||||||
pstmt.setLong(filters.size(), filter.getMaxMessages());
|
|
||||||
break;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Run query.
|
|
||||||
|
|
||||||
messages = pstmt.executeQuery();
|
|
||||||
|
|
||||||
// Compile list of messages.
|
|
||||||
|
|
||||||
sql = "SELECT Signature FROM SignatureTable WHERE EntryNum = ?";
|
|
||||||
pstmt = connection.prepareStatement(sql);
|
|
||||||
|
|
||||||
while (messages.next()){
|
|
||||||
|
|
||||||
// Get entry number and retrieve signatures.
|
|
||||||
|
|
||||||
entryNum = messages.getLong(1);
|
|
||||||
pstmt.setLong(1, entryNum);
|
|
||||||
signatures = pstmt.executeQuery();
|
|
||||||
|
|
||||||
// Create message and append signatures.
|
|
||||||
|
|
||||||
messageBuilder = BulletinBoardMessage.newBuilder()
|
|
||||||
.setEntryNum(entryNum)
|
|
||||||
.setMsg(UnsignedBulletinBoardMessage.parseFrom(messages.getBytes(2)));
|
|
||||||
|
|
||||||
while (signatures.next()){
|
|
||||||
messageBuilder.addSig(Signature.parseFrom(signatures.getBytes(1)));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Finalize message and add to message list.
|
|
||||||
|
|
||||||
resultListBuilder.addMessage(messageBuilder.build());
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
pstmt.close();
|
|
||||||
|
|
||||||
} catch (SQLException e){
|
|
||||||
throw new CommunicationException("Error reading messages from DB: " + e.getMessage());
|
|
||||||
} catch (InvalidProtocolBufferException e) {
|
|
||||||
throw new CommunicationException("Invalid data from DB: " + e.getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
//Combine results and return.
|
|
||||||
|
|
||||||
return resultListBuilder.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -0,0 +1,109 @@
|
||||||
|
package meerkat.bulletinboard.sqlserver;
|
||||||
|
|
||||||
|
import meerkat.protobuf.BulletinBoardAPI.*;
|
||||||
|
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static meerkat.protobuf.BulletinBoardAPI.FilterType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Arbel Deutsch Peled on 09-Dec-15.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class SQLiteQueryProvider implements BulletinBoardSQLServer.SQLQueryProvider {
|
||||||
|
|
||||||
|
String dbConnectionString;
|
||||||
|
|
||||||
|
public SQLiteQueryProvider(String dbAddress) {
|
||||||
|
dbConnectionString = "jdbc:sqlite:" + dbAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getSQLString(QueryType queryType) throws IllegalArgumentException{
|
||||||
|
|
||||||
|
switch(queryType) {
|
||||||
|
case ADD_SIGNATURE:
|
||||||
|
return "INSERT OR IGNORE INTO SignatureTable (EntryNum, SignerId, Signature) VALUES (?,?,?)";
|
||||||
|
case CONNECT_TAG:
|
||||||
|
return "INSERT OR IGNORE INTO MsgTagTable (TagId, EntryNum)"
|
||||||
|
+ " SELECT TagTable.TagId, ? AS EntryNum FROM TagTable WHERE Tag = ?";
|
||||||
|
case FIND_MSG_ID:
|
||||||
|
return "SELECT EntryNum From MsgTable WHERE MsgId = ?";
|
||||||
|
case GET_MESSAGES:
|
||||||
|
return "SELECT MsgTable.EntryNum, MsgTable.Msg FROM MsgTable";
|
||||||
|
case GET_SIGNATURES:
|
||||||
|
return "SELECT Signature FROM SignatureTable WHERE EntryNum = ?";
|
||||||
|
case INSERT_MSG:
|
||||||
|
return "INSERT INTO MsgTable (MsgId, Msg) VALUES(?,?)";
|
||||||
|
case INSERT_NEW_TAG:
|
||||||
|
return "INSERT OR IGNORE INTO TagTable(Tag) VALUES (?)";
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException("Cannot serve a query of type " + queryType);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getCondition(FilterType filterType) throws IllegalArgumentException {
|
||||||
|
|
||||||
|
switch(filterType) {
|
||||||
|
case EXACT_ENTRY:
|
||||||
|
return "MsgTable.EntryNum = ?";
|
||||||
|
case MAX_ENTRY:
|
||||||
|
return "MsgTable.EntryNum <= ?";
|
||||||
|
case MAX_MESSAGES:
|
||||||
|
return "LIMIT = ?";
|
||||||
|
case MSG_ID:
|
||||||
|
return "MsgTable.MsgId = ?";
|
||||||
|
case SIGNER_ID:
|
||||||
|
return "EXISTS (SELECT 1 FROM SignatureTable"
|
||||||
|
+ " WHERE SignatureTable.SignerId = ? AND SignatureTable.EntryNum = MsgTable.EntryNum)";
|
||||||
|
case TAG:
|
||||||
|
return "EXISTS (SELECT 1 FROM TagTable"
|
||||||
|
+ " INNER JOIN MsgTagTable ON TagTable.TagId = MsgTagTable.TagId"
|
||||||
|
+ " WHERE TagTable.Tag = ? AND MsgTagTable.EntryNum = MsgTable.EntryNum)";
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException("Cannot serve a filter of type " + filterType);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getConnectionString() {
|
||||||
|
return dbConnectionString;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> getSchemaCreationCommands() {
|
||||||
|
List<String> list = new LinkedList<String>();
|
||||||
|
|
||||||
|
list.add("CREATE TABLE IF NOT EXISTS MsgTable (EntryNum INTEGER PRIMARY KEY, MsgId BLOB UNIQUE, Msg BLOB)");
|
||||||
|
|
||||||
|
list.add("CREATE TABLE IF NOT EXISTS TagTable (TagId INTEGER PRIMARY KEY, Tag varchar(50) UNIQUE)");
|
||||||
|
list.add("CREATE TABLE IF NOT EXISTS MsgTagTable (EntryNum BLOB, TagId INTEGER, FOREIGN KEY (EntryNum)"
|
||||||
|
+ " REFERENCES MsgTable(EntryNum), FOREIGN KEY (TagId) REFERENCES TagTable(TagId), UNIQUE (EntryNum, TagID))");
|
||||||
|
|
||||||
|
list.add("CREATE TABLE IF NOT EXISTS SignatureTable (EntryNum BLOB, SignerId BLOB, Signature BLOB UNIQUE,"
|
||||||
|
+ " FOREIGN KEY (EntryNum) REFERENCES MsgTable(EntryNum))");
|
||||||
|
list.add("CREATE INDEX IF NOT EXISTS SignerIndex ON SignatureTable(SignerId)");
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> getSchemaDeletionCommands() {
|
||||||
|
List<String> list = new LinkedList<String>();
|
||||||
|
|
||||||
|
list.add("DROP TABLE IF EXISTS MsgTagTable");
|
||||||
|
|
||||||
|
list.add("DROP INDEX IF EXISTS SignerIndex");
|
||||||
|
list.add("DROP TABLE IF EXISTS SignatureTable");
|
||||||
|
|
||||||
|
list.add("DROP TABLE IF EXISTS TagTable");
|
||||||
|
list.add("DROP TABLE IF EXISTS MsgTable");
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
}
|
|
@ -12,7 +12,8 @@ import javax.ws.rs.core.Context;
|
||||||
import javax.ws.rs.core.MediaType;
|
import javax.ws.rs.core.MediaType;
|
||||||
|
|
||||||
import meerkat.bulletinboard.BulletinBoardServer;
|
import meerkat.bulletinboard.BulletinBoardServer;
|
||||||
import meerkat.bulletinboard.sqlserver.SQLiteBulletinBoardServer;
|
import meerkat.bulletinboard.sqlserver.BulletinBoardSQLServer;
|
||||||
|
import meerkat.bulletinboard.sqlserver.SQLiteQueryProvider;
|
||||||
import meerkat.comm.CommunicationException;
|
import meerkat.comm.CommunicationException;
|
||||||
import meerkat.protobuf.BulletinBoardAPI.BoolMsg;
|
import meerkat.protobuf.BulletinBoardAPI.BoolMsg;
|
||||||
import meerkat.protobuf.BulletinBoardAPI.BulletinBoardMessage;
|
import meerkat.protobuf.BulletinBoardAPI.BulletinBoardMessage;
|
||||||
|
@ -51,7 +52,7 @@ public class BulletinBoardWebApp implements BulletinBoardServer, ServletContextL
|
||||||
String dbType = servletContext.getInitParameter("dbtype");
|
String dbType = servletContext.getInitParameter("dbtype");
|
||||||
|
|
||||||
if (dbType.compareTo("SQLite") == 0){
|
if (dbType.compareTo("SQLite") == 0){
|
||||||
bulletinBoard = new SQLiteBulletinBoardServer();
|
bulletinBoard = new BulletinBoardSQLServer(new SQLiteQueryProvider(meerkatDB));
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -1,54 +0,0 @@
|
||||||
package meerkat.bulletinboard;
|
|
||||||
|
|
||||||
import meerkat.bulletinboard.sqlserver.EnhancedSQLiteBulletinBoardServer;
|
|
||||||
import meerkat.comm.CommunicationException;
|
|
||||||
import org.junit.After;
|
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
|
|
||||||
import static org.junit.Assert.fail;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by Arbel Deutsch Peled on 07-Dec-15.
|
|
||||||
*/
|
|
||||||
public class EnhancedSQLiteBulletinBoardServerTest{
|
|
||||||
|
|
||||||
private String testFilename = "EnhancedSQLiteDBTest.db";
|
|
||||||
|
|
||||||
private GenericBulletinBoardServerTest serverTest;
|
|
||||||
|
|
||||||
@Before
|
|
||||||
public void init(){
|
|
||||||
|
|
||||||
File old = new File(testFilename);
|
|
||||||
old.delete();
|
|
||||||
|
|
||||||
BulletinBoardServer bulletinBoardServer = new EnhancedSQLiteBulletinBoardServer();
|
|
||||||
try {
|
|
||||||
bulletinBoardServer.init(testFilename);
|
|
||||||
|
|
||||||
} catch (CommunicationException e) {
|
|
||||||
System.err.println("Failed to initialize server " + e.getMessage());
|
|
||||||
fail("Failed to initialize server " + e.getMessage());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
serverTest = new GenericBulletinBoardServerTest();
|
|
||||||
serverTest.init(bulletinBoardServer);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void bulkTest() {
|
|
||||||
System.err.println("Testing Enhanced SQLite Server");
|
|
||||||
serverTest.testInsert();
|
|
||||||
serverTest.testSimpleTagAndSignature();
|
|
||||||
}
|
|
||||||
|
|
||||||
@After
|
|
||||||
public void close() {
|
|
||||||
serverTest.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -32,6 +32,7 @@ public class GenericBulletinBoardServerTest {
|
||||||
|
|
||||||
protected BulletinBoardServer bulletinBoardServer;
|
protected BulletinBoardServer bulletinBoardServer;
|
||||||
private ECDSASignature signers[];
|
private ECDSASignature signers[];
|
||||||
|
private ByteString[] signerIDs;
|
||||||
|
|
||||||
private Random random;
|
private Random random;
|
||||||
|
|
||||||
|
@ -71,6 +72,7 @@ public class GenericBulletinBoardServerTest {
|
||||||
this.bulletinBoardServer = bulletinBoardServer;
|
this.bulletinBoardServer = bulletinBoardServer;
|
||||||
|
|
||||||
signers = new ECDSASignature[2];
|
signers = new ECDSASignature[2];
|
||||||
|
signerIDs = new ByteString[signers.length];
|
||||||
signers[0] = new ECDSASignature();
|
signers[0] = new ECDSASignature();
|
||||||
signers[1] = new ECDSASignature();
|
signers[1] = new ECDSASignature();
|
||||||
|
|
||||||
|
@ -81,17 +83,21 @@ public class GenericBulletinBoardServerTest {
|
||||||
try {
|
try {
|
||||||
keyStoreBuilder = signers[0].getPKCS12KeyStoreBuilder(keyStream, password);
|
keyStoreBuilder = signers[0].getPKCS12KeyStoreBuilder(keyStream, password);
|
||||||
|
|
||||||
signers[0].loadSigningCertificate(keyStoreBuilder);
|
signers[0].loadSigningCertificate(keyStoreBuilder);
|
||||||
|
|
||||||
signers[0].loadVerificationCertificates(getClass().getResourceAsStream(CERT1_PEM_EXAMPLE));
|
signers[0].loadVerificationCertificates(getClass().getResourceAsStream(CERT1_PEM_EXAMPLE));
|
||||||
|
|
||||||
keyStream = getClass().getResourceAsStream(KEYFILE_EXAMPLE3);
|
keyStream = getClass().getResourceAsStream(KEYFILE_EXAMPLE3);
|
||||||
password = KEYFILE_PASSWORD3.toCharArray();
|
password = KEYFILE_PASSWORD3.toCharArray();
|
||||||
|
|
||||||
keyStoreBuilder = signers[1].getPKCS12KeyStoreBuilder(keyStream, password);
|
keyStoreBuilder = signers[1].getPKCS12KeyStoreBuilder(keyStream, password);
|
||||||
signers[1].loadSigningCertificate(keyStoreBuilder);
|
signers[1].loadSigningCertificate(keyStoreBuilder);
|
||||||
|
|
||||||
signers[1].loadVerificationCertificates(getClass().getResourceAsStream(CERT3_PEM_EXAMPLE));
|
signers[1].loadVerificationCertificates(getClass().getResourceAsStream(CERT3_PEM_EXAMPLE));
|
||||||
|
|
||||||
|
for (int i = 0 ; i < signers.length ; i++) {
|
||||||
|
signerIDs[i] = signers[i].getSignerID();
|
||||||
|
}
|
||||||
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
System.err.println("Failed reading from signature file " + e.getMessage());
|
System.err.println("Failed reading from signature file " + e.getMessage());
|
||||||
|
@ -334,7 +340,7 @@ public class GenericBulletinBoardServerTest {
|
||||||
assertThat(messages.size(), is(expectedMsgCount));
|
assertThat(messages.size(), is(expectedMsgCount));
|
||||||
|
|
||||||
for (BulletinBoardMessage msg : messages) {
|
for (BulletinBoardMessage msg : messages) {
|
||||||
for (int j = 0 ; j < i ; j++) {
|
for (int j = 0 ; j <= i ; j++) {
|
||||||
assertThat((msg.getEntryNum() >>> j) % 2, is((long) 1));
|
assertThat((msg.getEntryNum() >>> j) % 2, is((long) 1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -345,11 +351,11 @@ public class GenericBulletinBoardServerTest {
|
||||||
filterListBuilder = MessageFilterList.newBuilder()
|
filterListBuilder = MessageFilterList.newBuilder()
|
||||||
.addFilter(MessageFilter.newBuilder()
|
.addFilter(MessageFilter.newBuilder()
|
||||||
.setType(FilterType.SIGNER_ID)
|
.setType(FilterType.SIGNER_ID)
|
||||||
.setId(signers[0].getSignerID())
|
.setId(signerIDs[0])
|
||||||
.build())
|
.build())
|
||||||
.addFilter(MessageFilter.newBuilder()
|
.addFilter(MessageFilter.newBuilder()
|
||||||
.setType(FilterType.SIGNER_ID)
|
.setType(FilterType.SIGNER_ID)
|
||||||
.setId(signers[1].getSignerID())
|
.setId(signerIDs[1])
|
||||||
.build()
|
.build()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,122 @@
|
||||||
|
package meerkat.bulletinboard;
|
||||||
|
|
||||||
|
import meerkat.bulletinboard.sqlserver.BulletinBoardSQLServer;
|
||||||
|
import meerkat.bulletinboard.sqlserver.BulletinBoardSQLServer.SQLQueryProvider;
|
||||||
|
import meerkat.bulletinboard.sqlserver.H2QueryProvider;
|
||||||
|
import meerkat.comm.CommunicationException;
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.lang.management.ManagementFactory;
|
||||||
|
import java.lang.management.ThreadMXBean;
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.sql.DriverManager;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.sql.Statement;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Arbel Deutsch Peled on 07-Dec-15.
|
||||||
|
*/
|
||||||
|
public class H2BulletinBoardServerTest {
|
||||||
|
|
||||||
|
private final String dbAddress = "~/meerkatTest";
|
||||||
|
|
||||||
|
private GenericBulletinBoardServerTest serverTest;
|
||||||
|
|
||||||
|
private final ThreadMXBean threadBean = ManagementFactory.getThreadMXBean(); // Used to time the tests
|
||||||
|
|
||||||
|
// @Before
|
||||||
|
public void init(){
|
||||||
|
|
||||||
|
System.err.println("Starting to initialize H2BulletinBoardServerTest");
|
||||||
|
long start = threadBean.getCurrentThreadCpuTime();
|
||||||
|
|
||||||
|
SQLQueryProvider queryProvider = new H2QueryProvider(dbAddress);
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
Connection conn = DriverManager.getConnection(queryProvider.getConnectionString());
|
||||||
|
Statement stmt = conn.createStatement();
|
||||||
|
|
||||||
|
List<String> deletionQueries = queryProvider.getSchemaDeletionCommands();
|
||||||
|
|
||||||
|
for (String deletionQuery : deletionQueries) {
|
||||||
|
stmt.execute(deletionQuery);
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (SQLException e) {
|
||||||
|
System.err.println(e.getMessage());
|
||||||
|
fail(e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
BulletinBoardServer bulletinBoardServer = new BulletinBoardSQLServer(queryProvider);
|
||||||
|
try {
|
||||||
|
bulletinBoardServer.init("");
|
||||||
|
|
||||||
|
} catch (CommunicationException e) {
|
||||||
|
System.err.println(e.getMessage());
|
||||||
|
fail(e.getMessage());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
serverTest = new GenericBulletinBoardServerTest();
|
||||||
|
try {
|
||||||
|
serverTest.init(bulletinBoardServer);
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.err.println(e.getMessage());
|
||||||
|
fail(e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
long end = threadBean.getCurrentThreadCpuTime();
|
||||||
|
System.err.println("Finished initializing H2BulletinBoardServerTest");
|
||||||
|
System.err.println("Time of operation: " + (end - start));
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Test
|
||||||
|
public void bulkTest() {
|
||||||
|
System.err.println("Starting bulkTest of H2BulletinBoardServerTest");
|
||||||
|
long start = threadBean.getCurrentThreadCpuTime();
|
||||||
|
|
||||||
|
try {
|
||||||
|
serverTest.testInsert();
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.err.println(e.getMessage());
|
||||||
|
fail(e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
try{
|
||||||
|
serverTest.testSimpleTagAndSignature();
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.err.println(e.getMessage());
|
||||||
|
fail(e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
try{
|
||||||
|
serverTest.testEnhancedTagsAndSignatures();
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.err.println(e.getMessage());
|
||||||
|
fail(e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
long end = threadBean.getCurrentThreadCpuTime();
|
||||||
|
System.err.println("Finished bulkTest of H2BulletinBoardServerTest");
|
||||||
|
System.err.println("Time of operation: " + (end - start));
|
||||||
|
}
|
||||||
|
|
||||||
|
// @After
|
||||||
|
public void close() {
|
||||||
|
System.err.println("Starting to close H2BulletinBoardServerTest");
|
||||||
|
long start = threadBean.getCurrentThreadCpuTime();
|
||||||
|
|
||||||
|
serverTest.close();
|
||||||
|
|
||||||
|
long end = threadBean.getCurrentThreadCpuTime();
|
||||||
|
System.err.println("Finished closing H2BulletinBoardServerTest");
|
||||||
|
System.err.println("Time of operation: " + (end - start));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,127 @@
|
||||||
|
package meerkat.bulletinboard;
|
||||||
|
|
||||||
|
import meerkat.bulletinboard.sqlserver.BulletinBoardSQLServer;
|
||||||
|
import meerkat.bulletinboard.sqlserver.BulletinBoardSQLServer.SQLQueryProvider;
|
||||||
|
import meerkat.bulletinboard.sqlserver.MySQLQueryProvider;
|
||||||
|
import meerkat.bulletinboard.sqlserver.SQLiteQueryProvider;
|
||||||
|
import meerkat.comm.CommunicationException;
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.lang.management.ManagementFactory;
|
||||||
|
import java.lang.management.ThreadMXBean;
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.sql.DriverManager;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.sql.Statement;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Arbel Deutsch Peled on 07-Dec-15.
|
||||||
|
*/
|
||||||
|
public class MySQLBulletinBoardServerTest {
|
||||||
|
|
||||||
|
private final String dbAddress = "//localhost:3306/meerkat";
|
||||||
|
private final String username = "arbel";
|
||||||
|
private final String password = "mypass";
|
||||||
|
|
||||||
|
private GenericBulletinBoardServerTest serverTest;
|
||||||
|
|
||||||
|
private final ThreadMXBean threadBean = ManagementFactory.getThreadMXBean(); // Used to time the tests
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void init(){
|
||||||
|
|
||||||
|
System.err.println("Starting to initialize MySQLBulletinBoardServerTest");
|
||||||
|
long start = threadBean.getCurrentThreadCpuTime();
|
||||||
|
|
||||||
|
SQLQueryProvider queryProvider = new MySQLQueryProvider(dbAddress,username,password);
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
Connection conn = DriverManager.getConnection(queryProvider.getConnectionString());
|
||||||
|
Statement stmt = conn.createStatement();
|
||||||
|
|
||||||
|
List<String> deletionQueries = queryProvider.getSchemaDeletionCommands();
|
||||||
|
|
||||||
|
for (String deletionQuery : deletionQueries) {
|
||||||
|
stmt.execute(deletionQuery);
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (SQLException e) {
|
||||||
|
System.err.println(e.getMessage());
|
||||||
|
fail(e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
BulletinBoardServer bulletinBoardServer = new BulletinBoardSQLServer(queryProvider);
|
||||||
|
try {
|
||||||
|
bulletinBoardServer.init("");
|
||||||
|
|
||||||
|
} catch (CommunicationException e) {
|
||||||
|
System.err.println(e.getMessage());
|
||||||
|
fail(e.getMessage());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
serverTest = new GenericBulletinBoardServerTest();
|
||||||
|
try {
|
||||||
|
serverTest.init(bulletinBoardServer);
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.err.println(e.getMessage());
|
||||||
|
fail(e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
long end = threadBean.getCurrentThreadCpuTime();
|
||||||
|
System.err.println("Finished initializing MySQLBulletinBoardServerTest");
|
||||||
|
System.err.println("Time of operation: " + (end - start));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void bulkTest() {
|
||||||
|
System.err.println("Starting bulkTest of MySQLBulletinBoardServerTest");
|
||||||
|
long start = threadBean.getCurrentThreadCpuTime();
|
||||||
|
|
||||||
|
try {
|
||||||
|
serverTest.testInsert();
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.err.println(e.getMessage());
|
||||||
|
fail(e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
try{
|
||||||
|
serverTest.testSimpleTagAndSignature();
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.err.println(e.getMessage());
|
||||||
|
fail(e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
try{
|
||||||
|
serverTest.testEnhancedTagsAndSignatures();
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.err.println(e.getMessage());
|
||||||
|
fail(e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
long end = threadBean.getCurrentThreadCpuTime();
|
||||||
|
System.err.println("Finished bulkTest of MySQLBulletinBoardServerTest");
|
||||||
|
System.err.println("Time of operation: " + (end - start));
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void close() {
|
||||||
|
System.err.println("Starting to close MySQLBulletinBoardServerTest");
|
||||||
|
long start = threadBean.getCurrentThreadCpuTime();
|
||||||
|
|
||||||
|
serverTest.close();
|
||||||
|
|
||||||
|
long end = threadBean.getCurrentThreadCpuTime();
|
||||||
|
System.err.println("Finished closing MySQLBulletinBoardServerTest");
|
||||||
|
System.err.println("Time of operation: " + (end - start));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
package meerkat.bulletinboard;
|
package meerkat.bulletinboard;
|
||||||
|
|
||||||
import meerkat.bulletinboard.sqlserver.SQLiteBulletinBoardServer;
|
import meerkat.bulletinboard.sqlserver.BulletinBoardSQLServer;
|
||||||
|
import meerkat.bulletinboard.sqlserver.SQLiteQueryProvider;
|
||||||
import meerkat.comm.CommunicationException;
|
import meerkat.comm.CommunicationException;
|
||||||
import meerkat.protobuf.*;
|
import meerkat.protobuf.*;
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
|
@ -36,9 +37,9 @@ public class SQLiteBulletinBoardServerTest{
|
||||||
File old = new File(testFilename);
|
File old = new File(testFilename);
|
||||||
old.delete();
|
old.delete();
|
||||||
|
|
||||||
BulletinBoardServer bulletinBoardServer = new SQLiteBulletinBoardServer();
|
BulletinBoardServer bulletinBoardServer = new BulletinBoardSQLServer(new SQLiteQueryProvider(testFilename));
|
||||||
try {
|
try {
|
||||||
bulletinBoardServer.init(testFilename);
|
bulletinBoardServer.init("");
|
||||||
|
|
||||||
} catch (CommunicationException e) {
|
} catch (CommunicationException e) {
|
||||||
System.err.println(e.getMessage());
|
System.err.println(e.getMessage());
|
||||||
|
@ -66,12 +67,25 @@ public class SQLiteBulletinBoardServerTest{
|
||||||
|
|
||||||
try {
|
try {
|
||||||
serverTest.testInsert();
|
serverTest.testInsert();
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.err.println(e.getMessage());
|
||||||
|
fail(e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
try{
|
||||||
serverTest.testSimpleTagAndSignature();
|
serverTest.testSimpleTagAndSignature();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
System.err.println(e.getMessage());
|
System.err.println(e.getMessage());
|
||||||
fail(e.getMessage());
|
fail(e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try{
|
||||||
|
serverTest.testEnhancedTagsAndSignatures();
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.err.println(e.getMessage());
|
||||||
|
fail(e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
long end = threadBean.getCurrentThreadCpuTime();
|
long end = threadBean.getCurrentThreadCpuTime();
|
||||||
System.err.println("Finished bulkTest of SQLiteBulletinBoardServerTest");
|
System.err.println("Finished bulkTest of SQLiteBulletinBoardServerTest");
|
||||||
System.err.println("Time of operation: " + (end - start));
|
System.err.println("Time of operation: " + (end - start));
|
||||||
|
|
Binary file not shown.
|
@ -1,6 +0,0 @@
|
||||||
#Mon Oct 26 15:30:44 IST 2015
|
|
||||||
distributionBase=GRADLE_USER_HOME
|
|
||||||
distributionPath=wrapper/dists
|
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
|
||||||
zipStorePath=wrapper/dists
|
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-2.9-bin.zip
|
|
Loading…
Reference in New Issue