From 49db19ab64a0b7d5b23a3c9f4031c0208a94ab3f Mon Sep 17 00:00:00 2001 From: Felix Klauke Date: Sun, 6 Sep 2020 13:55:55 +0200 Subject: [PATCH] Add database utilities --- build.gradle | 2 +- config/checkstyle/checkstyle.xml | 255 ++++++++++++++++++ settings.gradle | 3 + susceptor-dependency-injection/build.gradle | 11 + susceptor-persistence/build.gradle | 16 ++ .../persistence/DatastoreFactory.java | 32 +++ .../persistence/inject/PersistenceConfig.java | 124 +++++++++ .../persistence/inject/PersistenceModule.java | 81 ++++++ 8 files changed, 523 insertions(+), 1 deletion(-) create mode 100644 config/checkstyle/checkstyle.xml create mode 100644 susceptor-dependency-injection/build.gradle create mode 100644 susceptor-persistence/build.gradle create mode 100644 susceptor-persistence/src/main/java/de/marmeladenoma/susceptor/persistence/DatastoreFactory.java create mode 100644 susceptor-persistence/src/main/java/de/marmeladenoma/susceptor/persistence/inject/PersistenceConfig.java create mode 100644 susceptor-persistence/src/main/java/de/marmeladenoma/susceptor/persistence/inject/PersistenceModule.java diff --git a/build.gradle b/build.gradle index 973d2e4..1fbb2e6 100644 --- a/build.gradle +++ b/build.gradle @@ -4,7 +4,7 @@ plugins { subprojects { group "de.marmeladenoma" - version "0.1.0" + version "0.2.0" apply plugin: 'java' apply plugin: 'checkstyle' diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml new file mode 100644 index 0000000..af71a01 --- /dev/null +++ b/config/checkstyle/checkstyle.xml @@ -0,0 +1,255 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index ef6c445..4e2cb5e 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1 +1,4 @@ rootProject.name = 'susceptor' +include 'susceptor-persistence' +include 'susceptor-dependency-injection' + diff --git a/susceptor-dependency-injection/build.gradle b/susceptor-dependency-injection/build.gradle new file mode 100644 index 0000000..69fa466 --- /dev/null +++ b/susceptor-dependency-injection/build.gradle @@ -0,0 +1,11 @@ +dependencies { + compile 'com.google.inject:guice:4.2.3' +} + +jar { + from { + configurations + .compileClasspath + .collect { it.isDirectory() ? it : zipTree(it) } + } +} \ No newline at end of file diff --git a/susceptor-persistence/build.gradle b/susceptor-persistence/build.gradle new file mode 100644 index 0000000..96f5420 --- /dev/null +++ b/susceptor-persistence/build.gradle @@ -0,0 +1,16 @@ +plugins { + id 'java-library' +} + +dependencies { + api project(':susceptor-dependency-injection') + implementation 'dev.morphia.morphia:morphia-core:2.0.0' +} + +jar { + from { + configurations + .compileClasspath + .collect { it.isDirectory() ? it : zipTree(it) } + } +} \ No newline at end of file diff --git a/susceptor-persistence/src/main/java/de/marmeladenoma/susceptor/persistence/DatastoreFactory.java b/susceptor-persistence/src/main/java/de/marmeladenoma/susceptor/persistence/DatastoreFactory.java new file mode 100644 index 0000000..2d731b9 --- /dev/null +++ b/susceptor-persistence/src/main/java/de/marmeladenoma/susceptor/persistence/DatastoreFactory.java @@ -0,0 +1,32 @@ +package de.marmeladenoma.susceptor.persistence; + +import com.google.common.base.Preconditions; +import com.mongodb.client.MongoClient; +import dev.morphia.Datastore; +import dev.morphia.Morphia; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import javax.inject.Inject; +import javax.inject.Singleton; + +@Singleton +public final class DatastoreFactory { + private final MongoClient mongoClient; + private final Map datastores = new ConcurrentHashMap<>(); + + @Inject + private DatastoreFactory(MongoClient mongoClient) { + this.mongoClient = mongoClient; + } + + public Datastore createDatastore(String databaseName) { + Preconditions.checkNotNull(databaseName); + Preconditions.checkArgument(!databaseName.isEmpty()); + Preconditions.checkArgument(!databaseName.isBlank()); + return datastores.computeIfAbsent(databaseName, this::instantiateDatastore); + } + + private Datastore instantiateDatastore(String databaseName) { + return Morphia.createDatastore(mongoClient, databaseName); + } +} diff --git a/susceptor-persistence/src/main/java/de/marmeladenoma/susceptor/persistence/inject/PersistenceConfig.java b/susceptor-persistence/src/main/java/de/marmeladenoma/susceptor/persistence/inject/PersistenceConfig.java new file mode 100644 index 0000000..862ce82 --- /dev/null +++ b/susceptor-persistence/src/main/java/de/marmeladenoma/susceptor/persistence/inject/PersistenceConfig.java @@ -0,0 +1,124 @@ +package de.marmeladenoma.susceptor.persistence.inject; + +import com.google.common.base.MoreObjects; +import com.google.common.base.Preconditions; +import java.util.Objects; + +public final class PersistenceConfig { + private final String mongoConnectionString; + private final String mongoUser; + private final String mongoSource; + private final String mongoPassword; + + PersistenceConfig( + String mongoConnectionString, + String mongoUser, + String mongoSource, + String mongoPassword + ) { + this.mongoConnectionString = mongoConnectionString; + this.mongoUser = mongoUser; + this.mongoSource = mongoSource; + this.mongoPassword = mongoPassword; + } + + public String mongoHost() { + return mongoConnectionString; + } + + public String mongoUser() { + return mongoUser; + } + + public String mongoSource() { + return mongoSource; + } + + public String mongoPassword() { + return mongoPassword; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + PersistenceConfig that = (PersistenceConfig) o; + return mongoConnectionString.equals(that.mongoConnectionString) + && mongoUser.equals(that.mongoUser) + && mongoSource.equals(that.mongoSource) + && mongoPassword.equals(that.mongoPassword); + } + + @Override + public int hashCode() { + return Objects + .hash(mongoConnectionString, mongoUser, mongoSource, mongoPassword); + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("mongoHost", mongoConnectionString) + .add("mongoUser", mongoUser) + .add("mongoSource", mongoSource) + .add("mongoPassword", mongoPassword) + .toString(); + } + + public static PersistenceConfigBuilder newBuilder() { + return new PersistenceConfigBuilder(); + } + + public static final class PersistenceConfigBuilder { + private String mongoConnectionString; + private String mongoUser; + private String mongoSource; + private String mongoPassword; + + private PersistenceConfigBuilder() { + } + + public PersistenceConfigBuilder withMongoConnectionStrong( + String mongoConnectionString + ) { + Preconditions.checkNotNull(mongoConnectionString); + this.mongoConnectionString = mongoConnectionString; + return this; + } + + public PersistenceConfigBuilder withMongoUser(String mongoUser) { + Preconditions.checkNotNull(mongoUser); + this.mongoUser = mongoUser; + return this; + } + + public PersistenceConfigBuilder withMongoSource(String mongoSource) { + Preconditions.checkNotNull(mongoSource); + this.mongoSource = mongoSource; + return this; + } + + public PersistenceConfigBuilder withMongoPassword(String mongoPassword) { + Preconditions.checkNotNull(mongoPassword); + this.mongoPassword = mongoPassword; + return this; + } + + public PersistenceConfig build() { + Preconditions.checkNotNull(mongoConnectionString); + Preconditions.checkNotNull(mongoUser); + Preconditions.checkNotNull(mongoSource); + Preconditions.checkNotNull(mongoPassword); + return new PersistenceConfig( + mongoConnectionString, + mongoUser, + mongoSource, + mongoPassword + ); + } + } +} diff --git a/susceptor-persistence/src/main/java/de/marmeladenoma/susceptor/persistence/inject/PersistenceModule.java b/susceptor-persistence/src/main/java/de/marmeladenoma/susceptor/persistence/inject/PersistenceModule.java new file mode 100644 index 0000000..3b86ad5 --- /dev/null +++ b/susceptor-persistence/src/main/java/de/marmeladenoma/susceptor/persistence/inject/PersistenceModule.java @@ -0,0 +1,81 @@ +package de.marmeladenoma.susceptor.persistence.inject; + +import com.google.common.base.Preconditions; +import com.google.inject.AbstractModule; +import com.google.inject.Provides; +import com.google.inject.name.Names; +import com.mongodb.ConnectionString; +import com.mongodb.MongoClientSettings; +import com.mongodb.MongoCredential; +import com.mongodb.client.MongoClient; +import com.mongodb.client.MongoClients; +import javax.inject.Named; +import javax.inject.Singleton; + +public final class PersistenceModule extends AbstractModule { + private final PersistenceConfig persistenceConfig; + + private PersistenceModule(PersistenceConfig persistenceConfig) { + this.persistenceConfig = persistenceConfig; + } + + @Override + protected void configure() { + bindConstant().annotatedWith(Names.named("mongo_connection_string")) + .to(persistenceConfig.mongoHost()); + bindConstant().annotatedWith(Names.named("mongo_user")) + .to(persistenceConfig.mongoUser()); + bindConstant().annotatedWith(Names.named("mongo_source")) + .to(persistenceConfig.mongoSource()); + bindConstant().annotatedWith(Names.named("mongo_password")) + .to(persistenceConfig.mongoPassword()); + } + + @Provides + @Singleton + MongoClient provideMongoClient(MongoClientSettings clientSettings) { + return MongoClients.create(clientSettings); + } + + private static final String APPLICATION_NAME = "Susceptor"; + + @Provides + @Singleton + MongoClientSettings provideMongoClientSettings( + ConnectionString connectionString, + MongoCredential credential + ) { + return MongoClientSettings.builder() + .applicationName(APPLICATION_NAME) + .applyConnectionString(connectionString) + .credential(credential) + .build(); + } + + @Provides + @Singleton + ConnectionString provideConnectionString( + @Named("mongo_connection_string") String mongoConnectionString + ) { + return new ConnectionString(mongoConnectionString); + } + + @Provides + @Singleton + MongoCredential provideMongoCredential( + @Named("mongo_user") String mongoUser, + @Named("mongo_source") String mongoSource, + @Named("mongo_password") String mongoPassword + ) { + return MongoCredential.createScramSha256Credential( + mongoUser, + mongoSource, + mongoPassword.toCharArray() + ); + } + + public static PersistenceModule create(PersistenceConfig persistenceConfig) { + Preconditions.checkNotNull(persistenceConfig); + return new PersistenceModule(persistenceConfig); + } +}