JPA - Using Multiple data sources to define access control - jpa

I am totally new to JPA and JSF and hope you can help me with my questions.
My application is built using JSF 2.0 Framework, using JPA 2.0/EclipseLink running on Glassfish 3+, MySQL.
I set one persistence unit called "loginPU" using data source: "jdbc/loginDataSource"
"jdbc/loginDataSource" connects to MySQL using "login1" (defined in mysql.user table) and only has access to customer.user and customer.roles tables, with only select privileges.
I created 2 other data sources "jdbc/admin" and "jdbc/staff" in Glassfish JDBC Resources and both with different privileges
The login/authentication scenario is:
User login using form based authentication (username and password)
Create EntityManageFactory using persistence unit "loginPU" and "jdbc/loginDataSource"
create query to retrieve user role
if user role is admin, connect using "jdbc/admin" data source
if user role is staff, connect using "jdbc/staff" data source
My code for item 2 above looks like this:
Map properties = new HashMap();
properties.put(TRANSACTION_TYPE, "JTA");
// Configure the internal EclipseLink connection pool
properties.put(JDBC_DRIVER, "com.mysql.jdbc.Driver");
properties.put(JDBC_URL, "jdbc:mysql://localhost:3306/customer");
properties.put(JDBC_USER, "login1");
properties.put(JDBC_PASSWORD, "login1");
properties.put(JTA_DATASOURCE, "jdbc/loginDataSource");
EntityManageFactory emf = Persistence.createEntityManagerFactory("loginPU",properties);
I even keep my EntityManagerFactory in session attributes and retrieve it in the JpaController class
//save into session
session.setAttribute("entityManagerFactory", emf);
//retrieved in JpaController
public EntityManagerFactory getEmf() {
HttpServletRequest request = (HttpServletRequest) FacesContext.getCurrentInstance().getExternalContext().getRequest();
HttpSession s = request.getSession(true);
try {
emf = (EntityManagerFactory) s.getAttribute("entityManagerFactory");
} catch(NullPointerException ne){
System.out.println("EMF Exception: "+ne);
}
return emf;
}
Questions: How can I achieve number 4 or number 5? Is that possible to
do? Is it possible to assign either data source to "loginPU"
persistence unit? I manage to establish connection using loginPU and jdbc/loginDataSource
and then connect using jdbc/admin datasource, but when I access other
entities, it throws error and default to jdbc/loginDataSource
Note:
I am using JpaController classes created by netbeans, and also session beans to manage the entities.
My JpaController classes use
#Resource private UserTransaction utx;
#PersistenceUnit private EntityManagerFactory emf;
My session beans are all #Stateless, I tried to use #PersistenceContext with unitName and without unitName but no luck
#PersistenceContext
private EntityManager em;
I tried using multiple persistence units in persistence.xml, hoping to connect users using the persistence unit name based on the role, but it gives me error when deploying to server.
I read about application-managed persistence and container-managed, I think what I am trying to achieve is to use application-managed, but not sure how to do it.
If I am to use container-managed persistence, is it possible to use multiple data sources? Any suggestion is greatly appreciated.
Thank you for any comments or suggestions in advance.
[SOLVED]
First I defined my persistence.xml as follows:
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="mdbAdminPU" >
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<jta-data-source>jdbc/login</jta-data-source>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
</persistence-unit>
</persistence>
I don't use any #PersistenceUnit or #PersistenceContext in my session beans.(I'm using Netbeans and these beans were created when I created JSF Pages from Entity Classes)
In all session beans, they look like this:
#Stateless
public class UserFacade extends AbstractFacade<User> {
#Override
protected EntityManager getEntityManager() {
HttpSession session = (HttpSession) FacesContext.getCurrentInstance().getExternalContext().getSession(false);
EntityManagerFactory emf = (EntityManagerFactory) session.getAttribute("entityManagerFactory");
EntityManager em = emf.createEntityManager();
return em;
}
public UserFacade() {
super(User.class);
}
}
The login scenario above (5 items) has become 7:
User login using form based authentication (username and password)
Create EntityManageFactory using persistence unit "loginPU" and "jdbc/loginDataSource"
create query to retrieve user role
if user role is admin, connect using "jdbc/admin" data source
if user role is staff, connect using "jdbc/staff" data source
plus
remove or clear EntityManagerFactory created in item 2 using
emf.close();
Keep new EntityManagerFactory created in either item 4 or 5 in
HttpSession

You are probably best off using three separate persistence units in your persistence.xml if you need three different logins. Or just have a single login with full access and validate security in your application (which you seem to be doing in part anyway).
What error did you get on deploy?
You can do it with one persistence unit in EclipseLink but it is more involved, and you cannot use container managed entity managers. You would inject a #PersistenceUnit (EntityManagerFactory) instead of an #PersistenceContext (EntityManager), then you would need to pass the new login parameters to createEntityManager(). You would need to set the "eclipselink.jdbc.exclusive-connection.mode" property to "Always" (or "Isolated" and make the secure data isolated).
See,
http://wiki.eclipse.org/EclipseLink/Examples/JPA/Auditing

Related

Creating Datasource Dynamically in SpringBoot OpenJPA Application (Implementing Multitenancy with OpenJPA)

I am creating a Springboot application with OpenJPA.
My requirement is that I need to connect to multiple datasources dynamically and the datasource credentials are obtained at runtime by calling some rest-endpoints.
Here is the controller class:
#RestController
public class StationController {
#Autowired
BasicDataSource dataSource;
I have a service which returns me the jdbc_url depending on the customer name:
public String getDSInfo(String customername){
// code to get the datasource info (JDBC URL)
}
My questions are:
Is there a way in which I can create datasources at runtime by getting datasource credentials by calling some other service (which takes the customer id and returns the customer specific datasource) ?
Since my application is a web based application, many customers will be accessing it at the same time, so how to create and handle so many different datasources?
NOTE:
The code will get information about the customer specific data source only by firing some service at the runtime, so I cannot hardcode the datasource credentials in the XML configuration file.
I found some implementations with Hibernate but i am using Springboot with OpenJPA. So need OpenJPA specific help.
It sounds like you want a multi-tenancy solution.
Datasources are easy to create programmatically, just use a DataSourceBuilder with your connection details pulled in from a central source (e.g. a central config database or Spring Config Server).
Then you'll need to look at a multi-tenancy framework to tie the datasources back to clients.
See here:
https://www.youtube.com/watch?v=nBSHiUTHjWA
and here
https://dzone.com/articles/multi-tenancy-using-jpa-spring-and-hibernate-part
The video is a long watch but a good one. Basically you have a map of customer data sources (from memory) that allow an entityManager to pick up a datasource from the map by using a thread scoped custom spring scope of "customer" which is set when a user for a particular customer somehow logs into your app.

EJB jpa Dynamic creation of EntityManager

My problem is actually simple but I really do not find a good solution to it.
I've currently to manage several DB in my application:
one UNIQUE admin DB (with a static name);
one client DB, with a name depending on the client.
I'm using JPA 2.0 genericdao and ejb3 and I would like to create (produce) dynamically EntityManagers for client DB.
The first entytymanger (properties saved in persistence.xml) to find the the client DB properties ( name, login, password, dialect ... ) stored in the admin DB.
I want to use
#PersistenceContext(name = "nscloud_PU",type= PersistenceContextType.EXTENDED )
and ejb3 to resolve the LazyInitializationException

Performance problems using a Spring Batch FieldSetMapper to map into an object that will be written with a JpaItemWriter?

We are writing a set of Spring Batch jobs that read values from text files and use that information to update objects that are read and written from the database using JPA. These jobs are not run in a web container, but on an application server. My problem seems to be with how the EntityManager is configured.
The code reads files from various vendors that update an order's status. The text file specifies the customer by name and the order by date/time. If the customer doesn't exist, the line from the text file is skipped. If the order exists, we update it. If not, then we create it.
We currently use DeltaSpike to get instances of our DAO objects like this:
DependentProvider<CustomerDaoImpl> provider = BeanProvider.getDependent(CustomerDaoImpl.class);
ICustomerDao custDao = provider.get();
I cache the DAO objects in my mapper so I am only getting them once. But every call to BeanProvider.getDependent() creates a new EntityManager through "Spring Batch Magic." The EntityManager is specified thusly:
#Configuration
public class BaseBatchConfiguration {
#Bean
#Produces
public EntityManager entityManager() {
Map<String, String> properties = new HashMap<String, String>();
properties.put("hibernate.connection.url", System.getProperty("JDBC_URL"));
properties.put("hibernate.default_schema", System.getProperty("APP_SCHEMA"));
properties.put("hibernate.connection.username", System.getProperty("APP_DB_ID"));
properties.put("hibernate.connection.password", System.getProperty("APP_DB_PWD"));
EntityManagerFactory emf = Persistence.createEntityManagerFactory(System.getProperty("PU_NAME"), properties);
return emf.createEntityManager();
}
}
I tried caching the EntityManager, but a new instance of the BaseBatchConfiguration class is used every time. This means that each DAO gets created with it's own EntityManager, so no real object caching is taking place across DAOs (reading a customer with the CustomerDaoImpl isn't cached and used when OrderDaoImpl loads an order that references that same customer).
This is causing a lot of unwanted object loading as we process through the text file.
Is there some other way we should be declaring our EntityManager?

Dynamic Datasources with JPA 2.1 and JTA on JBoss WildFly

I m getting mad with Jboss WildFly9 with JPA and JTA.
In my project requirements i have to implement multitenancy so i have to change dynamically datasource inside my persistence.xml.
Using jee approach this is not possibile so someone suggest me to use the classic:
EntityManagerFactory emf = Persistence.createEntityManagerFactory("idelivery");
EntityManager em = emf.createEntityManager();
So till now it's working, i can create on by myself the enetitymanager and i can set jpa properties in a hashmap (included datasource).
Now i want to use JTA at least to handle transaction using transaction manager.
So these are the properties i set by code:
Properties properties = new Properties();
properties.put ("hibernate.dialect", "org.hibernate.dialect.Oracle10gDialect");
properties.put("javax.persistence.provider", "org.hibernate.jpa.HibernatePersistenceProvider");
properties.put("javax.persistence.transactionType", "JTA");
properties.put("javax.persistence.jtaDataSource", dataSourcePath);
Transaction type now is JTA. So i expect that i can use some code like:
EntityManagerFactory emf = Persistence.createEntityManagerFactory("idelivery");
EntityManager em = emf.createEntityManager();
MyEntity exUser= new MyEntity();
try{
Context context = new InitialContext();
UserTransaction userTransaction = (UserTransaction)context.lookup("java:comp/UserTransaction");
userTransaction.begin();
em.persist(exUser);
userTransaction.commit();
Of course this code doesn't work at all as Hibernate rises an exception:
java.lang.NullPointerException at org.hibernate.engine.transaction.internal.jta.JtaStatusHelper.getStatus()
Telling me being not able to join a transaction at the creation of entity manager moment.
So ... how can i respect my project requirements... creating my own persistence with my dynamic datasouce and at the same time using the Transaction Manager?
Hibernate has its own solution for multi-tenancy. This is not part of the JPA standard, but it's compatible with and largely orthogonal to it.
It does work with managed persistence units and is compatible with JTA.
I've used the SCHEMA strategy successfully on WildFly 8.2.0.Final and 9.0.1.Final.
You just need to implement two helper classes and configure them in your persistence.xml.
If you can tell before hand how many datasources you would require then you can implement some kind of contextual selection of your entity managers by using CDI producer pattern.
Define all the possible datasources in your persistence.xml and then using some kind of producer singleton factory class to inject them based on their persistence unit.
Create a producer method which selects the correct entity manager based on your current context.
Then in your ejb or cdi beans get an instance of entitymanager through CDI injection
#Inject
private EntityManager em

Create Entity Manager Factory without persistence.xml

Is there a way to create the EntityManagerFactory without a persistence unit defined? Can you give all the required properties to create an entity manager factory? I need to create the EntityManagerFactory from the user's specified values at runtime. Updating the persistence.xml and recompiling is not an option.
Currently I am using eclipselink dynamic persistence so i need to create the EntityManagerFactory without a persistence unit defined ? I have groups of runtime entities that need to map single group of entities to different database in runtime and no persistence unit entry is available for this runtime group of entities .
Any idea on how to do this is more than welcomed!
Your best option is most likely to access the PersistenceProvider directly and use the EJB container API to create the EntityManagerFactory from a PersistenceUnitInfo.
PersistenceProvider.createContainerEntityManagerFactory()
See,
http://www.eclipse.org/eclipselink/api/2.5/org/eclipse/persistence/jpa/PersistenceProvider.html#createContainerEntityManagerFactory%28javax.persistence.spi.PersistenceUnitInfo,%20java.util.Map%29
Just seen in the DataNucleus documentation:
import org.datanucleus.metadata.PersistenceUnitMetaData;
import org.datanucleus.api.jpa.JPAEntityManagerFactory;
PersistenceUnitMetaData pumd = new PersistenceUnitMetaData("dynamic-unit", "RESOURCE_LOCAL", null);
pumd.addClassName("org.datanucleus.test.A");
pumd.setExcludeUnlistedClasses();
pumd.addProperty("javax.persistence.jdbc.url", "jdbc:h2:mem:nucleus");
pumd.addProperty("javax.persistence.jdbc.driver", "org.h2.Driver");
pumd.addProperty("javax.persistence.jdbc.user", "sa");
pumd.addProperty("javax.persistence.jdbc.password", "");
pumd.addProperty("datanucleus.autoCreateSchema", "true");
EntityManagerFactory emf = new JPAEntityManagerFactory(pumd, null);
http://www.datanucleus.org/products/accessplatform_3_2/jpa/persistence_unit.html