Multi tenant architecture in spring mvc with jpa - java

I stucked with a serious problem in architecture of my enterprise application. My current application is a web application using spring framework 3.2+ and jpa 2.0. Now I need to support multi tenancy in current application.
My requirement is that when a user logged in to the system the data for the user should be served from respective database. In short I need multiple database support which may cause different connection string. So how can I connect to database dynamically?
My another problem is that tenant (particular client of the applications) can register himself on the fly, and on successful registration I need to create a environment containing database creation and initialization etc. for that tenant and on successful creation of environment users of tenants are able to access the application. So problem is how to create environment dynamically, how create EntityManagerFactory dynamically?
Any suggestions to achieve the multi tenancy are most welcome...

In a web environment, the multi-tenancy can be implemented with the creation of tenant-specific aliases to be defined in your /etc/hosts file or Windows\System32\drivers\etc\hosts in order to map tenant-specific hosts to the same servlet container.
Once you've done that you can define a servlet filter which gonna read the current used host and compare it to another mapping, to be defined in a properties file, for example, and populate a HTTP session parameter indicating the current tenant.
Here you've got the tenant in the session.
You have to target a common database and a specific 'tenant_database' table. This table must hold the database name, the password, the port, etc. All the datasource information to establish the connection to a targeted tenant database.
You can build an entityManagerFactory at this point:
Map<String, String> properties = new HashMap<String, String>();
properties.put("javax.persistence.jdbc.user", "admin");
properties.put("javax.persistence.jdbc.password", "admin");
EntityManagerFactory emf = Persistence.createEntityManagerFactory(
"jdbc:mysql://localhost:3306/myDB", properties);
You just have to think about obtaining it from the right place now.. :)
Hope it helps

Related

Perform search operations in multiple Databases in Spring Boot project

My Question- I have mongodb installed in ubuntu server and it has multiple databases and I want to connect to mongodb installed on server and get all the databases (name of databases, collections of every databases) and perform search operations on all the databases.
Note - I did not know the names of database
It won't work out-of-the-box. If you include the spring-boot mongodb starter project, it will look for the property 'spring.data.mongodb.uri' to connect to a single database, and if it does not find it, it will try to connect to 'localhost:27017'. This single database will then be used for all Spring Data Repositories automatically.
You can add extra MongoClient beans for different databases, but you'll need some work to connect different Spring Data Repositories to those different beans.
And if you want to work with a dynamic set of databases, i.e. when you don't know which databases or how many, you can't work with fixed MongoClients as spring beans anyway. You'll need some sort of factory that creates multiple MongoClient beans based on the number of databases, and multiple SearchRepository beans connected to each of those MongoClient beans.
In depends on the complexity of your project, but for this usecase I would not use Spring Data at all, but stick to the MongoDB Java client API:
Map<String, MongoClient> clientsPerDatabase = new HashMap<>();
// Setup
MongoClient mongoClient = new MongoClient(/* default database */);
MongoCursor<String> dbsCursor = mongoClient.listDatabaseNames().iterator();
while(dbsCursor.hasNext()) {
String databaseName = dbsCursor.next();
if (!"admin".equals(databaseName)) {
clientsPerDatabase.put(databaseName, new MongoClient(...+databaseName);
}
}
// Query
for(MongoClient client: clientsPerDatabase.values()){
...
}
I'd configure the Spring Boot application with admin access to the database and then use native queries to retrieve info on all existing databases, schemas, etc

Connecting to different database dynamically in java springs

I have created the Databse dropdown list using the JSP. If I select anyone of the database and it should be pointing to the database and then the query written should be executed to the database which I have selected.
Present work done.
Now I have created statically like how much database I have that much Properties are written in the property file and all the credentials will be taken by Context.xml so how can i create it dynamically so that I dont want to write the different properties for each database and i dont want to create the different session nor I don't want to restart the server when ever I select the DataBase ?
In the property file I have written the different properties for each and every databases and in XML also we have created the different sessions for each and every databases so i donit need to write the different sessions nor restart my Server after the selection of the Database
My question is to can we implement as per my requirement.??????
And another thing for the different database we have created the interface and for that interface we have created the implementation
I believe there is nothing prohibit you from programmatically creating all DB related artifacts (e.g. Datasource, JdbcTemplate, EntityManager etc), and perform transaction management programmatically. Of course you will be giving up a lot of facilities provided by the container (or, I should say, still achievable with high cost)
Another idea I believe will work (though I haven't tried) is to create a child application context from your main app context. The child context will prepare/lookup datasource etc base on properties. Your parent context will of course need to provide correct properties to the child context. By doing so, it should be easy to leverage on feature provided by Spring.

Passing db info to Hibernate at runtime?

The problem with hibernate is, you need to put the database info (username/pw etc) in an xml file. However, if you deploy your app on Amazon web services, e.g on Beanstalk, you get the db info passed in via System.getProperty("RDS_DATABASE_USER"), etc. The advantage is, if more instances of your app are created, the db info is passed on automatically, without having to manually edit config files.
Is there a way to pass the db info to hibernate at runtime? If not, is there another good ORM library for java, to which you can pass this info at runtime? I'm using MySQL.
As a matter of fact, the method PersistenceUtil.createEntityManagerFactory allows you to provide a properties map. Using this map you can provide the user name and password in dynamic way.
How you do this may well depend on what specific frameworks you are using.
Based on the tags in your question it is not clear if you are using Hibernate or if you are using OpenJPA.
The Open JPA documentation in the section Obtaining an EntityManagerFactory provides the list of properties you could use.
Map<String,String> properties = new HashMap<>();
properties.put("openjpa.ConnectionUserName", "userName");
properties.put("openjpa.ConnectionPassword", "password");
EntityManagerFactory emf = Persistence.createEntityManagerFactory("MyPersistenceUnit",properties);
Hibernate supports a similar set of properties. Most probably you already have them in your persistence.xml file.
Some dependency injection frameworks, like Spring, don't even require a persistence.xml file and can read such properties dynamically from some other places, like environment variables.

JPA persistence.xml data-source for SE app

Various sources (e.g. Oracle) say that you have to specify jdbc connection details in your persistence.xml for Java SE apps which use JPA via things like <property name="javax.persistence.jdbc.url" value="..."/>.
This is a real pain when you want to run the app against different databases, for example local, test and production. I currently get around this by having multiple persistence-units that are all effectively the same but with different connection details, and then get the app to pick the right persistence-unit based on the environment that it is running in.
The problems with this are:
Duplication of config. When I add an Entity class I have to add <class>MyClass</class> to every persistence-unit. I would rather just specify it once.
Database connection config packaged with the app. If I want to change what database is being used in an environment, I need to fiddle with persistence.xml and re-build the app. I would rather have a config file in each of my environments which specifies the database credentials. That way, I could have many environments but just a single persistence-unit defined, and I could change the database credentials for a given environment by just editing one file in that environment and then re-starting the app.
Do you know of a better way to configure persistence? Is there some way of getting <jta-data-source> or <non-jta-data-source> to do something appropriate in a Java SE environment?
U can config it manually in code
Map<String, String> props = new HashMap<String, String>();
props.put("javax.persistence.jdbc.url", "YourURL");
EntityManagerFactory emf = Persistence.createEntityManagerFactory("UnitName", props);
EntityManager em = emf.createEntityManager();

lookup datasource in context every time, Is it right?

In my application i configured more than one datasource (for diff databases). Whenever user sends a request depends upon user category i need to look up for the respective datasource in the context and get a connection from that datasource to execute queries which are assigned to that user. Is it right way to achieve my requirement? I am using tomcat 6, struts 1.3. The databases may be oracle or mysql or both.
Give me an optimized solution.
Thanks in advance.
Alternatively, you can create a Service Locator where you can cache every JNDI objects retrieved. That way, you don't have to invoke the JNDI lookup every time but pull out from the cache.

Categories