I want to submit a form with a file, and other simple fields. Because sending a file and saving it in filesystem is typical to web tier, I'm doing it in CDI managed bean. From this CDI managed bean I also call EJB to store other data in database. Saving a file could fail, so I annotated my CDI bean's method with @Transactional (JEE7). What I'm expecting is to rollback EJB's transaction when saving a file fail, but it is not happen. Is it normal behavior? How to rollback EJB's transaction in this case?
@Named
@javax.faces.view.ViewScoped
public class LectureCtrl
{
@Inject LecturesFacade lecturesFacade;
@Getter @Setter UploadedFile paper;
@Getter @Setter Lecture lecture;
@Transactional(rollbackOn={FileNotFoundException.class})
public void create(Lecture _lecture) throws MessagingException, IOException
{
try{
Long _lectureId = lecturesFacade.create( _lecture );
//args: file, path, constant filename "abstract"
WebUtils.handleFileUpload( this.paper, "conferences/"+lecture.getConference().getId()+"/lectures/"+_lectureId, "abstract" );
}catch(Exception e){
System.out.println(e);
throw e;
}
}
public String onSubmitNewLecture(){
//JSF-specific code
this.create(this.lecture);
//JSF-specific code
}
}
@Stateless
public class LecturesFacade {
@PersistenceContext EntityManager em;
@Inject EmailSubsystem emailSubsystem;
public Long create( Lecture lecture ) throws MessagingException
{
em.persist(lecture);
em.flush();
em.refresh(lecture);
Long id = lecture.getId();
emailSubsystem.sendEmailOnNewLecture(lecture);
return id;
}
}
Exception:
INFO: java.io.FileNotFoundException: C:\konferencje\files\conferences\3\lectures\20\abstract (Access is denied)
at java.io.FileOutputStream.open(Native Method)
at java.io.FileOutputStream.<init>(FileOutputStream.java:212)
at java.io.FileOutputStream.<init>(FileOutputStream.java:165)
at BackingBeans.WebUtils.handleFileUpload(WebUtils.java:154)
at BackingBeans.LectureCtrl.create(LectureCtrl.java:56)
...
When WebUtils.handleFileUpload
fails, I want to also rollback changes made by lecturesFacade.create
.
EDIT
I have annotated my LectureFacade.create
method with @TransactionAttribute(TransactionAttributeType.MANDATORY)
and it thrown me an javax.ejb.EJBTransactionRequiredException
so it looks like CDI transaction is not propagated to EJB transaction.
I just realized that I am invoking @Transactional method (create) from non-transactional method (onSubmitNewLecture) of the same class, so @Transactional interceptor will be ommited.