Spring remote EJB not resolving bean on Liberty - spring

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

#Tracy's answer is 100% the correct explanation of what the issue is. Though if you're here you're likely looking for what to do now.
We were able to get around this by extending some of the Spring classes and changing the lookups slightly.
Here is a summary of the changes we made.
Originally our bean definition was configured as
<jee:remote-slsb id="testRemoteEJB"
jndi-name="jndi/testRemoteEJB"
business-interface="com.ibm.temp.ejb.ConverterRemote">
</jee:remote-slsb>
We replaced this with
<bean id="testRemoteEJB" class="com.ibm.ejb.access.MySimpleRemoteStatelessSessionProxyFactoryBean">
<property name="jndiName" value="jndi/testRemoteEJB"/>
<property name="businessInterface" value="com.ibm.temp.ejb.ConverterRemote"/>
</bean>
We created the class MySimpleRemoteStatellessSessionProxyFactoryBean by extending the class SimpleRemoteStatelessSessionProxyFactoryBean
We overwrite the create() method and manually did the EJB lookup.
package com.ibm.ejb.access;
import java.lang.reflect.InvocationTargetException;
import javax.naming.NamingException;
import javax.rmi.PortableRemoteObject;
import org.springframework.ejb.access.SimpleRemoteStatelessSessionProxyFactoryBean;
//import com.ibm.temp.ejb.ConverterRemote;
public class MySimpleRemoteStatelessSessionProxyFactoryBean extends SimpleRemoteStatelessSessionProxyFactoryBean {
#Override
protected Object create() throws NamingException, InvocationTargetException {
System.out.println("MySimpleRemote: create()");
//String remoteURL = "corbaname::localhost:22809#ejb/global/TempEAR-0.0.1/com.ibm.temp-TempEJB-0.0.1/ConverterBean!com.ibm.temp.ejb.ConverterRemote";
Object homeObject = this.lookup();
String jndiValue = homeObject.toString();
System.out.println("jndi = " + jndiValue);
if (homeObject instanceof String) {
//Note if your spring mvc references a jndi is looked up again, you might have to do a double lookup
homeObject = this.lookup(jndiValue);
}
Object myEJB = PortableRemoteObject.narrow(homeObject, this.getBusinessInterface());
System.out.println("jndi = " + myEJB);
return myEJB;
}
}
depending on if you pass in the remote lookup URL in the spring xml or if you pass in the jndi and specify the remote lookup URL in the Liberty server.xml, the code will have to do 1 or 2 lookups. Then we manually process the narrow.
This works for us and allowed the customer to proceed without having to make any changes to their original code, only modifying the spring xml config files.
We created a sample app to demonstrate this which you can read along to here
https://github.com/rcauchon/app-modernization-ejb

The #EJB annotation 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:
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);
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 #EJB annotation would work as expected.
However, in this scenario, the #EJB annotation is on a springframework managed object, so it is springframework that is performing the processing of the #EJB annotation, 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 the narrow() converts the generic Stub instance into a specific Stub instance that does implement the remote interface. If springframework could be updated to perform the narrow(), 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 #EJB on 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 a narrow() is performed.

Related

Should Oracle's ucp.jar reside in Tomcat's lib or application's war? Missing ResultSetMetaData. Achieving clean redeploy of Tomcat app with Oracle?

Suppose it is 2016. I am building a very simple Java EE app with Spring for DI, jdbc template and web, Oracle for persistence and Deploy it to Tomcat. Sounds easy, not sure if it could be more trivial.
There are the following most recent stable versions:
Tomcat 8.5
Oracle jdbc drivers v 12.x
and Spring 4.3.x
Tomcat recommends putting jdbc drivers to $CATALINA_BASE/lib, so I follow this recommendation. Oracle recommends using their UCP pool and tutorials at oracle.com also suggest putting ucp.jar together with ojdbc.jar (to Tomcat's lib folder). I use Spring to manage lifecycle of UCP pool and pass it as a datasource to JdbcTemplate.
I use a single dedicated server at production and for the best experience of my users I use a Tomcat's Parallel deployment feature. There is nothing very special about this feature, it allows to deploy a new version with no downtime and automatically (and gracefully) undeploy an old version when there are no active sessions left for it.
The missing ResultSetMetaData problem
The unexpected problem I may have after deploying a new version of application with such a simple setup:
INFO [http-nio-8080-exec-6] org.apache.catalina.loader.WebappClassLoaderBase.checkStateForResourceLoading Illegal access: this web application instance has been stopped already. Could not load [java.sql.ResultSetMetaData]. The following stack trace is thrown for debugging purposes as well as to attempt to terminate the thread which caused the illegal access.
java.lang.IllegalStateException: Illegal access: this web application instance has been stopped already. Could not load [java.sql.ResultSetMetaData]. The following stack trace is thrown for debugging purposes as well as to attempt to terminate the thread which caused the illegal access.
at org.apache.catalina.loader.WebappClassLoaderBase.checkStateForResourceLoading(WebappClassLoaderBase.java:1427)
at org.apache.catalina.loader.WebappClassLoaderBase.checkStateForClassLoading(WebappClassLoaderBase.java:1415)
at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1254)
at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1215)
at com.sun.proxy.$Proxy31.getMetaData(Unknown Source)
at org.springframework.jdbc.core.SingleColumnRowMapper.mapRow(SingleColumnRowMapper.java:89)
at org.springframework.jdbc.core.RowMapperResultSetExtractor.extractData(RowMapperResultSetExtractor.java:93)
at org.springframework.jdbc.core.RowMapperResultSetExtractor.extractData(RowMapperResultSetExtractor.java:60)
at org.springframework.jdbc.core.JdbcTemplate$1QueryStatementCallback.doInStatement(JdbcTemplate.java:465)
at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:407)
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:477)
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:487)
at org.springframework.jdbc.core.JdbcTemplate.queryForObject(JdbcTemplate.java:497)
at org.springframework.jdbc.core.JdbcTemplate.queryForObject(JdbcTemplate.java:503)
at example.App.rsMetadataTest(App.java:82)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:204)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:132)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:97)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:854)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:765)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:967)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:901)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:861)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:655)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:764)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:542)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:687)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:382)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:893)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1726)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)
at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:748)
And now the app is broken. Any subsequent attempt to make a call involving ResultSetMetaData (i.e. jdbcTemplate.queryForObject("select 'hello' from dual", String.class)) will fail with:
java.lang.NoClassDefFoundError: java/sql/ResultSetMetaData
com.sun.proxy.$Proxy31.getMetaData(Unknown Source)
org.springframework.jdbc.core.SingleColumnRowMapper.mapRow(SingleColumnRowMapper.java:89)
org.springframework.jdbc.core.RowMapperResultSetExtractor.extractData(RowMapperResultSetExtractor.java:93)
org.springframework.jdbc.core.RowMapperResultSetExtractor.extractData(RowMapperResultSetExtractor.java:60)
org.springframework.jdbc.core.JdbcTemplate$1QueryStatementCallback.doInStatement(JdbcTemplate.java:465)
org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:407)
org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:477)
org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:487)
org.springframework.jdbc.core.JdbcTemplate.queryForObject(JdbcTemplate.java:497)
org.springframework.jdbc.core.JdbcTemplate.queryForObject(JdbcTemplate.java:503)
example.App.rsMetadataTest(App.java:82)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.lang.reflect.Method.invoke(Method.java:498)
org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:204)
org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:132)
org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:97)
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:854)
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:765)
org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:967)
org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:901)
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970)
org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:861)
javax.servlet.http.HttpServlet.service(HttpServlet.java:655)
org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)
javax.servlet.http.HttpServlet.service(HttpServlet.java:764)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
How to reproduce
Unfortunately I do not understand the root cause of the exception. The ResultSetMetaData is a JDK class, how it can be not found? Was it unloaded? At least after some experiments I know exactly the minimum steps required to reproduce it:
deploy 1st version of an app and init db pool (i.e. with a simple connection, but which DOES NOT involve ResulstSetMetaData, i.e. jdbcTempalte.query()).
deploy the 2nd version of an app
wait for the 1st version to undeploy (as gracefully as possible)
and make a call which involves ResultSetMetaData.
Boom! The ResultSetMetaData not found again and the app is broken.
This bug does not depend on Tomcat's Parallel deployment feature. You can have the most recent (9.x) Tomcat with stock configuration, 2 different webapps using the same Oracle jdbc driver, deploy it in the order and under the same conditions I described above and get the same error.
Also I would like to add that the following statement from Tomcat is incorrect:
this web application instance has been stopped already
I know exactly that the 2nd (just deployed) app gets invoked (not the unloaded one), it is alive and could not be stopped. But it fails at reaching ResultSetMetaData on it's way.
With the help of docker-compose I did many experiments to isolate the problem and see what can fix it. One thing that fixes the problem is putting ucp.jar to .war, not into Tomcat's lib.
That's the reason for the question in the title:
Should Oracle's ucp.jar reside in Tomcat's lib or be bundled to application's war?
ucp.jar itself is not a jdbc driver which gets registered with a global service-provider. Do you put HikariCP to Tomcat's lib? I do not think so. And bundling ucp to webapp fixes the ResultSetMetaData problem. Are there any other reasons for ucp.jar to be placed to Tomcat's lib?
Broken reflection
Unfortunately moving ucp.jar to war by setting compile or runtime scope for it in Maven can lead to another problem:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'oracleDataSource' defined in example.App: Initialization of bean failed; nested exception is java.lang.ArrayStoreException: sun.reflect.annotation.AnnotationTypeMismatchExceptionProxy
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:562)
....
... 64 more
Caused by: java.lang.ArrayStoreException: sun.reflect.annotation.AnnotationTypeMismatchExceptionProxy
at sun.reflect.annotation.AnnotationParser.parseEnumArray(AnnotationParser.java:744)
...
at java.lang.Class.getAnnotations(Class.java:3446)
at org.springframework.transaction.annotation.AnnotationTransactionAttributeSource.determineTransactionAttribute(AnnotationTransactionAttributeSource.java:152)
The context won't start as soon as you add #EnableTransactionManagement in your Spring Java config or <tx:annotation-driven/> if you prefer XML. But I do want to use #Transactional annotations in my app. So I am stuck again. Here at least I was able to understand the problem. Spring 4 tries to read annotations on PoolDataSourceImpl to see if the bean needs to proxied to support annotation-based transaction control. The Class#getAnnotations() fails to read annotations on the PoolDataSourceImpl class, because oracle.jdbc.logging.annotations.Feature exists in both jars (ucp and jdbc). And there are 2 class loaders having different instances of Class<oracle.jdbc.logging.annotations.Feature>. The part of introspection capabilities on PoolDataSourceImpl is broken with a weird ArrayStoreExceotion!
The presence of such an error is an argument for keeping both Oracle jars in the same classpath.
If you faced the above problems in 2016 (when there was no higher versions of Oracle driver), what would you do? I am asking this, because the project I work on is a bit stuck in the past. Earlier, upgrading Oracle driver had led to unexpected and unobvious problems in production, so at the nearest release we are hesitant to update the jdbc driver. But since the project was recently upgraded from Tomcat 7 to Tomcat 8, there is now a risk to face the missing ResultSetMetaData problem, which should be solved.
I forgot to say: you might face the stacktrace complaining on missing ResultSetMetaData in a previous version of Tomcat: 7.x. But it did not spoil the observable behaviour. Unlike Tomcat 9.x and 8.x, Tomcat 7.x printed the exception once, but somehow managed to execute the query and successfully handle the request. Tomcat 7.x did not break the app. Does it mean that modern Tomcat has the regression which Tomcat 7.x did not have?
The potential memory leak Tomcat warnings
What I also do not like at redeployment is the following lines at logs:
WARNING [Catalina-utility-2] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesThreads The web application [app##1] appears to have started a thread named [Timer-0] but has failed to stop it. This is very likely to create a memory leak. Stack trace of thread:
java.lang.Object.wait(Native Method)
java.lang.Object.wait(Object.java:502)
java.util.TimerThread.mainLoop(Timer.java:526)
java.util.TimerThread.run(Timer.java:505)
WARNING [Catalina-utility-2] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesThreads The web application [app##1] appears to have started a thread named [oracle.jdbc.driver.BlockSource.ThreadedCachingBlockSource.BlockReleaser] but has failed to stop it. This is very likely to create a memory leak. Stack trace of thread:
java.lang.Object.wait(Native Method)
oracle.jdbc.driver.BlockSource$ThreadedCachingBlockSource$BlockReleaser.run(BlockSource.java:329)
WARNING [Catalina-utility-2] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesThreads The web application [app##1] appears to have started a thread named [InterruptTimer] but has failed to stop it. This is very likely to create a memory leak. Stack trace of thread:
java.lang.Object.wait(Native Method)
java.lang.Object.wait(Object.java:502)
java.util.TimerThread.mainLoop(Timer.java:526)
java.util.TimerThread.run(Timer.java:505)
Is it possible to fix them at all? From my tests they are not caused by UCP, but rather come from ojdbc.jar. I did not find any solution here. Neither latest version of ojdbc8 (or ojdbc11), nor using other pools or lifecycle methods of Oracle's UniversalConnectionPoolManager (as suggested here) have helped here.
If you replace ojdbc with postgres database and driver, you won't see similar warnings and your logs will be clean.
The source code
I did not provide any code in the post, it is already pretty long, but I created a repo with the minimal application example and parameterised docker-compose test. So you can easily play with it and reproduce all the problems I mentioned with a single command: docker-compose rm -fs && docker-compose up --build
I am aware that you mentioned I use Spring to manage lifecycle of UCP pool and pass it as a datasource to JdbcTemplate but my advice will be to create your datasource as a tomcat resource (i.e., at the context level):
<Resource
name="tomcat/UCPPool"
auth="Container"
<!-- Defines UCP or JDBC factory for connections -->
factory="oracle.ucp.jdbc.PoolDataSourceImpl"
<!-- Defines type of the datasource instance -->
type="oracle.ucp.jdbc.PoolDataSource"
description="UCP Pool in Tomcat"
<!-- Defines the Connection Factory to get the physical connections -->
connectionFactoryClassName="oracle.jdbc.pool.OracleDataSource”
minPoolSize="2"
maxPoolSize="60"
initialPoolSize="15"
autoCommit="false"
user="scott"
password="tiger"
<!-- FCF is auto-enabled in 12.2. Use this property only if you are using Pre 12.2 UCP
fastConnectionFailoverEnabled=”true” -->
<!-- Database URL -->
url="jdbc:oracle:thin:#(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=tcp)(HOST=proddbclust
er-scan)(PORT=1521)))(CONNECT_DATA=(SERVICE_NAME=proddb)))"
</Resource>
The example is obtained from the guide provided for Oracle when describing Configure Tomcat for UCP.
And try to acquire a reference to that datasource through JNDI:
#Bean
public DataSource dataSource() {
final JndiDataSourceLookup dsLookup = new JndiDataSourceLookup();
dsLookup.setResourceRef(false);
DataSource dataSource = dsLookup.getDataSource("tomcat/UCPPool");
return dataSource;
}
You are very likely facing a class loading issue and putting ucp.jar together with ojdbc.jar in your $CATALINA_BASE/lib and configuring this JNDI lookup can solve the problem.
Regarding your warnings, please, consider read this related SO question, especially this answer: it seems that there is a bug in the Oracle JDBC drive and an update to driver version 12.2 should solve the problem.
P.S.: Great question, very well documented!!
The messages "appears to have started a thread named [...] but has failed to stop it" point directly at the heart of the problem, which is a very common issue when re-deploying webapps within a webapp container, whether tomcat or jetty or any other. The issue is that some long-running threads were started by the app, but not explicitly shutdown, so they keep running, and hence they keep an instance of the WebappClassLoader for this webapp in memory, which references the classes previously loaded by it. When you then redeploy the same webapp, a new distinct WebappClassLoader with the same resources is created, which however doesn't have access to the classes loaded by the prior incarnation that the JVM is still referencing, thus leading to the NoClassDefFoundError.
There are only three general means of dealing with this:
a) Always restart the webapp container when redeploying webapps.
b) Fix all code in the webapps so that all such long-running threads are shut down. This means implementing ServletContextListeners that will perform explicit shutdown operations, stopping pool management threads etc. when the ServletContext is stopped (i.e. the webapp is undeployed).
c) Relocate the offending code so it is not loaded by the WebappClassLoader but by the SystemClassLoader, and thus never goes out of scope. In this case you would achieve that by moving the ojdbc.jar to the system classpath (tomcat/lib) and the datasource definition to the server configuration file (tomcat/conf/server.xml). It is anyway a bad practice to include database drivers within a webapp, such fundamental code should be centrally located so that only one instance of it runs within the JVM. Having these inside webapps can lead to conflicts.

Postgres connection has been closed error in Spring Boot

I am running a Spring Boot application to create REST apis. Often I get an error saying that the database connection is closed, and after that I cannot make any calls to the application. I'm using Postgres DB. This is the complete stack trace:
org.springframework.transaction.CannotCreateTransactionException: Could not open JPA EntityManager for transaction; nested exception is javax.persistence.PersistenceException: org.hibernate.TransactionException: JDBC begin transaction failed:
at org.springframework.orm.jpa.JpaTransactionManager.doBegin(JpaTransactionManager.java:431)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager.java:373)
at org.springframework.transaction.interceptor.TransactionAspectSupport.createTransactionIfNecessary(TransactionAspectSupport.java:457)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:276)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207)
at com.sun.proxy.$Proxy91.findByUriMoniker(Unknown Source)
at com.mypkg.businessobjects.OrderInfoBO.getOrderInfo(OrderInfoBO.java:76)
at com.mypkg.controller.OrderInfoController.getOrderInfo(OrderInfoController.java:78)
at sun.reflect.GeneratedMethodAccessor104.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:221)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:137)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:110)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:777)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:706)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:943)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:877)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:966)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:857)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:687)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:842)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)
at io.undertow.servlet.handlers.ServletHandler.handleRequest(ServletHandler.java:85)
at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:130)
at com.mypkg.config.CORSFilter.doFilter(CORSFilter.java:39)
at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:60)
at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:132)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:88)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:60)
at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:132)
at io.undertow.servlet.handlers.FilterHandler.handleRequest(FilterHandler.java:85)
at io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:61)
at io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36)
at io.undertow.servlet.handlers.security.SSLInformationAssociationHandler.handleRequest(SSLInformationAssociationHandler.java:131)
at io.undertow.servlet.handlers.security.ServletAuthenticationCallHandler.handleRequest(ServletAuthenticationCallHandler.java:56)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.security.handlers.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java:45)
at io.undertow.servlet.handlers.security.ServletConfidentialityConstraintHandler.handleRequest(ServletConfidentialityConstraintHandler.java:63)
at io.undertow.security.handlers.AuthenticationMechanismsHandler.handleRequest(AuthenticationMechanismsHandler.java:58)
at io.undertow.servlet.handlers.security.CachedAuthenticatedSessionHandler.handleRequest(CachedAuthenticatedSessionHandler.java:70)
at io.undertow.security.handlers.SecurityInitialHandler.handleRequest(SecurityInitialHandler.java:76)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:261)
at io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:247)
at io.undertow.servlet.handlers.ServletInitialHandler.access$000(ServletInitialHandler.java:76)
at io.undertow.servlet.handlers.ServletInitialHandler$1.handleRequest(ServletInitialHandler.java:166)
at io.undertow.server.Connectors.executeRootHandler(Connectors.java:197)
at io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:759)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
Caused by: javax.persistence.PersistenceException: org.hibernate.TransactionException: JDBC begin transaction failed:
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1763)
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1677)
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.throwPersistenceException(AbstractEntityManagerImpl.java:1771)
at org.hibernate.jpa.internal.TransactionImpl.begin(TransactionImpl.java:64)
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.beginTransaction(HibernateJpaDialect.java:159)
at org.springframework.orm.jpa.JpaTransactionManager.doBegin(JpaTransactionManager.java:380)
... 56 more
Caused by: org.hibernate.TransactionException: JDBC begin transaction failed:
at org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction.doBegin(JdbcTransaction.java:76)
at org.hibernate.engine.transaction.spi.AbstractTransactionImpl.begin(AbstractTransactionImpl.java:162)
at org.hibernate.internal.SessionImpl.beginTransaction(SessionImpl.java:1435)
at org.hibernate.jpa.internal.TransactionImpl.begin(TransactionImpl.java:61)
... 58 more
Caused by: org.postgresql.util.PSQLException: This connection has been closed.
at org.postgresql.jdbc2.AbstractJdbc2Connection.checkClosed(AbstractJdbc2Connection.java:833)
at org.postgresql.jdbc2.AbstractJdbc2Connection.getAutoCommit(AbstractJdbc2Connection.java:794)
at sun.reflect.GeneratedMethodAccessor35.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at org.apache.tomcat.jdbc.pool.ProxyConnection.invoke(ProxyConnection.java:126)
at org.apache.tomcat.jdbc.pool.JdbcInterceptor.invoke(JdbcInterceptor.java:108)
at org.apache.tomcat.jdbc.pool.DisposableConnectionFacade.invoke(DisposableConnectionFacade.java:81)
at com.sun.proxy.$Proxy56.getAutoCommit(Unknown Source)
at org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction.doBegin(JdbcTransaction.java:68)
... 61 more
When I restart the application, it goes away. I think this problem occurs when I restart my postgres DB. Why is this happening?
This is kind of half-answered by the other posts and I wanted to be very explicit. Also I wanted to be more Spring-Boot-esque. Feel free to change the time intervals as necessary.
Option 1: Toss out broken connections from the pool.
Use these properties:
spring.datasource.test-on-borrow=true
spring.datasource.validation-query=SELECT 1;
spring.datasource.validation-interval=30000
Option 2: Keep connections in the pool alive.
Use these properties:
spring.datasource.test-while-idle=true
spring.datasource.validation-query=SELECT 1;
spring.datasource.time-between-eviction-runs-millis=60000
Option 3: Proactively toss out idle connections.
Use these properties (Note: I was not able to find reliable documentation on this one for Spring Boot. Also the timeout is in seconds not milliseconds):
spring.datasource.remove-abandoned=true
spring.datasource.remove-abandoned-timeout=60
Happy booting!
Very valid question and this problem is usually faced by many. The exception generally occurs, when network connection is lost between pool and database (most of the time due to restart). Looking at the stack trace you have specified, it is quite clear that you are using jdbc pool to get the connection. JDBC pool has options to fine-tune various connection pool settings and log details about whats going on inside pool.
You can refer to to detailed apache documentation on pool configuration to specify abandon timeout
Check for removeAbandoned, removeAbandonedTimeout, logAbandoned parameters
Additionally you can make use of additional properties to further tighten the validation
Use testXXX and validationQuery for connection validity.
I had the exact same problem, with this setup, also using DataSource from Tomcat (org.apache.tomcat.jdbc.pool) to connect to Heroku Postgres:
org.springframework.transaction.CannotCreateTransactionException:
Could not open JPA EntityManager for transaction
org.hibernate.TransactionException: JDBC begin transaction failed: ]
with root cause
org.postgresql.util.PSQLException: This connection has been closed.
What solved it for me was adding this to DataSource init code (borrowing from a Grails question):
dataSource.setTestOnBorrow(true);
dataSource.setTestWhileIdle(true);
dataSource.setTestOnReturn(true);
dataSource.setValidationQuery("SELECT 1");
I'm not sure if all these three are needed to get a stable connection—perhaps not—but having all enabled probably doesn't hurt much.
The JavaDocs clarify what's going on: see e.g. setTestOnBorrow(). A little surprising, perhaps, that by default no such tests are made.
This exception basically says the JDBC connection was closed, but it doesn't mean that
the database server is not running (there is another exception for that). This could happen when the DB server was restarted
or after the DB server dropped the connection (eg. because of a timeout).
So the question here is why the application does not reconnect to the server on a new HTTP request.
Usually this is a misconfiguration of the connection pool which should validate the connection each time the application
"borrows" one. All you need to solve this problem is the following:
spring.datasource.validation-query=SELECT 1;
spring.datasource.test-on-borrow=true
Other configuration parameters (from other answers) are optimzations that are not strictly required for this exception.
But sometimes even if the JDBC pool is properly configured there could be a certain application bug in which the application holds the DB connection
without returning it to the JDBC pool after the HTTP request ends.
So the JDBC pool does not even have the possibility to validate the DB connection (all it knows is that the DB connection is "ALLOCATED").
The general solution here is to make sure the application returns the connection and "borrow" a new connection on each HTTP request.
One example of such a bug:
#Component
public MyService {
#Resource
private EntityManagerFactory emf;
private EntityManager em;
public MyService() {
em = emf.createEntityManager();//em never return back its JDBC connection to the pool (using em.close())
}
}
The solution for the bug above is either to use an injected/managed EntityManager (prefered)
#Component
public MyService {
#PersistenceContext
private EntityManager em;
}
or if you really need to manage it yourself create an EntityManager for every HTTP request and close it in a try-finally block if you really
#Component
public MyService {
#Resource
private EntityManagerFactory emf;
private EntityManager em;
public void myMethod() {
EntityManager em = emf.createEntityManager();
try {
} finaly {
em.close();//do not forget other cleanup operations like rolling back the transaction
}
}
}
I had exactly the same problem but in my case the afore mentioned answers did not help. I figured out that when doing a long query the same error appears. In my case I called findAll(Iterable ids) and passed a huge list of more than 100'000 ids. Partitioning the list (e.g. using ListUtils from Apache Commons or Google Guava) and calling the findAll() with less ids did the trick.
when you write queries in repository try to keep #Repository annotation there in repository

EJB call to varargs method failing from Java7 client

We have stateless session bean (EJB 3.0) that has a method which accepts varargs(variable arguments) as inputs. Method signature is as below:-
public String operation1(String arg1,List...arg4);
This EJB is deployed on Weblogic 10.3.2 running on a "Java6" JRE.
When this EJB method is invoked from a Java6 standalone client, the call is successful.
When I change the JRE from Java6 to Java7(without changing any other client code),the call fails with an unmarshal exception(Stack trace below).
javax.ejb.EJBException: Could not unmarshal method ID; nested exception is:
java.rmi.UnmarshalException: Method not found: 'operation1(Ljava.lang.String;Ljava.util.List...;)'; nested exception is: java.rmi.UnmarshalException: Method not found: 'operation1(Ljava.lang.String;Ljava.util.List...;)'
at weblogic.ejb.container.internal.RemoteBusinessIntfProxy.unwrapRemoteException(RemoteBusinessIntfProxy.java:109)
at weblogic.ejb.container.internal.RemoteBusinessIntfProxy.invoke(RemoteBusinessIntfProxy.java:91)
at com.sun.proxy.$Proxy5.operation1(Unknown Source)
at com.MyEJBStandaloneClient.testOperation1(MyEJBStandaloneClient.java:78)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
EJB Code
#Stateless(mappedName = "MyBean")
public class MyBean implements MyBeanRemote{
public String operation1(String arg1,List...arg4) {
System.out.println("Input1 is:-"+arg1);
return "newString";
}
}
Remote class
#Remote
public interface MyBeanRemote {
public String operation1(String arg1,List... arg4);
}
The non-varargs methods(if any are added), within the same EJB are invoked successfully from Java7 clients & it is only the varargs methods in the EJB that have this problem.
Note that the same call works fine even with Java7 if the method signature on the Remote interface class is changed to the following
public String operation1(String arg1,List[] arg4);
But is there any way to make it work without changing the method signature?
Are there any known issues around this?
Thanks.
The problem you described is the consequence of an old bug from WebLogic.
In fact, EJB methods using varargs are ignored when it generates its stub classes.
The deep reason is that WebLogic EJB compiler incorrectly tries to append a transient modifier to the varargs argument.
Obviously, it results in an error, and so, the method stub is not generated.
At that time BEA created a path, CR327275, for WebLogic 10.0.MP1 to correct the issue. Unfortunately, this patch was apparently NOT included in WebLogic 10.3 release...
Feedbacks on this point are not that easy to find, but the Seam community made some. Here they are:
http://in.relation.to/Bloggers/Weblogic10SeamAndEJB3#H-Option1ApplyTheTtCR327275ttPatchBut
https://docs.jboss.org/seam/2.1.2/reference/en-US/html/weblogic.html
So, to solve your issue:
either, as you guessed, you have to change the method signature
or you contact WebLogic to get and install the former patch.
Regards,
Thomas

How to use Java-8 default-interface-implementation in a OSGi-Service

I would like to use Java 8 features on the latest Apache-Karaf release (3.0.2) which is supposed to support Java 8.
I have a service-interface within my domain-layer (repository) which has a default-method for identity-generation
public interface MyRepository{
...
default MyId nextIdentity() {
return new MyId(UUID.randomUUID().toString().toUpperCase());
}
}
Then I have a Implementation of that interface which is exposed as a OSGi-Service using Blueprint (Apache-Aries).
When I run my application the bundles get installed successfully, the services get registered, but when the application-layer is calling the method nextIdentity I get a Exception.
IncompatibleClassChangeError: Found interface MyRepository, but class was expected
The application-layer is straight forward: Interface-Attribute which gets its class (in this case OSGi-Service-Reference) injected via Blueprint.
I did check the compilation: all modules are compiled with Java 8 compliance level in Eclipse. I am guessing the problem is related to a aries-proxy which is not Java 8, but since karaf supports it....
EDIT: added Stacktrace
org.apache.wicket.WicketRuntimeException: Can't instantiate page using constructor 'public bikeshop.http.wicket.page.GaragePage()'. Might be it doesn't exist, may be it is not visible (public).
at org.apache.wicket.session.DefaultPageFactory.newPage(DefaultPageFactory.java:193)[92:org.apache.wicket.core:6.7.0]
at org.apache.wicket.session.DefaultPageFactory.newPage(DefaultPageFactory.java:66)[92:org.apache.wicket.core:6.7.0]
at org.ops4j.pax.wicket.internal.PaxWicketPageFactory.newPage(PaxWicketPageFactory.java:76)[100:org.ops4j.pax.wicket.service:3.0.2]
at org.apache.wicket.DefaultMapperContext.newPageInstance(DefaultMapperContext.java:133)[92:org.apache.wicket.core:6.7.0]
at org.apache.wicket.core.request.handler.PageProvider.resolvePageInstance(PageProvider.java:268)[92:org.apache.wicket.core:6.7.0]
at org.apache.wicket.core.request.handler.PageProvider.getPageInstance(PageProvider.java:166)[92:org.apache.wicket.core:6.7.0]
at org.apache.wicket.request.handler.render.PageRenderer.getPage(PageRenderer.java:78)[92:org.apache.wicket.core:6.7.0]
at org.apache.wicket.request.handler.render.WebPageRenderer.respond(WebPageRenderer.java:244)[92:org.apache.wicket.core:6.7.0]
at org.apache.wicket.core.request.handler.RenderPageRequestHandler.respond(RenderPageRequestHandler.java:165)[92:org.apache.wicket.core:6.7.0]
at org.apache.wicket.request.cycle.RequestCycle$HandlerExecutor.respond(RequestCycle.java:854)[92:org.apache.wicket.core:6.7.0]
at org.apache.wicket.request.RequestHandlerStack.execute(RequestHandlerStack.java:64)[91:org.apache.wicket.request:6.7.0]
at org.apache.wicket.request.cycle.RequestCycle.execute(RequestCycle.java:254)[92:org.apache.wicket.core:6.7.0]
at org.apache.wicket.request.cycle.RequestCycle.processRequest(RequestCycle.java:211)[92:org.apache.wicket.core:6.7.0]
at org.apache.wicket.request.cycle.RequestCycle.processRequestAndDetach(RequestCycle.java:282)[92:org.apache.wicket.core:6.7.0]
at org.apache.wicket.protocol.http.WicketFilter.processRequestCycle(WicketFilter.java:259)[92:org.apache.wicket.core:6.7.0]
at org.apache.wicket.protocol.http.WicketFilter$$EnhancerByCGLIB$$91ca4a1b.CGLIB$processRequestCycle$4(<generated>)[92:org.apache.wicket.core:6.7.0]
at org.apache.wicket.protocol.http.WicketFilter$$EnhancerByCGLIB$$91ca4a1b$$FastClassByCGLIB$$36c566fa.invoke(<generated>)[92:org.apache.wicket.core:6.7.0]
at net.sf.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:228)[99:org.apache.servicemix.bundles.cglib:2.2.2.1]
at org.ops4j.pax.wicket.internal.servlet.PAXWicketServlet$WicketFilterCallback.intercept(PAXWicketServlet.java:150)[100:org.ops4j.pax.wicket.service:3.0.2]
at org.apache.wicket.protocol.http.WicketFilter$$EnhancerByCGLIB$$91ca4a1b.processRequestCycle(<generated>)[92:org.apache.wicket.core:6.7.0]
at org.apache.wicket.protocol.http.WicketFilter.processRequest(WicketFilter.java:201)[92:org.apache.wicket.core:6.7.0]
at org.apache.wicket.protocol.http.WicketFilter$$EnhancerByCGLIB$$91ca4a1b.CGLIB$processRequest$12(<generated>)[92:org.apache.wicket.core:6.7.0]
at org.apache.wicket.protocol.http.WicketFilter$$EnhancerByCGLIB$$91ca4a1b$$FastClassByCGLIB$$36c566fa.invoke(<generated>)[92:org.apache.wicket.core:6.7.0]
at net.sf.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:228)[99:org.apache.servicemix.bundles.cglib:2.2.2.1]
at org.ops4j.pax.wicket.internal.servlet.PAXWicketServlet$WicketFilterCallback.intercept(PAXWicketServlet.java:150)[100:org.ops4j.pax.wicket.service:3.0.2]
at org.apache.wicket.protocol.http.WicketFilter$$EnhancerByCGLIB$$91ca4a1b.processRequest(<generated>)[92:org.apache.wicket.core:6.7.0]
at org.apache.wicket.protocol.http.WicketFilter.doFilter(WicketFilter.java:282)[92:org.apache.wicket.core:6.7.0]
at org.apache.wicket.protocol.http.WicketFilter$$EnhancerByCGLIB$$91ca4a1b.CGLIB$doFilter$10(<generated>)[92:org.apache.wicket.core:6.7.0]
at org.apache.wicket.protocol.http.WicketFilter$$EnhancerByCGLIB$$91ca4a1b$$FastClassByCGLIB$$36c566fa.invoke(<generated>)[92:org.apache.wicket.core:6.7.0]
at net.sf.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:228)[99:org.apache.servicemix.bundles.cglib:2.2.2.1]
at org.ops4j.pax.wicket.internal.servlet.PAXWicketServlet$WicketFilterCallback.intercept(PAXWicketServlet.java:150)[100:org.ops4j.pax.wicket.service:3.0.2]
at org.apache.wicket.protocol.http.WicketFilter$$EnhancerByCGLIB$$91ca4a1b.doFilter(<generated>)[92:org.apache.wicket.core:6.7.0]
at org.ops4j.pax.wicket.internal.servlet.PAXWicketServlet.service(PAXWicketServlet.java:98)[100:org.ops4j.pax.wicket.service:3.0.2]
at org.ops4j.pax.wicket.internal.filter.PAXWicketFilterChain.doFilter(PAXWicketFilterChain.java:61)[100:org.ops4j.pax.wicket.service:3.0.2]
at org.ops4j.pax.wicket.internal.filter.FilterDelegator.doFilter(FilterDelegator.java:82)[100:org.ops4j.pax.wicket.service:3.0.2]
at org.ops4j.pax.wicket.internal.servlet.ServletCallInterceptor.service(ServletCallInterceptor.java:168)[100:org.ops4j.pax.wicket.service:3.0.2]
at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:684)[71:org.eclipse.jetty.aggregate.jetty-all-server:8.1.15.v20140411]
at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:503)[71:org.eclipse.jetty.aggregate.jetty-all-server:8.1.15.v20140411]
at org.ops4j.pax.web.service.jetty.internal.HttpServiceServletHandler.doHandle(HttpServiceServletHandler.java:69)[80:org.ops4j.pax.web.pax-web-jetty:3.1.2]
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:137)[71:org.eclipse.jetty.aggregate.jetty-all-server:8.1.15.v20140411]
at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:557)[71:org.eclipse.jetty.aggregate.jetty-all-server:8.1.15.v20140411]
at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:231)[71:org.eclipse.jetty.aggregate.jetty-all-server:8.1.15.v20140411]
at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1086)[71:org.eclipse.jetty.aggregate.jetty-all-server:8.1.15.v20140411]
at org.ops4j.pax.web.service.jetty.internal.HttpServiceContext.doHandle(HttpServiceContext.java:240)[80:org.ops4j.pax.web.pax-web-jetty:3.1.2]
at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:429)[71:org.eclipse.jetty.aggregate.jetty-all-server:8.1.15.v20140411]
at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:193)[71:org.eclipse.jetty.aggregate.jetty-all-server:8.1.15.v20140411]
at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1020)[71:org.eclipse.jetty.aggregate.jetty-all-server:8.1.15.v20140411]
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:135)[71:org.eclipse.jetty.aggregate.jetty-all-server:8.1.15.v20140411]
at org.ops4j.pax.web.service.jetty.internal.JettyServerHandlerCollection.handle(JettyServerHandlerCollection.java:77)[80:org.ops4j.pax.web.pax-web-jetty:3.1.2]
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:116)[71:org.eclipse.jetty.aggregate.jetty-all-server:8.1.15.v20140411]
at org.eclipse.jetty.server.Server.handle(Server.java:370)[71:org.eclipse.jetty.aggregate.jetty-all-server:8.1.15.v20140411]
at org.eclipse.jetty.server.AbstractHttpConnection.handleRequest(AbstractHttpConnection.java:494)[71:org.eclipse.jetty.aggregate.jetty-all-server:8.1.15.v20140411]
at org.eclipse.jetty.server.AbstractHttpConnection.headerComplete(AbstractHttpConnection.java:971)[71:org.eclipse.jetty.aggregate.jetty-all-server:8.1.15.v20140411]
at org.eclipse.jetty.server.AbstractHttpConnection$RequestHandler.headerComplete(AbstractHttpConnection.java:1033)[71:org.eclipse.jetty.aggregate.jetty-all-server:8.1.15.v20140411]
at org.eclipse.jetty.http.HttpParser.parseNext(HttpParser.java:644)[71:org.eclipse.jetty.aggregate.jetty-all-server:8.1.15.v20140411]
at org.eclipse.jetty.http.HttpParser.parseAvailable(HttpParser.java:235)[71:org.eclipse.jetty.aggregate.jetty-all-server:8.1.15.v20140411]
at org.eclipse.jetty.server.AsyncHttpConnection.handle(AsyncHttpConnection.java:82)[71:org.eclipse.jetty.aggregate.jetty-all-server:8.1.15.v20140411]
at org.eclipse.jetty.io.nio.SelectChannelEndPoint.handle(SelectChannelEndPoint.java:696)[71:org.eclipse.jetty.aggregate.jetty-all-server:8.1.15.v20140411]
at org.eclipse.jetty.io.nio.SelectChannelEndPoint$1.run(SelectChannelEndPoint.java:53)[71:org.eclipse.jetty.aggregate.jetty-all-server:8.1.15.v20140411]
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:608)[71:org.eclipse.jetty.aggregate.jetty-all-server:8.1.15.v20140411]
at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:543)[71:org.eclipse.jetty.aggregate.jetty-all-server:8.1.15.v20140411]
at java.lang.Thread.run(Thread.java:745)[:1.8.0_20]
Caused by: java.lang.reflect.InvocationTargetException
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)[:1.8.0_20]
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)[:1.8.0_20]
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)[:1.8.0_20]
at java.lang.reflect.Constructor.newInstance(Constructor.java:408)[:1.8.0_20]
at org.apache.wicket.session.DefaultPageFactory.newPage(DefaultPageFactory.java:174)[92:org.apache.wicket.core:6.7.0]
... 61 more
Caused by: java.lang.IncompatibleClassChangeError: Found interface bikeshop.domain.repository.BikeRepository, but class was expected
at Proxy04d92f46_988d_4726_9355_6b6381790fde.nextIdentity(Unknown Source)
at bikeshop.application.service.BikeApplicationService.loadGarage(BikeApplicationService.java:22)
at Proxyc25af47a_a344_4a1b_8d0e_429a76d453c6.loadGarage(Unknown Source)
at Proxy163e0a74_12bc_4124_827b_2119133222e8.loadGarage(Unknown Source)
at bikeshop.presentation.internal.GaragePresentationService.init(GaragePresentationService.java:21)
at Proxy5a3bd46a_6830_438c_b5eb_0ca9ec091479.init(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)[:1.8.0_20]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)[:1.8.0_20]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)[:1.8.0_20]
at java.lang.reflect.Method.invoke(Method.java:483)[:1.8.0_20]
at org.ops4j.pax.wicket.util.proxy.LazyInitProxyFactory$JdkHandler.invoke(LazyInitProxyFactory.java:253)
at org.ops4j.pax.wicket.util.proxy.$Proxy22.init(Unknown Source)
at bikeshop.http.wicket.page.GaragePage.<init>(GaragePage.java:30)
The culprit here is probably Blueprint, which generates a proxy class for every imported service, rather than giving you the service object directly. I don't believe that Aries Blueprint has been updated for Java 8 compatibility.
The solution would be to avoid Blueprint and use something like Declarative Services (DS), which is much closer to "real" OSGi Services and gives your consumer the actual service instance. DS definitely works with Java 8 interfaces having default methods.
Update:
This issue seems to be fixed in the proxy-impl 1.1.4 of Aries / Karaf 4.2.3
KARAF-6087
ARIES-1849

Spring Data Neo4j - Cross store persistence

I am new to SDN, I am trying to do a cross store persistence with hibernate. The tutorial given in website has examples for the same, I have checked the github ones too. I have two questions
I am unable to do xml configuration as mentioned in the docs or examples. <neo4j:config/> doesn't support entityManagerFactory. My assumption is it creates the default Neo4jConfiguration which doesn't have a setter for entityManagerFactory. The workaround i have found is to define a CrossStoreNeo4jConfiguration bean.
#Bean
public CrossStoreNeo4jConfiguration crossStoreNeo4jConfiguration(){
CrossStoreNeo4jConfiguration configuration = new CrossStoreNeo4jConfiguration();
configuration.setEntityManagerFactory(entityManagerFactory);
configuration.setGraphDatabaseService(graphDatabaseService);
return configuration;
}
How to do this inside<neo4j:config/>
What happens when you refer a Neo4jTemplate to your repository using neo4j-template-ref when you define repositories using neo4j:repositories? what is the purpose?
UDPATE
The reason it was unable to create CrossStoreNeo4jConfiguration with <neo4j:config/> was , i was missing the dependency spring-data-neo4j-cross-store`. But now i get exception on application start up.
Caused by: java.lang.IllegalStateException: Singleton 'nodeEntityStateFactory' isn't currently in creation
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.afterSingletonCreation(DefaultSingletonBeanRegistry.java:312)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:239)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:291)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)
at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:292)
at org.springframework.data.neo4j.cross_store.config.CrossStoreNeo4jConfiguration$$EnhancerByCGLIB$$779c5955.nodeEntityStateFactory(<generated>)
at org.springframework.data.neo4j.config.Neo4jConfiguration.mappingContext(Neo4jConfiguration.java:199)
at org.springframework.data.neo4j.cross_store.config.CrossStoreNeo4jConfiguration$$EnhancerByCGLIB$$779c5955.CGLIB$mappingContext$11(<generated>)
at org.springframework.data.neo4j.cross_store.config.CrossStoreNeo4jConfiguration$$EnhancerByCGLIB$$779c5955$$FastClassByCGLIB$$3134c8a8.invoke(<generated>)
at net.sf.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:228)
at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:280)
at org.springframework.data.neo4j.cross_store.config.CrossStoreNeo4jConfiguration$$EnhancerByCGLIB$$779c5955.mappingContext(<generated>)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:149)
Thanks in advance.
This should work:
<neo4j:config entityManagerFactory="entityManagerFactory"/>
No need to create your custom implementation.
The template passed to the repository config is the one used by its infrastructure. In most cases there is no need to configure something different.

Resources