EJB TransactionRequiredException in GlassFish 2.1 - java

In my Stateful bean, I have the following lines:
#Stateful(mappedName = "ejb/RegistrationBean")
#StatefulTimeout(unit = TimeUnit.MINUTES, value = 30)
#TransactionManagement(value=TransactionManagementType.CONTAINER)
public class RegistrationStateful implements RegistrationStatefulRemote {
#PersistenceContext
EntityManager em;
private List<Event> reservedSessions = new ArrayList<Event>();
private boolean madePayment = false;
...
#TransactionAttribute(TransactionAttributeType.REQUIRED)
private void cancelReservation() {
if (reservedSessions.size() != 0) {
Teacher theTeacher;
for (Event session : reservedSessions) {
if ((theTeacher = session.teacher) == null) theTeacher = bestTeacher.teacher;
theTeacher = em.merge(theTeacher) //The exception is thrown here
//Make changes to theTeacher
em.flush(); //The exception is also thrown here
}
//Clear the reservedSessions list
reservedSessions.clear();
}
}
#Remove
public void endRegistration() {}
#PreDestroy
public void destroy() {
//Cancel outstanding reservations if payment has not been made
if (!madePayment) cancelReservation();
}
}
The line em.merge(someEntity) throws the TransactionRequiredException. Could someone please tell me why it happens? I thought with TransactionAttribute.REQUIRED, a transaction will AUTOMATICALLY be created if there isn't an active one. I tried to use em.joinTransaction() but it throws the same Exception. I'm a beginner at this transaction thing. I'd be very grateful if someone could explain this to me.
UPDATE: I'd like to add a bit more information
The Stateful bean actually also has the following function:
#TransactionAttribute(TransactionAttributeType.REQUIRED)
private void reserveSession(List<Event> sessions) throws ReservationException {
//Reserve the sessions
Teacher theTeacher;
for (Event session : sessions) {
if ((theTeacher = session.teacher) == null) theTeacher = bestTeacher.teacher;
theTeacher = em.merge(theTeacher);
//Make changes to theTeacher
em.flush();
}
}
The flow is as following: the user tells me his free time and I reserve some seats for him. After that, I show him his reserved seats and he can choose to make payment or cancel the reservations.
The reserved() function worked perfectly as expected but the cancelReservation() did not.
UPDATE 2: I have fixed the problem last night by commenting out the lines "#TransactionAttribute(TransactionAttributeType.REQUIRED)", "em.merge(theTeacher)" and "em.flush()" in the "cancelReservation()" function. The result is perfect. Would it be safe if I cut off those lines? I was afraid I would get "detached entity" exception when I used "em.merge()" in the first place.

The only thing that springs to mind (if you'll excuse the pun) is that if you're calling cancelReservation() from another method inside the bean, then i'm not sure the transaction annotation will be observed. The annotation ultimately works by summoning an interceptor, and i believe interceptors are only applied to calls between different classes (this is something i should really check).
So, if you have a non-transactional method on the bean which calls a transactional method, then a transaction won't be started when the transactional method is called.
I could be completely wrong about this. I'll go and have a bit of a read of the spec and get back to you.
EDIT: I had a read of the spec, and it reminded me what a disaster zone the J2EE specs are. Horrific. However, the section on transactions does seem to imply that the transaction attributes only apply to calls made to an EJB's business interface. I believe calls from one method to another inside a bean are not considered to go through the business interface, even when the method being called is part of that interface. Therefore, you wouldn't expect them to attract transactions.
Something you could try would be to route them through the interface; there is no nice way of doing this, but you should be able to inject a business-interface self-reference like this:
public class RegistrationStateful implements RegistrationStatefulRemote {
#EJB
private RegistrationStatefulRemote self;
You can then change your #PreDestroy method to look like this:
#PreDestroy
public void destroy() {
self.cancelReservation();
}
And i believe that should count as a normal business interface call, with transactions and so on.
I have never actually tried this, so this could be complete rubbish. If you try it, let me know how it works out!

Related

TransactionAttributeType.REQUIRES_NEW in conjunction with #Observes(during = TransactionPhase.AFTER_SUCCESS)

I recently stumbled into the next piece of Java EE6 code:
#TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public void example(#Observes(during = TransactionPhase.AFTER_SUCCESS) final ExampleEvent exampleEvent) {
Is REQUIRES_NEW really needed?
I mean example method will always be called only after any previous transaction has ended successfully ( because of TransactionPhase.AFTER_SUCCESS).
Or am I missing something?
Your are only observing ExampleEvent, so your example()-Method will not be called by itself (based on the #TransactionAttribute) unless your do something like this:
#Inject
private Event<ExampleEvent> exampleEvent;
#TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public void example(#Observes(during = TransactionPhase.AFTER_SUCCESS) final ExampleEvent exampleEvent) {
ExampleEvent event = new ExampleEvent();
exampleEvent.fire(event);
}
It makes sense to keep the #TransactionAttribute because the previous transaction just finished (AFTER_SUCCESS), so there is no current transaction therefore a new one is needed to be created. It can be possible that this would be done automatically (depending on the AS implementation) even without the annotation, but the result should be the same.

What Dropwizard-Hibernate doc is trying to say?

I have run into LazyInitializationException and then I ran into the following paragraph from the official doc. Unfortunately, it makes absolutely no sense to me. Please help.
(The code block above the paragraph in the doc.)
#GET
#Timed
#UnitOfWork
public Person findPerson(#PathParam("id") LongParam id) {
return dao.findById(id.get());
}
Important
The Hibernate session is closed before your resource method’s return
value (e.g., the Person from the database), which means your resource
method (or DAO) is responsible for initializing all lazily-loaded
collections, etc., before returning. Otherwise, you’ll get a
LazyInitializationException thrown in your template (or null values
produced by Jackson).
First The Hibernate session is closed before your resource method’s return value. How is this possible? This would have been possible had there been a try-finally block around my resource's return statement, but that is not the case here.
My resource should have been invoked by another method, which I am guessing would open the Hibernate session before my resource method is invoked and would then close the session after my resource method returns. How can it close it before my method returns. I don't get it.
The most important part - which means your resource method (or DAO) is responsible for initializing all lazily-loaded collections, etc., before returning. I have no Hibernate experience. I am using it for the first time now. How do I initialize, or rather what is exactly is meant by "initialize" in context of Hibernate? A code example will help a lot.
PS: This question might look odd, and someone at a cursory glance might even suggest to move it to "English Language and Usage", but please read it carefully. This is a technical question, not paragraph dissection.
Edit:
Added the code block from the doc else it won't make sense anyone. Also I removed one paragraph from my question, which became clear to me, immediately after posting the question.
First The Hibernate session is closed before your resource method’s
return value. How is this possible? This would have been possible had
there been a try-finally block around my resource's return statement,
but that is not the case here.
I know nothing about Dropwizard. So let's see the source (I change it a bit).
From UnitOfWorkAwareProxyFactory
class UnitOfWorkAwareProxyFactory {
public <T> T create(Class<T> clazz) {
final ProxyFactory factory = new ProxyFactory();
factory.setSuperclass(clazz);
final Proxy proxy = (Proxy) factory.createClass().newInstance();
proxy.setHandler(new MethodHandler() {
#Override
public Object invoke(Object self, Method overridden,
Method proceed, Object[] args) {
final UnitOfWork unitOfWork = overridden.getAnnotation(UnitOfWork.class);
final UnitOfWorkAspect unitOfWorkAspect = new UnitOfWorkAspect(sessionFactories);
try {
unitOfWorkAspect.beforeStart(unitOfWork);
Object result = proceed.invoke(self, args);
unitOfWorkAspect.afterEnd();
return result;
} catch (Exception e) {
unitOfWorkAspect.onError();
throw e;
}
}
});
return (T) proxy;
}
}
if you have a class
class PersonDao {
#UnitOfWork
public Person findPerson(LongParam id) {
return dao.findById(id.get());
}
}
You can do something like this
UnitOfWorkAwareProxyFactory factory = new UnitOfWorkAwareProxyFactory();
PersonDao proxy = factory.create(PersonDao.class);
when you do
Person person = proxy.findPerson(1L);
that line becomes
unitOfWorkAspect.beforeStart(unitOfWork);
Object result = findPerson.invoke(proxy, 1L);
unitOfWorkAspect.afterEnd();
return result;
Methods unitOfWorkAspect.beforeStart(unitOfWork) and unitOfWorkAspect.afterEnd() from the source UnitOfWorkAspect
class UnitOfWorkAspect {
public void beforeStart(UnitOfWork unitOfWork) {
session = sessionFactory.openSession();
configureSession();
beginTransaction();
}
public void afterEnd() {
try {
commitTransaction();
} catch (Exception e) {
rollbackTransaction();
throw e;
} finally {
session.close();
}
}
}
The most important part - which means your resource method (or DAO) is responsible for initializing all lazily-loaded collections, etc., before returning. I have no Hibernate experience. I am using it for the first time now. How do I initialize, or rather what is exactly is meant by "initialize" in context of Hibernate?
Initialize in this context means the collection data should be loaded from a database. Some methods of an initialization
1.Use an eager loading, for an example
class User {
#ManyToMany(fetch = FetchType.EAGER)
private List<Role> roles;
}
Hibernate will load roles via joins or subselects, when you get a User entity.
Use Hibernate.initialize(user.getRoles())
Use join fetch in HQL — from User user left join fetch user.roles
Use Criteria with setFetchMode()
Use fetch profiles, entity graphs. Don't know can entity graphs be used with a session, it is a JPA feature: http://docs.jboss.org/hibernate/orm/5.1/userguide/html_single/chapters/fetching/Fetching.html
If you don't need to fetch collections, you can use a partial objects loading with transforming to the root entity: How to transform a flat result set using Hibernate

Spring hibernate transactions propagations aren't working properly

I have a transactional class in my project with following 2 methods:
#Repository(value = "usersDao")
#Transactional(propagation = Propagation.REQUIRED)
public class UsersDaoImpl implements UsersDao {
#Autowired
SessionFactory sessionFactory;
/* some methods here... */
#Override
#Transactional(propagation = Propagation.REQUIRES_NEW,readOnly = false,rollbackFor = {Exception.class})
public void pay(Users payer, int money) throws Exception {
if( payer.getMoney() < money ) {
throw new Exception("");
}
payer.setMoney(payer.getMoney()-money);
this.sessionFactory.getCurrentSession().update(payer);
}
#Override
#Transactional(readOnly = false,rollbackFor = {Exception.class})
public void makeTransfer(Users from, Users to, int money) throws Exception {
System.out.println("Attempting to make a transfer from " + from.getName() + " to " + to.getName() + "... sending "+ money +"$");
to.setMoney(to.getMoney()+money);
if( from.getMoney() < 10 ) {
throw new Exception("");
}
pay(from, 10);
if( from.getMoney() < money ) {
throw new Exception("");
}
from.setMoney(from.getMoney()-money);
this.sessionFactory.getCurrentSession().update(from);
this.sessionFactory.getCurrentSession().update(to);
}
}
The assumption is that when somebody's making a transfer, they must pay 10$ tax. Let's say there are 2 users who have 100$ both and I want to make a transfer (User1->User2) of 95$. First in makeTransfer I check if User1 is able to pay a tax. He is so I'm moving forward and checking if he's got 95$ left for transfer. He doesn't so the transaction is rolled back. The problem is, in the end they both have 100$. Why? For method pay I set Propagation.REQUIRES_NEW, which means it executes in a separate transaction. So why is it also rolled back? The tax payment should be actually save into a database and only the transfer should be rolled back. The whole point of doing this for me is understanding propagations. I understand them teoretically but can't manage to do some real example of it(How propagation change affects my project). If this example is misunderstanding I'd love to see another one.
What M. Deinum said.
Furthermore, according to the Spring documentation:
Consider the use of AspectJ mode (see mode attribute in table below)
if you expect self-invocations to be wrapped with transactions as
well. In this case, there will not be a proxy in the first place;
instead, the target class will be weaved (that is, its byte code will
be modified) in order to turn #Transactional into runtime behavior on
any kind of method.
To use aspectj, write
<tx:annotation-driven transaction-manager="transactionManager" mode="aspectj"/>
instead of
<tx:annotation-driven transaction-manager="transactionManager" />
Source:
http://docs.spring.io/spring/docs/current/spring-framework-reference/html/transaction.html
I solved my problem. Thanks guys for pointing out allowing AspectJ but that wasn't the end. I did deeper research and it turned out that in #Transactional Spring Beans there's an aspect proxy, which is responsible(as far as get it) for operating on transactions(creating, rolling back etc.) for #Transactional methods. But it fails on self reference, because it bypasses proxy, so no new transactions are created. A simple way I used to get this working is calling function pay(..) not refering to this, but to a bean from the spring container, like this:
UsersDaoImpl self = (UsersDaoImpl)this.context.getBean("usersDao");
self.pay(from, 10);
Now, as it refers to the bean, it goes through the proxy so it creates a new transaction.
Just for learning issues I used those two lines to detect whether the two transactions are the same objects or not:
TransactionStatus status = TransactionAspectSupport.currentTransactionStatus();
System.out.println("Current transaction: " + status.toString());

What makes a transaction a transaction in Spring/Java (specific scenario)?

I've read through the definitions of transactions on this site, as well as some other external sources. But I'm having a hard time grappling with the specific notion of a transaction when writing code.
I have a BuyService class that is transactional. The BuyService class is declared transactional, and its only method is buyWidget(String widgetId). This method calls on the ExampleService class, which has a deleteWidgit(String widgetId) method. It also calls on the InvoiceService class, which uses the writeInvoice(String widgitId) method. Here is the code:
BuyService class:
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
#Transactional
public class BuyService implements BuyServiceInterface
{
private ExampleServiceInterface exampleService;
private InvoiceServiceInterface invoiceService;
public void setExampleService(ExampleServiceInterface exampleService)
{
this.exampleService = exampleService;
}
public void setInvoiceService(InvoiceServiceInterface invoiceService)
{
this.invoiceService = invoiceService;
}
#Override
#Transactional(propagation=Propagation.REQUIRED)
public void buyWidget(Widget widgetId)
{
try
{
Widget purchasedWidget = this.exampleService.getWidgetById(String widgetId);
this.exampleService.deleteWidget(purchasedWidget);
this.invoiceService.writeInvoice(purchasedWidget);
}
catch (WidgetNotFoundException e)
{
System.out.println("Widget with widgetId " + widgetId + " not found.");
}
}
}
I am pretty sure that the buyWidget method constitutes a transaction. It requires the deletion of a widget in a database (in exampleService) and the insertion of data in the purchase database (in invoiceService). But I am confused about terminology after this point. Are the methods deleteWidget and writeInvoice themselves transactions as well?
ExampleService class:
public class ExampleService implements ExampleServiceInterface
{
private ExampleServiceDaoInterface dao;
public void setExampleServiceDao(ExampleServiceDaoInterface dao)
{
this.dao = dao;
}
#Override
public void deleteWidget(Widget oldWidget)
throws WidgetNotFoundException
{
this.dao.delete(oldWidget);
}
#Override
public Widget getWidgetById(String widgetId)
{
return this.dao.getById(widgetId);
}
}
InvoiceService class:
public class InvoiceService implements InvoiceServiceInterface
{
private InvoiceServiceDaoInterface InvoiceServiceDao;
public void setInvoiceServiceDao(InvoiceServiceDaoInterface InvoiceServiceDao)
{
this.InvoiceServiceDao = InvoiceServiceDao;
}
#Override
public void writeInvoice(Widget purchasedWidget)
{
Date purchaseDate = new Date(new java.util.Date().getTime());
String isbn = purchasedWidget.getIsbn();
Purchases newPurchase = new Purchases(purchaseDate, isbn);
this.InvoiceServiceDao.savePurchase(newPurchase);
}
}
Are the two methods called on by buyWidget transactions as well? That is, even if neither of those methods are declared as transactions.
What are some potential pitfalls of not declaring the two child methods as transactions? (Since they apparently appear to be a part of one already).
Are the methods deleteWidget and writeInvoice themselves transactions as well?
They will take part in the buyWidget transaction, but they are not by themselves transactional
Are the two methods called on by buyWidget transactions as well?
The transaction is started before entering the buyWidget method and stopped or rolled back before the method is completed. The two methods will take part in the buyWidget transaction, but are not themselves transactions.
Are the two methods called on by buyWidget transactions as well?
None of the methods are transactions. The annotation #Transactional(propagation=Propagation.REQUIRED) means " Support a current transaction, create a new one if none exists." This transaction will include anything called from the buyWidget() method. Basically, when the method is entered a transaction is started, and when it's exited that transaction will be committed (if everything works out) or rolled back (if there is an Exception thrown, a problem on the DB side, or the transaction is rolled back via Java code).
That is, even if neither of those methods are declared as transactions.
As long as those methods operate on a DB that is aware of JTA, it will work with the existing transaction.
What are some potential pitfalls of not declaring the two child methods as transactions? (Since they apparently appear to be a part of one already).
If those methods are called directly, they will not be part of a transaction. This could result in an inconsistent state of the DB if those methods result in multiple SQL statements (it doesn't look like that, but cannot be definitely ruled out just by looking at the code).

How to refresh an entity in a Future?

I am not really sure where my problem lies, as I am experimenting in two areas that I don't have much experience with: JPA and Futures (using Play! Framework's Jobs and Promises).
I have the following bit of code, which I want to return a Meeting object, when one of the fields of this object has been given a value, by another thread from another HTTP request. Here is what I have:
Promise<Meeting> meetingPromise = new Job<Meeting> () {
#Override
public Meeting doJobWithResult() throws Exception {
Meeting meeting = Meeting.findById(id);
while (meeting.bbbMeetingId == null) {
Thread.sleep(1000);
meeting = meeting.refresh(); // I tried each of these
meeting = meeting.merge(); // lines but to no avail; I
meeting = Meeting.findById(id); // get the same result
}
return meeting;
}
}.now();
Meeting meeting = await(meetingPromise);
As I note in the comments, there are three lines in there, any one of which I think should allow me to refresh the contents of my object from the database. From the debugger, it seems that the many-to-one relationships are refreshed by these calls, but the single values are not.
My Meeting object extends Play! Framework's Model, and for convenience, here is the refresh method:
/**
* Refresh the entity state.
*/
public <T extends JPABase> T refresh() {
em().refresh(this);
return (T) this;
}
and the merge method:
/**
* Merge this object to obtain a managed entity (usefull when the object comes from the Cache).
*/
public <T extends JPABase> T merge() {
return (T) em().merge(this);
}
So, how can I refresh my model from the database?
So, I ended up cross-posting this question on the play-framework group, and I got an answer there. So, for the discussion, check out that thread.
In the interest of having the answer come up in a web search to anyone who has this problem in the future, here is what the code snippet that I pasted earlier looks like:
Promise<Meeting> meetingPromise = new Job<Meeting> () {
#Override
public Meeting doJobWithResult() throws Exception {
Meeting meeting = Meeting.findById(id);
while (meeting.bbbMeetingId == null) {
Thread.sleep(1000);
if (JPA.isInsideTransaction()) {
JPAPlugin.closeTx(false);
}
JPAPlugin.startTx(true);
meeting = Meeting.findById(id);
JPAPlugin.closeTx(false);
}
return meeting;
}
}.now();
Meeting meeting = await(meetingPromise);
I am not using the #NoTransaction annotation, because that messes up some other code that checks if the request is coming from a valid user.
I'm not sure about it but JPA transactions are managed automatically by Play in the request/controller context (the JPAPlugin opens a transaction before invocation and closes it after invocation).
But I'm not sure at all what happens within jobs and I don't think transactions are auto-managed (or it's a feature I don't know). So, is your entity attached to an entitymanager or still transient? Is there a transaction somewhere? I don't really know but it may explain some weird behavior if not...

Categories