Search code examples
jakarta-eeweblogicwildflyjndijca

Determine JNDI portable name within an javax.enterprise.inject.spi.Extension


I am implementing a JCA inbound resource adapter to allow an EIS to send messages to an application deployed on a Java EE Application server.

Only EJBs annotated with my annotation should be accessible so I have used a javax.enterprise.inject.spi.Extension in order to observe ProcessAnnotatedType which I can then use to store details about all EJB methods annotated with my annotation which are deployed on the application server.

The annotation contains a short unique name which can be used like a logical service name to allow inbound calls from the EIS. These calls are then dispatched via JNDI to the respective endpoint.

This all works fine at the moment but the JNDI name must currently be provided as a value in my annotation. I would like to remove this requirement and have my Extension determine the Global Portable JNDI Name.

As I am inside a JCA Resource Adapter I must use the java:global form:

java:global[/application name]/module name/enterprise bean name[/interface name]

My examples I am testing against include:

java:global/testappwar01/SimpleService!org.example.service.ISimpleService
java:global/testappear01/test-ejb/SimpleService!org.example.service.ISimpleService

The interface name and the enterprise bean name I more or less can work out, from the ProcessAnnotatedType object I receive, but application name and module name are proving to be a little more elusive.

I have tried using lookups of java:app/AppName and java:module/Module name. These work fine with wildfly (10.x) when the deployment is a .war, but within an .ear these values for some reason do not exist. Within weblogic 12.x these values do not exist at all regardless of the deployment archive type.

I am looking for something which will work on any Java EE compliant application server, so ideally without app server specific dependencies. Though worse case scenario something that works with weblogic and wildfly would be acceptable.

Updated - wildfly log:

Deployed application are not exactly as described previously, I had sanitied them:

casual-test-app-0.0.1.ear has a custom name in the application.xml "casual-test-app-custom-2" which contains test-ejb.jar and test-ejb2.jar

casual-java-testapp.war is where I can get appName and moduleName to work.

casual-jca-0.0.1.ear is my Resource Adapter

2018-02-21 10:18:03,226 INFO  [org.jboss.weld.deployer] (MSC service thread 1-7) WFLYWELD0003: Processing weld deployment casual-test-app-0.0.1.ear
2018-02-21 10:18:03,520 INFO  [org.jboss.weld.deployer] (MSC service thread 1-3) WFLYWELD0003: Processing weld deployment casual-jca-0.0.1.ear
2018-02-21 10:18:03,852 INFO  [org.jboss.weld.deployer] (MSC service thread 1-8) WFLYWELD0003: Processing weld deployment test-ejb.jar
2018-02-21 10:18:03,853 INFO  [org.jboss.weld.deployer] (MSC service thread 1-2) WFLYWELD0003: Processing weld deployment test-ejb2.jar
2018-02-21 10:18:03,873 INFO  [org.jboss.weld.deployer] (MSC service thread 1-5) WFLYWELD0003: Processing weld deployment casual-java-testapp.war
2018-02-21 10:18:03,877 INFO  [org.jboss.as.ejb3.deployment] (MSC service thread 1-2) WFLYEJB0473: JNDI bindings for session bean named 'SimpleServiceNoViewEjb' in deployment unit 'subdeployment "test-ejb2.jar" of deployment "casual-test-app-0.0.1.ear"' are as follows:

    java:global/casual-test-app-custom-2/test-ejb2/SimpleServiceNoViewEjb!se.kodarkatten.casual.example.service.SimpleServiceNoViewEjb
    java:app/test-ejb2/SimpleServiceNoViewEjb!se.kodarkatten.casual.example.service.SimpleServiceNoViewEjb
    java:module/SimpleServiceNoViewEjb!se.kodarkatten.casual.example.service.SimpleServiceNoViewEjb
    java:global/casual-test-app-custom-2/test-ejb2/SimpleServiceNoViewEjb
    java:app/test-ejb2/SimpleServiceNoViewEjb
    java:module/SimpleServiceNoViewEjb

2018-02-21 10:18:03,878 INFO  [org.jboss.as.ejb3.deployment] (MSC service thread 1-2) WFLYEJB0473: JNDI bindings for session bean named 'SimpleService2' in deployment unit 'subdeployment "test-ejb2.jar" of deployment "casual-test-app-0.0.1.ear"' are as follows:

    java:global/casual-test-app-custom-2/test-ejb2/SimpleService2!se.kodarkatten.casual.example.service.ISimpleService2
    java:app/test-ejb2/SimpleService2!se.kodarkatten.casual.example.service.ISimpleService2
    java:module/SimpleService2!se.kodarkatten.casual.example.service.ISimpleService2
    java:jboss/exported/casual-test-app-custom-2/test-ejb2/SimpleService2!se.kodarkatten.casual.example.service.ISimpleService2
    java:global/casual-test-app-custom-2/test-ejb2/SimpleService2
    java:app/test-ejb2/SimpleService2
    java:module/SimpleService2

2018-02-21 10:18:03,881 INFO  [org.jboss.as.ejb3.deployment] (MSC service thread 1-8) WFLYEJB0473: JNDI bindings for session bean named 'SimpleService2' in deployment unit 'subdeployment "test-ejb.jar" of deployment "casual-test-app-0.0.1.ear"' are as follows:

    java:global/casual-test-app-custom-2/test-ejb/SimpleService2!se.kodarkatten.casual.example.service.ISimpleService2
    java:app/test-ejb/SimpleService2!se.kodarkatten.casual.example.service.ISimpleService2
    java:module/SimpleService2!se.kodarkatten.casual.example.service.ISimpleService2
    java:jboss/exported/casual-test-app-custom-2/test-ejb/SimpleService2!se.kodarkatten.casual.example.service.ISimpleService2
    java:global/casual-test-app-custom-2/test-ejb/SimpleService2
    java:app/test-ejb/SimpleService2
    java:module/SimpleService2

2018-02-21 10:18:03,909 INFO  [org.jboss.weld.deployer] (MSC service thread 1-2) WFLYWELD0003: Processing weld deployment casual-jca-0.0.1.rar
2018-02-21 10:18:03,911 INFO  [org.jboss.as.connector.deployment] (MSC service thread 1-2) WFLYJCA0002: Bound JCA ConnectionFactory [java:/JmsXA]
2018-02-21 10:18:03,912 INFO  [org.wildfly.extension.messaging-activemq] (MSC service thread 1-2) WFLYMSGAMQ0002: Bound messaging object to jndi name java:jboss/DefaultJMSConnectionFactory
2018-02-21 10:18:03,916 INFO  [org.jboss.weld.deployer] (MSC service thread 1-1) WFLYWELD0003: Processing weld deployment casual-inbound-handler-fielded-buffer.jar
2018-02-21 10:18:03,917 INFO  [org.jboss.as.ejb3.deployment] (MSC service thread 1-1) WFLYEJB0473: JNDI bindings for session bean named 'FieldedBufferHandler' in deployment unit 'subdeployment "casual-inbound-handler-fielded-buffer.jar" of deployment "casual-jca-0.0.1.ear"' are as follows:

    java:global/casual-jca-app/casual-inbound-handler-fielded-buffer/FieldedBufferHandler!se.kodarkatten.casual.jca.inbound.handler.buffer.BufferHandler
    java:app/casual-inbound-handler-fielded-buffer/FieldedBufferHandler!se.kodarkatten.casual.jca.inbound.handler.buffer.BufferHandler
    java:module/FieldedBufferHandler!se.kodarkatten.casual.jca.inbound.handler.buffer.BufferHandler
    java:global/casual-jca-app/casual-inbound-handler-fielded-buffer/FieldedBufferHandler
    java:app/casual-inbound-handler-fielded-buffer/FieldedBufferHandler
    java:module/FieldedBufferHandler

2018-02-21 10:18:03,918 INFO  [org.jboss.weld.deployer] (MSC service thread 1-7) WFLYWELD0003: Processing weld deployment casual-inbound-handler-jscd-buffer.jar
2018-02-21 10:18:03,919 INFO  [org.jboss.weld.deployer] (MSC service thread 1-4) WFLYWELD0003: Processing weld deployment casual-inbound-handler-javaee-service.jar
2018-02-21 10:18:03,919 INFO  [org.jboss.weld.deployer] (MSC service thread 1-3) WFLYWELD0003: Processing weld deployment casual-inbound-handler-casual-service.jar
2018-02-21 10:18:03,920 INFO  [org.jboss.weld.deployer] (MSC service thread 1-6) WFLYWELD0003: Processing weld deployment casual-inbound.jar
2018-02-21 10:18:03,921 INFO  [org.jboss.as.ejb3.deployment] (MSC service thread 1-7) WFLYEJB0473: JNDI bindings for session bean named 'JavaServiceCallBufferHandler' in deployment unit 'subdeployment "casual-inbound-handler-jscd-buffer.jar" of deployment "casual-jca-0.0.1.ear"' are as follows:

    java:global/casual-jca-app/casual-inbound-handler-jscd-buffer/JavaServiceCallBufferHandler!se.kodarkatten.casual.jca.inbound.handler.buffer.BufferHandler
    java:app/casual-inbound-handler-jscd-buffer/JavaServiceCallBufferHandler!se.kodarkatten.casual.jca.inbound.handler.buffer.BufferHandler
    java:module/JavaServiceCallBufferHandler!se.kodarkatten.casual.jca.inbound.handler.buffer.BufferHandler
    java:global/casual-jca-app/casual-inbound-handler-jscd-buffer/JavaServiceCallBufferHandler
    java:app/casual-inbound-handler-jscd-buffer/JavaServiceCallBufferHandler
    java:module/JavaServiceCallBufferHandler

2018-02-21 10:18:03,921 INFO  [org.jboss.as.ejb3.deployment] (MSC service thread 1-3) WFLYEJB0473: JNDI bindings for session bean named 'CasualServiceHandler' in deployment unit 'subdeployment "casual-inbound-handler-casual-service.jar" of deployment "casual-jca-0.0.1.ear"' are as follows:

    java:global/casual-jca-app/casual-inbound-handler-casual-service/CasualServiceHandler!se.kodarkatten.casual.jca.inbound.handler.service.ServiceHandler
    java:app/casual-inbound-handler-casual-service/CasualServiceHandler!se.kodarkatten.casual.jca.inbound.handler.service.ServiceHandler
    java:module/CasualServiceHandler!se.kodarkatten.casual.jca.inbound.handler.service.ServiceHandler
    java:global/casual-jca-app/casual-inbound-handler-casual-service/CasualServiceHandler
    java:app/casual-inbound-handler-casual-service/CasualServiceHandler
    java:module/CasualServiceHandler

2018-02-21 10:18:03,921 INFO  [org.jboss.as.ejb3.deployment] (MSC service thread 1-4) WFLYEJB0473: JNDI bindings for session bean named 'JavaeeServiceHandler' in deployment unit 'subdeployment "casual-inbound-handler-javaee-service.jar" of deployment "casual-jca-0.0.1.ear"' are as follows:

    java:global/casual-jca-app/casual-inbound-handler-javaee-service/JavaeeServiceHandler!se.kodarkatten.casual.jca.inbound.handler.service.ServiceHandler
    java:app/casual-inbound-handler-javaee-service/JavaeeServiceHandler!se.kodarkatten.casual.jca.inbound.handler.service.ServiceHandler
    java:module/JavaeeServiceHandler!se.kodarkatten.casual.jca.inbound.handler.service.ServiceHandler
    java:global/casual-jca-app/casual-inbound-handler-javaee-service/JavaeeServiceHandler
    java:app/casual-inbound-handler-javaee-service/JavaeeServiceHandler
    java:module/JavaeeServiceHandler

2018-02-21 10:18:03,964 INFO  [org.jboss.as.ejb3.deployment] (MSC service thread 1-5) WFLYEJB0473: JNDI bindings for session bean named 'EchoService' in deployment unit 'deployment "casual-java-testapp.war"' are as follows:

    java:global/casual-java-testapp/EchoService!se.kodarkatten.casual.example.EchoService
    java:app/casual-java-testapp/EchoService!se.kodarkatten.casual.example.EchoService
    java:module/EchoService!se.kodarkatten.casual.example.EchoService
    java:global/casual-java-testapp/EchoService
    java:app/casual-java-testapp/EchoService
    java:module/EchoService

2018-02-21 10:18:03,968 INFO  [org.jboss.as.ejb3.deployment] (MSC service thread 1-5) WFLYEJB0473: JNDI bindings for session bean named 'SimpleService' in deployment unit 'deployment "casual-java-testapp.war"' are as follows:

    java:global/casual-java-testapp/SimpleService!se.kodarkatten.casual.example.service.ISimpleService
    java:app/casual-java-testapp/SimpleService!se.kodarkatten.casual.example.service.ISimpleService
    java:module/SimpleService!se.kodarkatten.casual.example.service.ISimpleService
    java:jboss/exported/casual-java-testapp/SimpleService!se.kodarkatten.casual.example.service.ISimpleService
    java:global/casual-java-testapp/SimpleService
    java:app/casual-java-testapp/SimpleService
    java:module/SimpleService

2018-02-21 10:18:03,968 INFO  [org.jboss.as.ejb3.deployment] (MSC service thread 1-5) WFLYEJB0473: JNDI bindings for session bean named 'QueueService' in deployment unit 'deployment "casual-java-testapp.war"' are as follows:

    java:global/casual-java-testapp/QueueService!se.kodarkatten.casual.example.QueueService
    java:app/casual-java-testapp/QueueService!se.kodarkatten.casual.example.QueueService
    java:module/QueueService!se.kodarkatten.casual.example.QueueService
    java:global/casual-java-testapp/QueueService
    java:app/casual-java-testapp/QueueService
    java:module/QueueService

2018-02-21 10:18:03,972 INFO  [org.jboss.as.ejb3.deployment] (MSC service thread 1-5) WFLYEJB0473: JNDI bindings for session bean named 'InboundOrderRestService' in deployment unit 'deployment "casual-java-testapp.war"' are as follows:

    java:global/casual-java-testapp/InboundOrderRestService!se.kodarkatten.casual.example.inbound.InboundOrderRestService
    java:app/casual-java-testapp/InboundOrderRestService!se.kodarkatten.casual.example.inbound.InboundOrderRestService
    java:module/InboundOrderRestService!se.kodarkatten.casual.example.inbound.InboundOrderRestService
    java:global/casual-java-testapp/InboundOrderRestService
    java:app/casual-java-testapp/InboundOrderRestService
    java:module/InboundOrderRestService

2018-02-21 10:18:03,973 INFO  [org.jboss.as.ejb3.deployment] (MSC service thread 1-5) WFLYEJB0473: JNDI bindings for session bean named 'OrderRestService' in deployment unit 'deployment "casual-java-testapp.war"' are as follows:

    java:global/casual-java-testapp/OrderRestService!se.kodarkatten.casual.example.order.OrderRestService
    java:app/casual-java-testapp/OrderRestService!se.kodarkatten.casual.example.order.OrderRestService
    java:module/OrderRestService!se.kodarkatten.casual.example.order.OrderRestService
    java:global/casual-java-testapp/OrderRestService
    java:app/casual-java-testapp/OrderRestService
    java:module/OrderRestService

2018-02-21 10:18:03,974 INFO  [org.jboss.as.ejb3.deployment] (MSC service thread 1-5) WFLYEJB0473: JNDI bindings for session bean named 'CasualOrderService' in deployment unit 'deployment "casual-java-testapp.war"' are as follows:

    java:global/casual-java-testapp/CasualOrderService!se.kodarkatten.casual.example.service.order.ICasualOrderServiceRemote
    java:app/casual-java-testapp/CasualOrderService!se.kodarkatten.casual.example.service.order.ICasualOrderServiceRemote
    java:module/CasualOrderService!se.kodarkatten.casual.example.service.order.ICasualOrderServiceRemote
    java:jboss/exported/casual-java-testapp/CasualOrderService!se.kodarkatten.casual.example.service.order.ICasualOrderServiceRemote
    java:global/casual-java-testapp/CasualOrderService!se.kodarkatten.casual.example.service.order.ICasualOrderService
    java:app/casual-java-testapp/CasualOrderService!se.kodarkatten.casual.example.service.order.ICasualOrderService
    java:module/CasualOrderService!se.kodarkatten.casual.example.service.order.ICasualOrderService

2018-02-21 10:18:03,975 INFO  [org.jboss.as.ejb3.deployment] (MSC service thread 1-5) WFLYEJB0473: JNDI bindings for session bean named 'OrderService' in deployment unit 'deployment "casual-java-testapp.war"' are as follows:

    java:global/casual-java-testapp/OrderService!se.kodarkatten.casual.example.service.order.IOrderService
    java:app/casual-java-testapp/OrderService!se.kodarkatten.casual.example.service.order.IOrderService
    java:module/OrderService!se.kodarkatten.casual.example.service.order.IOrderService
    java:global/casual-java-testapp/OrderService!se.kodarkatten.casual.example.service.order.IOrderServiceRemote
    java:app/casual-java-testapp/OrderService!se.kodarkatten.casual.example.service.order.IOrderServiceRemote
    java:module/OrderService!se.kodarkatten.casual.example.service.order.IOrderServiceRemote
    java:jboss/exported/casual-java-testapp/OrderService!se.kodarkatten.casual.example.service.order.IOrderServiceRemote

2018-02-21 10:18:04,005 INFO  [org.jboss.weld.Version] (MSC service thread 1-3) WELD-000900: 2.3.5 (Final)

Solution

  • I have found a few different ways to implement this, but none were exactly ideal. In the end we have opted to go for solution 2 as this worked in the majority of the scenarios we need to support.

    Solution 1 - Use annotation data to create service when required

    Use of CDI BeanManager in order to create my remote service object from the information discovered in the SPI Extension annotation metadata. This is sort of documented here in section 16.5 though here is the final version that worked:

    public Object getServiceReference( AnnotatedType<CasualService> type )
    {
        BeanManager beanManager = CDI.current().getBeanManager();
        CreationalContext<CasualService> ctx = beanManager.createCreationalContext(null);
        BeanAttributes<CasualService> attributes = beanManager.createBeanAttributes( type );
        InjectionTargetFactory<CasualService> itf = beanManager.getInjectionTargetFactory( type );
        Bean<CasualService> bean = beanManager.createBean( attributes, type.getJavaClass(), itf );
        Object reference = beanManager.getReference( bean, type.getBaseType(), ctx );
        return reference;
    }
    

    Unfortunately this only worked well in Wildfly and not in Weblogic. The issue in weblogic was due to the way in which the Weblogic bean manager implementation creates a bean; it does not use the current Threads classloader resulting in Exceptions due to unsatisfied dependencies or class not found.

    I was also not entirely happy with needing to create the service object each time as the application server settings for slb cache etc would not be honoured.

    Solution 2 - Perform lazy lookup with timer service traversing JNDI tree for matches

    1. During spi Extension discovery of the annotations, save all the annotation metadata.
    2. A timer service runs periodically to traverse the JNDI tree to find all proxy objects / remote services. (timer service required because weblogic does not have JNDI entries available when the Extension discover runs.)
    3. Using the service annotation metadata "match" them to candidate JNDI urls. Text based match based on information from Global Portable JNDI names
    4. Using the proxy objects classloader load the implementation class to check it's methods annotation data to see if it was the expected service (load class is required as proxy class methods do not contain any annotation meta data)
    5. Repeat process until all services have a matching JNDI.

    There are a few edge cases where the match does not work, but for those edge cases I have created another annotation that can be provided on the service Class which hardcodes the expected JNDI path, so we don't have to search.

    This approach works in both wildfly and weblogic.