Added named parameters to the BulletinBoardSQLServer.

Added support for H2 SQL engine.
Further generalization of the BulletinBoardSQLServer.
Bulletin-Board-Client-phase_1
Arbel Deutsch Peled 2015-12-12 11:54:52 +02:00
parent 3de54f16a2
commit 520697d121
12 changed files with 502 additions and 281 deletions

View File

@ -47,6 +47,7 @@ dependencies {
compile 'org.glassfish.jersey.containers:jersey-container-servlet:2.22.+' compile 'org.glassfish.jersey.containers:jersey-container-servlet:2.22.+'
// JDBC connections // JDBC connections
compile 'org.springframework:spring-jdbc:4.2.+'
compile 'org.xerial:sqlite-jdbc:3.7.+' compile 'org.xerial:sqlite-jdbc:3.7.+'
compile 'mysql:mysql-connector-java:5.1.+' compile 'mysql:mysql-connector-java:5.1.+'
compile 'com.h2database:h2:1.0.+' compile 'com.h2database:h2:1.0.+'
@ -73,8 +74,14 @@ dependencies {
test { test {
exclude '**/*SQLite*Test*' exclude '**/*SQLite*Test*'
exclude '**/*H2*Test*'
exclude '**/*MySql*Test'
exclude '**/*IntegrationTest*' exclude '**/*IntegrationTest*'
outputs.upToDateWhen { false } }
task dbTest(type: Test) {
include '**/*H2*Test*'
include '**/*MySql*Test'
} }
task integrationTest(type: Test) { task integrationTest(type: Test) {

View File

@ -3,10 +3,12 @@ package meerkat.bulletinboard.sqlserver;
import java.sql.*; import java.sql.*;
import java.util.*; import java.util.*;
import com.google.protobuf.InvalidProtocolBufferException;
import com.google.protobuf.ProtocolStringList; import com.google.protobuf.ProtocolStringList;
import meerkat.bulletinboard.BulletinBoardServer; import meerkat.bulletinboard.BulletinBoardServer;
import meerkat.bulletinboard.sqlserver.mappers.EntryNumMapper;
import meerkat.bulletinboard.sqlserver.mappers.MessageMapper;
import meerkat.bulletinboard.sqlserver.mappers.SignatureMapper;
import meerkat.comm.CommunicationException; import meerkat.comm.CommunicationException;
import meerkat.protobuf.BulletinBoardAPI.*; import meerkat.protobuf.BulletinBoardAPI.*;
import meerkat.protobuf.Crypto.Signature; import meerkat.protobuf.Crypto.Signature;
@ -14,6 +16,13 @@ import meerkat.protobuf.Crypto.SignatureVerificationKey;
import meerkat.crypto.Digest; import meerkat.crypto.Digest;
import meerkat.crypto.concrete.SHA256Digest; import meerkat.crypto.concrete.SHA256Digest;
import javax.sql.DataSource;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.support.GeneratedKeyHolder;
import org.springframework.jdbc.support.KeyHolder;
/** /**
* This is a generic SQL implementation of the BulletinBoardServer API. * This is a generic SQL implementation of the BulletinBoardServer API.
*/ */
@ -27,16 +36,80 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{
/** /**
* Allowed query types. * Allowed query types.
* Note that each query returned has to comply with the placeholder ("?") requirements written in its comment. * Note that each query returned has to comply with the parameter names specified ny getParamNames
*/ */
public static enum QueryType { public static enum QueryType {
FIND_MSG_ID, // Placeholders for: MsgId
INSERT_MSG, // Placeholders for: MsgId, Msg FIND_MSG_ID(new String[] {"MsgId"}),
INSERT_NEW_TAG, // Placeholders for: Tag INSERT_MSG(new String[] {"MsgId","Msg"}),
CONNECT_TAG, // Placeholders for: EntryNum, Tag INSERT_NEW_TAG(new String[] {"Tag"}),
ADD_SIGNATURE, // Placeholders for: EntryNum, SignerId, Signature CONNECT_TAG(new String[] {"EntryNum","Tag"}),
GET_SIGNATURES, // Placeholders for: EntryNum ADD_SIGNATURE(new String[] {"EntryNum","SignerId","Signature"}),
GET_MESSAGES // Placeholders for: N/A GET_SIGNATURES(new String[] {"EntryNum"}),
GET_MESSAGES(new String[] {});
private String[] paramNames;
private QueryType(String[] paramNames) {
this.paramNames = paramNames;
}
public String[] getParamNames() {
return paramNames;
}
}
/**
* This enum provides the standard translation between a filter type and the corresponding parameter name in the SQL query
*/
public static enum FilterTypeParam {
ENTRY_NUM("EntryNum", Types.INTEGER),
MSG_ID("MsgId", Types.BLOB),
SIGNER_ID("SignerId", Types.BLOB),
TAG("Tag", Types.VARCHAR),
LIMIT("Limit", Types.INTEGER);
private FilterTypeParam(String paramName, int paramType) {
this.paramName = paramName;
this.paramType = paramType;
}
private String paramName;
private int paramType;
public static FilterTypeParam getFilterTypeParamName(FilterType filterType) {
switch (filterType) {
case MSG_ID:
return MSG_ID;
case EXACT_ENTRY: // Go through
case MAX_ENTRY:
return ENTRY_NUM;
case SIGNER_ID:
return SIGNER_ID;
case TAG:
return TAG;
case MAX_MESSAGES:
return LIMIT;
default:
return null;
}
}
public String getParamName() {
return paramName;
}
public int getParamType() {
return paramType;
}
} }
/** /**
@ -46,12 +119,21 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{
*/ */
public String getSQLString(QueryType queryType) throws IllegalArgumentException; public String getSQLString(QueryType queryType) throws IllegalArgumentException;
public String getCondition(FilterType filterType) throws IllegalArgumentException; /**
* Used to retrieve a condition to add to an SQL statement that will make the result comply with the filter type
* @param filterType is the filter type
* @param serialNum is a unique number used to identify the condition variables from other condition instances
* @return The SQL string for the condition
* @throws IllegalArgumentException if the filter type used is not supported
*/
public String getCondition(FilterType filterType, int serialNum) throws IllegalArgumentException;
public String getConditionParamTypeName(FilterType filterType) throws IllegalArgumentException;
/** /**
* @return the string needed in order to connect to the DB. * @return the string needed in order to connect to the DB.
*/ */
public String getConnectionString(); public DataSource getDataSource();
/** /**
* This is used to get a list of queries that together create the schema needed for the DB. * This is used to get a list of queries that together create the schema needed for the DB.
@ -70,6 +152,30 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{
} }
private Object getParam(MessageFilter messageFilter) {
switch (messageFilter.getType()) {
case MSG_ID: // Go through
case SIGNER_ID:
return messageFilter.getId().toByteArray();
case EXACT_ENTRY: // Go through
case MAX_ENTRY:
return messageFilter.getEntry();
case TAG:
return messageFilter.getTag();
case MAX_MESSAGES:
return messageFilter.getMaxMessages();
default:
return null;
}
}
/** /**
* This class implements a comparator for the MessageFilter class * This class implements a comparator for the MessageFilter class
* The comparison is done solely by comparing the type of the filter * The comparison is done solely by comparing the type of the filter
@ -85,7 +191,7 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{
protected SQLQueryProvider sqlQueryProvider; protected SQLQueryProvider sqlQueryProvider;
protected Connection connection; protected NamedParameterJdbcTemplate jdbcTemplate;
protected Digest digest; protected Digest digest;
@ -103,18 +209,19 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{
this.sqlQueryProvider = sqlQueryProvider; this.sqlQueryProvider = sqlQueryProvider;
} }
/**
* This method creates the schema in the given DB to prepare for future transactions
* It does not assume anything about the current state of the database
* @throws SQLException
*/
private void createSchema() throws SQLException { private void createSchema() throws SQLException {
final int TIMEOUT = 20; final int TIMEOUT = 20;
Statement statement = connection.createStatement();
statement.setQueryTimeout(TIMEOUT);
for (String command : sqlQueryProvider.getSchemaCreationCommands()) { for (String command : sqlQueryProvider.getSchemaCreationCommands()) {
statement.executeUpdate(command); jdbcTemplate.update(command,(Map) null);
} }
statement.close();
} }
/** /**
@ -126,13 +233,7 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{
digest = new SHA256Digest(); digest = new SHA256Digest();
try{ jdbcTemplate = new NamedParameterJdbcTemplate(sqlQueryProvider.getDataSource());
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 { try {
createSchema(); createSchema();
@ -161,25 +262,17 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{
*/ */
protected void insertNewTags(String[] tags) throws SQLException { protected void insertNewTags(String[] tags) throws SQLException {
PreparedStatement pstmt;
String sql; String sql;
try {
sql = sqlQueryProvider.getSQLString(SQLQueryProvider.QueryType.INSERT_NEW_TAG); sql = sqlQueryProvider.getSQLString(SQLQueryProvider.QueryType.INSERT_NEW_TAG);
pstmt = connection.prepareStatement(sql); Map namedParameters[] = new HashMap[tags.length];
for (String tag : tags){ for (int i = 0 ; i < tags.length ; i++){
pstmt.setString(1, tag); namedParameters[i] = new HashMap();
pstmt.addBatch(); namedParameters[i].put("Tag", tags[i]);
} }
pstmt.executeBatch(); jdbcTemplate.batchUpdate(sql, namedParameters);
pstmt.close();
} catch (SQLException e){
throw new SQLException("Error adding new tags to table: " + e.getMessage());
}
} }
@ -201,9 +294,9 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{
return boolToBoolMsg(false); return boolToBoolMsg(false);
} }
PreparedStatement pstmt;
ResultSet rs;
String sql; String sql;
Map[] namedParameterArray;
byte[] msgID; byte[] msgID;
long entryNum; long entryNum;
@ -222,35 +315,27 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{
// Add message to table if needed and store entry number of message. // Add message to table if needed and store entry number of message.
try {
sql = sqlQueryProvider.getSQLString(SQLQueryProvider.QueryType.FIND_MSG_ID); sql = sqlQueryProvider.getSQLString(SQLQueryProvider.QueryType.FIND_MSG_ID);
pstmt = connection.prepareStatement(sql); Map namedParameters = new HashMap();
pstmt.setBytes(1, msgID); namedParameters.put("MsgId",msgID);
rs = pstmt.executeQuery();
if (rs.next()){ List<Long> entryNums = jdbcTemplate.query(sql, new MapSqlParameterSource(namedParameters), new EntryNumMapper());
entryNum = rs.getLong(1); if (entryNums.size() > 0){
entryNum = entryNums.get(0);
} else{ } else{
sql = sqlQueryProvider.getSQLString(SQLQueryProvider.QueryType.INSERT_MSG); sql = sqlQueryProvider.getSQLString(SQLQueryProvider.QueryType.INSERT_MSG);
pstmt = connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS); namedParameters.put("Msg", msg.getMsg().toByteArray());
pstmt.setBytes(1, msgID);
pstmt.setBytes(2, msg.getMsg().toByteArray());
pstmt.executeUpdate();
rs = pstmt.getGeneratedKeys(); KeyHolder keyHolder = new GeneratedKeyHolder();
rs.next(); jdbcTemplate.update(sql,new MapSqlParameterSource(namedParameters),keyHolder);
entryNum = rs.getLong(1);
} entryNum = keyHolder.getKey().longValue();
pstmt.close();
} catch (SQLException e) {
throw new CommunicationException("Error inserting into MsgTable: " + e.getMessage());
} }
// Retrieve tags and store new ones in tag table. // Retrieve tags and store new ones in tag table.
@ -269,23 +354,17 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{
// Connect message to tags. // Connect message to tags.
try{
sql = sqlQueryProvider.getSQLString(SQLQueryProvider.QueryType.CONNECT_TAG); sql = sqlQueryProvider.getSQLString(SQLQueryProvider.QueryType.CONNECT_TAG);
pstmt = connection.prepareStatement(sql);
pstmt.setLong(1, entryNum); namedParameterArray = new HashMap[tags.length];
for (String tag : tags){ for (int i = 0 ; i < tags.length ; i++) {
pstmt.setString(2, tag); namedParameterArray[i] = new HashMap();
pstmt.addBatch(); namedParameterArray[i].put("EntryNum", entryNum);
namedParameterArray[i].put("Tag", tags[i]);
} }
pstmt.executeBatch(); jdbcTemplate.batchUpdate(sql, namedParameterArray);
pstmt.close();
} catch (SQLException e) {
throw new CommunicationException("Error Linking tags: " + e.getMessage());
}
// Retrieve signatures. // Retrieve signatures.
@ -295,169 +374,110 @@ public class BulletinBoardSQLServer implements BulletinBoardServer{
// Connect message to signatures. // Connect message to signatures.
try{
sql = sqlQueryProvider.getSQLString(SQLQueryProvider.QueryType.ADD_SIGNATURE); sql = sqlQueryProvider.getSQLString(SQLQueryProvider.QueryType.ADD_SIGNATURE);
pstmt = connection.prepareStatement(sql);
pstmt.setLong(1, entryNum); namedParameterArray = new HashMap[signatures.length];
for (Signature sig : signatures){ for (int i = 0 ; i < signatures.length ; i++) {
namedParameterArray[i] = new HashMap();
pstmt.setBytes(2, sig.getSignerId().toByteArray()); namedParameterArray[i].put("EntryNum", entryNum);
pstmt.setBytes(3, sig.toByteArray()); namedParameterArray[i].put("SignerId", signatures[i].getSignerId().toByteArray());
pstmt.addBatch(); namedParameterArray[i].put("Signature", signatures[i].toByteArray());
} }
pstmt.executeBatch(); jdbcTemplate.batchUpdate(sql,namedParameterArray);
pstmt.close();
} catch (SQLException e) {
throw new CommunicationException("Error Linking tags: " + e.getMessage());
}
return boolToBoolMsg(true); return boolToBoolMsg(true);
} }
@Override @Override
public BulletinBoardMessageList readMessages(MessageFilterList filterList) throws CommunicationException { public BulletinBoardMessageList readMessages(MessageFilterList filterList) throws CommunicationException {
PreparedStatement pstmt;
ResultSet messages, signatures;
long entryNum;
BulletinBoardMessageList.Builder resultListBuilder = BulletinBoardMessageList.newBuilder(); BulletinBoardMessageList.Builder resultListBuilder = BulletinBoardMessageList.newBuilder();
BulletinBoardMessage.Builder messageBuilder;
String sql; String sql;
MapSqlParameterSource namedParameters;
int paramNum;
MessageMapper messageMapper = new MessageMapper();
SignatureMapper signatureMapper = new SignatureMapper();
List<MessageFilter> filters = new ArrayList<MessageFilter>(filterList.getFilterList()); List<MessageFilter> filters = new ArrayList<MessageFilter>(filterList.getFilterList());
int i;
boolean tagsRequired = false;
boolean signaturesRequired = false;
boolean isFirstFilter = true; boolean isFirstFilter = true;
Collections.sort(filters, new FilterTypeComparator()); Collections.sort(filters, new FilterTypeComparator());
// Check if Tag/Signature tables are required for filtering purposes. // Check if Tag/Signature tables are required for filtering purposes
sql = sqlQueryProvider.getSQLString(SQLQueryProvider.QueryType.GET_MESSAGES); sql = sqlQueryProvider.getSQLString(SQLQueryProvider.QueryType.GET_MESSAGES);
// Add conditions. // Add conditions
if (!filters.isEmpty()){ namedParameters = new MapSqlParameterSource();
if (!filters.isEmpty()) {
sql += " WHERE "; sql += " WHERE ";
for (MessageFilter filter : filters){ for (paramNum = 0 ; paramNum < filters.size() ; paramNum++) {
if (filter.getType().getNumber() != FilterType.MAX_MESSAGES_VALUE){ MessageFilter filter = filters.get(paramNum);
if (isFirstFilter){
if (filter.getType().getNumber() != FilterType.MAX_MESSAGES_VALUE) {
if (isFirstFilter) {
isFirstFilter = false; isFirstFilter = false;
} else{ } else {
sql += " AND "; sql += " AND ";
} }
} }
sql += sqlQueryProvider.getCondition(filter.getType()); sql += sqlQueryProvider.getCondition(filter.getType(), paramNum);
SQLQueryProvider.FilterTypeParam filterTypeParam = SQLQueryProvider.FilterTypeParam.getFilterTypeParamName(filter.getType());
namedParameters.addValue(
filterTypeParam.getParamName() + Integer.toString(paramNum),
getParam(filter),
filterTypeParam.getParamType(),
sqlQueryProvider.getConditionParamTypeName(filter.getType()));
} }
} }
// Make query. // Run query
try { List<BulletinBoardMessage.Builder> msgBuilders = jdbcTemplate.query(sql, namedParameters, messageMapper);
pstmt = connection.prepareStatement(sql);
// Specify values for filters.
i = 1; // Compile list of messages
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); sql = sqlQueryProvider.getSQLString(SQLQueryProvider.QueryType.GET_SIGNATURES);
pstmt = connection.prepareStatement(sql);
while (messages.next()){ for (BulletinBoardMessage.Builder msgBuilder : msgBuilders) {
// Get entry number and retrieve signatures. // Retrieve signatures
entryNum = messages.getLong(1); namedParameters = new MapSqlParameterSource();
pstmt.setLong(1, entryNum); namedParameters.addValue("EntryNum", msgBuilder.getEntryNum());
signatures = pstmt.executeQuery();
// Create message and append signatures. List<Signature> signatures = jdbcTemplate.query(sql, namedParameters, signatureMapper);
messageBuilder = BulletinBoardMessage.newBuilder() // Append signatures
.setEntryNum(entryNum) msgBuilder.addAllSig(signatures);
.setMsg(UnsignedBulletinBoardMessage.parseFrom(messages.getBytes(2)));
while (signatures.next()){
messageBuilder.addSig(Signature.parseFrom(signatures.getBytes(1)));
}
// Finalize message and add to message list. // Finalize message and add to message list.
resultListBuilder.addMessage(messageBuilder.build()); resultListBuilder.addMessage(msgBuilder.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. //Combine results and return.
return resultListBuilder.build(); return resultListBuilder.build();
} }
@Override @Override
public void close() throws CommunicationException { public void close() {}
try{
connection.close();
} catch (SQLException e) {
throw new CommunicationException("Couldn't close connection to the database");
}
}
} }

View File

@ -1,7 +1,12 @@
package meerkat.bulletinboard.sqlserver; package meerkat.bulletinboard.sqlserver;
import meerkat.protobuf.BulletinBoardAPI.FilterType; import meerkat.protobuf.BulletinBoardAPI.FilterType;
import org.h2.jdbcx.JdbcDataSource;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
@ -11,10 +16,14 @@ import java.util.List;
public class H2QueryProvider implements BulletinBoardSQLServer.SQLQueryProvider { public class H2QueryProvider implements BulletinBoardSQLServer.SQLQueryProvider {
private String dbConnectionString; private String dbAddress;
private String username;
private String password;
public H2QueryProvider(String dbAddress) { public H2QueryProvider(String dbAddress, String username, String password) {
dbConnectionString = "jdbc:h2:" + dbAddress + ";MODE=MYSQL"; this.dbAddress = dbAddress;
this.username = username;
this.password = password;
} }
@ -23,20 +32,33 @@ public class H2QueryProvider implements BulletinBoardSQLServer.SQLQueryProvider
switch(queryType) { switch(queryType) {
case ADD_SIGNATURE: case ADD_SIGNATURE:
return "INSERT IGNORE INTO SignatureTable (EntryNum, SignerId, Signature) VALUES (?,?,?)"; return "INSERT INTO SignatureTable (EntryNum, SignerId, Signature)"
+ " SELECT DISTINCT :EntryNum AS Entry, :SignerId AS Id, :Signature AS Sig FROM UtilityTable AS Temp"
+ " WHERE NOT EXISTS"
+ " (SELECT 1 FROM SignatureTable AS SubTable WHERE SubTable.SignerId = :SignerId AND SubTable.EntryNum = :EntryNum)";
case CONNECT_TAG: case CONNECT_TAG:
return "INSERT IGNORE INTO MsgTagTable (TagId, EntryNum)" return "INSERT INTO MsgTagTable (TagId, EntryNum)"
+ " SELECT TagTable.TagId, ? AS EntryNum FROM TagTable WHERE Tag = ?"; + " SELECT DISTINCT TagTable.TagId, :EntryNum AS NewEntry FROM TagTable WHERE Tag = :Tag"
+ " AND NOT EXISTS (SELECT 1 FROM MsgTagTable AS SubTable WHERE SubTable.TagId = TagTable.TagId"
+ " AND SubTable.EntryNum = :EntryNum)";
case FIND_MSG_ID: case FIND_MSG_ID:
return "SELECT EntryNum From MsgTable WHERE MsgId = ?"; return "SELECT EntryNum From MsgTable WHERE MsgId = :MsgId";
case GET_MESSAGES: case GET_MESSAGES:
return "SELECT MsgTable.EntryNum, MsgTable.Msg FROM MsgTable"; return "SELECT MsgTable.EntryNum, MsgTable.Msg FROM MsgTable";
case GET_SIGNATURES: case GET_SIGNATURES:
return "SELECT Signature FROM SignatureTable WHERE EntryNum = ?"; return "SELECT Signature FROM SignatureTable WHERE EntryNum = :EntryNum";
case INSERT_MSG: case INSERT_MSG:
return "INSERT INTO MsgTable (MsgId, Msg) VALUES(?,?)"; return "INSERT INTO MsgTable (MsgId, Msg) VALUES(:MsgId,:Msg)";
case INSERT_NEW_TAG: case INSERT_NEW_TAG:
return "INSERT IGNORE INTO TagTable(Tag) VALUES (?)"; return "INSERT INTO TagTable(Tag) SELECT DISTINCT :Tag AS NewTag FROM UtilityTable WHERE"
+ " NOT EXISTS (SELECT 1 FROM TagTable AS SubTable WHERE SubTable.Tag = :Tag)";
default: default:
throw new IllegalArgumentException("Cannot serve a query of type " + queryType); throw new IllegalArgumentException("Cannot serve a query of type " + queryType);
} }
@ -44,24 +66,26 @@ public class H2QueryProvider implements BulletinBoardSQLServer.SQLQueryProvider
} }
@Override @Override
public String getCondition(FilterType filterType) throws IllegalArgumentException { public String getCondition(FilterType filterType, int serialNum) throws IllegalArgumentException {
String serialString = Integer.toString(serialNum);
switch(filterType) { switch(filterType) {
case EXACT_ENTRY: case EXACT_ENTRY:
return "MsgTable.EntryNum = ?"; return "MsgTable.EntryNum = :EntryNum" + serialString;
case MAX_ENTRY: case MAX_ENTRY:
return "MsgTable.EntryNum <= ?"; return "MsgTable.EntryNum <= :EntryNum" + serialString;
case MAX_MESSAGES: case MAX_MESSAGES:
return "LIMIT ?"; return "LIMIT :Limit" + serialString;
case MSG_ID: case MSG_ID:
return "MsgTable.MsgId = ?"; return "MsgTable.MsgId = MsgId" + serialString;
case SIGNER_ID: case SIGNER_ID:
return "EXISTS (SELECT 1 FROM SignatureTable" return "EXISTS (SELECT 1 FROM SignatureTable"
+ " WHERE SignatureTable.SignerId = ? AND SignatureTable.EntryNum = MsgTable.EntryNum)"; + " WHERE SignatureTable.SignerId = :SignerId" + serialString + " AND SignatureTable.EntryNum = MsgTable.EntryNum)";
case TAG: case TAG:
return "EXISTS (SELECT 1 FROM TagTable" return "EXISTS (SELECT 1 FROM TagTable"
+ " INNER JOIN MsgTagTable ON TagTable.TagId = MsgTagTable.TagId" + " INNER JOIN MsgTagTable ON TagTable.TagId = MsgTagTable.TagId"
+ " WHERE TagTable.Tag = ? AND MsgTagTable.EntryNum = MsgTable.EntryNum)"; + " WHERE TagTable.Tag = :Tag" + serialString + " AND MsgTagTable.EntryNum = MsgTable.EntryNum)";
default: default:
throw new IllegalArgumentException("Cannot serve a filter of type " + filterType); throw new IllegalArgumentException("Cannot serve a filter of type " + filterType);
} }
@ -69,8 +93,43 @@ public class H2QueryProvider implements BulletinBoardSQLServer.SQLQueryProvider
} }
@Override @Override
public String getConnectionString() { public String getConditionParamTypeName(FilterType filterType) throws IllegalArgumentException {
return dbConnectionString;
switch(filterType) {
case EXACT_ENTRY: // Go through
case MAX_ENTRY: // Go through
case MAX_MESSAGES:
return "INT";
case MSG_ID: // Go through
case SIGNER_ID:
return "TINYBLOB";
case TAG:
return "VARCHAR";
default:
throw new IllegalArgumentException("Cannot serve a filter of type " + filterType);
}
}
@Override
public DataSource getDataSource() {
// TODO: Fix this
JdbcDataSource dataSource = new JdbcDataSource();
dataSource.setURL("jdbc:h2:~/" + dbAddress + "/meerkat"); // TODO: make this generic
dataSource.setUser(username);
dataSource.setPassword(password);
// Context ctx = null;
// try {
// ctx = new InitialContext();
// ctx.bind("jdbc/dsName", dataSource);
// } catch (NamingException e) {
// e.printStackTrace();
// }
return dataSource;
} }
@ -80,7 +139,7 @@ public class H2QueryProvider implements BulletinBoardSQLServer.SQLQueryProvider
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 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 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," list.add("CREATE TABLE IF NOT EXISTS MsgTagTable (EntryNum INT, TagId INT,"
+ " FOREIGN KEY (EntryNum) REFERENCES MsgTable(EntryNum)," + " FOREIGN KEY (EntryNum) REFERENCES MsgTable(EntryNum),"
@ -90,7 +149,13 @@ public class H2QueryProvider implements BulletinBoardSQLServer.SQLQueryProvider
list.add("CREATE TABLE IF NOT EXISTS SignatureTable (EntryNum INT, SignerId TINYBLOB, Signature TINYBLOB UNIQUE," list.add("CREATE TABLE IF NOT EXISTS SignatureTable (EntryNum INT, SignerId TINYBLOB, Signature TINYBLOB UNIQUE,"
+ " FOREIGN KEY (EntryNum) REFERENCES MsgTable(EntryNum))"); + " FOREIGN KEY (EntryNum) REFERENCES MsgTable(EntryNum))");
list.add("CREATE UNIQUE INDEX IF NOT EXISTS SignerIdIndex ON SignatureTable(SignerId)"); list.add("CREATE INDEX IF NOT EXISTS SignerIndex ON SignatureTable(SignerId)");
list.add("CREATE UNIQUE INDEX IF NOT EXISTS SignerIndex ON SignatureTable(SignerId, EntryNum)");
// This is used to create a simple table with one entry.
// It is used for implementing a workaround for the missing INSERT IGNORE syntax
list.add("CREATE TABLE IF NOT EXISTS UtilityTable (Entry INT)");
list.add("INSERT INTO UtilityTable (Entry) VALUES (1)");
return list; return list;
} }
@ -99,6 +164,7 @@ public class H2QueryProvider implements BulletinBoardSQLServer.SQLQueryProvider
public List<String> getSchemaDeletionCommands() { public List<String> getSchemaDeletionCommands() {
List<String> list = new LinkedList<String>(); List<String> list = new LinkedList<String>();
list.add("DROP TABLE IF EXISTS UtilityTable");
list.add("DROP INDEX IF EXISTS SignerIdIndex"); list.add("DROP INDEX IF EXISTS SignerIdIndex");
list.add("DROP TABLE IF EXISTS MsgTagTable"); list.add("DROP TABLE IF EXISTS MsgTagTable");
list.add("DROP TABLE IF EXISTS SignatureTable"); list.add("DROP TABLE IF EXISTS SignatureTable");

View File

@ -1,7 +1,10 @@
package meerkat.bulletinboard.sqlserver; package meerkat.bulletinboard.sqlserver;
import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;
import meerkat.bulletinboard.sqlserver.BulletinBoardSQLServer.SQLQueryProvider;
import meerkat.protobuf.BulletinBoardAPI.FilterType; import meerkat.protobuf.BulletinBoardAPI.FilterType;
import javax.sql.DataSource;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
@ -9,12 +12,16 @@ import java.util.List;
* Created by Arbel Deutsch Peled on 09-Dec-15. * Created by Arbel Deutsch Peled on 09-Dec-15.
*/ */
public class MySQLQueryProvider implements BulletinBoardSQLServer.SQLQueryProvider { public class MySQLQueryProvider implements SQLQueryProvider {
String dbConnectionString; private String dbAddress;
private String username;
private String password;
public MySQLQueryProvider(String dbAddress, String username, String password) { public MySQLQueryProvider(String dbAddress, String username, String password) {
dbConnectionString = "jdbc:mysql:" + dbAddress + "?user=" + username + "&password=" + password; this.dbAddress = dbAddress;
this.username = username;
this.password = password;
} }
@Override @Override
@ -22,20 +29,20 @@ public class MySQLQueryProvider implements BulletinBoardSQLServer.SQLQueryProvid
switch(queryType) { switch(queryType) {
case ADD_SIGNATURE: case ADD_SIGNATURE:
return "INSERT IGNORE INTO SignatureTable (EntryNum, SignerId, Signature) VALUES (?,?,?)"; return "INSERT IGNORE INTO SignatureTable (EntryNum, SignerId, Signature) VALUES (:EntryNum, :SignerId, :Signature)";
case CONNECT_TAG: case CONNECT_TAG:
return "INSERT IGNORE INTO MsgTagTable (TagId, EntryNum)" return "INSERT IGNORE INTO MsgTagTable (TagId, EntryNum)"
+ " SELECT TagTable.TagId, ? AS EntryNum FROM TagTable WHERE Tag = ?"; + " SELECT TagTable.TagId, :EntryNum AS EntryNum FROM TagTable WHERE Tag = :Tag";
case FIND_MSG_ID: case FIND_MSG_ID:
return "SELECT EntryNum From MsgTable WHERE MsgId = ?"; return "SELECT EntryNum From MsgTable WHERE MsgId = :MsgId";
case GET_MESSAGES: case GET_MESSAGES:
return "SELECT MsgTable.EntryNum, MsgTable.Msg FROM MsgTable"; return "SELECT MsgTable.EntryNum, MsgTable.Msg FROM MsgTable";
case GET_SIGNATURES: case GET_SIGNATURES:
return "SELECT Signature FROM SignatureTable WHERE EntryNum = ?"; return "SELECT Signature FROM SignatureTable WHERE EntryNum = :EntryNum";
case INSERT_MSG: case INSERT_MSG:
return "INSERT INTO MsgTable (MsgId, Msg) VALUES(?,?)"; return "INSERT INTO MsgTable (MsgId, Msg) VALUES(:MsgId, :Msg)";
case INSERT_NEW_TAG: case INSERT_NEW_TAG:
return "INSERT IGNORE INTO TagTable(Tag) VALUES (?)"; return "INSERT IGNORE INTO TagTable(Tag) VALUES (:Tag)";
default: default:
throw new IllegalArgumentException("Cannot serve a query of type " + queryType); throw new IllegalArgumentException("Cannot serve a query of type " + queryType);
} }
@ -43,24 +50,26 @@ public class MySQLQueryProvider implements BulletinBoardSQLServer.SQLQueryProvid
} }
@Override @Override
public String getCondition(FilterType filterType) throws IllegalArgumentException { public String getCondition(FilterType filterType, int serialNum) throws IllegalArgumentException {
String serialString = Integer.toString(serialNum);
switch(filterType) { switch(filterType) {
case EXACT_ENTRY: case EXACT_ENTRY:
return "MsgTable.EntryNum = ?"; return "MsgTable.EntryNum = :EntryNum" + serialString;
case MAX_ENTRY: case MAX_ENTRY:
return "MsgTable.EntryNum <= ?"; return "MsgTable.EntryNum <= :EntryNum" + serialString;
case MAX_MESSAGES: case MAX_MESSAGES:
return "LIMIT ?"; return "LIMIT :Limit" + serialString;
case MSG_ID: case MSG_ID:
return "MsgTable.MsgId = ?"; return "MsgTable.MsgId = :MsgId" + serialString;
case SIGNER_ID: case SIGNER_ID:
return "EXISTS (SELECT 1 FROM SignatureTable" return "EXISTS (SELECT 1 FROM SignatureTable"
+ " WHERE SignatureTable.SignerId = ? AND SignatureTable.EntryNum = MsgTable.EntryNum)"; + " WHERE SignatureTable.SignerId = :SignerId" + serialString + " AND SignatureTable.EntryNum = MsgTable.EntryNum)";
case TAG: case TAG:
return "EXISTS (SELECT 1 FROM TagTable" return "EXISTS (SELECT 1 FROM TagTable"
+ " INNER JOIN MsgTagTable ON TagTable.TagId = MsgTagTable.TagId" + " INNER JOIN MsgTagTable ON TagTable.TagId = MsgTagTable.TagId"
+ " WHERE TagTable.Tag = ? AND MsgTagTable.EntryNum = MsgTable.EntryNum)"; + " WHERE TagTable.Tag = :Tag" + serialString + " AND MsgTagTable.EntryNum = MsgTable.EntryNum)";
default: default:
throw new IllegalArgumentException("Cannot serve a filter of type " + filterType); throw new IllegalArgumentException("Cannot serve a filter of type " + filterType);
} }
@ -68,10 +77,37 @@ public class MySQLQueryProvider implements BulletinBoardSQLServer.SQLQueryProvid
} }
@Override @Override
public String getConnectionString() { public String getConditionParamTypeName(FilterType filterType) throws IllegalArgumentException {
return dbConnectionString;
switch(filterType) {
case EXACT_ENTRY: // Go through
case MAX_ENTRY: // Go through
case MAX_MESSAGES:
return "INT";
case MSG_ID: // Go through
case SIGNER_ID:
return "TINYBLOB";
case TAG:
return "VARCHAR";
default:
throw new IllegalArgumentException("Cannot serve a filter of type " + filterType);
} }
}
@Override
public DataSource getDataSource() {
MysqlDataSource dataSource = new MysqlDataSource();
dataSource.setDatabaseName("meerkat"); //TODO: Make generic
dataSource.setUser(username);
dataSource.setPassword(password);
dataSource.setServerName(dbAddress);
return dataSource;
}
@Override @Override
public List<String> getSchemaCreationCommands() { public List<String> getSchemaCreationCommands() {
@ -79,15 +115,15 @@ public class MySQLQueryProvider implements BulletinBoardSQLServer.SQLQueryProvid
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 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 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," list.add("CREATE TABLE IF NOT EXISTS MsgTagTable (EntryNum INT, TagId INT,"
+ " CONSTRAINT FOREIGN KEY (EntryNum) REFERENCES MsgTable(EntryNum)," + " CONSTRAINT FOREIGN KEY (EntryNum) REFERENCES MsgTable(EntryNum),"
+ " CONSTRAINT FOREIGN KEY (TagId) REFERENCES TagTable(TagId)," + " CONSTRAINT FOREIGN KEY (TagId) REFERENCES TagTable(TagId),"
+ " CONSTRAINT UNIQUE (EntryNum, TagID))"); + " CONSTRAINT UNIQUE (EntryNum, TagID))");
list.add("CREATE TABLE IF NOT EXISTS SignatureTable (EntryNum INT, SignerId TINYBLOB, Signature TINYBLOB, UNIQUE(Signature(150))," list.add("CREATE TABLE IF NOT EXISTS SignatureTable (EntryNum INT, SignerId TINYBLOB, Signature TINYBLOB,"
+ " INDEX(SignerId(50)), CONSTRAINT FOREIGN KEY (EntryNum) REFERENCES MsgTable(EntryNum))"); + " INDEX(SignerId(32)), CONSTRAINT Uni UNIQUE(SignerId(32), EntryNum), CONSTRAINT FOREIGN KEY (EntryNum) REFERENCES MsgTable(EntryNum))");
return list; return list;
} }

View File

@ -1,22 +1,22 @@
package meerkat.bulletinboard.sqlserver; package meerkat.bulletinboard.sqlserver;
import meerkat.protobuf.BulletinBoardAPI.*; import meerkat.protobuf.BulletinBoardAPI.*;
import org.sqlite.SQLiteDataSource;
import javax.sql.DataSource;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import static meerkat.protobuf.BulletinBoardAPI.FilterType;
/** /**
* Created by Arbel Deutsch Peled on 09-Dec-15. * Created by Arbel Deutsch Peled on 09-Dec-15.
*/ */
public class SQLiteQueryProvider implements BulletinBoardSQLServer.SQLQueryProvider { public class SQLiteQueryProvider implements BulletinBoardSQLServer.SQLQueryProvider {
String dbConnectionString; String dbName;
public SQLiteQueryProvider(String dbAddress) { public SQLiteQueryProvider(String dbName) {
dbConnectionString = "jdbc:sqlite:" + dbAddress; this.dbName = dbName;
} }
@Override @Override
@ -24,20 +24,20 @@ public class SQLiteQueryProvider implements BulletinBoardSQLServer.SQLQueryProvi
switch(queryType) { switch(queryType) {
case ADD_SIGNATURE: case ADD_SIGNATURE:
return "INSERT OR IGNORE INTO SignatureTable (EntryNum, SignerId, Signature) VALUES (?,?,?)"; return "INSERT OR IGNORE INTO SignatureTable (EntryNum, SignerId, Signature) VALUES (:EntryNum,:SignerId,:Signature)";
case CONNECT_TAG: case CONNECT_TAG:
return "INSERT OR IGNORE INTO MsgTagTable (TagId, EntryNum)" return "INSERT OR IGNORE INTO MsgTagTable (TagId, EntryNum)"
+ " SELECT TagTable.TagId, ? AS EntryNum FROM TagTable WHERE Tag = ?"; + " SELECT TagTable.TagId, :EntryNum AS EntryNum FROM TagTable WHERE Tag = :Tag";
case FIND_MSG_ID: case FIND_MSG_ID:
return "SELECT EntryNum From MsgTable WHERE MsgId = ?"; return "SELECT EntryNum From MsgTable WHERE MsgId = :MsgId";
case GET_MESSAGES: case GET_MESSAGES:
return "SELECT MsgTable.EntryNum, MsgTable.Msg FROM MsgTable"; return "SELECT MsgTable.EntryNum, MsgTable.Msg FROM MsgTable";
case GET_SIGNATURES: case GET_SIGNATURES:
return "SELECT Signature FROM SignatureTable WHERE EntryNum = ?"; return "SELECT Signature FROM SignatureTable WHERE EntryNum = :EntryNum";
case INSERT_MSG: case INSERT_MSG:
return "INSERT INTO MsgTable (MsgId, Msg) VALUES(?,?)"; return "INSERT INTO MsgTable (MsgId, Msg) VALUES(:MsgId,:Msg)";
case INSERT_NEW_TAG: case INSERT_NEW_TAG:
return "INSERT OR IGNORE INTO TagTable(Tag) VALUES (?)"; return "INSERT OR IGNORE INTO TagTable(Tag) VALUES (:Tag)";
default: default:
throw new IllegalArgumentException("Cannot serve a query of type " + queryType); throw new IllegalArgumentException("Cannot serve a query of type " + queryType);
} }
@ -45,24 +45,26 @@ public class SQLiteQueryProvider implements BulletinBoardSQLServer.SQLQueryProvi
} }
@Override @Override
public String getCondition(FilterType filterType) throws IllegalArgumentException { public String getCondition(FilterType filterType, int serialNum) throws IllegalArgumentException {
String serialString = Integer.toString(serialNum);
switch(filterType) { switch(filterType) {
case EXACT_ENTRY: case EXACT_ENTRY:
return "MsgTable.EntryNum = ?"; return "MsgTable.EntryNum = :EntryNum" + serialString;
case MAX_ENTRY: case MAX_ENTRY:
return "MsgTable.EntryNum <= ?"; return "MsgTable.EntryNum <= :EntryNum" + serialString;
case MAX_MESSAGES: case MAX_MESSAGES:
return "LIMIT = ?"; return "LIMIT = :Limit" + serialString;
case MSG_ID: case MSG_ID:
return "MsgTable.MsgId = ?"; return "MsgTable.MsgId = :MsgId" + serialString;
case SIGNER_ID: case SIGNER_ID:
return "EXISTS (SELECT 1 FROM SignatureTable" return "EXISTS (SELECT 1 FROM SignatureTable"
+ " WHERE SignatureTable.SignerId = ? AND SignatureTable.EntryNum = MsgTable.EntryNum)"; + " WHERE SignatureTable.SignerId = :SignerId" + serialString + " AND SignatureTable.EntryNum = MsgTable.EntryNum)";
case TAG: case TAG:
return "EXISTS (SELECT 1 FROM TagTable" return "EXISTS (SELECT 1 FROM TagTable"
+ " INNER JOIN MsgTagTable ON TagTable.TagId = MsgTagTable.TagId" + " INNER JOIN MsgTagTable ON TagTable.TagId = MsgTagTable.TagId"
+ " WHERE TagTable.Tag = ? AND MsgTagTable.EntryNum = MsgTable.EntryNum)"; + " WHERE TagTable.Tag = :Tag" + serialString + " AND MsgTagTable.EntryNum = MsgTable.EntryNum)";
default: default:
throw new IllegalArgumentException("Cannot serve a filter of type " + filterType); throw new IllegalArgumentException("Cannot serve a filter of type " + filterType);
} }
@ -70,8 +72,18 @@ public class SQLiteQueryProvider implements BulletinBoardSQLServer.SQLQueryProvi
} }
@Override @Override
public String getConnectionString() { public String getConditionParamTypeName(FilterType filterType) throws IllegalArgumentException {
return dbConnectionString; return null; //TODO: write this.
}
@Override
public DataSource getDataSource() {
// TODO: Fix this
SQLiteDataSource dataSource = new SQLiteDataSource();
dataSource.setUrl("jdbc:sqlite:" + dbName);
dataSource.setDatabaseName("meerkat"); //TODO: Make generic
return dataSource;
} }
@ -85,9 +97,11 @@ public class SQLiteQueryProvider implements BulletinBoardSQLServer.SQLQueryProvi
list.add("CREATE TABLE IF NOT EXISTS MsgTagTable (EntryNum BLOB, TagId INTEGER, FOREIGN KEY (EntryNum)" 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))"); + " 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," list.add("CREATE TABLE IF NOT EXISTS SignatureTable (EntryNum INTEGER, SignerId BLOB, Signature BLOB,"
+ " FOREIGN KEY (EntryNum) REFERENCES MsgTable(EntryNum))"); + " FOREIGN KEY (EntryNum) REFERENCES MsgTable(EntryNum))");
list.add("CREATE INDEX IF NOT EXISTS SignerIndex ON SignatureTable(SignerId)"); list.add("CREATE INDEX IF NOT EXISTS SignerIndex ON SignatureTable(SignerId)");
list.add("CREATE UNIQUE INDEX IF NOT EXISTS SignerIndex ON SignatureTable(SignerId, EntryNum)");
return list; return list;
} }

View File

@ -0,0 +1,18 @@
package meerkat.bulletinboard.sqlserver.mappers;
import meerkat.protobuf.BulletinBoardAPI.MessageID;
import org.springframework.jdbc.core.RowMapper;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* Created by Arbel Deutsch Peled on 11-Dec-15.
*/
public class EntryNumMapper implements RowMapper<Long> {
@Override
public Long mapRow(ResultSet rs, int rowNum) throws SQLException {
return rs.getLong(1);
}
}

View File

@ -0,0 +1,32 @@
package meerkat.bulletinboard.sqlserver.mappers;
import com.google.protobuf.InvalidProtocolBufferException;
import meerkat.protobuf.BulletinBoardAPI.UnsignedBulletinBoardMessage;
import meerkat.protobuf.BulletinBoardAPI.BulletinBoardMessage;
import org.springframework.jdbc.core.RowMapper;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* Created by Arbel Deutsch Peled on 11-Dec-15.
*/
public class MessageMapper implements RowMapper<BulletinBoardMessage.Builder> {
@Override
public BulletinBoardMessage.Builder mapRow(ResultSet rs, int rowNum) throws SQLException {
BulletinBoardMessage.Builder builder = BulletinBoardMessage.newBuilder();
try {
builder.setEntryNum(rs.getLong(1))
.setMsg(UnsignedBulletinBoardMessage.parseFrom(rs.getBytes(2)));
} catch (InvalidProtocolBufferException e) {
throw new SQLException(e.getMessage(), e);
}
return builder;
}
}

View File

@ -0,0 +1,28 @@
package meerkat.bulletinboard.sqlserver.mappers;
import com.google.protobuf.InvalidProtocolBufferException;
import meerkat.protobuf.BulletinBoardAPI.BulletinBoardMessage;
import meerkat.protobuf.BulletinBoardAPI.UnsignedBulletinBoardMessage;
import meerkat.protobuf.Crypto.Signature;
import org.springframework.jdbc.core.RowMapper;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* Created by Arbel Deutsch Peled on 11-Dec-15.
*/
public class SignatureMapper implements RowMapper<Signature> {
@Override
public Signature mapRow(ResultSet rs, int rowNum) throws SQLException {
try {
return Signature.parseFrom(rs.getBytes(1));
} catch (InvalidProtocolBufferException e) {
throw new SQLException(e.getMessage(), e);
}
}
}

View File

@ -356,8 +356,7 @@ public class GenericBulletinBoardServerTest {
.addFilter(MessageFilter.newBuilder() .addFilter(MessageFilter.newBuilder()
.setType(FilterType.SIGNER_ID) .setType(FilterType.SIGNER_ID)
.setId(signerIDs[1]) .setId(signerIDs[1])
.build() .build());
);
try { try {
messages = bulletinBoardServer.readMessages(filterListBuilder.build()).getMessageList(); messages = bulletinBoardServer.readMessages(filterListBuilder.build()).getMessageList();

View File

@ -7,13 +7,11 @@ import meerkat.comm.CommunicationException;
import org.junit.After; import org.junit.After;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.Result;
import java.lang.management.ManagementFactory; import java.lang.management.ManagementFactory;
import java.lang.management.ThreadMXBean; import java.lang.management.ThreadMXBean;
import java.sql.Connection; import java.sql.*;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.List; import java.util.List;
import static org.junit.Assert.fail; import static org.junit.Assert.fail;
@ -23,23 +21,25 @@ import static org.junit.Assert.fail;
*/ */
public class H2BulletinBoardServerTest { public class H2BulletinBoardServerTest {
private final String dbAddress = "~/meerkatTest"; private final String dbAddress = "meerkatTest";
private GenericBulletinBoardServerTest serverTest; private GenericBulletinBoardServerTest serverTest;
private SQLQueryProvider queryProvider;
private final ThreadMXBean threadBean = ManagementFactory.getThreadMXBean(); // Used to time the tests private final ThreadMXBean threadBean = ManagementFactory.getThreadMXBean(); // Used to time the tests
// @Before @Before
public void init(){ public void init(){
System.err.println("Starting to initialize H2BulletinBoardServerTest"); System.err.println("Starting to initialize H2BulletinBoardServerTest");
long start = threadBean.getCurrentThreadCpuTime(); long start = threadBean.getCurrentThreadCpuTime();
SQLQueryProvider queryProvider = new H2QueryProvider(dbAddress); queryProvider = new H2QueryProvider(dbAddress, "", "");
try { try {
Connection conn = DriverManager.getConnection(queryProvider.getConnectionString()); Connection conn = queryProvider.getDataSource().getConnection();
Statement stmt = conn.createStatement(); Statement stmt = conn.createStatement();
List<String> deletionQueries = queryProvider.getSchemaDeletionCommands(); List<String> deletionQueries = queryProvider.getSchemaDeletionCommands();
@ -76,7 +76,7 @@ public class H2BulletinBoardServerTest {
System.err.println("Time of operation: " + (end - start)); System.err.println("Time of operation: " + (end - start));
} }
// @Test @Test
public void bulkTest() { public void bulkTest() {
System.err.println("Starting bulkTest of H2BulletinBoardServerTest"); System.err.println("Starting bulkTest of H2BulletinBoardServerTest");
long start = threadBean.getCurrentThreadCpuTime(); long start = threadBean.getCurrentThreadCpuTime();
@ -107,7 +107,7 @@ public class H2BulletinBoardServerTest {
System.err.println("Time of operation: " + (end - start)); System.err.println("Time of operation: " + (end - start));
} }
// @After @After
public void close() { public void close() {
System.err.println("Starting to close H2BulletinBoardServerTest"); System.err.println("Starting to close H2BulletinBoardServerTest");
long start = threadBean.getCurrentThreadCpuTime(); long start = threadBean.getCurrentThreadCpuTime();

View File

@ -3,20 +3,17 @@ package meerkat.bulletinboard;
import meerkat.bulletinboard.sqlserver.BulletinBoardSQLServer; import meerkat.bulletinboard.sqlserver.BulletinBoardSQLServer;
import meerkat.bulletinboard.sqlserver.BulletinBoardSQLServer.SQLQueryProvider; import meerkat.bulletinboard.sqlserver.BulletinBoardSQLServer.SQLQueryProvider;
import meerkat.bulletinboard.sqlserver.MySQLQueryProvider; import meerkat.bulletinboard.sqlserver.MySQLQueryProvider;
import meerkat.bulletinboard.sqlserver.SQLiteQueryProvider;
import meerkat.comm.CommunicationException; import meerkat.comm.CommunicationException;
import org.junit.After; import org.junit.After;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import java.io.File;
import java.lang.management.ManagementFactory; import java.lang.management.ManagementFactory;
import java.lang.management.ThreadMXBean; import java.lang.management.ThreadMXBean;
import java.sql.Connection; import java.sql.Connection;
import java.sql.DriverManager; import java.sql.DriverManager;
import java.sql.SQLException; import java.sql.SQLException;
import java.sql.Statement; import java.sql.Statement;
import java.util.LinkedList;
import java.util.List; import java.util.List;
import static org.junit.Assert.fail; import static org.junit.Assert.fail;
@ -26,7 +23,7 @@ import static org.junit.Assert.fail;
*/ */
public class MySQLBulletinBoardServerTest { public class MySQLBulletinBoardServerTest {
private final String dbAddress = "//localhost:3306/meerkat"; private final String dbAddress = "localhost";
private final String username = "arbel"; private final String username = "arbel";
private final String password = "mypass"; private final String password = "mypass";
@ -44,7 +41,7 @@ public class MySQLBulletinBoardServerTest {
try { try {
Connection conn = DriverManager.getConnection(queryProvider.getConnectionString()); Connection conn = queryProvider.getDataSource().getConnection();
Statement stmt = conn.createStatement(); Statement stmt = conn.createStatement();
List<String> deletionQueries = queryProvider.getSchemaDeletionCommands(); List<String> deletionQueries = queryProvider.getSchemaDeletionCommands();

View File

@ -52,6 +52,10 @@ enum FilterType {
MAX_ENTRY = 2; // Find all entries in database up to specified entry number (chronological) MAX_ENTRY = 2; // Find all entries in database up to specified entry number (chronological)
SIGNER_ID = 3; // Find all entries in database that correspond to specific signature (signer) SIGNER_ID = 3; // Find all entries in database that correspond to specific signature (signer)
TAG = 4; // Find all entries in database that have a specific tag TAG = 4; // Find all entries in database that have a specific tag
// NOTE: The MAX_MESSAGES filter must remain the last filter type
// This is because the condition it specifies in an SQL statement must come last in the statement
// Keeping it last here allows for easily sorting the filters and keeping the code general
MAX_MESSAGES = 5; // Return at most some specified number of messages MAX_MESSAGES = 5; // Return at most some specified number of messages
} }