batch admin console - DispatcherServlet using InternalResourceViewResolver instead of FreeMarkerViewResolver
Asked Answered
P

1

1

I have an issue with integrating the spring batch admin console into my application.

The good news is that when i go to http://mymachine.com:8080/ReportingManager/batch/configuration I can get to the admin console.

But when I go to http://mymachine.com:8080/ReportingManager/batch/job-configuration i get a 404 and an error saying that /batch/jobs can't be found.

I've just gone through the exercise of comparing the difference in output of org.springframework.web logs between my application logs and the spring-batch-admin-sample application which I know is working.

After looking at the logs it looks like the URL mappings can be found for the spring batch admin console but the DispatcherServlet is trying to use InternalResourceViewResolver instead of the FreeMarkerViewResolver

My application logs below show the wrong ViewResolver is being used for /ReportingManager/batch/jobs...

    2014-05-27 20:16:22,770 DEBUG [DispatcherServlet] - DispatcherServlet with name 'Batch Servlet' processing GET request for [/ReportingManager/batch/jobs]
    2014-05-27 20:16:22,770 DEBUG [RequestMappingHandlerMapping] - Looking up handler method for path /jobs
    2014-05-27 20:16:22,770 DEBUG [RequestMappingHandlerMapping] - Returning handler method [public void org.springframework.batch.admin.web.JobController.jobs(org.springframework.ui.ModelMap,int,int)]
    2014-05-27 20:16:22,770 DEBUG [DispatcherServlet] - Last-Modified value for [/ReportingManager/batch/jobs] is: -1
    2014-05-27 20:16:23,598 DEBUG [DispatcherServlet] - Rendering view [org.springframework.web.servlet.view.JstlView: name 'jobs'; URL [/WEB-INF/pages/jobs.jsp]] in DispatcherServlet with name 'Batch Servlet'
    2014-05-27 20:16:23,598 DEBUG [JstlView] - Added model object 'endJob' of type [java.lang.Integer] to request in view with name 'jobs'
    2014-05-27 20:16:23,598 DEBUG [JstlView] - Added model object 'jobs' of type [java.util.ArrayList] to request in view with name 'jobs'
    2014-05-27 20:16:23,598 DEBUG [JstlView] - Added model object 'startJob' of type [java.lang.Integer] to request in view with name 'jobs'
    2014-05-27 20:16:23,598 DEBUG [JstlView] - Added model object 'totalJobs' of type [java.lang.Integer] to request in view with name 'jobs'
    2014-05-27 20:16:23,598 DEBUG [JstlView] - Added model object 'jobName' of type [java.lang.String] to request in view with name 'jobs'
    2014-05-27 20:16:23,598 DEBUG [JstlView] - Forwarding to resource [/WEB-INF/pages/jobs.jsp] in InternalResourceView 'jobs'
    2014-05-27 20:16:23,598 DEBUG [DispatcherServlet] - Successfully completed request

Whereas when I look at the longs for the spring-batch-admin-sample I can see that /spring_admin_console/jobs is using AjaxFreeMarkerView...

[5/27/14 19:57:13:962 EST] 00000023 SystemOut     O 19:57:13,950 DEBUG WebContainer : 0 servlet.DispatcherServlet:693 - DispatcherServlet with name 'Batch Servlet' processing GET request for [/s
pring_admin_console/jobs]
[5/27/14 19:57:13:978 EST] 00000023 SystemOut     O 19:57:13,965 DEBUG WebContainer : 0 annotation.DefaultAnnotationHandlerMapping:221 - Mapping [/jobs] to HandlerExecutionChain with handler [or
g.springframework.batch.admin.web.JobController@52e052e0] and 3 interceptors
[5/27/14 19:57:14:000 EST] 00000023 SystemOut     O 19:57:13,988 DEBUG WebContainer : 0 servlet.DispatcherServlet:769 - Last-Modified value for [/spring_admin_console/jobs] is: -1
[5/27/14 19:57:14:045 EST] 00000023 SystemOut     O 19:57:14,031 DEBUG WebContainer : 0 support.HandlerMethodInvoker:155 - Invoking model attribute method: public java.lang.String org.spring
framework.batch.admin.web.JobController.getJobName(javax.servlet.http.HttpServletRequest)
[5/27/14 19:57:14:091 EST] 00000023 SystemOut     O 19:57:14,078 DEBUG WebContainer : 0 support.HandlerMethodInvoker:173 - Invoking request handler method: public void org.springframework.batch.admin.web.JobController.jobs(org.springframework.ui.ModelMap,int,int)
[5/27/14 19:57:14:125 EST] 00000023 SystemOut     O 19:57:14,113 DEBUG WebContainer : 0 servlet.DispatcherServlet:1045 - Rendering view org.springframework.batch.admin.web.freemarker.AjaxFreeMarkerView: name 'jobs'; URL [/layouts/html/standard.ftl]] in DispatcherServlet with name 'Batch Servlet'
[5/27/14 19:57:14:144 EST] 00000023 SystemOut     O 19:57:14,130 DEBUG WebContainer : 0 freemarker.AjaxFreeMarkerView:328 - Added model object 'springMacroRequestContext' of type [org.springframework.web.servlet.support.RequestContext] to request in view with name 'jobs'
[5/27/14 19:57:14:158 EST] 00000023 SystemOut     O 19:57:14,144 DEBUG WebContainer : 0 freemarker.AjaxFreeMarkerView:328 - Added model object 'startJob' of type [java.lang.Integer] to request i
n view with name 'jobs'
[5/27/14 19:57:14:172 EST] 00000023 SystemOut     O 19:57:14,159 DEBUG WebContainer : 0 freemarker.AjaxFreeMarkerView:328 - Added model object 'totalJobs' of type [java.lang.Integer] to request
in view with name 'jobs'
[5/27/14 19:57:14:186 EST] 00000023 SystemOut     O 19:57:14,172 DEBUG WebContainer : 0 freemarker.AjaxFreeMarkerView:328 - Added model object 'servletPath' of type [java.lang.String] to request
 in view with name 'jobs'
[5/27/14 19:57:14:200 EST] 00000023 SystemOut     O 19:57:14,186 DEBUG WebContainer : 0 freemarker.AjaxFreeMarkerView:328 - Added model object 'jobName' of type [java.lang.String] to request in
view with name 'jobs'
[5/27/14 19:57:14:214 EST] 00000023 SystemOut     O 19:57:14,200 DEBUG WebContainer : 0 freemarker.AjaxFreeMarkerView:328 - Added model object 'jobs' of type [java.util.ArrayList] to request in
view with name 'jobs'
[5/27/14 19:57:14:228 EST] 00000023 SystemOut     O 19:57:14,214 DEBUG WebContainer : 0 freemarker.AjaxFreeMarkerView:328 - Added model object 'titleText' of type [java.lang.String] to request i
n view with name 'jobs'
[5/27/14 19:57:14:242 EST] 00000023 SystemOut     O 19:57:14,228 DEBUG WebContainer : 0 freemarker.AjaxFreeMarkerView:328 - Added model object 'titleCode' of type [java.lang.String] to request i
n view with name 'jobs'
[5/27/14 19:57:14:255 EST] 00000023 SystemOut     O 19:57:14,242 DEBUG WebContainer : 0 freemarker.AjaxFreeMarkerView:328 - Added model object 'endJob' of type [java.lang.Integer] to request in
view with name 'jobs'
[5/27/14 19:57:14:269 EST] 00000023 SystemOut     O 19:57:14,256 DEBUG WebContainer : 0 freemarker.AjaxFreeMarkerView:328 - Added model object 'body' of type [java.lang.String] to request in vie
w with name 'jobs'
[5/27/14 19:57:14:287 EST] 00000023 SystemOut     O 19:57:14,274 DEBUG WebContainer : 0 freemarker.AjaxFreeMarkerView:279 - Rendering FreeMarker template [/layouts/html/standard.ftl] in FreeMark
erView 'jobs'
[5/27/14 19:57:14:909 EST] 00000023 SystemOut     O 19:57:14,895 DEBUG WebContainer : 0 servlet.DispatcherServlet:674 - Successfully completed request

I've spent a while trying to find out what is happening and am not sure. I suspect maybe I am doing something wrong in my web.xml. Maybe relating to the order of the servlets.

I am going to post an excerpt from my web.xml in the hopes that someone will see something I am doing wrong.

Thanks in advance for having a look at this for me.

I've put my web.xml here.

http://pastebin.com/eBkHMe8g

Purcell answered 27/5, 2014 at 2:56 Comment(0)
M
2

In your web project make sure you have this folder structure: WEB-INF\classes\META-INF\spring\batch\override. And under this folder create a new .xml file. Name it whatever name you want. The content of the file should be something like this:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="resourceService" class="org.springframework.batch.admin.web.resources.DefaultResourceService">
        <property name="servletPath" value="/batch" />
    </bean>
</beans>

The value for the servletPath needs to match your servlet-mapping in your web.xml. I used /batch because this is what you have in yours.

More about this here. Also, it does help to have a look at the Spring Batch Admin source code. In that resources-context.xml you can see that a certain SPeL expression is used for various servletPath resources: <prop key="servletPath">#{resourceService.servletPath}</prop>. You need to search for the bean called resourceService, have a look at its source code and from there you can establish what property to change for DefaultResourceService in your custom .xml file.

LATER EDIT: As a general suggestion, your mvc-dispatcher DispatcherServlet is picking up automatically and by default the file located at /WEB-INF/mvc-dispatcher-servlet.xml. You'll have the beans under mvc-dispatcher-servlet.xml being picked up and loaded twice in two different app contexts because you have this file specified as one of the contextConfigLocation values. There is a hierarchy of contexts there, root one (defined by contextConfigLocation) being the parent. The idea is to place beans that are non-web (or that are to be used by web) in the root context and the web to be able to "use" these beans. Other way around doesn't quite make sense, because a DAO or Service class doesn't need access to web.

Metal answered 27/5, 2014 at 9:15 Comment(20)
Hi thanks for your help. Really struggling with this one. I have already has what you have suggested in place exactly how you had it and was getting the results received above. I've just gone through comparing the debug output from the sample batch admin project and my own. They are different. I will post above because it might help.Purcell
Also I tried to take your suggestion and put a breakpoint on DefaultResourceService to try and see what is happening but unfortunately the debugger doesn't stop on that class for some reason.Purcell
For my test I used Spring Batch Admin 1.2.1 built locally. In my webapp I placed under WEB-INF/lib spring-batch-admin-manager-1.2.1.RELEASE.jar, spring-batch-admin-resources-1.2.1.RELEASE.jar and all dependent jars (Spring Batch, Integration, commons and few more). In web.xml I, also, added shallowEtagHeaderFilter and hiddenHttpMethodFilter and its mappings for the same /batch/*. Under WEB-INF\classes I, also, have the initialization properties files from the sample admin (batch-default.properties, batch-hsql.properties, business-schema-hsqldb.sql and log4j config).Metal
Can I ask you what you have set for batch.remote.base.url?Purcell
Haven't touched it: batch.remote.base.url=http://localhost:8080/spring-batch-admin-sampleMetal
I've got 2 servlets defined in my web.xml. The first servlet uses InternalResourceViewResolver which looks for views in /WEB-INF/pages/. From the logs above it looks as if it might be using this viewresolver instead of the FreeMarkerViewResolver which is defined in spring-batch-admin-resources/src/main/resources/META-INF/spring/batch/servlet/resources/resources-context.xml. Maybe resources-context.xml is not being loaded in. Do you have any hinches why?Purcell
I'm going to take a break from this. I've spent a while on it unsuccessfully trying to fix. If you don't mind could you double check my web.xml for me? I will post a better extract of it. Thanks again for your helpPurcell
Enable debug logging and use bastebin.com to provide a complete log from the start of your app server until you test the failing url.Metal
thanks. I've only put org.springframework.web logs at pastebin.com/kh7z0VMGPurcell
The internalViewResolver is defined in mvc-dispatcher-servlet.xml which you can see is defined in the contextConfigLocation in my web.xml. Because of the location in web.xml where I have specified mvc-dispatcher-servlet.xml could it be possible the InternalViewResolver is taking precedence over the FreeMarkerViewResolver?Purcell
I was expecting to see a DEBUG globally enabled, not just org.springframework.web package.Metal
Sorry about that. I was being stingy and not buying a pro account and was limited by a char limit. I'm now a paying customer of pastebin and have modified the same pastebin link above to have org.springframework.security, org.springframework.web, org.springframework.core, org.springframework.beans, org.springframework.context.Purcell
Two things: I'm not seeing in your logs messages that show instances of certain beans are created. For example: DefaultListableBeanFactory - Finished creating instance of bean 'org.springframework.batch.admin.web.HomeMenu#0' or DefaultListableBeanFactory - Finished creating instance of bean 'org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver#7f6bc966'. These are missing.Metal
Secondly, I wondered this since you created this on SO: why do you have contextConfigLocation set to /WEB-INF/appServlet-servlet.xml for the root container when, by default, your appServlet will pick up automatically the file located at /WEB-INF/appServlet-servlet.xml.Metal
In previous comment I meant mvc-dispatcher DispatcherServlet picking up automatically and by default the file located at /WEB-INF/mvc-dispatcher-servlet.xml. So, if I'm not mistaken you'll have the beans under mvc-dispatcher-servlet.xml being picked up and loaded twice in two different app contexts.Metal
Thanks a lot for you previous 3 comments. It has forced me to go back and re-visit the way I was registering my beans. I have since gained a newfound understanding that there is a root application context and a child application context (web application context). The beans in the child context can see the beans in the parent context but not the other way around. It's forced me try and make some changes. i.e. to remove explicit declaration of the mvc-dispatcher-servlet.xml.Purcell
This has left me with a lot of re-work. I'm hoping I will be finished sometime tomorrow night with the re-work I think and hoping it fixes the problems with the spring batch admin console. Could you keep an eye on this discussion please. I will let you know how it goes as soon as I'm done with the re-work. Thanks. I'm so glad you made these points to me.Purcell
Exactly. There is a hierarchy of contexts there. The idea is to place beans that are non-web (or that are to be used by web) in the root context and the web to be able to "use" these beans. Other way around doesn't quite make sense, because a DAO or Service class doesn't need access to web.Metal
I have great news. After doing all the re-work I spoke about spring batch admin console works!! Thanks for your help. It cleared up my understanding of the things we discussed.Purcell
Great :-), glad to be of help. I have updated my answer with the suggestion I made in one of the last comments that made you re-work your configuration and lead you to fixing the problem and make Spring Batch Admin work.Metal

© 2022 - 2024 — McMap. All rights reserved.