Hasan Tuncay
Hasan Tuncay

Reputation: 1108

Call Methods Asynchronous in EJB

I try to save the result of a login process for statistics to the database asynchronously to save time during the login method. But somehow the login process takes longer if i add a thread.sleep to the async method. Why is that? I thought the authenticate method will not wait for the writeResultToStats methode to finish.

    @Stateless
    @LocalBean
    @ConcurrencyManagement(ConcurrencyManagementType.CONTAINER)
    @TransactionManagement(TransactionManagementType.CONTAINER)
    public class CustomerBeanTest {

        @PersistenceContext(unitName = WebPersistenceUnits.QISADS)
        private EntityManager em_local;

        @TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
        public void authenticate(Long loginid, String cmppassword) {
            try {
                Login l = em_local.find(Login.class, loginid);
                String s = l.getPassword();
                if (!s.equalsIgnoreCase(cmppassword))
                    throw new PasswordMissmatchException();
                writeResultToStats(loginid, true);
            } catch (PasswordMissmatchException e) {
                writeResultToStats(loginid, false);
            }
        }

        @Asynchronous
        @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
        private void writeResultToStats(Long loginID, boolean success) {

            try { // just for testing
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

            LogUtils log = new LogUtils(this);
            Login l = em_local.find(Login.class, loginID);
            if (success) {
                l.setSuccessLast(new Date());
                l.setSuccessCount(l.getSuccessCount()+1);
                log.log(Level.INFO, "Update Login Stat Success [%d, %s, %d]", l.getId(), l.getName(), Thread.currentThread().getId());
            } else {
                l.setFailureLast(new Date());
                l.setFailureCount(l.getFailureCount()+1);
                log.log(Level.INFO, "Update Login Stat Fail [%d, %s, %d]", l.getId(), l.getName(), Thread.currentThread().getId());
            }

        }

    }

Upvotes: 7

Views: 15147

Answers (2)

jigga
jigga

Reputation: 175

Take a look at this example - it shows that You do not need to create separate EJB.

If you have a bean which has both synchronous and asynchronous methods, the asynchronous method cannot be called from within the synchronous one because the container will not intercept it.

But instead of creating another bean, you can call the asynchronous bean method through the SessionContext:

@Stateless
public class OrderProcessorBean {
    @Inject
    SessionContext ctx;
    //synchronous method invoked from EJB call outside this class
    public void synch() {
        //call asynch method
        ctx.getBusinessObject(OrderProcessorBean.class).asynch();
    }

    @Asynchronous
    public void asynch() {
         //asynch logic
    }
}

Upvotes: 7

Aksel Willgert
Aksel Willgert

Reputation: 11537

Try to break out the asynchronous method into a separate ejb. Methods invoked from inside the same ejb will be handled just like local method-invocations. The container is not capable of intercept the method call.

EJB-Annotations is only in play when invocation is done by the container.

Alternative

You can have the method in the same EJB but make sure you use the EJB Local interface to lookup the bean and access the methord.

Upvotes: 10

Related Questions