diff --git a/bulletin-board-server/build.gradle b/bulletin-board-server/build.gradle index 593dfbc..5989499 100644 --- a/bulletin-board-server/build.gradle +++ b/bulletin-board-server/build.gradle @@ -45,7 +45,11 @@ dependencies { // Jersey for RESTful API compile 'org.glassfish.jersey.containers:jersey-container-servlet:2.22.+' + + // JDBC connections compile 'org.xerial:sqlite-jdbc:3.7.+' + compile 'mysql:mysql-connector-java:5.1.+' + compile 'com.h2database:h2:1.0.+' // Servlets compile 'javax.servlet:javax.servlet-api:3.0.+' diff --git a/bulletin-board-server/src/main/java/meerkat/bulletinboard/httpserver/BulletinBoardHttpServer.java b/bulletin-board-server/src/main/java/meerkat/bulletinboard/httpserver/BulletinBoardHttpServer.java deleted file mode 100644 index 9989706..0000000 --- a/bulletin-board-server/src/main/java/meerkat/bulletinboard/httpserver/BulletinBoardHttpServer.java +++ /dev/null @@ -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 - } - - } - -} diff --git a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/BulletinBoardSQLServer.java b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/BulletinBoardSQLServer.java index b8fc3cd..2689f70 100644 --- a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/BulletinBoardSQLServer.java +++ b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/BulletinBoardSQLServer.java @@ -1,16 +1,11 @@ package meerkat.bulletinboard.sqlserver; -import java.util.Arrays; -import java.util.List; +import java.sql.*; +import java.util.*; +import com.google.protobuf.InvalidProtocolBufferException; 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.comm.CommunicationException; import meerkat.protobuf.BulletinBoardAPI.*; @@ -19,8 +14,77 @@ import meerkat.protobuf.Crypto.SignatureVerificationKey; import meerkat.crypto.Digest; 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 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 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 { + + @Override + public int compare(MessageFilter filter1, MessageFilter filter2) { + return filter1.getTypeValue() - filter2.getTypeValue(); + } + } + + protected SQLQueryProvider sqlQueryProvider; + protected Connection connection; protected Digest digest; @@ -30,18 +94,52 @@ public abstract class BulletinBoardSQLServer implements BulletinBoardServer{ protected List> pollingCommitteeSignatureVerificationKeyArray; protected int minCommiteeSignatures; - + /** - * This method initializes the signatures but does not implement the DB connection. - * Any full (non-abstract) extension of this class should - * 1. Establish a DB connection, and - * 2. Call this procedure + * This constructor sets the type of SQL language in use. + * @param sqlQueryProvider is the provider of the SQL query strings required for actual operation of the server. + */ + 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 public void init(String meerkatDB) throws CommunicationException { // TODO write signature reading part. 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. * @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. @@ -73,7 +193,7 @@ public abstract class BulletinBoardSQLServer implements BulletinBoardServer{ .setValue(b) .build(); } - + @Override public BoolMsg postMessage(BulletinBoardMessage msg) throws CommunicationException { @@ -104,7 +224,7 @@ public abstract class BulletinBoardSQLServer implements BulletinBoardServer{ try { - sql = "SELECT EntryNum From MsgTable WHERE MsgId = ?"; + sql = sqlQueryProvider.getSQLString(SQLQueryProvider.QueryType.FIND_MSG_ID); pstmt = connection.prepareStatement(sql); pstmt.setBytes(1, msgID); rs = pstmt.executeQuery(); @@ -115,8 +235,8 @@ public abstract class BulletinBoardSQLServer implements BulletinBoardServer{ } else{ - sql = "INSERT INTO MsgTable (MsgId, Msg) VALUES(?,?)"; - pstmt = connection.prepareStatement(sql); + sql = sqlQueryProvider.getSQLString(SQLQueryProvider.QueryType.INSERT_MSG); + pstmt = connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS); pstmt.setBytes(1, msgID); pstmt.setBytes(2, msg.getMsg().toByteArray()); pstmt.executeUpdate(); @@ -150,7 +270,7 @@ public abstract class BulletinBoardSQLServer implements BulletinBoardServer{ // Connect message to tags. 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.setLong(1, entryNum); @@ -176,7 +296,7 @@ public abstract class BulletinBoardSQLServer implements BulletinBoardServer{ // Connect message to signatures. try{ - sql = "INSERT OR IGNORE INTO SignatureTable (EntryNum, SignerId, Signature) VALUES (?,?,?)"; + sql = sqlQueryProvider.getSQLString(SQLQueryProvider.QueryType.ADD_SIGNATURE); pstmt = connection.prepareStatement(sql); pstmt.setLong(1, entryNum); @@ -197,41 +317,147 @@ public abstract class BulletinBoardSQLServer implements BulletinBoardServer{ return boolToBoolMsg(true); } - - public String testPrint(){ - - String s = ""; - - try { - - Statement statement = connection.createStatement(); - ResultSet rs = statement.executeQuery("select * from MsgTable"); - while (rs.next()) { - // read the result set - s += "entry = " + rs.getInt("EntryNum") + " \n"; - s += "id = " + Arrays.toString(rs.getBytes("MsgId")) + " \n"; - s += "msg = " + Arrays.toString(rs.getBytes("Msg")) + " \n"; - s += "signer ID = " + Arrays.toString(rs.getBytes("SignerId")) + "\t\n
"; + + @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; + + List filters = new ArrayList(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 = 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
"; - } - - 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
"; - } - } 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"); + + } + } } diff --git a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/EnhancedSQLiteBulletinBoardServer.java b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/EnhancedSQLiteBulletinBoardServer.java deleted file mode 100644 index 6baac36..0000000 --- a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/EnhancedSQLiteBulletinBoardServer.java +++ /dev/null @@ -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{ - - @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 filters = new ArrayList(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(); - } -} diff --git a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/H2QueryProvider.java b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/H2QueryProvider.java new file mode 100644 index 0000000..d80b302 --- /dev/null +++ b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/H2QueryProvider.java @@ -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 getSchemaCreationCommands() { + List list = new LinkedList(); + + 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 getSchemaDeletionCommands() { + List list = new LinkedList(); + + 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; + } + +} diff --git a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/MySQLQueryProvider.java b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/MySQLQueryProvider.java new file mode 100644 index 0000000..18d8189 --- /dev/null +++ b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/MySQLQueryProvider.java @@ -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 getSchemaCreationCommands() { + List list = new LinkedList(); + + 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 getSchemaDeletionCommands() { + List list = new LinkedList(); + + 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; + } +} diff --git a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/SQLiteBulletinBoardServer.java b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/SQLiteBulletinBoardServer.java deleted file mode 100644 index bfbbc1a..0000000 --- a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/SQLiteBulletinBoardServer.java +++ /dev/null @@ -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 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(); - } - -} diff --git a/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/SQLiteQueryProvider.java b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/SQLiteQueryProvider.java new file mode 100644 index 0000000..5978c9d --- /dev/null +++ b/bulletin-board-server/src/main/java/meerkat/bulletinboard/sqlserver/SQLiteQueryProvider.java @@ -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 getSchemaCreationCommands() { + List list = new LinkedList(); + + 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 getSchemaDeletionCommands() { + List list = new LinkedList(); + + 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; + } +} diff --git a/bulletin-board-server/src/main/java/meerkat/bulletinboard/webapp/BulletinBoardWebApp.java b/bulletin-board-server/src/main/java/meerkat/bulletinboard/webapp/BulletinBoardWebApp.java index 69f2ba4..5dae671 100644 --- a/bulletin-board-server/src/main/java/meerkat/bulletinboard/webapp/BulletinBoardWebApp.java +++ b/bulletin-board-server/src/main/java/meerkat/bulletinboard/webapp/BulletinBoardWebApp.java @@ -12,7 +12,8 @@ import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; 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.protobuf.BulletinBoardAPI.BoolMsg; import meerkat.protobuf.BulletinBoardAPI.BulletinBoardMessage; @@ -51,7 +52,7 @@ public class BulletinBoardWebApp implements BulletinBoardServer, ServletContextL String dbType = servletContext.getInitParameter("dbtype"); if (dbType.compareTo("SQLite") == 0){ - bulletinBoard = new SQLiteBulletinBoardServer(); + bulletinBoard = new BulletinBoardSQLServer(new SQLiteQueryProvider(meerkatDB)); } try { diff --git a/bulletin-board-server/src/test/java/meerkat/bulletinboard/EnhancedSQLiteBulletinBoardServerTest.java b/bulletin-board-server/src/test/java/meerkat/bulletinboard/EnhancedSQLiteBulletinBoardServerTest.java deleted file mode 100644 index 8d643e4..0000000 --- a/bulletin-board-server/src/test/java/meerkat/bulletinboard/EnhancedSQLiteBulletinBoardServerTest.java +++ /dev/null @@ -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(); - } - -} diff --git a/bulletin-board-server/src/test/java/meerkat/bulletinboard/GenericBulletinBoardServerTest.java b/bulletin-board-server/src/test/java/meerkat/bulletinboard/GenericBulletinBoardServerTest.java index 3572a42..61354e7 100644 --- a/bulletin-board-server/src/test/java/meerkat/bulletinboard/GenericBulletinBoardServerTest.java +++ b/bulletin-board-server/src/test/java/meerkat/bulletinboard/GenericBulletinBoardServerTest.java @@ -32,6 +32,7 @@ public class GenericBulletinBoardServerTest { protected BulletinBoardServer bulletinBoardServer; private ECDSASignature signers[]; + private ByteString[] signerIDs; private Random random; @@ -71,6 +72,7 @@ public class GenericBulletinBoardServerTest { this.bulletinBoardServer = bulletinBoardServer; signers = new ECDSASignature[2]; + signerIDs = new ByteString[signers.length]; signers[0] = new ECDSASignature(); signers[1] = new ECDSASignature(); @@ -81,17 +83,21 @@ public class GenericBulletinBoardServerTest { try { keyStoreBuilder = signers[0].getPKCS12KeyStoreBuilder(keyStream, password); - signers[0].loadSigningCertificate(keyStoreBuilder); - - signers[0].loadVerificationCertificates(getClass().getResourceAsStream(CERT1_PEM_EXAMPLE)); - - keyStream = getClass().getResourceAsStream(KEYFILE_EXAMPLE3); - password = KEYFILE_PASSWORD3.toCharArray(); - - keyStoreBuilder = signers[1].getPKCS12KeyStoreBuilder(keyStream, password); - signers[1].loadSigningCertificate(keyStoreBuilder); - - signers[1].loadVerificationCertificates(getClass().getResourceAsStream(CERT3_PEM_EXAMPLE)); + signers[0].loadSigningCertificate(keyStoreBuilder); + + signers[0].loadVerificationCertificates(getClass().getResourceAsStream(CERT1_PEM_EXAMPLE)); + + keyStream = getClass().getResourceAsStream(KEYFILE_EXAMPLE3); + password = KEYFILE_PASSWORD3.toCharArray(); + + keyStoreBuilder = signers[1].getPKCS12KeyStoreBuilder(keyStream, password); + signers[1].loadSigningCertificate(keyStoreBuilder); + + signers[1].loadVerificationCertificates(getClass().getResourceAsStream(CERT3_PEM_EXAMPLE)); + + for (int i = 0 ; i < signers.length ; i++) { + signerIDs[i] = signers[i].getSignerID(); + } } catch (IOException e) { System.err.println("Failed reading from signature file " + e.getMessage()); @@ -334,7 +340,7 @@ public class GenericBulletinBoardServerTest { assertThat(messages.size(), is(expectedMsgCount)); 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)); } } @@ -345,11 +351,11 @@ public class GenericBulletinBoardServerTest { filterListBuilder = MessageFilterList.newBuilder() .addFilter(MessageFilter.newBuilder() .setType(FilterType.SIGNER_ID) - .setId(signers[0].getSignerID()) + .setId(signerIDs[0]) .build()) .addFilter(MessageFilter.newBuilder() .setType(FilterType.SIGNER_ID) - .setId(signers[1].getSignerID()) + .setId(signerIDs[1]) .build() ); diff --git a/bulletin-board-server/src/test/java/meerkat/bulletinboard/H2BulletinBoardServerTest.java b/bulletin-board-server/src/test/java/meerkat/bulletinboard/H2BulletinBoardServerTest.java new file mode 100644 index 0000000..6210dd4 --- /dev/null +++ b/bulletin-board-server/src/test/java/meerkat/bulletinboard/H2BulletinBoardServerTest.java @@ -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 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)); + } + +} diff --git a/bulletin-board-server/src/test/java/meerkat/bulletinboard/MySQLBulletinBoardServerTest.java b/bulletin-board-server/src/test/java/meerkat/bulletinboard/MySQLBulletinBoardServerTest.java new file mode 100644 index 0000000..af1cfb4 --- /dev/null +++ b/bulletin-board-server/src/test/java/meerkat/bulletinboard/MySQLBulletinBoardServerTest.java @@ -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 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)); + } + +} diff --git a/bulletin-board-server/src/test/java/meerkat/bulletinboard/SQLiteBulletinBoardServerTest.java b/bulletin-board-server/src/test/java/meerkat/bulletinboard/SQLiteBulletinBoardServerTest.java index c071807..1d7aae0 100644 --- a/bulletin-board-server/src/test/java/meerkat/bulletinboard/SQLiteBulletinBoardServerTest.java +++ b/bulletin-board-server/src/test/java/meerkat/bulletinboard/SQLiteBulletinBoardServerTest.java @@ -1,6 +1,7 @@ package meerkat.bulletinboard; -import meerkat.bulletinboard.sqlserver.SQLiteBulletinBoardServer; +import meerkat.bulletinboard.sqlserver.BulletinBoardSQLServer; +import meerkat.bulletinboard.sqlserver.SQLiteQueryProvider; import meerkat.comm.CommunicationException; import meerkat.protobuf.*; import org.junit.After; @@ -36,9 +37,9 @@ public class SQLiteBulletinBoardServerTest{ File old = new File(testFilename); old.delete(); - BulletinBoardServer bulletinBoardServer = new SQLiteBulletinBoardServer(); + BulletinBoardServer bulletinBoardServer = new BulletinBoardSQLServer(new SQLiteQueryProvider(testFilename)); try { - bulletinBoardServer.init(testFilename); + bulletinBoardServer.init(""); } catch (CommunicationException e) { System.err.println(e.getMessage()); @@ -66,12 +67,25 @@ public class SQLiteBulletinBoardServerTest{ 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 SQLiteBulletinBoardServerTest"); System.err.println("Time of operation: " + (end - start)); diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index 05ef575..0000000 Binary files a/gradle/wrapper/gradle-wrapper.jar and /dev/null differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index 2237c68..0000000 --- a/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -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