Search code examples
asynchronousjava-ee-6

Asynchronous method in JavaEE 6


I trying to use Asynchronous method in JavaEE 6. I created Following classes. However, the result of output log is synchronous. It's not correct.

Stateless Class

   @javax.ejb.Stateless
    public class MailManager implements Serializable{
    @Asynchronous
        public void send(List<String> toList, Mail mail, final SystemSetting systemSetting) throws MailException, UnsupportedEncodingException{

            boolean isError = false;
            for(InternetAddress addr :addressList){
                    MimeMessage msg = getMimeMessage(addr, mail, session);
                    Transport.send(msg);
                    log.info("Sent email to ["+addr+"].");
            }
            if(isError){
                throw new MailException("Mail sending error occurred. Check error log.");
            }
            log.debug("Async finish.");
        }
    }

ManagedBean

@Named
@SessionScoped
public class MailController extends AbstractController{
    @Inject @new(MailCreater.class)
    private MailFactory mailCreater;

    @Inject
    private MailManager mailManager;

    public void send(){
        Mail mail = null;
            mail = mailCreater.createFromTemplate(this, false,
                    mimeInfo, "template/testTemplate.txt","template/FOOTER1.body", map);
            mailManager.send(list, mail, systemSetting);
        log.debug("send() finish.");
    }
}

log

INFO[Log4jLogger] - Sent email to [test1@test.co.jp].
INFO [Log4jLogger] - Sent email to [test2@test.co.jp].
.
.
.
DEBUG [Log4jLogger] - Async finish.
DEBUG [Log4jLogger] - send() finish.

Update

Error Code when I change @Inject to @EJB

warning : javax.ejb.EJBException: javax.ejb.EJBException:
javax.ejb.CreateException: Could not create stateless EJB
        at
com.sun.ejb.containers.StatelessSessionContainer._getContext(StatelessSessionContainer.java:454)
        at com.sun.ejb.containers.BaseContainer.getContext(BaseContainer.java:2547)
        at com.sun.ejb.containers.BaseContainer.preInvoke(BaseContainer.java:1899)
        at com.sun.ejb.containers.EjbAsyncTask.call(EjbAsyncTask.java:99)
        at java.util.concurrent.FutureTask.run(FutureTask.java:262)
        at
java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
        at
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
        at java.lang.Thread.run(Thread.java:745)
Caused by: javax.ejb.EJBException: javax.ejb.CreateException: Could not
create stateless EJB
        at
com.sun.ejb.containers.StatelessSessionContainer$SessionContextFactory.create(StatelessSessionContainer.java:726)
        at
com.sun.ejb.containers.util.pool.NonBlockingPool.getObject(NonBlockingPool.java:247)
        at
com.sun.ejb.containers.StatelessSessionContainer._getContext(StatelessSessionContainer.java:449)
        ... 7 more
Caused by: javax.ejb.CreateException: Could not create stateless EJB
        at
com.sun.ejb.containers.StatelessSessionContainer.createStatelessEJB(StatelessSessionContainer.java:534)
        at
com.sun.ejb.containers.StatelessSessionContainer.access$000(StatelessSessionContainer.java:95)
        at
com.sun.ejb.containers.StatelessSessionContainer$SessionContextFactory.create(StatelessSessionContainer.java:724)
        ... 9 more
Caused by: java.lang.NullPointerException
        at java.util.concurrent.ConcurrentHashMap.hash(ConcurrentHashMap.java:333)
        at java.util.concurrent.ConcurrentHashMap.get(ConcurrentHashMap.java:988)
        at
org.jboss.weld.manager.BeanManagerImpl.getBean(BeanManagerImpl.java:1076)
        at org.jboss.weld.manager.BeanManagerImpl.getBean(BeanManagerImpl.java:148)
        at
org.glassfish.weld.services.JCDIServiceImpl._createJCDIInjectionContext(JCDIServiceImpl.java:169)
        at
org.glassfish.weld.services.JCDIServiceImpl.createJCDIInjectionContext(JCDIServiceImpl.java:146)
        at
com.sun.ejb.containers.BaseContainer.createEjbInstanceAndContext(BaseContainer.java:1639)
        at
com.sun.ejb.containers.StatelessSessionContainer.createStatelessEJB(StatelessSessionContainer.java:475)
        ... 11 more

Solution

  • Your code MailController.send() sample is missing how you are currently getting the reference to MailManager. I assume mailManager is the reference but the sample doesn't show how that reference is made so I am flying a little blind here in terms of telling you exactly what's wrong.

    However, in general, what you need to do is inject the MailManager EJB into MailController with something like @EJB MailManager mailManager;

    Also its looks like you are relying on your logs to tell you if things are really going async or not. This can be problematic due to timing. Also the log snippet you have included does not include the "Sent email to" message which it looks like MailManager.send() should be emitting if all goes well.

    -- Update --

    @KensukeSato raised a good question which was, "Should I use @Inject or @EJB as both 'work' in his case?"

    It basically comes down to the fact the as of JavaEE6 CDI beans and EJB beans provide different functionality and that EJB session beans ARE CDI beans but CDI beans are not EJB session beans. So if you simply want EJB services you can use @EJB to inject your session bean into your CDI bean. However, if in addition to @EJB services you want the bean to leverage CDI services then you should use @Inject.

    What does CDI give you that EJB alone does not?

    • Annotation-based programming model; stereotypes
    • Type-safe injection, interceptors, decorators
    • Context management, scopes, conversations
    • Events and observers
    • Producers and disposers
    • Extensibility via custom scopes; programmatically defined beans; etc.

    So if you need any of that in addition to EJB functionality then you would use @Inject, otherwise you can simply use @EJB.