Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Various upgrades #4

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,6 @@ Conclusion

I don't think that this is the best approach to archive this functionality but it just works without reinventing spring-data-mongodb.

With just a `ThreadLocal` it is not done, if you walso want to create Indexes. So I added a bit more sugar to it.


Just take a [look into Application.java](src/main/java/com/github/zarathustra/Application.java)

Happy Hacking!
Expand Down
16 changes: 8 additions & 8 deletions pom.xml
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.github.zarathustra</groupId>
<artifactId>multi-tenant-spring-mongodb</artifactId>
<version>0.0.1-SNAPSHOT</version>

<properties>
<spring.version>4.0.5.RELEASE</spring.version>
<spring.boot.version>1.1.1.RELEASE</spring.boot.version>
<!-- because spring-data-mongo comes with a old one where index creation
<spring.version>5.1.8.RELEASE</spring.version>
<spring.boot.version>2.1.6.RELEASE</spring.boot.version>
<!-- because spring-data-mongo comes with a old one where index creation
was faulty -->
<mongo.java.driver.version>2.12.2</mongo.java.driver.version>
<spring.data.mongodb.version>1.5.0.RELEASE</spring.data.mongodb.version>
<mongo.java.driver.version>3.10.2</mongo.java.driver.version>
<spring.data.mongodb.version>2.1.9.RELEASE</spring.data.mongodb.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
</properties>
Expand All @@ -23,8 +23,8 @@
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<source>1.11</source>
<target>1.11</target>
</configuration>
</plugin>
<plugin>
Expand Down
30 changes: 17 additions & 13 deletions src/main/java/com/github/zarathustra/Application.java
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package com.github.zarathustra;

import java.time.LocalDate;
import java.time.Month;
import java.time.temporal.ChronoUnit;

import com.github.zarathustra.domain.Person;
import com.github.zarathustra.mongo.MultiTenantMongoDbFactory;
import com.github.zarathustra.service.PersonRepository;
import com.mongodb.MongoClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
Expand All @@ -12,10 +12,9 @@
import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.core.MongoTemplate;

import com.github.zarathustra.domain.Person;
import com.github.zarathustra.mongo.MultiTenantMongoDbFactory;
import com.github.zarathustra.service.PersonRepository;
import com.mongodb.Mongo;
import java.time.LocalDate;
import java.time.Month;
import java.time.temporal.ChronoUnit;

@Configuration
@EnableAutoConfiguration
Expand All @@ -28,16 +27,21 @@ public class Application implements CommandLineRunner {
PersonRepository personRepository;

@Bean
public MongoTemplate mongoTemplate(final Mongo mongo) throws Exception {
return new MongoTemplate(mongoDbFactory(mongo));
public MongoClient mongoClient() {
return new MongoClient("localhost");
}

@Bean
public MongoTemplate mongoTemplate(final MongoClient mongoClient) throws Exception {
return new MongoTemplate(mongoDbFactory(mongoClient));
}

@Bean
public MultiTenantMongoDbFactory mongoDbFactory(final Mongo mongo) throws Exception {
return new MultiTenantMongoDbFactory(mongo, "test");
public MultiTenantMongoDbFactory mongoDbFactory(final MongoClient mongoClient) throws Exception {
return new MultiTenantMongoDbFactory(mongoClient, "test");
}

// just to make it as simple as possible.
// just to make it as simple as possible.
private Person createPerson(final String name, final String surename, final long age) {
Person p = new Person();
p.setName(name);
Expand Down
5 changes: 2 additions & 3 deletions src/main/java/com/github/zarathustra/domain/Person.java
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
package com.github.zarathustra.domain;


import com.google.common.base.Objects;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.index.CompoundIndex;
import org.springframework.data.mongodb.core.index.CompoundIndexes;
import org.springframework.data.mongodb.core.mapping.Document;

import com.google.common.base.Objects;

@CompoundIndexes({
@CompoundIndex(name = "primary_index", collection = "person", def = "{'name': 1, 'surname': 1}")
@CompoundIndex(name = "primary_index", def = "{'name': 1, 'surname': 1}")
})
@Document(collection = "person")
public class Person {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,44 +1,27 @@
package com.github.zarathustra.mongo;

import java.util.HashMap;

import com.mongodb.MongoClient;
import com.mongodb.client.MongoDatabase;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.SimpleMongoDbFactory;
import org.springframework.data.mongodb.core.index.MongoPersistentEntityIndexResolver;
import org.springframework.data.mongodb.core.index.MongoPersistentEntityIndexResolver.IndexDefinitionHolder;
import org.springframework.data.mongodb.core.mapping.BasicMongoPersistentEntity;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
import org.springframework.util.Assert;

import com.mongodb.DB;
import com.mongodb.Mongo;
import java.util.HashMap;

public class MultiTenantMongoDbFactory extends SimpleMongoDbFactory {

private final String defaultName;
private static final Logger logger = LoggerFactory.getLogger(MultiTenantMongoDbFactory.class);

private MongoTemplate mongoTemplate;

private static final ThreadLocal<String> dbName = new ThreadLocal<String>();
private static final HashMap<String, Object> databaseIndexMap = new HashMap<String, Object>();
private static final Logger logger = LoggerFactory.getLogger(MultiTenantMongoDbFactory.class);
private static final ThreadLocal<String> dbName = new ThreadLocal<>();
private static final HashMap<String, Object> databaseIndexMap = new HashMap<>();
private final String defaultName;

public MultiTenantMongoDbFactory(final Mongo mongo, final String defaultDatabaseName) {
public MultiTenantMongoDbFactory(final MongoClient mongo, final String defaultDatabaseName) {
super(mongo, defaultDatabaseName);
logger.debug("Instantiating " + MultiTenantMongoDbFactory.class.getName() + " with default database name: " + defaultDatabaseName);
logger.debug("Instantiating " + MultiTenantMongoDbFactory.class.getName() + " with default database name: "
+ defaultDatabaseName);
this.defaultName = defaultDatabaseName;
}

// dirty but ... what can I do?
public void setMongoTemplate(final MongoTemplate mongoTemplate) {
Assert.isNull(this.mongoTemplate, "You can set MongoTemplate just once");
this.mongoTemplate = mongoTemplate;
}

public static void setDatabaseNameForCurrentThread(final String databaseName) {
logger.debug("Switching to database: " + databaseName);
dbName.set(databaseName);
Expand All @@ -52,52 +35,10 @@ public static void clearDatabaseNameForCurrentThread() {
}

@Override
public DB getDb() {
public MongoDatabase getDb() {
final String tlName = dbName.get();
final String dbToUse = (tlName != null ? tlName : this.defaultName);
logger.debug("Acquiring database: " + dbToUse);
createIndexIfNecessaryFor(dbToUse);
return super.getDb(dbToUse);
}

private void createIndexIfNecessaryFor(final String database) {
if (this.mongoTemplate == null) {
logger.error("MongoTemplate is null, will not create any index.");
return;
}
// sync and init once
boolean needsToBeCreated = false;
synchronized (MultiTenantMongoDbFactory.class) {
final Object syncObj = databaseIndexMap.get(database);
if (syncObj == null) {
databaseIndexMap.put(database, new Object());
needsToBeCreated = true;
}
}
// make sure only one thread enters with needsToBeCreated = true
synchronized (databaseIndexMap.get(database)) {
if (needsToBeCreated) {
logger.debug("Creating indices for database name=[" + database + "]");
createIndexes();
logger.debug("Done with creating indices for database name=[" + database + "]");
}
}
}

private void createIndexes() {
final MongoMappingContext mappingContext = (MongoMappingContext) this.mongoTemplate.getConverter().getMappingContext();
final MongoPersistentEntityIndexResolver indexResolver = new MongoPersistentEntityIndexResolver(mappingContext);
for (BasicMongoPersistentEntity<?> persistentEntity : mappingContext.getPersistentEntities()) {
checkForAndCreateIndexes(indexResolver, persistentEntity);
}
}
private void checkForAndCreateIndexes(final MongoPersistentEntityIndexResolver indexResolver, final MongoPersistentEntity<?> entity) {
// make sure its a root document
if (entity.findAnnotation(Document.class) != null) {
for (IndexDefinitionHolder indexDefinitionHolder : indexResolver.resolveIndexForClass(entity.getType())) {
// work because of javas reentered lock feature
this.mongoTemplate.indexOps(entity.getType()).ensureIndex(indexDefinitionHolder);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package com.github.zarathustra.service;

import org.springframework.data.mongodb.repository.MongoRepository;

import com.github.zarathustra.domain.Person;
import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface PersonRepository extends MongoRepository<Person, String> {

}