I have an EJB server running on one Liberty server and the Client running on another server.
If I do a manual lookup of the remote EJB using the code below, I can access the EJB.
Context ctx = new InitialContext();
Object homeObject = ctx.lookup("corbaname::localhost:22809#ejb/global/TempEAR-0.0.1/com.ibm.temp-TempEJB-0.0.1/ConverterBean!com.ibm.temp.ejb.ConverterRemote")
ConverterRemote myRemoteEJB = (ConverterRemote) PortableRemoteObject.narrow(homeObject, ConverterRemote.class);
System.out.println("RESULT " + myRemoteEJB.celsiusToFar(1));
The above works as expected, it's able to call the remote EJB running on the other server instance and works as expected.
I'm trying to instead use Spring within my @Controller class, and reference the EJB through annotations @EJB or @Autowired
@EJB(name="testRemoteEJB")
ConverterRemote testRemoteEJB;
mvc-dispatcher-servlet.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jee="http://www.springframework.org/schema/jee"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
http://www.springframework.org/schema/jee
http://www.springframework.org/schema/jee/spring-jee-3.0.xsd">
<context:component-scan
base-package="com.ibm.common.controller" />
<mvc:annotation-driven />
<jee:remote-slsb id="testRemoteEJB"
jndi-name="jndi/testRemoteEJB"
business-interface="com.ibm.temp.ejb.ConverterRemote">
</jee:remote-slsb>
</beans>
liberty server.xml
<jndiEntry id="testRemoteEJB" jndiName="jndi/testRemoteEJB" value="corbaname::localhost:22809#ejb/global/TempEAR-0.0.1/com.ibm.temp-TempEJB-0.0.1/ConverterBean!com.ibm.temp.ejb.ConverterRemote"/>
When I print out the testRemoteEJB object it returns a com.sun.proxy.$Proxy41 object, and when I try to call the method funtion I get the below exception
[err] org.springframework.remoting.RemoteProxyFailureException: No matching RMI stub method found for: public abstract double com.ibm.temp.ejb.Converter.celsiusToFar(double) throws java.rmi.RemoteException; nested exception is java.lang.NoSuchMethodException: java.lang.String.celsiusToFar(double)
[err] at org.springframework.remoting.rmi.RmiClientInterceptorUtils.invokeRemoteMethod(RmiClientInterceptorUtils.java:83)
[err] at org.springframework.ejb.access.SimpleRemoteSlsbInvokerInterceptor.doInvoke(SimpleRemoteSlsbInvokerInterceptor.java:98)
[err] at org.springframework.ejb.access.AbstractRemoteSlsbInvokerInterceptor.invokeInContext(AbstractRemoteSlsbInvokerInterceptor.java:140)
[err] at org.springframework.ejb.access.AbstractSlsbInvokerInterceptor.invoke(AbstractSlsbInvokerInterceptor.java:189)
[err] at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
[err] at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207)
[err] at com.sun.proxy.$Proxy41.celsiusToFar(Unknown Source)
[err] at com.ibm.common.controller.JSONController.lookupEJB(JSONController.java:89)
[err] at com.ibm.common.controller.JSONController.getTempCtoF(JSONController.java:157)
[err] at sun.reflect.GeneratedMethodAccessor663.invoke(Unknown Source)
[err] at java.lang.reflect.Method.invoke(Method.java:498)
[err] at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:221)
[err] at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:137)
[err] at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:110)
[err] at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:806)
[err] at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:729)
[err] at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
[err] at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:959)
[err] at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:893)
[err] at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970)
[err] at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:861)
[err] at javax.servlet.http.HttpServlet.service(HttpServlet.java:687)
[err] at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)
[err] at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)
[err] at com.ibm.ws.webcontainer.servlet.ServletWrapper.service(ServletWrapper.java:1258)
[err] at [internal classes]
[err] at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
[err] at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
[err] at java.lang.Thread.run(Thread.java:748)
[err] Caused by: java.lang.NoSuchMethodException: java.lang.String.celsiusToFar(double)
[err] at java.lang.Class.getMethod(Class.java:1786)
[err] at org.springframework.remoting.rmi.RmiClientInterceptorUtils.invokeRemoteMethod(RmiClientInterceptorUtils.java:75)
[err] ... 48 more
So it's clear that the remote lookup isn't resolving, but I'm confused because I know I'm able to access it manually, so the connection string should be valid.
If there anything I can be missing?
This came originally working with traditional WAS, but not working on Liberty
The
@EJBannotation is intended to provide the equivalent of the first 3 lines of the working manual example, and then setting the result on the field the annotation is applied to. So, it should perform the following:If the field with the annotation were on a Java EE container managed object, such as a servlet, servlet filter, EJB, interceptor, etc., then Liberty would perform that behavior and the
@EJBannotation would work as expected.However, in this scenario, the
@EJBannotation is on a springframework managed object, so it is springframework that is performing the processing of the@EJBannotation, and it appears that springframework has omitted the use of 'PortableRemoteObject.narrow()`.A COS Naming lookup of a CORBA remote object is not guaranteed to return a specific _Stub implementation for the remote interface. Likely, it is an instance of a generic stub class, such as
org.omg.stub.java.rmi._Remote_Stub. When springframework then attempts to call a method on such a stub, it will fail with a NoSuchMethodException since the stub does not implement the remote interface. Performing thenarrow()converts the generic Stub instance into a specific Stub instance that does implement the remote interface. If springframework could be updated to perform thenarrow(), then the scenario would work.The behavior for this scenario is going to be different between traditional WebSphere and Liberty because each use a very different CORBA ORB implementation.
Traditional WebSphere uses the IBM ORB, which anticipates that the application is going to want a specific Stub class and attempts to provide a narrowed stub on the lookup; a subsequent narrow() call will be a no-op. The IBM ORB is proactive with the narrow in an attempt to improve performance. However, it should be noted that even when using the IBM ORB, the Stub returned on a lookup is not always a specific Stub; a
narrow()should always be performed.Liberty uses the Yoko ORB, which does not attempt to return specific Stubs instances on a JNDI Lookup, as this is not required by the specification. The returned Stub will almost always be a generic Stub and the lookup should always be followed by a
narrow().Either the application needs to be updated to utilize
@EJBon a Java EE managed object, or there needs to be a change to the mechanism used by springframework to obtain the EJB reference such that anarrow()is performed.