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)
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
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.