Compare commits
19 Commits
master
...
vote-regis
Author | SHA1 | Date |
---|---|---|
Vladimir Eliezer Tokarev | e75317efa9 | |
Vladimir Eliezer Tokarev | 5971e8c16e | |
Vladimir Eliezer Tokarev | de835a8c13 | |
Vladimir Eliezer Tokarev | 109135ae1b | |
Vladimir Eliezer Tokarev | 7734ba8c91 | |
Vladimir Eliezer Tokarev | 8546a347ca | |
Vladimir Eliezer Tokarev | 65bc8bc160 | |
Vladimir Eliezer Tokarev | 36d94b41ab | |
Vladimir Eliezer Tokarev | 87e8ad9470 | |
Vladimir Eliezer Tokarev | 717c2e6e65 | |
Vladimir Eliezer Tokarev | 51b9f9decd | |
Vladimir Eliezer Tokarev | 05871a2ea7 | |
Vladimir Eliezer Tokarev | 070b851203 | |
Vladimir Eliezer Tokarev | 4aa6c25c0f | |
Vladimir Eliezer Tokarev | 84555f0639 | |
Vladimir Eliezer Tokarev | 42bc35cbe8 | |
Vladimir Eliezer Tokarev | f9d7b4b1ce | |
Vladimir Eliezer Tokarev | 25eefc4b16 | |
Arbel Deutsch Peled | a12685d757 |
|
@ -0,0 +1,235 @@
|
|||
|
||||
plugins {
|
||||
id "us.kirchmeier.capsule" version "1.0.1"
|
||||
id 'com.google.protobuf' version '0.7.0'
|
||||
}
|
||||
|
||||
apply plugin: 'java'
|
||||
apply plugin: 'com.google.protobuf'
|
||||
apply plugin: 'eclipse'
|
||||
apply plugin: 'idea'
|
||||
|
||||
apply plugin: 'maven-publish'
|
||||
|
||||
// Is this a snapshot version?
|
||||
ext { isSnapshot = false }
|
||||
|
||||
ext {
|
||||
groupId = 'org.factcenter.meerkat'
|
||||
nexusRepository = "https://cs.idc.ac.il/nexus/content/groups/${isSnapshot ? 'unstable' : 'public'}/"
|
||||
|
||||
// Credentials for IDC nexus repositories (needed only for using unstable repositories and publishing)
|
||||
// Should be set in ${HOME}/.gradle/gradle.properties
|
||||
nexusUser = project.hasProperty('nexusUser') ? project.property('nexusUser') : ""
|
||||
nexusPassword = project.hasProperty('nexusPassword') ? project.property('nexusPassword') : ""
|
||||
}
|
||||
|
||||
description = "Meerkat Bulletin Board Client implementation"
|
||||
|
||||
// Your project version
|
||||
version = "0.0"
|
||||
|
||||
version += "${isSnapshot ? '-SNAPSHOT' : ''}"
|
||||
|
||||
|
||||
dependencies {
|
||||
|
||||
// Meerkat common
|
||||
compile project(':meerkat-common')
|
||||
compile project(':restful-api-common')
|
||||
|
||||
// Jersey for RESTful API
|
||||
compile 'org.glassfish.jersey.containers:jersey-container-servlet:2.22.+'
|
||||
compile 'org.xerial:sqlite-jdbc:3.7.+'
|
||||
|
||||
// Logging
|
||||
compile 'org.slf4j:slf4j-api:1.7.7'
|
||||
runtime 'ch.qos.logback:logback-classic:1.1.2'
|
||||
runtime 'ch.qos.logback:logback-core:1.1.2'
|
||||
|
||||
// Google protobufs
|
||||
compile 'com.google.protobuf:protobuf-java:3.+'
|
||||
|
||||
// Crypto
|
||||
compile 'org.factcenter.qilin:qilin:1.1+'
|
||||
compile 'org.bouncycastle:bcprov-jdk15on:1.53'
|
||||
compile 'org.bouncycastle:bcpkix-jdk15on:1.53'
|
||||
|
||||
testCompile 'junit:junit:4.+'
|
||||
testCompile 'org.hamcrest:hamcrest-all:1.3'
|
||||
|
||||
runtime 'org.codehaus.groovy:groovy:2.4.+'
|
||||
}
|
||||
|
||||
test {
|
||||
exclude '**/*IntegrationTest*'
|
||||
}
|
||||
|
||||
task integrationTest(type: Test) {
|
||||
include '**/*IntegrationTest*'
|
||||
// debug = true
|
||||
outputs.upToDateWhen { false }
|
||||
|
||||
}
|
||||
|
||||
/*==== You probably don't have to edit below this line =======*/
|
||||
|
||||
|
||||
// Setup test configuration that can appear as a dependency in
|
||||
// other subprojects
|
||||
configurations {
|
||||
testOutput.extendsFrom (testCompile)
|
||||
}
|
||||
|
||||
task testJar(type: Jar, dependsOn: testClasses) {
|
||||
classifier = 'tests'
|
||||
from sourceSets.test.output
|
||||
}
|
||||
|
||||
artifacts {
|
||||
testOutput testJar
|
||||
}
|
||||
|
||||
|
||||
|
||||
// The run task added by the application plugin
|
||||
// is also of type JavaExec.
|
||||
tasks.withType(JavaExec) {
|
||||
// Assign all Java system properties from
|
||||
// the command line to the JavaExec task.
|
||||
systemProperties System.properties
|
||||
}
|
||||
|
||||
|
||||
protobuf {
|
||||
// Configure the protoc executable
|
||||
protoc {
|
||||
// Download from repositories
|
||||
artifact = 'com.google.protobuf:protoc:3.+'
|
||||
}
|
||||
}
|
||||
|
||||
idea {
|
||||
module {
|
||||
project.sourceSets.each { sourceSet ->
|
||||
|
||||
def srcDir = "${protobuf.generatedFilesBaseDir}/$sourceSet.name/java"
|
||||
|
||||
// add protobuf generated sources to generated source dir.
|
||||
if ("test".equals(sourceSet.name)) {
|
||||
testSourceDirs += file(srcDir)
|
||||
} else {
|
||||
sourceDirs += file(srcDir)
|
||||
}
|
||||
generatedSourceDirs += file(srcDir)
|
||||
|
||||
}
|
||||
|
||||
// Don't exclude build directory
|
||||
excludeDirs -= file(buildDir)
|
||||
}
|
||||
}
|
||||
|
||||
/*===================================
|
||||
* "Fat" Build targets
|
||||
*===================================*/
|
||||
|
||||
if (project.hasProperty('mainClassName') && (mainClassName != null)) {
|
||||
|
||||
task mavenCapsule(type: MavenCapsule) {
|
||||
description = "Generate a capsule jar that automatically downloads and caches dependencies when run."
|
||||
applicationClass mainClassName
|
||||
destinationDir = buildDir
|
||||
}
|
||||
|
||||
task fatCapsule(type: FatCapsule) {
|
||||
description = "Generate a single capsule jar containing everything. Use -Pfatmain=... to override main class"
|
||||
|
||||
destinationDir = buildDir
|
||||
|
||||
def fatMain = hasProperty('fatmain') ? fatmain : mainClassName
|
||||
|
||||
applicationClass fatMain
|
||||
|
||||
def testJar = hasProperty('test')
|
||||
|
||||
if (hasProperty('fatmain')) {
|
||||
appendix = "fat-${fatMain}"
|
||||
} else {
|
||||
appendix = "fat"
|
||||
}
|
||||
|
||||
if (testJar) {
|
||||
from sourceSets.test.output
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*===================================
|
||||
* Repositories
|
||||
*===================================*/
|
||||
|
||||
repositories {
|
||||
|
||||
mavenLocal();
|
||||
|
||||
// Prefer the local nexus repository (it may have 3rd party artifacts not found in mavenCentral)
|
||||
maven {
|
||||
url nexusRepository
|
||||
|
||||
if (isSnapshot) {
|
||||
credentials { username
|
||||
password
|
||||
|
||||
username nexusUser
|
||||
password nexusPassword
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Use 'maven central' for other dependencies.
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
task "info" << {
|
||||
println "Project: ${project.name}"
|
||||
println "Description: ${project.description}"
|
||||
println "--------------------------"
|
||||
println "GroupId: $groupId"
|
||||
println "Version: $version (${isSnapshot ? 'snapshot' : 'release'})"
|
||||
println ""
|
||||
}
|
||||
info.description 'Print some information about project parameters'
|
||||
|
||||
|
||||
/*===================================
|
||||
* Publishing
|
||||
*===================================*/
|
||||
|
||||
publishing {
|
||||
publications {
|
||||
mavenJava(MavenPublication) {
|
||||
groupId project.groupId
|
||||
pom.withXml {
|
||||
asNode().appendNode('description', project.description)
|
||||
}
|
||||
from project.components.java
|
||||
|
||||
}
|
||||
}
|
||||
repositories {
|
||||
maven {
|
||||
url "https://cs.idc.ac.il/nexus/content/repositories/${project.isSnapshot ? 'snapshots' : 'releases'}"
|
||||
credentials { username
|
||||
password
|
||||
|
||||
username nexusUser
|
||||
password nexusPassword
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -4,4 +4,4 @@ include 'bulletin-board-server'
|
|||
include 'polling-station'
|
||||
include 'restful-api-common'
|
||||
include 'bulletin-board-client'
|
||||
|
||||
include 'voter-registry'
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
/protoc.exe
|
||||
/bin/
|
||||
/comment-info.txt
|
|
@ -0,0 +1,195 @@
|
|||
|
||||
plugins {
|
||||
id "us.kirchmeier.capsule" version "1.0.1"
|
||||
id 'com.google.protobuf' version '0.7.0'
|
||||
}
|
||||
|
||||
apply plugin: 'java'
|
||||
apply plugin: 'eclipse'
|
||||
apply plugin: 'idea'
|
||||
|
||||
apply plugin: 'maven-publish'
|
||||
|
||||
// Uncomment the lines below to define an application
|
||||
// (this will also allow you to build a "fatCapsule" which includes
|
||||
// the entire application, including all dependencies in a single jar)
|
||||
//apply plugin: 'application'
|
||||
//mainClassName='your.main.ApplicationClass'
|
||||
|
||||
|
||||
// Is this a snapshot version?
|
||||
ext { isSnapshot = false }
|
||||
|
||||
ext {
|
||||
groupId = 'org.factcenter.meerkat'
|
||||
nexusRepository = "https://cs.idc.ac.il/nexus/content/groups/${isSnapshot ? 'unstable' : 'public'}/"
|
||||
|
||||
// Credentials for IDC nexus repositories (needed only for using unstable repositories and publishing)
|
||||
// Should be set in ${HOME}/.gradle/gradle.properties
|
||||
nexusUser = project.hasProperty('nexusUser') ? project.property('nexusUser') : ""
|
||||
nexusPassword = project.hasProperty('nexusPassword') ? project.property('nexusPassword') : ""
|
||||
}
|
||||
|
||||
description = "Meerkat Voter SimpleRegistry application"
|
||||
|
||||
// Your project version
|
||||
version = "0.0"
|
||||
|
||||
version += "${isSnapshot ? '-SNAPSHOT' : ''}"
|
||||
|
||||
|
||||
dependencies {
|
||||
// Meerkat common
|
||||
compile project(':meerkat-common')
|
||||
compile project(':bulletin-board-client')
|
||||
|
||||
// Logging
|
||||
compile 'org.slf4j:slf4j-api:1.7.7'
|
||||
runtime 'ch.qos.logback:logback-classic:1.1.2'
|
||||
runtime 'ch.qos.logback:logback-core:1.1.2'
|
||||
|
||||
// Google protobufs
|
||||
compile 'com.google.protobuf:protobuf-java:3.+'
|
||||
|
||||
testCompile 'junit:junit:4.+'
|
||||
|
||||
runtime 'org.codehaus.groovy:groovy:2.4.+'
|
||||
}
|
||||
|
||||
|
||||
/*==== You probably don't have to edit below this line =======*/
|
||||
|
||||
protobuf {
|
||||
// Configure the protoc executable
|
||||
protoc {
|
||||
// Download from repositories
|
||||
artifact = 'com.google.protobuf:protoc:3.+'
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
idea {
|
||||
module {
|
||||
project.sourceSets.each { sourceSet ->
|
||||
|
||||
def srcDir = "${protobuf.generatedFilesBaseDir}/$sourceSet.name/java"
|
||||
|
||||
// add protobuf generated sources to generated source dir.
|
||||
if ("test".equals(sourceSet.name)) {
|
||||
testSourceDirs += file(srcDir)
|
||||
} else {
|
||||
sourceDirs += file(srcDir)
|
||||
}
|
||||
generatedSourceDirs += file(srcDir)
|
||||
|
||||
}
|
||||
|
||||
// Don't exclude build directory
|
||||
excludeDirs -= file(buildDir)
|
||||
}
|
||||
}
|
||||
|
||||
/*===================================
|
||||
* "Fat" Build targets
|
||||
*===================================*/
|
||||
|
||||
|
||||
if (project.hasProperty('mainClassName') && (mainClassName != null)) {
|
||||
|
||||
task mavenCapsule(type: MavenCapsule) {
|
||||
description = "Generate a capsule jar that automatically downloads and caches dependencies when run."
|
||||
applicationClass mainClassName
|
||||
destinationDir = buildDir
|
||||
}
|
||||
|
||||
task fatCapsule(type: FatCapsule) {
|
||||
description = "Generate a single capsule jar containing everything. Use -Pfatmain=... to override main class"
|
||||
|
||||
destinationDir = buildDir
|
||||
|
||||
def fatMain = hasProperty('fatmain') ? fatmain : mainClassName
|
||||
|
||||
applicationClass fatMain
|
||||
|
||||
def testJar = hasProperty('test')
|
||||
|
||||
if (hasProperty('fatmain')) {
|
||||
appendix = "fat-${fatMain}"
|
||||
} else {
|
||||
appendix = "fat"
|
||||
}
|
||||
|
||||
if (testJar) {
|
||||
from sourceSets.test.output
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*===================================
|
||||
* Repositories
|
||||
*===================================*/
|
||||
|
||||
repositories {
|
||||
|
||||
// Prefer the local nexus repository (it may have 3rd party artifacts not found in mavenCentral)
|
||||
maven {
|
||||
url nexusRepository
|
||||
|
||||
if (isSnapshot) {
|
||||
credentials { username
|
||||
password
|
||||
|
||||
username nexusUser
|
||||
password nexusPassword
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Use local maven repository
|
||||
mavenLocal()
|
||||
|
||||
// Use 'maven central' for other dependencies.
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
task "info" << {
|
||||
println "Project: ${project.name}"
|
||||
println "Description: ${project.description}"
|
||||
println "--------------------------"
|
||||
println "GroupId: $groupId"
|
||||
println "Version: $version (${isSnapshot ? 'snapshot' : 'release'})"
|
||||
println ""
|
||||
}
|
||||
info.description 'Print some information about project parameters'
|
||||
|
||||
|
||||
/*===================================
|
||||
* Publishing
|
||||
*===================================*/
|
||||
|
||||
publishing {
|
||||
publications {
|
||||
mavenJava(MavenPublication) {
|
||||
groupId project.groupId
|
||||
pom.withXml {
|
||||
asNode().appendNode('description', project.description)
|
||||
}
|
||||
from project.components.java
|
||||
|
||||
}
|
||||
}
|
||||
repositories {
|
||||
maven {
|
||||
url "https://cs.idc.ac.il/nexus/content/repositories/${project.isSnapshot ? 'snapshots' : 'releases'}"
|
||||
credentials { username
|
||||
password
|
||||
|
||||
username nexusUser
|
||||
password nexusPassword
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -0,0 +1 @@
|
|||
../gradlew
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,231 @@
|
|||
package meerkat;
|
||||
|
||||
import com.google.protobuf.ByteString;
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
import meerkat.ProtobufsMessages.BasicMessage;
|
||||
import meerkat.ProtobufsMessages.Tag;
|
||||
import meerkat.bulletinboard.SimpleBulletinBoardClient;
|
||||
import meerkat.comm.CommunicationException;
|
||||
import meerkat.crypto.Encryption;
|
||||
import meerkat.protobuf.BulletinBoardAPI;
|
||||
import meerkat.protobuf.Crypto;
|
||||
import util.AccurateTimestamp;
|
||||
import util.CollectionMessagesUtils;
|
||||
import util.RegistryTags;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.text.ParseException;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Created by Vladimir Eliezer Tokarev on 1/8/2016.
|
||||
* Gives the ability to manage voters information
|
||||
*/
|
||||
public class SimpleRegistry {
|
||||
|
||||
protected Encryption signatory;
|
||||
|
||||
protected SimpleBulletinBoardClient communicator;
|
||||
|
||||
public SimpleRegistry(Encryption signatory, SimpleBulletinBoardClient communicator) {
|
||||
this.signatory = signatory;
|
||||
this.communicator = communicator;
|
||||
}
|
||||
|
||||
private Tag.Builder[] GetTagsArrayInLength(int length) {
|
||||
Tag.Builder[] tags = new Tag.Builder[length];
|
||||
|
||||
for (int i = 0; i < length; i++) {
|
||||
tags[i] = Tag.newBuilder();
|
||||
}
|
||||
return tags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates BulletinBoardMessage with signed basicMessage and UnsignedBulletinBoardMessage that contains the basic message
|
||||
*
|
||||
* @param basicMessage BasicMessage
|
||||
* @return BulletinBoardAPI.BulletinBoardMessage
|
||||
*/
|
||||
private BulletinBoardAPI.BulletinBoardMessage CreateBulletinBoardMessage(BasicMessage basicMessage) throws IOException {
|
||||
BulletinBoardAPI.BulletinBoardMessage.Builder bulletinBoardMessage =
|
||||
BulletinBoardAPI.BulletinBoardMessage.newBuilder();
|
||||
|
||||
Crypto.RerandomizableEncryptedMessage encryptedMessage =
|
||||
signatory.encrypt(basicMessage, signatory.generateRandomness(new Random()));
|
||||
|
||||
Crypto.Signature.Builder messageSignature = Crypto.Signature.newBuilder();
|
||||
messageSignature.mergeFrom(encryptedMessage);
|
||||
|
||||
BulletinBoardAPI.UnsignedBulletinBoardMessage.Builder unsignedBulletinBoardMessage =
|
||||
BulletinBoardAPI.UnsignedBulletinBoardMessage.newBuilder();
|
||||
unsignedBulletinBoardMessage.setData(basicMessage.toByteString());
|
||||
|
||||
bulletinBoardMessage.addSig(messageSignature);
|
||||
|
||||
bulletinBoardMessage.setMsg(unsignedBulletinBoardMessage);
|
||||
|
||||
return bulletinBoardMessage.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets messages that have the wanted id tag and have or the ADD_TO_GROUP_TAG or REMOVE_FROM_GROUP_TAG
|
||||
*
|
||||
* @param tags the tags based on which the messages will be filtered
|
||||
* @return List<BulletinBoardAPI.BulletinBoardMessage>
|
||||
*/
|
||||
private List<BulletinBoardAPI.BulletinBoardMessage> GetRelevantMessages(List<Tag> tags) {
|
||||
BulletinBoardAPI.MessageFilterList.Builder filters =
|
||||
BulletinBoardAPI.MessageFilterList.newBuilder();
|
||||
|
||||
for (Tag tag : tags) {
|
||||
BulletinBoardAPI.MessageFilter.Builder idFilter =
|
||||
BulletinBoardAPI.MessageFilter.newBuilder().setTag(tag.getContent());
|
||||
|
||||
filters.addFilter(idFilter);
|
||||
}
|
||||
return communicator.readMessages(filters.build());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets Relevant bulletinBoard messages from communicator than converts them to VoterRegistryMessages
|
||||
*
|
||||
* @param tags list of tags that will be used as filters
|
||||
* @return List<VoterRegistryMessage>
|
||||
*/
|
||||
private List<VoterRegistryMessage> GetRelevantVoterRegistryMessages(List<Tag> tags) throws InvalidProtocolBufferException {
|
||||
List<BulletinBoardAPI.BulletinBoardMessage> relevantMessages = GetRelevantMessages(tags);
|
||||
List<BasicMessage> messages = CollectionMessagesUtils.GetBasicMessagesFromBulletinBoardMessages(relevantMessages);
|
||||
List<VoterRegistryMessage> voterRegistryMessages = CollectionMessagesUtils.ConvertToVoterRegistryMessages(messages);
|
||||
|
||||
return voterRegistryMessages;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds new voter to the bulletin-board
|
||||
*
|
||||
* @param voterID
|
||||
* @param personalData for example residence location
|
||||
* @return void
|
||||
* @throws throws CommunicationException
|
||||
*/
|
||||
public void AddVoter(String voterID, String personalData) throws CommunicationException, IOException {
|
||||
Tag.Builder[] tags = GetTagsArrayInLength(3);
|
||||
tags[0].setContent(RegistryTags.ID_TAG + " " + voterID);
|
||||
tags[1].setContent(RegistryTags.VOTER_ENTRY_TAG.toString());
|
||||
tags[2].setContent(RegistryTags.ACTION_TIMESTAMP_TAG + " " + AccurateTimestamp.GetCurrentTimestampString());
|
||||
|
||||
BasicMessage.Builder basicMessage = BasicMessage.newBuilder().addTag(tags[0]).addTag(tags[1]).addTag(tags[1]);
|
||||
basicMessage.setData(ByteString.copyFrom(personalData.getBytes()));
|
||||
|
||||
communicator.postMessage(CreateBulletinBoardMessage(basicMessage.build()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Adding given voter to given group
|
||||
*
|
||||
* @param voterID
|
||||
* @param groupID
|
||||
* @return true if the adding action succeeded else return false
|
||||
* @throws CommunicationException
|
||||
*/
|
||||
public void AddToGroup(String voterID, String groupID) throws CommunicationException, IOException {
|
||||
Tag.Builder[] tags = GetTagsArrayInLength(4);
|
||||
tags[0].setContent(RegistryTags.ID_TAG + " " + voterID);
|
||||
tags[1].setContent(RegistryTags.GROUP_ID_TAG + " " + groupID);
|
||||
tags[2].setContent(RegistryTags.GROUP_ACTION_TAG + " " + RegistryTags.ADD_TO_GROUP_TAG);
|
||||
tags[3].setContent(RegistryTags.ACTION_TIMESTAMP_TAG + " " + AccurateTimestamp.GetCurrentTimestampString());
|
||||
|
||||
BasicMessage.Builder basicMessage =
|
||||
BasicMessage.newBuilder().addTag(tags[0]).addTag(tags[1]).addTag(tags[2]).addTag(tags[3]);
|
||||
|
||||
communicator.postMessage(CreateBulletinBoardMessage(basicMessage.build()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes given voter from given group
|
||||
*
|
||||
* @param voterID
|
||||
* @param groupID
|
||||
* @return true if the removing action succeeded else return false
|
||||
* @throws CommunicationException
|
||||
*/
|
||||
public void RemoveFromGroup(String voterID, String groupID) throws CommunicationException, IOException {
|
||||
Tag.Builder[] tags = GetTagsArrayInLength(4);
|
||||
tags[0].setContent(RegistryTags.ID_TAG + " " + voterID);
|
||||
tags[1].setContent(RegistryTags.GROUP_ID_TAG + " " + groupID);
|
||||
tags[2].setContent(RegistryTags.GROUP_ACTION_TAG + " " + RegistryTags.REMOVE_FROM_GROUP_TAG);
|
||||
tags[3].setContent(RegistryTags.ACTION_TIMESTAMP_TAG + " " + AccurateTimestamp.GetCurrentTimestampString());
|
||||
|
||||
BasicMessage.Builder basicMessage =
|
||||
BasicMessage.newBuilder().addTag(tags[0]).addTag(tags[1]).addTag(tags[2]).addTag(tags[3]);
|
||||
|
||||
communicator.postMessage(CreateBulletinBoardMessage(basicMessage.build()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets that the voter have voted
|
||||
*
|
||||
* @param id id tag string
|
||||
* @return true if the set voted succeded else false
|
||||
* @throws CommunicationException
|
||||
*/
|
||||
public void AddVoter(String id) throws CommunicationException, IOException {
|
||||
Tag.Builder[] tags = GetTagsArrayInLength(3);
|
||||
tags[0].setContent(RegistryTags.ID_TAG + " " + id);
|
||||
tags[1].setContent(RegistryTags.VOTE_ACTION_TAG.toString());
|
||||
tags[2].setContent(RegistryTags.ACTION_TIMESTAMP_TAG + " " + AccurateTimestamp.GetCurrentTimestampString());
|
||||
|
||||
BasicMessage.Builder basicMessage = BasicMessage.newBuilder().addTag(tags[0]).addTag(tags[1]).addTag(tags[2]);
|
||||
|
||||
communicator.postMessage(CreateBulletinBoardMessage(basicMessage.build()));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Requests all the groups that the given id voter is in
|
||||
*
|
||||
* @param id id tag string
|
||||
* @return list of groups ids (or names), if the method fails its empty
|
||||
* @throws CommunicationException, InvalidProtocolBufferException
|
||||
*/
|
||||
public List<String> GetGroups(String id) throws CommunicationException, InvalidProtocolBufferException {
|
||||
List<Tag> GroupsActionsTags = new ArrayList<Tag>();
|
||||
GroupsActionsTags.add(Tag.newBuilder().setContent(RegistryTags.ID_TAG + " " + id).build());
|
||||
GroupsActionsTags.add(Tag.newBuilder().setContent(RegistryTags.GROUP_ACTION_TAG + " " + RegistryTags.REMOVE_FROM_GROUP_TAG).build());
|
||||
GroupsActionsTags.add(Tag.newBuilder().setContent(RegistryTags.GROUP_ACTION_TAG + " " + RegistryTags.ADD_TO_GROUP_TAG).build());
|
||||
|
||||
List<VoterRegistryMessage> voterRegistryMessages = GetRelevantVoterRegistryMessages(GroupsActionsTags);
|
||||
|
||||
try {
|
||||
Map<String, VoterRegistryMessage> groupIdToMessage = CollectionMessagesUtils.GetLatestGroupsActions(voterRegistryMessages);
|
||||
return CollectionMessagesUtils.GetListOfGroupIds(groupIdToMessage);
|
||||
} catch (ParseException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves list of strings that represents voter
|
||||
*
|
||||
* @param id id tag string
|
||||
* @return list of strings (empty list if the lookup failed)
|
||||
* @throws CommunicationException
|
||||
*/
|
||||
public List<String> GetPersonIDDetails(String id) throws CommunicationException, InvalidProtocolBufferException, ParseException {
|
||||
List<Tag> GroupsActionsTags = new ArrayList<Tag>();
|
||||
GroupsActionsTags.add(Tag.newBuilder().setContent(RegistryTags.ID_TAG + " " + id).build());
|
||||
GroupsActionsTags.add(Tag.newBuilder().setContent(RegistryTags.VOTER_ENTRY_TAG.toString()).build());
|
||||
|
||||
List<VoterRegistryMessage> voterRegistryMessages = GetRelevantVoterRegistryMessages(GroupsActionsTags);
|
||||
VoterRegistryMessage LatestMessage = voterRegistryMessages.get(0);
|
||||
|
||||
for (VoterRegistryMessage message : voterRegistryMessages) {
|
||||
if (message.GetBasicMessageActionTimestamp().before(LatestMessage.GetBasicMessageActionTimestamp())) {
|
||||
LatestMessage = message;
|
||||
}
|
||||
}
|
||||
|
||||
return Arrays.asList(LatestMessage.GetWantedTagFromBasicMessage(RegistryTags.ID_TAG), LatestMessage.base.getData().toString());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
package meerkat;
|
||||
|
||||
import util.AccurateTimestamp;
|
||||
import util.RegistryTags;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import java.text.ParseException;
|
||||
|
||||
/**
|
||||
* Created by Vladimir Eliezer Tokarev on 1/15.2016
|
||||
* this class wraps BasicMessage and gives the ability to find wanted tags
|
||||
*/
|
||||
public class VoterRegistryMessage {
|
||||
|
||||
public ProtobufsMessages.BasicMessage base;
|
||||
|
||||
public VoterRegistryMessage(ProtobufsMessages.BasicMessage message){
|
||||
base = ProtobufsMessages.BasicMessage.newBuilder().addAllTag(message.getTagList()).build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the wanted tag from given basic message
|
||||
* @param tagName
|
||||
* @return string
|
||||
*/
|
||||
public String GetWantedTagFromBasicMessage(RegistryTags tagName){
|
||||
for (ProtobufsMessages.Tag tag : base.getTagList()) {
|
||||
if ( tag.getContent().contains(tagName.toString())) {
|
||||
return tag.getContent();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the timestamp of the tag adding
|
||||
* @return Timestamp
|
||||
* @throws ParseException
|
||||
*/
|
||||
public Timestamp GetBasicMessageActionTimestamp() throws ParseException {
|
||||
for (ProtobufsMessages.Tag tag : base.getTagList()) {
|
||||
if ( tag.getContent().contains(RegistryTags.ACTION_TIMESTAMP_TAG.toString())) {
|
||||
String[] tagParts = tag.getContent().split(" ");
|
||||
String timestamp = tagParts[tagParts.length - 1];
|
||||
return AccurateTimestamp.GetTimestampFromString(timestamp);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given message have the ADD_TO_GROUP_TAG
|
||||
* @return
|
||||
*/
|
||||
public boolean IsGroupAdding() {
|
||||
for (ProtobufsMessages.Tag tag : base.getTagList()) {
|
||||
if ( tag.getContent().contains(RegistryTags.ADD_TO_GROUP_TAG.toString())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
package util;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* Created by Vladimir Eliezer Tokarev on 1/15/2016.
|
||||
* converts time stamps to strings and the other way
|
||||
*/
|
||||
public abstract class AccurateTimestamp {
|
||||
|
||||
private static final String DATE_FORMAT = "yyyy-MM-dd hh:mm:ss.SSS";
|
||||
|
||||
/**
|
||||
* Converts current timestamp to string
|
||||
* @return
|
||||
*/
|
||||
public static String GetCurrentTimestampString(){
|
||||
return new SimpleDateFormat(DATE_FORMAT).format(new java.util.Date());
|
||||
}
|
||||
|
||||
/**
|
||||
* Convets string timesta,p tp java.sql.timestamp
|
||||
* @param timestamp string
|
||||
* @return
|
||||
* @throws ParseException
|
||||
*/
|
||||
public static java.sql.Timestamp GetTimestampFromString(String timestamp) throws ParseException {
|
||||
Date date = new SimpleDateFormat(DATE_FORMAT).parse(timestamp);
|
||||
return new Timestamp(date.getTime());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
package util;
|
||||
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
import meerkat.ProtobufsMessages;
|
||||
import meerkat.VoterRegistryMessage;
|
||||
import meerkat.protobuf.BulletinBoardAPI;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Created by Vladimir Eliezer Tokarev on 1/15/2016.
|
||||
* adds extra functionality to Messages collections
|
||||
*/
|
||||
public abstract class CollectionMessagesUtils {
|
||||
|
||||
/**
|
||||
* Converts lost of BasicMessages to VoterRegistryMessags
|
||||
* @param messages list<BasicMessages>
|
||||
* @return List<VoterRegistryMessage>
|
||||
*/
|
||||
public static List<VoterRegistryMessage> ConvertToVoterRegistryMessages(List<ProtobufsMessages.BasicMessage> messages){
|
||||
List<VoterRegistryMessage> voterRegistryMessages = new ArrayList<VoterRegistryMessage>();
|
||||
for (ProtobufsMessages.BasicMessage message : messages){
|
||||
voterRegistryMessages.add(new VoterRegistryMessage(message));
|
||||
}
|
||||
return voterRegistryMessages;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets map of GroupId to basicMessage, where the basicMessages are the last actions for those groups
|
||||
* @param messages List<BasicMessages>
|
||||
* @return Map<String, VoterRegistryMessage>
|
||||
* @throws ParseException
|
||||
*/
|
||||
public static Map<String, VoterRegistryMessage> GetLatestGroupsActions(List<VoterRegistryMessage> messages) throws ParseException {
|
||||
|
||||
Map<String, VoterRegistryMessage> groupIdToMessage = new HashMap<String, VoterRegistryMessage>();
|
||||
|
||||
// iterate trough all the messages and put into the map the last updated groups actions
|
||||
|
||||
for (int i = 0; i < messages.size(); i++) {
|
||||
String groupId = messages.get(i).GetWantedTagFromBasicMessage(RegistryTags.GROUP_ID_TAG);
|
||||
VoterRegistryMessage temp = groupIdToMessage.get(groupId);
|
||||
|
||||
if (temp != null) {
|
||||
if (temp != messages.get(i)) {
|
||||
if (temp.GetBasicMessageActionTimestamp().before(messages.get(i).GetBasicMessageActionTimestamp())) {
|
||||
groupIdToMessage.put(groupId, messages.get(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return groupIdToMessage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets list of groups ids of the basicMessages that carried the adding to group tag
|
||||
* @param groupIdToMessage Map<String, BasicMessage>
|
||||
* @return List<String>
|
||||
*/
|
||||
public static List<String> GetListOfGroupIds(Map<String, VoterRegistryMessage> groupIdToMessage) {
|
||||
List<String> groupsIds = new ArrayList<String>();
|
||||
|
||||
for (VoterRegistryMessage message : groupIdToMessage.values()) {
|
||||
if (message.IsGroupAdding()) {
|
||||
String groupId = message.GetWantedTagFromBasicMessage(RegistryTags.GROUP_ID_TAG);
|
||||
groupsIds.add(groupId);
|
||||
}
|
||||
}
|
||||
return groupsIds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all the basic messages from bulletin board messages
|
||||
* @param listOfMessages
|
||||
* @return List<BasicMessage> G
|
||||
* @throws InvalidProtocolBufferException
|
||||
*/
|
||||
public static final List<ProtobufsMessages.BasicMessage> GetBasicMessagesFromBulletinBoardMessages(
|
||||
List<BulletinBoardAPI.BulletinBoardMessage> listOfMessages) throws InvalidProtocolBufferException {
|
||||
|
||||
List<ProtobufsMessages.BasicMessage> basicMessages = new ArrayList<ProtobufsMessages.BasicMessage>();
|
||||
|
||||
for (BulletinBoardAPI.BulletinBoardMessage bulletinBoardMessage : listOfMessages){
|
||||
ProtobufsMessages.BasicMessage.Builder basicMessage =
|
||||
ProtobufsMessages.BasicMessage.newBuilder().mergeFrom(bulletinBoardMessage.getMsg().getData());
|
||||
basicMessages.add(basicMessage.build());
|
||||
}
|
||||
|
||||
return basicMessages;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
package util;
|
||||
|
||||
/**
|
||||
* Created by Vladimir Eliezer Tokarev on 1/9/2016.
|
||||
* Have the tags for the registry messages
|
||||
*/
|
||||
public enum RegistryTags {
|
||||
|
||||
ID_TAG("ID:"),
|
||||
VOTER_ENTRY_TAG("Voter Entry"),
|
||||
GROUP_ID_TAG("Group ID:"),
|
||||
GROUP_ACTION_TAG("Group Action:"),
|
||||
REMOVE_FROM_GROUP_TAG("Remove From Group"),
|
||||
ADD_TO_GROUP_TAG("Add To Group"),
|
||||
ACTION_TIMESTAMP_TAG("Action timestamp: "),
|
||||
VOTE_ACTION_TAG("Vote Action");
|
||||
|
||||
private final String text;
|
||||
|
||||
RegistryTags(final String text){
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
public String toString(){
|
||||
return text;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
package meerkat;
|
||||
|
||||
option java_outer_classname = "ProtobufsMessages";
|
||||
|
||||
message Tag {
|
||||
required string content = 1;
|
||||
}
|
||||
|
||||
message BasicMessage {
|
||||
repeated Tag tag = 1;
|
||||
optional bytes data = 2;
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
import junit.framework.TestCase;
|
||||
|
||||
/**
|
||||
* Created by Vladimir Eliezer Tokarev on 1/16/2016.
|
||||
* Tests the Simple Registry contents
|
||||
*
|
||||
*/
|
||||
public class SimpleRegistryTest extends TestCase{
|
||||
|
||||
/**
|
||||
* Initialize SimpleRegistry object
|
||||
*/
|
||||
public void setUp(){
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that add voter creates new correct bulletin board message and add the voter
|
||||
*/
|
||||
public void testAddVoter(){
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that set voted posts creates correct bulletin board message and sets that the user have been voted
|
||||
*/
|
||||
public void testSetVoted(){
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that add to group creates correct bulletin board message and adds a user to a group
|
||||
*/
|
||||
public void testAddToGroup(){
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that remove from group creates correct bulletin board message and removes the user from a group
|
||||
*/
|
||||
public void testRemoveFromGroup(){
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that get groups retrieves the right groups the user are in
|
||||
*/
|
||||
public void testGetGroups(){
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that the personal data outputted about the user is right
|
||||
*/
|
||||
public void testGetPersonalIDDetails(){
|
||||
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue