java-ee-6ejb-3.1interceptorejb-jar.xmlsessioncontext

Finding out what EJB view was used


Assume I have an EJB defining two views:

Both interfaces share the same method signatures, so it's like:

public interface MyBusinessCommon {
    void myMethod(Object o);
}

@Local
public interface MyBusinessLocal extends MyBusinessCommon { }

@Remote
public interface MyBusinessRemote extends MyBusinessCommon { }

@Stateless
public class MyBusinessBean implements MyBusinessLocal, MyBusinessRemote {
    public void myMethod(Object o) {
        // ...
    }
}

Is there a way to figure out what EJB view was called from within the EJB itself (or its interceptor?)

Let's say I would like to perform different authorization procedures depending on used view. Remote should be more constrained and local shouldn't.

I can invoke SessionContext#getInvokedBusinessInterface() but this gives me information only about the class object - not about EJB semantics of it. Plainly using reflection to check annotations presence on interfaces or bean is not enough (what about views defined in ejb-jar.xml?)

I doubt it is possible using straight EJB specification but perhaps there's something I missed.

If not, is it possible to get this information from the inners of an application server? (let's consider only JBoss AS 7.x, Glassfish 3.x and TomEE 1.5.1).


Solution

  • It's just like Arjan said - it is impossible to do just by following EJB spec.

    However, in Glassfish it's quite simple to do.

    All EJB interceptors accept the InvocationContext parameter. InvocationContext implementation in Glassfish is in fact com.sun.ejb.EjbInvocation class. It has the isLocal field that tolds you if it's intercepting local business call (or isRemote for remote business calls). You can use it e.g. as follows:

    import com.sun.ejb.EjbInvocation;
    
    import javax.interceptor.AroundInvoke;
    import javax.interceptor.Interceptor;
    import javax.interceptor.InvocationContext;
    
    @Interceptor
    public class CallSourceAwareInterceptor {
    
        @AroundInvoke
        public Object aroundInvoke(InvocationContext ictx) throws Exception {
            boolean isLocalCall = isLocalEJBCall(ictx);
    
            return ictx.proceed();
        }
    
        boolean isLocalEJBCall(final InvocationContext ictx) {
            if (ictx instanceof EjbInvocation) {
                return ((EjbInvocation) ictx).isLocal;
            }
            else {
                throw new IllegalArgumentException("Unknown InvocationContext implementation.");
            }
        }
    }
    

    To access this EjbInvocation internal Glassfish class you need to add following maven dependency:

    <dependency>
        <groupId>org.glassfish.main.ejb</groupId>
        <artifactId>ejb-container</artifactId>
        <version>4.0.1-b02</version>
        <scope>provided</scope>
    </dependency>
    

    And you might need to add following specific repository to get access to this artifact:

    <repositories>
        <repository>
            <id>maven-promoted</id>
            <url>https://maven.java.net/content/groups/promoted/</url>
        </repository>
    </repositories>
    

    I did a quick research (based on Richard's suggestion regarding Invocation object) how to achieve the same in JBoss but couldn't find answer...