At our project we experience, that our default Hibernate session seems to be lost, when adding another existing war file, to the embedded tomcat container in Grails/Spring boot.
As soon as we comment the statement, to add the war file, everything works as expected. When we deploy the application to production, this problem is not existing, anyway the war file we try to add at development, also starts up at production.
We are using Grails 3.3.1, that's build up upon Spring boot, and add the existing war file to the emnbedded tomcat this way, through the Applications.groovy file.
class Application extends GrailsAutoConfiguration implements EnvironmentAware {
static void main(String[] args) {
GrailsApp.run(Application, args)
}
@Bean
EmbeddedServletContainerFactory servletContainerFactory() {
return new TomcatEmbeddedServletContainerFactory() {
@Override
protected TomcatEmbeddedServletContainer getTomcatEmbeddedServletContainer(Tomcat tomcat) {
try {
// Ensure that the folder exists
tomcat.getHost().getAppBaseFile().mkdir()
String projektrod = System.getProperty('user.dir')
// Add external Orbeon war file
Context context = tomcat.addWebapp("/blanketdesigner/orbeon", "${projektrod}\\..\\blanket-orbeon-plugin\\orbeon\\orbeon.war")
context.setParentClassLoader(getClass().getClassLoader())
} catch (ServletException ex) {
throw new IllegalStateException("Failed to add webapp", ex)
}
return super.getTomcatEmbeddedServletContainer(tomcat)
}
}
}
When the above is set, both the application, and the external war file is starting up, and works as expected, but we have to call .withTransaction, .withNewTransaction, .withNewSession or something like that on domain objects.
This is also happening for services, that is annotated with @Transactional. If we are not doing this, we experience the following exception:
No Session found for current thread. Stacktrace follows:
java.lang.reflect.InvocationTargetException: null
at org.grails.core.DefaultGrailsControllerClass$ReflectionInvoker.invoke(DefaultGrailsControllerClass.java:211)
at org.grails.core.DefaultGrailsControllerClass.invoke(DefaultGrailsControllerClass.java:188)
at org.grails.web.mapping.mvc.UrlMappingsInfoHandlerAdapter.handle(UrlMappingsInfoHandlerAdapter.groovy:90)
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 org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)
at org.springframework.boot.web.filter.ApplicationContextHeaderFilter.doFilterInternal(ApplicationContextHeaderFilter.java:55)
at org.grails.web.servlet.mvc.GrailsWebRequestFilter.doFilterInternal(GrailsWebRequestFilter.java:77)
at org.grails.web.filters.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:67)
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: org.hibernate.HibernateException: No Session found for current thread
at org.grails.orm.hibernate.GrailsSessionContext.currentSession(GrailsSessionContext.java:117)
at org.hibernate.internal.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:688)
at org.grails.orm.hibernate.HibernateSession.createQuery(HibernateSession.java:177)
at org.grails.orm.hibernate.HibernateSession.createQuery(HibernateSession.java:170)
at org.grails.datastore.gorm.finders.FindAllByFinder.buildQuery(FindAllByFinder.java:63)
And if we remove the line that adds the war file
tomcat.addWebapp("....")
Everything works as expected, and we can work with domain objects without have to call .with...
As mentioned earlier, this problem seems to be a problem with the embedded tomcat server, and the function to add a war file, on beside.
We do not want to call .with... all over the code, as these is not the right solution.
Why we have to add the war file to the embedded tomcat at development, is because our main application depends on the other war for all function to work. On the production server it is running as a separate web-app too.
We can live with a fix to attach a default hibernate session when environment is development, but I cant figure out how to do this.
Thinking of something like this
if(grails.util.Environment.current == grails.util.Environment.DEVELOPMENT) {
// Then bind new default session to current thread
}
It should be easy to reproduce.
Will appreciate any help or suggestion
Thanks