Search code examples
jakarta-eejta

Transaction propagation from CDI to EJB


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.


Solution

  • 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.