Modify persistence.xml on runtime - java

I'm developping a program that uses JPA, and I deployed it in a single jar. I wish to modify (or ask to the user, in an menĂº item) the configuration of the connection data with the database server.
It's possible to modify the data (user, password, ip) of the server "on the fly"?
(I apologize my bad english)

how about making a HashMap<String,Object> containing your options and passing it to Persistence.createEntityManagerFactory("unitName",map)?
From the Docs:
public static EntityManagerFactory createEntityManagerFactory(String persistenceUnitName, Map properties)
Create and return an EntityManagerFactory for the named persistence unit using the given properties.
Source

The JPA spec doesn't allow for dynamic modification of persistence-units. Some implementations may provide an implementation-specific way of defining a persistence-unit dynamically. With DataNucleus JPA we do it as per the foot of this page

Related

Dynamic dialect with Hibernate and Hikari

I am new at Hibernate.
Into my code, the connection to the DB is managed with the Hikari data source.
My code is right now multitenant, but it manages the same hibernate dialect for all tenants.
Is it possible to create a configuration where each tenant can use a different dialect?
The type of dialect can be provided as a tenant's property.
This is an example of the entityManagerFactory:
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
Map<String, Object> jpaProperties = new HashMap<>();
jpaProperties.put(..., ...);
jpaProperties.put(org.hibernate.cfg.Environment.DIALECT, "myDialect");
LocalContainerEntityManagerFactoryBean emfBean = new LocalContainerEntityManagerFactoryBean();
emfBean.setPackagesToScan(new String[] {MyEntity.class.getPackage().getName()});
emfBean.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
emfBean.setJpaPropertyMap(jpaProperties);
return emfBean;
}
Edit
I was looking to this solution: it suggests to create a duplicated LocalContainerEntityManagerFactoryBean for each dialect.
What I do not understand is how can I tell when using one EntityManager (MySQL) and when the other one (Postgres or MsSQL): the solution discriminates the entities (each entity has its own DB) but in my case, all entities are on all DBs. Is the tenant that discriminates.
For example: if I create a second instance of LocalContainerEntityManagerFactoryBean (i.e. msSQLEntityManagerFactory()) with setted the dialect for SQL Server, the application fails to start with:
Application failed to start due to an exceptionorg.springframework.beans.factory.NoUniqueBeanDefinitionException:
No qualifying bean of type 'javax.persistence.EntityManagerFactory' available:
expected single matching bean but found 2:
msSQLEntityManagerFactory,entityManagerFactory
That's not really possible as the dialect affects certain quoting rules etc. which you can't just "swap out" at runtime based on a tenant identifier. Just create two persistence units, each pointing to a different data source for every database type. You will have to somehow lookup the appropriate EntityManager/EntityManagerFactory based on your tenant identifier which makes it a bit harder when you want to use Spring Data JPA as that requires a compilation static name reference for the entity manager factory. Maybe you can create a custom EntityManagerFactory that delegates all method calls to the appropriate instance based on the tenant identifier. Overall, this is not so easy and you will probably have to do a lot of trial and error.
IMO it would be better to have a separate application deployment with separate configuration if possible per database type.
I finally managed to find a solution for this problem.
I managed to get around the problem with the dialects by having an entity manager factory for each dialect (in this case MySQL, Postgres and MS SQL Server).
Create a bean for EntityManagerFactory and return a proxy of that interface and in the handler, based on your logic, you can switch which emf to use to suit the used data source.
I have created a video for this because it seems like there is no documentation online.
Session Scoped Connection
It is pretty similar to what you're trying to achieve but in my case the users are providing the credentials, so it's even more complicated.

Dynamically routed sqlSessionFactory in mybatis

Is it possible to choose Mapper to execute in Mybatis?
I am using dynamically routed datasource and give it as parameter to sqlSessionFactory - it is working.
The problem is, however, that different databases may require other SQL queries (very small differences, but differences).
Is it possible to create dynamically routed sqlSessionFactory - and give to them other package mappers?
This is how you obtain a session factory:
Reader reader = Resources.getResourceAsReader("mybatis-config.xml");
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader);
A couple of things are declared in in mybatis-config.xml, amongst whom are the datasources and the mappers.
Then create another Mybatis config file (with its own datesource and mappers) and dynamically choose the file to build the session factory. You can still provide the connection when opening the session, although I recommend using the implicit one provided by the factory because it will match with the mapper. (Unless this is a complex application where you need to reuse the connection, e.g: to complete a transaction)

how can I use my dynamic JNDI datasources with JPA?

We have an application which uses multiple databases to store the same data for different countries.
For example a Subscription object might be associated with Germany or Spain. If it's a German subscription, it needs to be stored in a different database to the Spanish subscriptions. The databases are identical in structure, but they have different contents.
We are running on jboss 5, and have a different datasource config (*ds.xml) file for each one, generated dynamically at startup. They are stored in JNDI - so we have DataSourceDE, DataSourceES, etc.
Here's how it should work: if a request comes in saying 'fetch subscription 17 for Germany' then I calculate that the datasource should be DataSourceDE and use JPA / hibernate to go fetch that object from the correct database. There will be a subscription 17 in the Spanish database too, which I don't want in this example.
I can generate the persistence.xml automatically to create the extra persistence units for the datasources, but the Subscription class is annotated with the following:
#PersistenceContext(unitName="core")
This is not going to work - how can I set the persistence context on the java object dynamically?
What you are trying to achieve is known as Multi-Tenancy. Here is a perfectly suitable tutorial for your question to make it work.
The main idea is to use a Stateless session bean which has a reference to both persistence units. Depending on what has to be done, this bean does a lookup to call the corresponding EntityManager. Furthermore here:
Multi-Tenancy With EJB 3.1 and JPA 2.0
You can change the persistence context for the EntityManager at runtime like this:
EntityManagerFactory emf =
Persistence.createEntityManagerFactory(persistenceUnitName);
EntityManager em = emf.createEntityManager();

how can I use persistence.xml to configurate apache-common-dbutils?

JPA is pretty good for immutable tables but I can't handle dynamic table.
Then I decide to use JPA for handle al the unalterable tables (the core of the application) and dbutils from apache to handle all my the dynamic tables
Both kind of tables are in the same database and I want to define the configuration of the database only in a single file
I define the jpa in a property file:
javax.persistence.jdbc.driver=com.mysql.jdbc.Driver
javax.persistence.jdbc.user=root
javax.persistence.jdbc.password=*****
javax.persistence.jdbc.url=jdbc:mysql://localhost:3306/database
But dbutils use the class "datasource" to configurate.
I didn't find how to get a "Datasource" from de "EntityManagerFactory" of jpa.
Or to get a instance of "EntityManagerFactory" from a "Datasource".
An EMF can be created for a (javax.sql.)DataSource by specifying the persistence-unit "jta-data-source" or "non-jta-data-source" (the JNDI name for the DataSource). So create the DataSource, make it accessible via JNDI, and then you can use it in the EMF and this "dbutils".

OSGi and Persistence Units

Good day guys, I'm programming an OSGi bundle in charge of authenticating users. For design reasons I'm obligated to perform queries over multiple database schemas (these schemas can be created or deleted dynamically). I'm running MySQL as storage engine.
Somehow I need to be able to create on demand entity managers for those schemas, but I haven't been successful in my attempts. Here is what I have tried that has got me closer to what I need:
Creating a persistence unit (Eclipselink) using a JTA data source that can, in fact, establish a database connection to the default schema. However, when I try to override any property, say, the javax.persistence.jdbc.url. However, it keeps pointing to the default schema always.
I believe I'm not overriding correctly the property, or that JTA datasource properties cannot be modified from EntityManager to EntityManager. Here is how I create the EntityManagers:
Map<String, String> dbProps = new HashMap<String, String>();
dbProps.put("javax.persistence.jdbc.url","jdbc:mysql://mydomain:3306/mydynamicdb);
EntityManagerFactory fact = Persistence.createEntityManagerFactory("myPersistenceUnit", dbProps);
EntityManager myEM = fact.createEntityManager();
At the end, they all keep poiting to the default schema, so my questions are:
Is this an efficient approach for dynamic EntityManager handling? if so, how can I override effectively the schema property?
Is there any other alternative besides the overriding?
I thank you in advance for any guidance you may provide.
If you want to use EclipseLink in OSGi you must use the Gemini JPA project that wraps EclipseLink and create and register an EntityManagerFactory and an EntityManagerFactoryBuilder services for your PU bundle.
If want to share the jdbc connections between PUs you can use JDBC services provided by Gemini DBAccess
You should be able to acquire the EntityManagerFactory as an OSGi service, you can (LDAP) filter the correct one using the service property osgi.unit.name as in:
ServiceReference[] refs = null;
String filter = "(osgi.unit.name=myPersistenceUnit)";
ServiceReference[] refs = ctx.getServiceReferences(EntityManagerFactory.class.getName(), filter);
//Should only be one reference, check (throw exception etc)
return (EntityManagerFactory)ctx.getService(refs[0]);
You can check that all Persistence Units are present, by listing the EntityManagerFactory services (with properties) in your OSGi shell.

Categories