Stateful session bean forgets values - java-ee-6

With Java EE I need to use a stateful session Bean.
#Stateful
#TransactionManagement(TransactionManagementType.BEAN)
public class FacadeExercice extends AbstractFacade<EntityBeanExercice>
implements IFacadeExercice {
#PersistenceContext(unitName = "GestionCours-ejbPU")
private EntityManager em;
#Resource
private UserTransaction transaction;
private int lastChange;
private int connections;
[...]
#Override
public EntityBeanExercice find(Object id) {
EntityBeanExercice ex = null;
connections += 5;
try {
transaction.begin();
ex = super.find(id);
lastChange = ex.getLastChange();
transaction.commit();
} catch (Exception ex1) {
Logger.getLogger(FacadeExercice.class.getName()).log(
Level.SEVERE, null, ex1);
}
return ex;
}
}
But every time I enter in my bean, the connections variable is set to 0.
I have no Idea where I can search a solution.

This problem can arise in these situations:
The lifetime of a SFSB is connected to the lifetime of its client.
Your SFSB works fine, if you have a command line client for example. When the command line application is terminated, the SFSB is removed as well.
If the SFSB is used by a JSP/servlet for example, it's lifetime ends, when the HTTP request is completed. If it is to survive the HTTP request, you have to put it's handle in the HTTP session: After you have got an instance from a JNDI lookup, you should put that instance as an attribute in the HttpSession. The next HTTP request to use this SFSB must get the handle from the HttpSession.
Each JNDI lookup returns a new instance
A quote from EJB 3.1, 4.6 Stateful Session Bean State Diagram
When a stateful session bean is looked up or otherwise obtained through the explicit
JNDI lookup mechanisms, the container must provide a new stateful session bean instance, as
required by the Java EE specification (Section “Java Naming and Directory Interface (JNDI)
Naming Context” [12]).
So you should not lookup the SFSB more than one time.

Related

JPA EntityManager.flush() is not called by java/jakarta EE container

JPA EntityManager.flush() is not called by glassfish 5.1 EE container.
In Java SE environment:
EntityTransaction t = em.getTransaction();
t.begin();
// persist entities
em.persist(entity);
t.commit();
commit() will flush entities in persistence context.
Java EE environment e.g. Glassfish:
#Stateless
public class DataManagerBean {
#PersistenceContext
EntityManager em;
public void persist(Object entity) {
em.persist(entity);
}
}
JSF Bean:
#Named
#ViewScoped
public class FooBean {
#EJB
DataManagerBean dataManagerBean;
public void createFoo() {
dataManagerBean.persist(foo);
}
}
Application can not call em.getTransaction(). Transaction is managed by container. JPA provider entityManager.flush() is not called before entityManager.close() is called. As a result the entity is not created in database.
In EE environment, the database connection obtained by JPA provider EntityManager is the same as one used by container?
How does EE container tell JPA provider to flush entities to persistence if flush() is not called?
It is dependant on the way you calling your business method. In one word, beeing defaulted -- transaction begins when your flow enters FIRST business method (or Interceptor, decorating your first business method) and ends when your flow leaves last business method in the stack (or Interceptor, decorating your first business method).
You can manage transactions using #TransactionAttribute annotation with appropriate TransactionAttributeType (REQUIRED is default if not annotated). For example:
#Stateless
public class DataManagerBean {
#PersistenceContext
EntityManager em;
#TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public void persist(Object entity) {
em.persist(entity);
}
}
In this case being called DataManagerBean.persist starts new transaction and commit and flush changes when being leaved. In case of error it will roll transaction back and throw exception you can catch at calling business method.

Spring Data MongoDB #Transactional isn't working?

I have below maven dependency & configuration set up
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
#Configuration
#EnableMongoAuditing
public class MongoConfig {
#Bean
MongoTransactionManager transactionManager(MongoDbFactory mongoDbFactory) {
return new MongoTransactionManager(mongoDbFactory);
}
}
Updated: I've taken the suggested solution to create a bean with #Transactional, and have it injected into my test class. Below is the service bean I created:
#Service
#Transactional
#RequiredArgsConstructor
public class MongoTransactionService {
private final UserRepo userRepo;
public void boundToFail() throws RuntimeException {
userRepo.save(User.builder().id("1").build());
throw new RuntimeException();
}
}
and test class where I inject a bean of MongoTransactionService:
#DataMongoTest(excludeAutoConfiguration = EmbeddedMongoAutoConfiguration.class,
includeFilters = #ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = MongoTransactionService.class))
#ExtendWith(SpringExtension.class)
class MongoTransactionServiceTest {
#Autowired
UserRepo userRepo;
#Autowired
MongoTransactionService mongoTransactionService;
#Test
void testTransactional() {
try {
mongoTransactionService.boundToFail();
} catch (Exception e) {
// do something
}
val user = userRepo.findById("1").orElse(null);
assertThat(user).isNull();
}
}
I am expecting a call to boundToFail(), which throws a RuntimeException, would roll back the saved user, but the user still gets persisted in the database after the call.
It turns out that #DataMongoTest doesn't activate the auto-configuration for MongoDB transactions. I've filed a ticket with Spring Boot to fix that. In the mean time, you can get this to work by adding
#ImportAutoConfiguration(TransactionAutoConfiguration.class)
to your test class.
Note that using MongoDB transactions requires a replica set database setup. If that's not given the creation of a transaction will fail and your test case will capture that exception and the test will still succeed. The data will not be inserted but that's not due to the RuntimeException being thrown but the transaction not being started in the first place.
The question previously presented a slightly different code arrangement that suffered from other problems. For reference, here's the previous answer:
#Transactional needs to live on public methods of a separate Spring bean as the transactional logic is implemented by wrapping the target object with a proxy that contains an interceptor interacting with the transaction infrastructure.
You example suffers from two problems:
The test itself is not a Spring bean. I.e. there's no transactional behavior added to boundToFail(…). #Transactional can be used on JUnit test methods but that's controlling the transactional behavior of the test. Most prominently, to roll back the transaction to make sure changes to the data store made in the test do not affect other tests. See this section of the reference documentation.
Even if there was transactional logic applied to boundToFail(…), a local method call to the method would never trigger it as it doesn't pass the proxy that's applying it. See more on that in the reference documentation.
The solution to your problem is to create a separate Spring bean that carries the #Transactional annotation, get that injected into your test case and call the method from the test.

JPA and EJB - When do I need to use transaction?

I'm learning persistence in Java following some tutorial.
I'm using Java EE 7 and Payara server.
I noticed that each uses a different method for persistence.
Examples:
simple
#Stateless
public class BookServiceBean implements BookService {
#PersistenceContext
private EntityManager em;
public void createOrUpdate(Book book) {
em.persist(book);
}
public void remove(Book book) {
em.remove(book);
}
}
with flush(), this is used when validation strategy isn't set on "AUTO" in persistene.xml, right?
#Stateless
public class BookServiceBean implements BookService {
#PersistenceContext
private EntityManager em;
public void createOrUpdate(Book book) {
em.persist(book);
em.flush();
}
public void remove(Book book) {
em.remove(book);
em.flush();
}
}
with transaction
#Stateless
public class BookServiceBean implements BookService {
#PersistenceContext
private EntityManager em;
public void createOrUpdate(Book book) {
utx.begin();
em.persist(book);
utx.commit();
}
public void remove(Book book) {
utx.begin();
em.remove(book);
utx.commit();
}
}
When and why do I have to use the last one?
Is it necessary to use em.close() at the end of each method?
What are the good practices?
The first one, an EJB method without all that manual flush and transaction fuzz, is the canonical approach. A single EJB method call counts by default already as a single full transaction. The EJB container will transparently begin the transaction before the method is invoked and commit the transaction when the method returns (or rollback when an application exception is thrown from the method).
The manual flush in second example is unnecessary. Generally, you want to use em.flush() only when you're modifying an entity (i.e. making it "dirty") and want afterwards (indirectly) perform a SELECT on it within the very same transaction. It's rare, but there are real world use cases for it, generally when you'd like to SELECT a parent whose the dirty entity is a child of.
The manual transaction management in third example is totally unnecessary. You should already realize that after having read the first paragraph. Manual transaction management is only necessary when you aren't using JTA, but RESOURCE_LOCAL (usually, in Java SE not Java EE).
See also:
When is it necessary or convenient to use Spring or EJB3 or all of them together?
JSF request scoped bean keeps recreating new Stateful session beans on every request?
Handling service layer exception in Java EE frontend method

Does Guice Persist provide transaction scoped or application managed EntityManager?

We use Guice Persist to inject EntityManager in our project.
E.g.
public class MyDao{
#Inject
EntityManager em;
public void someMethod(){
//uses em instance
}
}
But it is unclear for us how injected instance of EntityManager is about to be used.
What type of EntityManager is this? (see e.g.: types of entity managers) Under the hood Guice Persist instantiates it via EntityManagerFactory.createEntityManager() so I'd say it's application-managed entity manager. But in official Wiki they write about seesion-per-transaction strategy, which suggests that EntityManager is (pseudo) transaction-scoped.
Should we invoke close() on it manually? Or Guice will take care of it?
What is the scope of first level cache? Only single transaction (like in transaction-scoped entity managers) or as long as I use the same injected instance of EntityManager (like in application managed entity managers)?
Even though the question is perfectly answered by Piotr I'd like to add some practical advise on how to use guice-persist.
I've been having issues with it which were pretty hard to debug. In my application certain threads would display outdated data and sometimes EntityManager instances were left with old dead database connections. The root cause was to be found in the way I used the #Transactional annotation (I only used them for methods that do updates/inserts/deletes, not for read-only methods). guice-persist stores EntityManager instances in a ThreadLocal as soon as you call get() on an injected Provider<EntityManager> instance (which I did for read-only methods). However, this ThreadLocal is only removed if you also call UnitOfWork.end() (which normally is done by the interceptor if #Transactional is on the method). Not doing so will leave the EM instance in the ThreadLocal so that eventually every thread in your thread pool will have an old EM instance with stale cached entities.
So, as long as you stick to the following simple rules the usage of guice-persist is straight forward:
Always inject Provider<EntityManager> instead of EntityManager directly.
For transaction-scoped semantics: always annotate each method with #Transactional (even the read-only methods). This way the JpaLocalTxnInterceptor will intercept the calls to your annotated methods making sure not only to start and commit transactions but also to set and unset EM instances in the ThreadLocal.
For request-scoped semantics: use the PersistFilter servlet filter that ships with guice-persist. It will call begin() and end() on the UnitOfWork for you before and after the request is done, thereby populating and cleaning up the ThreadLocal.
Hope this helps!
I did some research of the source code of Guice-persist and read through comments under Guice-persist wiki pages and these are the answers that I needed:
1 . Lifecycle management of EntityManager is kind of broken if it's injected via #Inject EntityManager. As stated in one of the comments on the Wiki:
I confirm that inject directly an EntityManager instead of a provider
can be dangerous. If you're not inside a UnitOfWork or a method
annotated with #Transaction, the first injection of an EntityManager
in a thread will create a new EntityManager, never destroy it, and
always use this specific EntityManager for this thread (EM are stored
thread-local). This can lead to terrible issues, like injection of
dead entityManager (connection closed, etc) So my recommendation if to
always inject a Provider, or at least to inject
directly an EntityManager only inside an opened UnitOfWork.
So example in my question isn't the most correct usage. It creates singleton instance of EntityManager (per-thread) and will inject this instance everywhere :-(.
However if I've injected Provider and used it inside #Transactional method then the instance of EntityManager would be per-transaction. So the answer to this question is: if injected and used correctly, the entity manager is transaction-scoped.
2 . If injected and used correctly then I don't need to manualy close entity manager (guice-persist will handle that for me). If used incorrectly, closing manually would be very bad idea (closed instance of EntityManager would be injected in every place when I #Inject EntityManager )
3 . If injected and used correctly then the scope of L1 cache is single transaction. If used incorrectly, the scope of the L1 cache is the lifetime of application (EntityManager is singleton)
1. It depends on you module cofiguration. There are some basic bindings:
JpaPersistanceService
public class JpaPersistanceService implements Provider<EntityManager> {
private EntityManagerFactory factory;
public JpaPersistanceService(EntityManagerFactory factory) {
this.factory = factory;
}
#Override
public EntityManager get() {
return factory.createEntityManager();
}
}
Module binding
EntityManagerFactory factory = Persistence.createEntityManagerFactory(getEnvironment(stage));
bind(EntityManager.class).annotatedWith(Names.named("request")).toProvider(new JpaPersistanceService(factory)).in(RequestScoped.class);
bind(EntityManager.class).annotatedWith(Names.named("session")).toProvider(new JpaPersistanceService(factory)).in(SessionScoped.class);
bind(EntityManager.class).annotatedWith(Names.named("app")).toProvider(new JpaPersistanceService(factory)).asEagerSingleton;
Usage
#Inject #Named("request")
private EntityManager em; //inject a new EntityManager class every request
#Inject #Named("session")
private Provider<EntityManager> emProvider; //inject a new EntityManager class each session
//This is little bit tricky, cuz EntityManager is stored in session. In Stage.PRODUCTION are all injection created eagerly and there is no session at injection time. Session binding should be done in lazy way - inject provider and call emProvider.get() when em is needed;
#Inject #Named("application")
private EntityManager em; //inject singleton
2. Yes, you should or you will use JpaPersistModule [javadoc]
3. Well, this is about JPA configuration in persistence.xml and EntityManager scope
I'm injecting a provider .... but I suspect something is wrong.
When I try to redeploy an application ALWAYS I have to restar the server because the JPA classes are cached.
It happens the following pseudo-bug
https://bugs.eclipse.org/bugs/show_bug.cgi?id=326552
Theoretically by injecting a Provider and getting an instance of EntityManager you should not close anything ....

Callback between EJBs / local EJB calls

Can you register EJB A as callback in an MDB B?
B.register(Aref)
in B: A.callback()
What would be Aref if the EJBs use local calls?
SessionContext.getEJBLocalObject()?
What you ask is not really possible in the proposed way.
If B is a Message Driven Bean, then it's never possible to call a method on it. In the messaging paradigm, the type of the receiver of a message is unknown. You thus can't reference an instance of the MDB. Instead, you post messages to a queue or topic and if your MDB is configured to listen to that its onMessage() method will be invoked.
Secondly, in EJB you don't often pass references around like in your example code. What kind of EJB bean is A supposed to be? A stateless session bean, or a stateful session bean?
In case it's a stateless session bean, the instance might not matter and you can probably just inject it:
#MessageDriven
public class NSMessageDrivenBean implements MessageListener {
#EJB
private A yourABean;
public void onMessage(Message message) {
// process message and then call A
yourABean.someMethod();
}
}
If the callback needs to be done to a type that is unknown in advance (depending on the message being send), then one mechanism for this is via a JMS reply.
In the message being send to the message driven bean, you then include code like this:
message.setJMSReplyTo(someDestination);
message.setJMSCorrelationID(someCorrelationID);
someDestination represents your callback, it's a destination to which something is listening, and this something can then invoke the call on the stateless session bean (in the context of the client).
E.g. something like:
connection.createSession(false, Session.AUTO_ACKNOWLEDGE).createConsumer(someDestination).setMessageListener(
new MessageListener() {
#Override
public void onMessage(Message message) {
yourABean.someMethod();
}
}
In this case, someDestination can be a temporary destination.