i am developing a SaaS application by using JavaEE technologies (JPA, EJB, ..)
for multitenancy, i chose 'Shared Database, Separate Schemas' approach and designed the DB (PostgreSQL) like that
basically what i need to do is changing the default schema for user sessions in the application so that users can get their own data from the right schema
my business logic is implemented with EJB (Container-managed) and the app server is glassfishv3
so in my EJBs i am just injecting the EntityManager like this
#PersistenceContext(unitName="DBNAME")
private EntityManager em;
and leaving the transaction management to the glassfish
i tried to write #PostConstruct callbacks for Stateless EJBs injecting DataSource
but getClientInfo() returns null somehow so i can not even see the default schema. The reason why i injected DataSource was because i thought i have to do some low-level stuff to specify the schema.
i know if i manage the transactions in the application instead of leaving them to the app server, i can change the EntityManager values through EMF easily but i wanna keep the Container-managed infrastructure and just change some values at runtime
is there any way to do this with SessionContext or anything else ?
what is the best way of overcoming this issue ?
thanks in advance
#PostConstruct is by definition the wrong way, because it is only a hint to the bean that it has been constructed and its dependencies have been injected. The bean is now in the pool of EJBs waiting for the first service call. Then it will be connected to the client info of that call. After that call the client info is disconnected again.
I think any kind of standard injection and standard container managed persistence stuff will not work in your case because injection is done exactly once (at EJB creation time) but your case would require injection for each service call/transaction _AND your injection would depend on input data - the client request containing the tenant id.
Also: I hope, you have only up to 6 (or so) tenants due to the maintenance and performance burden of that approach. I have never seen this approach working in the wild.
Related
JPA defines PersistenceContextType, but it is not referenced anywhere in JPA api.
public enum PersistenceContextType {
TRANSACTION,
EXTENDED
}
Is persistence context (whether transaction or extended) is managed by container(e.g. JEE), not JPA itself?
but it is not referenced anywhere in JPA api
It is referenced by the declarative API - the type property of the #PersistenceContext annotation. It wouldn't make sense for it to be referenced by any programmatic API, because application-managed EntityManagers are always of the EXTENDED type, as the TRANSACTION type wouldn't make much sense.
Is persistence context (whether transaction or extended) is managed by container(e.g. JEE), not JPA itself?
Not entirely sure I understand the question but, as per the spec (Section 7.6):
When a container-managed entity manager is used, the lifecycle of the persistence context is always
managed automatically, transparently to the application, and the persistence context is propagated with
the JTA transaction.
Note that a container-managed, EXTENDED persistence context can only be requested (using #PersistenceContext(type = EXTENDED)) in stateful beans, which are barely used nowadays.
(see that section, and the sections that follow, for more details on how transaction and extended scopes work)
EDIT:
As for why #PersistenceContext and PersistenceContextType is part of the JPA API, the answer is: why shouldn't it? The JPA API is primarily a JEE API and everything persistence-related that your app may want to use as an API goes in there. In JEE context, Hibernate, EclipseLink etc. are technically not implementations of the JPA API; rather, they're service providers for the PersistenceProvider service. It's a very subtle difference; however, even though they obviously do 99% percent of the work, from the application's point of view, it is still the container that provides (exposes) the JPA API.
(Another point of view could be that JPA providers implement the programmatic part of the API while containers implement the declarative part, but that's a purely academic discussion).
Our application project is an OSGI bundle using JPA with EclipseLink and JTA, and needs single-table multi-tenancy, where tenant ID comes from a REST request. From what I've read and tried, it almost seems that is impossible:
Since tenant ID changes depending on the request, each request with a new tenant ID needs to manually create a new PersistenceContext (EntityManager) with the appropriate property.
But persistence contexts can't be manually created when using JTA (#PersistenceUnit does not get injected and Persistence.createEntityManagerFactory does not work), according to http://tomee.apache.org/jpa-concepts.html.
Am I missing something? Or is this literally impossible to do?
You can set multitenant/discriminator properties in the entity manager for a request. But it is not safe for multi-threading and lazy initialization.
I tried our CMobileCom JPA that supports single-table multitenancy. For each tenant, a new EntityManager should be used. That is, an EntityManager should not be shared to access data for multiple tenants. This is also true for EclipseLink.
Disclaimer: I am a developer of CMobileCom JPA, a light weight JPA implementation for Java and Android.
I currently use Jpa via Hibernate in my application. Since spring security oauth2 provides JdbcTokenStore, I started using it. But the problem with that is, I cannot use cache (which all my entities in the application currently share).
It hits the database in a separate flow.
I am thinking implementing JpaTokenStore thats backed by Jpa & leverage the cache advantages that comes with it.
Did anyone try implementing this/see any downsides using this approach?
In one project I've implmented org.springframework.security.oauth2.client.token.ClientTokenServices with JPA and didn't notice any problems. I was able to use all standard features of JPA including #Transactional for JPAClientTokenServices#saveAccessToken
There is nothing stopping you from doing it, and plenty of people do use JPA for all sorts of things, but IMO JPA is not ideal for handling storage of identity data. JPA is designed and optimized for cacheing data for the duration of a JDBC connection (a transaction basically), while identity data have a typically different and much longer lifetime. If you store long lived data using JPA, you have to deal with the consequences of what happens when you access it outside its normal lifetime, e.g. use DTOs, which ends up negating the benefits of using it in the first place to some extent.
Is it possible to create a DAO in Java EE environment, which uses JPA, but does not need to be a Stateless bean? I am asking because I have a huge number of EJBs, just because I need a few #Resources in the DAOs, i.e. EntityManager and so on.
What would you recommend as a way to simplify DAOs in huge project, it seems to me that having a full EJB (instead of a simple object) for a DAO is eccessive.
DAOs are accessed both from other EJBs and from servlets.
It's possible, but not recommended, to inject an EntityManager into other types of beans (like e.g. CDI managed beans) along with a UserTransaction and then manually manage your transactions.
In Java EE 7, JTA 1.2 contributes CDI compatible extensions for declarative transactions just like EJBs have, but at the moment there's no final release of any Java EE 7 AS yet.
it seems to me that having a full EJB (instead of a simple object) for a DAO is excessive.
Why do you think that? A "full" EJB is probably more lightweight than any other alternative, and almost certainly more lightweight than any home cooked thing you can come up with based on an EntityManager.
Don't forget that EJB beans share their resources automatically and that injection points only get proxies. If you mainly use stateless EJB beans, those proxies are akin to URLs, and not the "real" beans. This makes stateless and local EJB beans incredibly lightweight to inject.
Meaning, if you have a given Service where you inject (say) 10 DAOs, that each have an injected EntityManager, and during a given call 3 DAOs are invoked then only 3 beans are actually used and only 1 EntityManager instance. It really is rather efficient.
You can implement DAO as POJO is you want. But the DAO needs an EntitManager which must come from somewhere. Either
you look it up in the POJO with InitialContext#lookup
you pass it in the constructor of the POJO
You must pay attention that InitialContext#lookup will work only if the parent EJB has declared a dependency to the entity manager, even if it doesn't use it.
Whether it's worth the trouble is a judgment call. Local EJB are very cheap, and having many EJB is not a problem for the app server. It's more a problem of understandability by developpers. (See this other answer of me)
Another question to ask is whether you really need the DAOs. With EJB 3, they become very thin layer of logic, and it's worth pondering the pros and cons
We use EJB2.x entity beans with BMP (bean managed persistence). It appears BMP is not supported in EJB3. We had wanted to stay current and upgrade to EJB3. Does anyone know if there are in fact any BMP options available in 3.0?
From what I can tell, using 3.0, all entity beans have to use JPA and by definition ORM. There are some options to use native SQL but that is still just a way to use JPA to implement ORM.
I wasn't sure if there is another EJB3 approach to achieve the same functionality as with EJB2.x BMP entity beans. We currently use the standard ejbStore method to update the DB through native SQL and the ejbLoad method to lookup all beans and to refresh the bean in the event of a transaction rollback. I thought you might be able to do this with EJB3 session beans but I wasn't sure.
Perhaps instead of migrating to EJB3 beans we should migrate to Spring.
If you really want to code SQL by hand, go for POJOs and raw JDBC DAOs. But this is also maybe an opportunity to rethink the way you're doing things and embrace ORM/JPA.
In the past, I have mixed Hibernate + EJB2 (CMP + BMP) sharing transactional contexts with no issues, using JTA.
This problem is quite similar...
Take a look at https://cwiki.apache.org/GMOxDOC22/developing-bean-managed-persistence-with-jpa.html. You can implement your own EntityManager.
With luck, you may be even able to share transactional contexts.