jsr345-experts@ejb-spec.java.net

[jsr345-experts] Splitting Services (was: EJB 3.2 Lite Support for Asynchronous)

From: David Blevins <david.blevins_at_gmail.com>
Date: Wed, 28 Sep 2011 15:33:54 -0700

On Sep 28, 2011, at 12:55 AM, Antonio Goncalves wrote:

> What asynch servlets also have is a timeout (asyncSupported = true, asyncTimeout = 3000). It could also be interesting to have a timeout attribute on @Asynchronous, what do you think ?

See @javax.ejb.AccessTimeout. It's basically a wrapped version of the TimeUnit/long pair used in the java.util.concurrent APIs. Works for handling all multi-threaded access including @Asynchronous invocations.

The part that I wonder about is what we might do with the relationship between the Future and javax.ejb.SessionContext. The cancel logic is tied together.

Still preparing for JavaOne and don't have time for a concrete proposal, but off the top of my head it seems like we might want to start breaking up SessionContext into sub interfaces that are service specific to the related services. We've historically used the SessionContext (or EJBContext) as the way for beans to "talk to the container". We can still follow that pattern (and even keep compatibility) we probably just need to start slicing out methods into more specific interfaces.

Specifically, perhaps a javax.ejb.AsynchronousContext interface to contain the 'boolean wasCancelCalled();' method and be the container compliment to the javax.ejb.Asynchronous support and container controlled Future object that might be the result of an @Asynchronous call. This could be injected into any object leveraging @Asynchronous support.
We then make javax.ejb.

    package javax.ejb;
    public interface AsynchronousContext {
        boolean wasCancelCalled();
    }

We then make SessionContext implement that interface:

    public interface SessionContext extends EJBContext, AsynchronousContext {
        EJBLocalObject getEJBLocalObject() throws IllegalStateException;

        EJBObject getEJBObject() throws IllegalStateException;

        MessageContext getMessageContext() throws IllegalStateException;

        <T> T getBusinessObject(Class<T> businessInterface);

        Class getInvokedBusinessInterface();
    }

We could follow this pattern as we split up other parts. I can easily imagine the following:

    public interface SessionContext extends javax.ejb.EJBContext, AsynchronousContext {

        EJBLocalObject getEJBLocalObject() throws IllegalStateException;
        EJBObject getEJBObject() throws IllegalStateException;

        /**
         * These two methods could be interesting to any object using proxies
         * They allow the bean to call itself and get container services (interceptors, security, transaction)
         * Both are candidates for splitting
         */
        <T> T getBusinessObject(Class<T> businessInterface);
        Class getInvokedBusinessInterface();

        /**
         * Already a context object that can just be injected
         * No need to split out this method
         */
        MessageContext getMessageContext() throws IllegalStateException;
    }

    public interface AsynchronousContext {
        boolean wasCancelCalled();
    }

    public interface EJBContext extends SecurityContext, TransactionContext, NamingContext, InterceptorContext {

        EJBHome getEJBHome();
        EJBLocalHome getEJBLocalHome();

        /**
         * @deprecated
         */
        Properties getEnvironment();
        Identity getCallerIdentity();
        boolean isCallerInRole(Identity role);

        /**
         * Already a "context" object that can just be injected
         * No need to split out this method
         */
        TimerService getTimerService() throws IllegalStateException;
    }

    public interface SecurityContext {
        Principal getCallerPrincipal();
        boolean isCallerInRole(String roleName);
    }

    public interface TransactionContext {
        UserTransaction getUserTransaction() throws IllegalStateException;
        void setRollbackOnly() throws IllegalStateException;
        boolean getRollbackOnly() throws IllegalStateException;
    }

    public interface NamingContext {
        Object lookup(String name);
    }

    public interface InterceptorContext {
        Map<String, Object> getContextData();
    }

All these would be injectable via @Resource and have standard names directly under "java:comp/", such as java:comp/AsynchronousContext


-David