Pass Injected EntityManager to a web session persisted object - java

Is it secure to pass a Injected EntityManager created on an EJB, to a method that will return an Object, and after, persist that Object on a Web Session for web clients use it?
Like in this example:
the EJB
#Stateless(mappedName = "MyService")
#LocalBean
public class MyService implements MyServiceLocal {
#PersistenceContext(unitName="primary")
private EntityManager em;
/**
* Default constructor.
*/
public MyService() {
}
#Override
public Service newServiceX(User user) {
return new ServiceX(user,em); // here, passing the EntityManager
}
}
After, I persist this Service in a web client (using struts):
The base action
public class YAction extends ActionSupport implements SessionAware{
#Inject
private MyServiceLocal service;
public String execute(){
Service x = service.newServiceX();
persistInCookie("ServiceX",x);
}
public void persistInCookie(String, Object){
// persist
}
}
And after, using another Action:
// another Action that
class XAction{
public String useService(){
getService().doSomething();
}
protected Service getService(){
Service service = (Service) getSessionMap().get("ServiceX");
return service;
}
}
the POJO class ServiceX using the EntityManager:
public class ServiceX extends Service{
EntityManager em;
public ServiceX(User user, EntityManager em){
this.em = em;
}
public void doSomething(){
// do something with the EntityManager passed by the EJB
}
}
First, the action that would be call is the Y action to persist the Service on the Session, next, the X action will return the Service persisted on the Session and try to use it.
I believe that the EJB Stateless Session Bean can close My EntityManager and this ServiceX POJO class can't use it. This can happen? I found similar question HERE, but in this question, the EntityManager is passed to a helper class. In my case is different because I want to persist this Object on a session cookie, and use later.

I don't think It is a good idea to store a EntityManager in SessionMap. What is more, I don't even think that it is a good idea to perform EntityManager operations outside the EJB container.
Have read about transaction-boundaries in JPA?
By default, EJB container is using CMT (Container Managed Transactions). In this case, container uses entitymanager-per-request pattern which means that the transaction begins and ends when one of the business methods of MyService starts and ends (transaction is committed or rollbacked in case of RuntimeException). For whole transaction time, EntityManager is connected with the same PersistenceContext. After the transaction is ended the container closes EntityManager which means that the EntityManager is disconnected with recent PersistenceContext:
// transaction begins
Service x = service.newServiceX();
// transaction ends
This might be crucial if you were going to do some update/insert operations outside the transaction.
Now, when you call EntityManager operation (like find) outside the transaction, for every each operation the EntityManager will create new PersistentContext. This may cause some issues, as two entities that represent the same record will be treated as different entities:
// each operation occurs in a separate persistence context, and returns
// a new detached instance
Magazine mag1 = em.find(Magazine.class, magId);
Magazine mag2 = em.find(Magazine.class, magId);
assertTrue(mag2 != mag1);
Some more articles to read:
Persistent Context
Transactions and Concurrency
Entity Lifecycle Management

Related

Service delegate throws an "LazyInitializationException: could not initialize proxy - no Session"

I know there are plenty of "could not initialize proxy - no Session" questions but I did not found any answer to my problem.
So the problem is, when I delegate fetchLazy method, it throws an above mentioned exception. Here is a simplified version of my service class:
Service
public abstract class Service<S extends Service<S,E>, E extends Entity> {
#PersistenceContext private EntityManager entityManager;
// person = personService.fetchLazy(person, Person::getCompany); OK
public E fetchLazy(E entity, Function<E,?> proxyMapper) {
E attachedEntity = entityManager.find(entity.getClass(), entity.getId());
Object proxy = proxyMapper.apply(attachedEntity);
if (!Hibernate.isInitialized(proxy)) { Hibernate.initialize(proxy); }
return attachedEntity;
}
// person = personService.fetch(person).lazy(Person::getCompany); EXCEPTION
public FetchBuilder fetch(E entity) { return new FetchBuilder((S) this, entity); }
public class FetchBuilder {
private final S service; private final E entity;
LazyFetchBuilder(E e, S s) { this.entity = e; this.service = s; }
public E lazy(E entity, Function<E,?> proxyMapper) {
return service.fetchLazy(entity, proxyMapper); // DELEGATE
}
}
}
PersonService
#Stateless
public class PersonService extends Service<PersonService,Person> { ... }
PersonBean
#Named #ViewScoped
public class PersonBean implements Serializable {
#EJB private PersonService personService;
#PostConstruct public void init() {
person = personService.getById(id);
person = personService.fetchLazy(person, Person::getCompany); // OK
person = personService.fetch(person).lazy(Person::getCompany); // EXCEPTION
}
}
I will assume this service is a Java EE or Spring transactional service. Declarative transactions are proxy-based. When you get an instance of a service using dependency injection and call a transactional method, you in fact call the method of a transactional proxy that wraps the service:
client ----------> transactional proxy -----------> service
- start the transaction
- call the service
- commit
-return the value returned by the service
When you call fetchLazy(), everything works fine:
a transaction is started,
then the entity is found using the entity manager and its company proxy is initialized,
then the transaction is committed
then you get the entity with its initialized company.
When you call fetch(), here's what happens
a transaction is started,
a FetchBuilder is constructed
then the transaction is committed
then you get the FetchBuilder
This transaction is actually useless, since you never use the entity manager.
Now what happens when you call fetch() on the returned builder? It calls fetchLazy on the service instance variable of the FetchBuilder. This service is an instance of the actual service instance, not an instance of the proxy that wraps the service instance, since you initialized it with this, from the service instance itself. You're thus bypassing the proxy, and these is thus no transaction wrapping the call to find() and the intialization of the company.

How to pass a JPA entity to an Asynchronous EJB method

While processing a request, I would like to 'kick off' separate task in a separate transaction based on the data received and stored in the database.
The main advantage is that I can return the result to my request before all additional processing is done, also if additional processing fails, this will not affect the original processing of the request (as they are in different transactions). This additional processing might require adding extra information to the data.
I have the following setup in mind. Where using #Asynchronous the additional task is created.
#Stateless
public class Bean1
{
#EJB
Bean2 bean2;
#PersistenceContext
private EntityManager entityManager;
public MyResult doSomething(MyInput input) {
MyEntity myEntity = new MyEntity();
// Fill data based on input
entityManager.persist(myEntity);
bean2.asyncActOnData(myEntity);
// Perhaps do some more work and return result
}
}
#Stateless
public class Bean2
{
#Asynchronous // This causes a new transaction to happen
public void asyncActOnData(MyInput input){
// Act upon data and store result in DB
}
}
This seems like a clean way, however this causes JPA Entity to become detached, possibly during processing in Bean2.
Currently I don't plan on changing the data after the persist call (and asnyc), but as the application grows I feel it would be safer to allow this to avoid mistakes.
What is the correct way to kick off the separate asynchronous task based on the persisted data?
I am using: Java EE 6 with Eclipselink 2.5.2 for JPA.
You can continue to make use of the detached instance provided that:
You're not planning to perform further persistence operations;
All associated entities (if any) were available when asyncActOnData was invoked.
However, if you need to perform further persistence operations you can do the following:
#Stateless
public class Bean1
{
#EJB
Bean2 bean2;
#PersistenceContext
private EntityManager entityManager;
public MyResult doSomething(MyInput input) {
MyEntity myEntity = new MyEntity();
// Fill data based on input
entityManager.persist(myEntity);
// Flush the persistence context and detach the entity
// An entity is not permitted to be in more than one
// persistence context at a time. This should prevent
// a race condition with the merge in bean2.
entityManager.flush();
entityManager.detach(myEntity);
Future<Result> futureResult = bean2.asyncActOnData(myEntity);
// Perhaps do some more work and return result
....
return futureResult.get();
}
}
#Stateless
public class Bean2 {
#PersistenceContext
private EntityManager entityManager;
#Asynchronous
public Future<Result> asyncActOnData(MyInput input) {
// this will ensure that the database still matches input
// and add input into the persistence context
input = entityManager.merge(input);
...
return new javax.ejb.AsyncResult<Result>(result);
}
}
You will find it useful to read §3.2 of the "Java™ Persistence API, Version 2.1" specification.

Injected EntityManager's scope/lifecycle in a Stateless bean

Can someone explain the lifecycle of an injected EntityManager in a stateless bean? If a stateless bean has an injected EntityManager associated with a specific PersistenceContext, what happens to that association the second time the bean is used?
For example, I have the following:
#Stateless
public class TimeStepsBean
{
#PersistenceContext(unitName="DynamicDB")
private EntityManager em;
public List<TimeStep> timeSteps = new ArrayList<TimeStep>();
private void init()
{
if (timeSteps.isEmpty())
{
TypedQuery<TimeStep> query = em.createQuery("SELECT t FROM TimeStep t", TimeStep.class);
timeSteps = query.getResultList();.
}
}
public void refreshSteps()
{
init();
em.flush();
em.refresh(timeSteps.get(0));
}
}
When refreshSteps is called the second time the bean is used (a second transaction), I get a "java.lang.IllegalArgumentException: Entity not managed". The entityManager was injected, so I am assuming that it is always part of the current persistence context. Is that true?
Adding em.merge(timeSteps.get(0)) before the refresh still generates the same exception.
Your timeSteps is a state. Your class is annotated as stateless. It's a misuse of the framework.

JPA, when to open and close entityManager

I've setup a spring MVC application for a web application and I'm using Hibernates implementation of JPA 2.1.
I've created my models and am able to interact with the database just fine.
I've also decided to use service classes which will manage returning the entities. What I've done is created a BaseService class, so all other service classes will expand on this, and they'll have access to common functions such as create(), delete(), update() and list().
My problem is I'm unsure as to when I should be creating the EntityManager and when I should be closing it?
Currently, in my controller I'm initiating the required services when the controller loads;
#Controller
#RequestMapping("/mycontroller")
public class TestController {
CarService carService = new CarService();
ShowroomService showroomService = new ShowroomService();
}
}
Here is the BaseService that each other service extends;
public class Service<Ety> {
EntityManager em = null;
public Class<Ety> entityClass;
public Service(Class<Ety> entityClass) {
this.entityClass = entityClass;
em = JPAUtil.getEntityManager();
}
public Ety get(int id) {
Ety object = null;
em.getTransaction().begin();
object = em.find(entityClass, id);
em.getTransaction().commit();
return object;
}
public List list() {
List<Ety> objects;
em.getTransaction().begin();
objects = em.createQuery("SELECT c FROM "+entityClass.getName()+" c").getResultList();
em.getTransaction().commit();
return objects;
}
public void save(Ety object) {
em.getTransaction().begin();
em.persist(object);
em.getTransaction().commit();
}
public void update(Ety object) {
em.getTransaction().begin();
em.merge(object);
em.getTransaction().commit();
}
public void delete(Ety object) {
em.getTransaction().begin();
em.remove(object);
em.getTransaction().commit();
}
}
Here's an example Service which expands the above;
public class CarService extends Service<Car> {
public CarService() {
super(Car.class);
}
}
As you can see, I'm creating an EntityManager when the service is created, but at the moment I'm not closing it anywhere.
I'm I creating the entity manager in the correct place? when should I close it.
I had considered putting the entity manager in a static property and creating it within a filter, and then closing it at the end of the application, however I do believe this wouldn't be thread safe and would cause issues?
Any advice would be appreciated.
your CarService should be a spring bean and the instance is created from spring. NOT from your code. The same with the EntityManager. You can use the entityManager with the #autowired annotation.
You open a new EntityManager for each transaction.
This EntityManager is like a Bag mapped to the database, but with zero entity managed inside when it's just opened.
When you work with it, this Bag will be filled with some entities and Hibernate will work to create the adequate requests.
You will close this Bag to save memory at the end of the transaction.
Of course there is some tricks to have many transactions for a given EntityManager, but you have the most general idea. As always it depends...
If you use a framework like Spring or JavaEE, it will open and close the EntityManager, as well starting and committing transactions for you. You have only your business work to write.

Different ways of getting the EntityManager

The usual idiom I see for creating the EntityManager is something like this:
public class BaseDao {
private static final String PERSISTENCE_UNIT_NAME = "Employee";
EntityManagerFactory factory = Persistence.createEntityManagerFactory(PERSISTENCE_UNIT_NAME);
public EntityManager getEntityManager() {
return factory.createEntityManager();
}
}
Then it is used like this:
Employee emp = new Employee();
emp.setName("Joe M");
getEntityManager().persist(emp);
Question is why not do it this way:
public class BaseDao{
private static final String PERSISTENCE_UNIT_NAME = "Employee";
EntityManagerFactory factory = Persistence.createEntityManagerFactory(PERSISTENCE_UNIT_NAME);
private EntityManager entityManager = null;
public void setEntityManger() {
EntityManagerFactory factory = Persistence.createEntityManagerFactory(PERSISTENCE_UNIT_NAME);
this.entityManager = factory.createEntityManager();
}
public EntityManager getEntityManager() {
return this.entityManager;
}
}
In other words is there a need to always get the entity manager through factory.createEntityManager()? or can it be created as an instance (or even static) variable and retrieved like that?
To clarify, I am talking about an environment that doesn't use EJB or Spring containers.
Thanks.
There are two ways to create EntityManager instances.
One way is for SDK applications, and I use this way a lot in unit testing. This is what you have in your example:
EntityManagerFactory factory =
Persistence.createEntityManagerFactory(PERSISTENCE_UNIT_NAME);
In Enterprise applications you let the container create them for you and inject them when needed.
EntityManager is just a wrapper around a JDBC connection. It's very light weight and can be created and destroyed without performance penalty.
Keep in mind that the EntityManager is not thread safe, so if you have one instance, you may need to synchronize access to it. See transaction basics for details.
Here's how I would do it (roughly):
public class BaseDao{
private static final String PERSISTENCE_UNIT_NAME = "Employee";
private static EntityManagerFactory factory =
Persistence.createEntityManagerFactory(PERSISTENCE_UNIT_NAME);
public void create(MyEntiy person){
EntityManager em = factory.createEntityManager();
em.getTransaction().begin();
// do what ever you need
em.getTransaction().commit();
em.close();
}
// add more methods to the dao.
}
Once you get this protoyped and ready, you can use a generic DAO.
Today you should probably look at sometime like spring-data and #PersistanceUnit for managing your EntityManager.
An EntityManager is more than just a wrapper a wrapper for a JDBC connection. It defines the scope of a persistence context, which defines the unit of work that should be performed when a transaction is committed (of when you flush queries to the database). Within a persistence context you are also guaranteed that a given entity in the database will result in the same Java object, regardless if you load it directly, or access it through a OneToMany relation of another entity.
With regards to the original question about obtaining an EntityManagerFactory in a non-spring setting. You simply call
Persistence.createEntityManagerFactory(PERSISTENCE_UNIT_NAME);
This method is a static factory method, depending on your JPA implementation you either get the same instance for the same PU, or a shallow wrapper that wraps the underlying persistence session (of which there is one per PU).

Categories

Resources