Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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());
            }

        }

    }
like image 259
Hasan Tuncay Avatar asked May 28 '13 08:05

Hasan Tuncay


2 Answers

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.

like image 149
Aksel Willgert Avatar answered Sep 23 '22 08:09

Aksel Willgert


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
    }
}
like image 44
jigga Avatar answered Sep 23 '22 08:09

jigga