I'm trying to set up Spring Web Flow using only Java annotations in a Spring environment that also uses only Java annotations. However when I attempt to access my flow I get the following exception
SEVERE: Servlet.service() for servlet [dispatcher] in context with path [/forms] threw exception [Request processing failed; nested exception is org.springframework.webflow.execution.FlowExecutionException: Exception thrown in state 'referral' of flow 'test-flow'] with root cause
java.lang.ClassCastException: org.springframework.context.support.GenericApplicationContext cannot be cast to org.springframework.web.context.WebApplicationContext
at org.springframework.web.servlet.support.RequestContext.initContext(RequestContext.java:235)
at org.springframework.web.servlet.support.RequestContext.<init>(RequestContext.java:202)
at org.springframework.web.servlet.view.AbstractView.createRequestContext(AbstractView.java:316)
at org.springframework.web.servlet.view.AbstractView.createMergedOutputModel(AbstractView.java:296)
at org.springframework.web.servlet.view.AbstractView.render(AbstractView.java:265)
at org.springframework.webflow.mvc.servlet.ServletMvcView.doRender(ServletMvcView.java:55)
at org.springframework.webflow.mvc.view.AbstractMvcView.render(AbstractMvcView.java:196)
at org.springframework.webflow.engine.ViewState.render(ViewState.java:293)
at org.springframework.webflow.engine.ViewState.refresh(ViewState.java:242)
at org.springframework.webflow.engine.ViewState.resume(ViewState.java:220)
at org.springframework.webflow.engine.Flow.resume(Flow.java:537)
at org.springframework.webflow.engine.impl.FlowExecutionImpl.resume(FlowExecutionImpl.java:259)
at org.springframework.webflow.executor.FlowExecutorImpl.resumeExecution(FlowExecutorImpl.java:169)
at org.springframework.webflow.mvc.servlet.FlowHandlerAdapter.handle(FlowHandlerAdapter.java:228)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:938)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:870)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:961)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:852)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:624)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:837)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:731)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:220)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:505)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:170)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:957)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:423)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1079)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:620)
at org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.doRun(AprEndpoint.java:2476)
at org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.run(AprEndpoint.java:2465)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:745)
I've traced the source of the error to the instantiation of a RequestContext object, which is passed to views in order for them to access the ApplicationContext (among other things). Since Spring is able to invoke my flows I'm lead to believe that this exception is being thrown due to a bad configuration somewhere in my Web Flow files. I've reviewed them many times and can't find anything that seems glaringly obvious. You can find my Web Flow configuration files below:
DispatcherConfig
#Configuration
#ComponentScan(basePackages = "----")
public class DispatcherConfig {
#Autowired
private FlowDefinitionRegistry flowDefinitionRegistry;
#Autowired
private FlowExecutor flowExecutor;
#Autowired
private AnnotationConfigWebApplicationContext appContext;
#Bean
public FlowHandlerAdapter flowHandlerAdapter()
{
FlowHandlerAdapter flowHandlerAdapter = new FlowHandlerAdapter();
flowHandlerAdapter.setFlowExecutor(flowExecutor);
return flowHandlerAdapter;
}
#Bean
public FlowHandlerMapping flowHandlerMapping()
{
FlowHandlerMapping mapping = new FlowHandlerMapping();
mapping.setFlowRegistry(flowDefinitionRegistry);
mapping.setApplicationContext(appContext);
mapping.setOrder(-1);
return mapping;
}
}
WebFlowConfig
#Configuration
public class WebFlowConfig extends AbstractFlowConfiguration {
#Autowired
private List<ViewResolver> viewResolvers;
#Autowired
private ConversionService conversionService;
#Autowired
private AnnotationConfigWebApplicationContext appContext;
#Bean
public FlowDefinitionRegistry flowRegistry()
{
return getFlowDefinitionRegistryBuilder()
.setBasePath("/WEB-INF/flows")
.addFlowLocationPattern("/**/*-flow.xml")
.setFlowBuilderServices(getFlowBuilderServices())
.build();
}
#Bean
public FlowExecutor flowExecutor()
{
return getFlowExecutorBuilder(flowRegistry()).build();
}
public ExpressionParser getExpressionParser()
{
SpelExpressionParser spelExpressionParser = new SpelExpressionParser();
return new WebFlowSpringELExpressionParser(spelExpressionParser);
}
public FlowBuilderServices getFlowBuilderServices()
{
MvcViewFactoryCreator creator = new MvcViewFactoryCreator();
creator.setViewResolvers(viewResolvers);
creator.setApplicationContext(appContext);
creator.setUseSpringBeanBinding(true);
FlowBuilderServices services = new FlowBuilderServices();
services.setViewFactoryCreator(creator);
services.setConversionService(conversionService);
services.setExpressionParser(getExpressionParser());
return services;
}
}
WebMvcConfig
#EnableWebMvc
#Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter {
#Bean
public UrlBasedViewResolver velocityViewResolver()
{
UrlBasedViewResolver resolver = new VelocityViewResolver();
resolver.setSuffix(".vm");
resolver.setViewClass(VelocityView.class);
return resolver;
}
#Bean
public VelocityConfigurer velocityConfig()
{
VelocityConfigurer velocityConfigurer = new VelocityConfigurer();
velocityConfigurer.setResourceLoaderPath("/templates/views/");
return velocityConfigurer;
}
#Bean
public List<ViewResolver> viewResolvers()
{
List<ViewResolver> resolvers = new ArrayList<>();
resolvers.add(velocityViewResolver());
return resolvers;
}
}
The view technology I'm using is Velocity. Spring Webflow version 2.4.1.RELEASE, Spring version 4.1.2.RELEASE, Java 1.8.0_45, Tomcat 7.0.62.
Any ideas what may be causing this exception?
UPDATE: Fixed
Thanks to Roman for providing the answer. I made my FlowBuilderServices and MvcViewFactoryCreator #Bean and this got rid of the ClassCastException. However, there were still some problems with my configuration. My #Autowired List<ViewResolver> viewResolvers was not being instantiated until after the MvcViewFactoryCreator was. Thus I had to make a method that creates the ViewResolver list for the MvcViewFactoryCreator. I'm looking into ways to get the order of creation correct, but for now this works. Below are the changes I had to make to get the Web Flow functioning properly
WebFlowConfig
#Configuration
public class WebFlowConfig extends AbstractFlowConfiguration {
#Autowired
===
-private List<ViewResolver> viewResolvers;
====
+private UrlBasedViewResolver viewResolver
===
...
#Autowired
===
-private AnnotationConfigWebApplicationContext appContext;
===
+private MvcViewFactoryCreator mvcViewFactoryCreator;
===
...
+public List<ViewResolver> getViewResolvers()
+{
+ List<ViewResolver> resolvers = new ArrayList<>();
+ resolvers.add(viewResolver);
+
+ return resolvers;
+}
...
+#Bean
+public MvcViewFactoryCreator mvcViewFactoryCreator()
+{
+ MvcViewFactoryCreator creator = new MvcViewFactoryCreator();
+ creator.setViewResolvers(getViewResolvers());
+ creator.setUseSpringBeanBinding(true);
+ return creator;
+}
#Bean
public FlowBuilderServices flowBuilderServices()
{
===
-MvcViewFactoryCreator creator = new MvcViewFactoryCreator();
-creator.setViewResolvers(viewResolvers);
-creator.setApplicationContext(appContext);
-creator.setUseSpringBeanBinding(true);
===
FlowBuilderServices services = new FlowBuilderServices();
===
-services.setViewFactoryCreator(creator);
===
+services.setViewFactoryCreator(mvcViewFactoryCreator);
===
services.setConversionService(conversionService);
services.setExpressionParser(getExpressionParser());
return services;
}
}
FlowBuilderServices is meant to be a Spring-managed bean, but in your config it is just a new instance. It likes to be ApplicationContextAware and InitializingBean, but that is gonna work only if managed by Spring.
The solution is simple: put #Bean on getFlowBuilderServices() method. And I think you should also make MvcViewFactoryCreator a separate #Bean and not use its setApplicationContext() manually.
Related
I'm developing a web app with Java and Spring MVC (and hibernate to link to a MySQL database). I tried numerous ways to get my application to upload files. Unfortunately, I've encountered an error that says my temporary upload location is not valid. As a workaround, I've tried several locations like
C:\Temp\
C:\temp\
C:/temp/
/WEB-INF/tmp
C:\Users\Default\AppData
etc
Here is the error I'm getting
org.springframework.web.multipart.MultipartException: Could not parse multipart servlet request; nested exception is java.io.IOException: The temporary upload location [C:\Users\take\eclipse\sts-bundle\pivotal-tc-server-developer-3.1.4.RELEASE\base-instance\work\Catalina\localhost\ToolManagementSystem\WEB-INF\tmp] is not valid
at org.springframework.web.multipart.support.StandardMultipartHttpServletRequest.parseRequest(StandardMultipartHttpServletRequest.java:99)
at org.springframework.web.multipart.support.StandardMultipartHttpServletRequest.<init>(StandardMultipartHttpServletRequest.java:77)
at org.springframework.web.multipart.support.StandardServletMultipartResolver.resolveMultipart(StandardServletMultipartResolver.java:76)
at org.springframework.web.servlet.DispatcherServlet.checkMultipart(DispatcherServlet.java:1073)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:912)
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.doPost(FrameworkServlet.java:868)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:648)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:842)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:292)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:212)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:141)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:616)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:522)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1095)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:672)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:279)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Unknown Source)
Caused by: java.io.IOException: The temporary upload location [C:\Users\take\eclipse\sts-bundle\pivotal-tc-server-developer-3.1.4.RELEASE\base-instance\work\Catalina\localhost\ToolManagementSystem\WEB-INF\tmp] is not valid
at org.apache.catalina.connector.Request.parseParts(Request.java:2751)
at org.apache.catalina.connector.Request.getParts(Request.java:2685)
at org.apache.catalina.connector.RequestFacade.getParts(RequestFacade.java:1083)
at org.springframework.web.multipart.support.StandardMultipartHttpServletRequest.parseRequest(StandardMultipartHttpServletRequest.java:84)
... 30 common frames omitted
And here are my initializer and the configuration:
public class Initializer implements WebApplicationInitializer {
private static final String LOCATION = "/WEB-INF/tmp";
private static final int MAX_FILE_SIZE = 2097152;
private static final int MAX_REQUEST_SIZE = 2097152;
private static final int FILE_SIZE_THRESHOLD = 0;
public void onStartup(ServletContext servletContext) throws ServletException {
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
ctx.register(MvcConfiguration.class);
servletContext.addListener(new ContextLoaderListener(ctx));
ctx.setServletContext(servletContext);
Dynamic servlet = servletContext.addServlet("dispatcher", new DispatcherServlet(ctx));
servlet.addMapping("/");
servlet.setLoadOnStartup(1);
servlet.setMultipartConfig(getMultipartConfigElement());
}
public MultipartConfigElement getMultipartConfigElement(){
MultipartConfigElement multipartConfigElement = new MultipartConfigElement(LOCATION, MAX_FILE_SIZE, MAX_REQUEST_SIZE, FILE_SIZE_THRESHOLD);
return multipartConfigElement;
}
}
#Configuration
#ComponentScan(basePackages = "...*")
#EnableWebMvc
#EnableTransactionManagement
#PropertySource("classpath:application.properties")
#PropertySource("classpath:views.properties")
public class MvcConfiguration extends WebMvcConfigurerAdapter {
private static final String PROPERTY_NAME_DATABASE_DRIVER = "db.driver";
private static final String PROPERTY_NAME_DATABASE_PASSWORD = "db.password";
private static final String PROPERTY_NAME_DATABASE_URL = "db.url";
private static final String PROPERTY_NAME_DATABASE_USERNAME = "db.username";
private static final String PROPERTY_NAME_HIBERNATE_DIALECT = "hibernate.dialect";
private static final String PROPERTY_NAME_HIBERNATE_SHOW_SQL = "hibernate.show_sql";
private static final String PROPERTY_NAME_ENTITYMANAGER_PACKAGES_TO_SCAN = "entitymanager.packages.to.scan";
private static final String PROPERTY_NAME_HIBERNATE_HBM2DDL_AUTO = "hibernate.hbm2ddl.auto";
#Resource
private Environment env;
#Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(env.getRequiredProperty(PROPERTY_NAME_DATABASE_DRIVER));
dataSource.setUrl(env.getRequiredProperty(PROPERTY_NAME_DATABASE_URL));
dataSource.setUsername(env.getRequiredProperty(PROPERTY_NAME_DATABASE_USERNAME));
dataSource.setPassword(env.getRequiredProperty(PROPERTY_NAME_DATABASE_PASSWORD));
return dataSource;
}
#Bean
public LocalSessionFactoryBean sessionFactory() {
LocalSessionFactoryBean sessionFactoryBean = new LocalSessionFactoryBean();
sessionFactoryBean.setDataSource(dataSource());
sessionFactoryBean.setPackagesToScan(env.getRequiredProperty(PROPERTY_NAME_ENTITYMANAGER_PACKAGES_TO_SCAN));
sessionFactoryBean.setHibernateProperties(hibProperties());
return sessionFactoryBean;
}
private Properties hibProperties() {
Properties properties = new Properties();
properties.put(PROPERTY_NAME_HIBERNATE_DIALECT, env.getRequiredProperty(PROPERTY_NAME_HIBERNATE_DIALECT));
properties.put(PROPERTY_NAME_HIBERNATE_SHOW_SQL, env.getRequiredProperty(PROPERTY_NAME_HIBERNATE_SHOW_SQL));
properties.put(PROPERTY_NAME_HIBERNATE_HBM2DDL_AUTO, env.getRequiredProperty(PROPERTY_NAME_HIBERNATE_HBM2DDL_AUTO));
return properties;
}
#Bean
public HibernateTransactionManager transactionManager() {
HibernateTransactionManager transactionManager = new HibernateTransactionManager();
transactionManager.setSessionFactory(sessionFactory().getObject());
return transactionManager;
}
#Bean(name="multipartResolver")
public StandardServletMultipartResolver resolver(){
return new StandardServletMultipartResolver();
}
#Bean
public ViewResolver getViewResolver1() {
ResourceBundleViewResolver resolver = new ResourceBundleViewResolver();
resolver.setOrder(1);
resolver.setBasename("views");
return resolver;
}
#Bean
public ViewResolver getViewResolver2() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setOrder(2);
resolver.setPrefix("/WEB-INF/jsp/");
resolver.setSuffix(".jsp");
return resolver;
}
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
}
* holds base package name
Create a directory /tmp under -
C:\Users\take\eclipse\sts-bundle\pivotal-tc-server-developer-3.1.4.RELEASE\base-instance\work\Catalina\localhost\ToolManagementSystem\WEB-INF
So you have a directory -
C:\Users\take\eclipse\sts-bundle\pivotal-tc-server-developer-3.1.4.RELEASE\base-instance\work\Catalina\localhost\ToolManagementSystem\WEB-INF\tmp
The other option is to change the temp directory through your tomcat configuration, or you can use spring boot which can configure this through an application property
Thanks
For one of our environment it was happen when external process clean up temporary directory. So we solved it just with restarting application.
I am creating a Spring social based login or my spring application with spring security.
My SecurityConfig.java looks like this:
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.formLogin()
.loginPage("/login")
.loginProcessingUrl("/login/authenticate")
.failureUrl("/login?error=bad_credentials")
.and()
.logout()
.deleteCookies("JSESSIONID")
.logoutUrl("/logout")
.logoutSuccessUrl("/login")
.and()
.authorizeRequests()
.antMatchers(
"/auth/**",
"/login",
"/signup/**",
"/user/register/**"
).permitAll()
.and()
.apply(new SpringSocialConfigurer()
.postLoginUrl("/")
.alwaysUsePostLoginUrl(true));
}
#Bean
public SocialUserDetailsService socialUsersDetailService() {
return new UserDetailServiceImpl(userDetailsService());
}
WebConfig.java:
#EnableWebMvc
#Configuration
#ComponentScan({ "com.spark.webcontroller" })
#Import({ SecurityConfig.class, SocialConfig.class })
#PropertySource("classpath:resources/application.properties")
public class WebConfig extends WebMvcConfigurerAdapter {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
registry.addResourceHandler("/static/**").addResourceLocations("/static/");
}
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
#Bean
public ServletContextTemplateResolver templateResolver() {
ServletContextTemplateResolver templateResolver = new ServletContextTemplateResolver();
templateResolver.setPrefix("/WEB-INF/view/html/");
templateResolver.setSuffix(".html");
templateResolver.setTemplateMode("HTML5");
templateResolver.setOrder(1);
return templateResolver;
}
#Bean
public SpringTemplateEngine templateEngine() {
SpringTemplateEngine templateEngine = new SpringTemplateEngine();
templateEngine.setTemplateResolver(templateResolver());
return templateEngine;
}
#Bean
public ThymeleafViewResolver viewResolver() {
ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
viewResolver.setTemplateEngine(templateEngine());
viewResolver.setOrder(1);
return viewResolver;
}
And finally my WebInitilizar.java
public class WebInitilizer extends
AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class[] { RootConfig.class };
}
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class[] { WebConfig.class };
}
#Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
RootConfig.java is only for adding service classes.
When I am running this app on Tomcat8 I am getting
org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'springSecurityFilterChain' is defined
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:687)
at org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:1168)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:281)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:962)
at org.springframework.web.filter.DelegatingFilterProxy.initDelegate(DelegatingFilterProxy.java:324)
at org.springframework.web.filter.DelegatingFilterProxy.initFilterBean(DelegatingFilterProxy.java:235)
at org.springframework.web.filter.GenericFilterBean.init(GenericFilterBean.java:199)
at org.apache.catalina.core.ApplicationFilterConfig.initFilter(ApplicationFilterConfig.java:279)
at org.apache.catalina.core.ApplicationFilterConfig.(ApplicationFilterConfig.java:109)
at org.apache.catalina.core.StandardContext.filterStart(StandardContext.java:4615)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5222)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1409)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1399)
at java.util.concurrent.FutureTask.run(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
Any help on this will be appreciated
I really need your help to solve this problem... I'm working with Spring-MVC 4.1.6.RELEASE, Spring-Security 4.0.0.RELEASE
I'm having this ERROR just... "sometimes" when I start the server. That's the real problem it just happens sometimes.
java.lang.IllegalStateException: No WebApplicationContext found: no ContextLoaderListener registered?
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:252)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:100)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:953)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1041)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:603)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:310)
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)
Then you will say, that's easy you just have to add a ContextLoaderListener but when I do, I get this:
java.lang.IllegalStateException: Cannot initialize context because there is already a root application context present - check whether you have multiple ContextLoader* definitions in your web.xml!
But it is not always... So I guess there is something wrong in the order that the context are being initialized but I don't know how to fix it...
These are my configuration classes:
WebInitializer.java
public class WebInitializer implements WebApplicationInitializer {
#Override
public void onStartup(ServletContext servletContext)
throws ServletException {
AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
rootContext.register(ServerApplicationConfig.class);
servletContext.addListener(new RequestContextListener());
servletContext.addListener(new ContextLoaderListener(rootContext));
FacesServlet facesServlet = new FacesServlet();
ServletRegistration.Dynamic facesServletDynamic = servletContext.addServlet("facesServlet", facesServlet);
facesServletDynamic.addMapping("*.jsf");
facesServletDynamic.setLoadOnStartup(1);
servletContext.addListener(ConfigureListener.class);
//Oauth2Filter
servletContext.addFilter("auth2ClientContextFilter", OAuth2ClientContextFilter.class);
}
}
ServerApplicationConfig.java
#EnableWebMvc
#Import({ WebSecurityConfig.class, HibernateConfig.class })
#ComponentScan(basePackages = { "com.agrichem.server" }, scopedProxy = ScopedProxyMode.TARGET_CLASS)
#Configuration
public class ServerApplicationConfig {
#Bean
public PropertyPlaceholderConfigurer getPropertyPlaceholderConfigurer() {
TimeZone.setDefault(TimeZone.getTimeZone("Etc/UTC"));
PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
ClassPathResource[] resources = new ClassPathResource[] {
new ClassPathResource("jdbc.properties"),
new ClassPathResource("oada-client.properties") };
ppc.setLocations(resources);
return ppc;
}
#Bean
#Qualifier("viewResolver")
public ViewResolver getViewResolver() {
UrlBasedViewResolver viewResolver = new UrlBasedViewResolver();
viewResolver.setViewClass(JsfView.class);
viewResolver.setPrefix("/views/");
viewResolver.setSuffix(".xhtml");
return viewResolver;
}
}
WebSecurityInitializer.java
#Configuration
#Order(1)
public class WebSecurityInitializer extends
AbstractSecurityWebApplicationInitializer {
}
WebSecurityConfig.java
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
#Qualifier("customUserDetailsService")
private UserDetailsService customUserDetailsService;
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth)
throws Exception {
auth.userDetailsService(customUserDetailsService);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
http.logout().logoutUrl("/logout.jsf").permitAll()
.logoutSuccessUrl("/home/login.jsf");
http.authorizeRequests()
.antMatchers("*.css", "*.js", "**.gif", "*.jpg", "*.jpeg",
"*.png", "*.css.jsf", "*.js.jsf", "**.gif.jsf",
"*.jpg.jsf", "*.jpeg.jsf", "*.png.jsf")
.permitAll()
.antMatchers("/**/*.css", "/**/*.js", "/**/*.gif", "/**/*.jpg",
"/**/*.jpeg", "/**/*.png", "/**/*.css.jsf",
"/**/*.js.jsf", "/**/*.gif.jsf", "/**/*.jpg.jsf",
"/**/*.jpeg.jsf", "/**/*.png.jsf")
.permitAll()
.antMatchers("/**/*.woff2", "/**/*.eot", "/**/*.woff",
"/**/*.ttf", "/**/*.svg", "*.woff2", "*.eot", "*.woff",
"*.ttf", "*.svg", "/**/*.woff2.jsf", "/**/*.eot.jsf", "/**/*.woff.jsf",
"/**/*.ttf.jsf", "/**/*.svg.jsf", "*.woff2.jsf", "*.eot.jsf", "*.woff.jsf",
"*.ttf.jsf", "*.svg.jsf")
.permitAll();
http.authorizeRequests().antMatchers("/admin/**.jsf").hasRole("ADMIN");
// http.authorizeRequests().antMatchers("/farms/**.jsf").hasAnyRole("HEAD_OFFICER");
http.authorizeRequests().antMatchers("/home/logout.jsf").permitAll()
.antMatchers("/rest/**").permitAll();
http.authorizeRequests().anyRequest().authenticated().and().formLogin()
.loginPage("/home/login.jsf").permitAll()
.failureUrl("/home/login.jsf?error=denied").permitAll()
.defaultSuccessUrl("/home/index.jsf", true);
}
}
Thanks for your help in advance.
I am in the proces of creating simple CRUD program with Spring data rest Spring data rest,
but I have a problem with security configuration (example was taken from here.
I have a WebAppInitializer:
public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class<?>[]{JpaRepositoryConfig.class, SecurityConfig.class};
}
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{CustRepositoryRestMvcConfiguration.class};
}
#Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
#Override
protected Filter[] getServletFilters() {
return new Filter[]{ new DelegatingFilterProxy("springSecurityFilterChain")};
}
}
I have a next crud repository:
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.data.rest.repository.annotation.RestResource;
import org.springframework.security.access.prepost.PreAuthorize;
#PreAuthorize("hasRole('ROLE_USER')")
#RestResource(path = "products", rel = "products")
public interface ProductRepository extends PagingAndSortingRepository<Product, Long> {
#PreAuthorize("hasRole('ROLE_ADMIN')")
#Override
Product save(Product s);
#PreAuthorize("hasRole('ROLE_ADMIN')")
#Override
void delete(Long aLong);
}
I have a next security configuration:
#Configuration
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("greg").password("turnquist").roles("USER").and()
.withUser("ollie").password("gierke").roles("USER", "ADMIN");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.httpBasic().and()
.authorizeRequests()
.antMatchers(HttpMethod.POST, "/products").hasRole("ADMIN")
.antMatchers(HttpMethod.PUT, "/products/**").hasRole("ADMIN")
.antMatchers(HttpMethod.PATCH, "/products/**").hasRole("ADMIN").and()
.csrf().disable();
}
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
I used next version of dependencies:
<java-version>1.7</java-version>
<spring-data-rest-version>1.0.0.RELEASE</spring-data-rest-version>
<spring.version>3.2.2.RELEASE</spring.version>
<org.slf4j-version>1.7.5</org.slf4j-version>
From project configured log4j I am getting these errors:
SEVERE: Error filterStart
org.apache.catalina.core.StandardContext startInternal
SEVERE: Context [/admin] startup failed due to previous errors
INFO : org.springframework.web.context.support.AnnotationConfigWebApplicationCon
text - Closing Root WebApplicationContext: startup date [Tue Dec 30 00:09:21 EET
2014]; root of context hierarchy
......
DEBUG: org.springframework.beans.factory.support.DisposableBeanAdapter - Invokin
g destroy() on bean with name 'org.springframework.security.config.annotation.au
thentication.configuration.AuthenticationConfiguration'
DEBUG: org.springframework.beans.factory.support.DefaultListableBeanFactory - Re
trieved dependent beans for bean '(inner bean)': [(inner bean), productRepositor
y]
DEBUG: org.springframework.beans.factory.support.DisposableBeanAdapter - Invokin
g destroy() on bean with name 'securityConfig'
From tomcat 7.0.56 localhost log I also have these errors in the logs:
SEVERE: Exception starting filter delegatingFilterProxy
org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'springSecurityFilterChain' is defined
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:568)
at org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:1102)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:278)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:198)
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1121)
at org.springframework.web.filter.DelegatingFilterProxy.initDelegate(DelegatingFilterProxy.java:326)
at org.springframework.web.filter.DelegatingFilterProxy.initFilterBean(DelegatingFilterProxy.java:236)
at org.springframework.web.filter.GenericFilterBean.init(GenericFilterBean.java:194)
at org.apache.catalina.core.ApplicationFilterConfig.initFilter(ApplicationFilterConfig.java:279)
at org.apache.catalina.core.ApplicationFilterConfig.<init>(ApplicationFilterConfig.java:109)
at org.apache.catalina.core.StandardContext.filterStart(StandardContext.java:4830)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5510)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:901)
at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:877)
at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:649)
at org.apache.catalina.startup.HostConfig.deployWAR(HostConfig.java:1083)
at org.apache.catalina.startup.HostConfig$DeployWar.run(HostConfig.java:1879)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)
at java.util.concurrent.FutureTask.run(FutureTask.java:262)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:745)
What is causing the errors in these logs?
According to the documentation spring batch admin is very easy to embed into the existing application. Simply copying web.xml and index.jsp then adding needed dependencies is enough getting it to work.
But if I want to use it in an existing spring boot project it getting worse. According to this example the configuration is a bit hacky but it works. UNTIL I try to use #EnableBatchProcessing annotation in my configuriton bean. Then I get the following exception.
Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'jobBuilders' defined in class path resource [org/springframework/batch/core/configuration/annotation/SimpleBatchConfiguration.class]: Instantiation of bean failed; nested exception is org.springframework.beans.factory.BeanDefinitionStoreException: Factory method [public org.springframework.batch.core.configuration.annotation.JobBuilderFactory org.springframework.batch.core.configuration.annotation.AbstractBatchConfiguration.jobBuilders() throws java.lang.Exception] threw exception; nested exception is java.lang.ClassCastException: org.springframework.batch.core.repository.support.JobRepositoryFactoryBean$$EnhancerBySpringCGLIB$$49fa0273 cannot be cast to org.springframework.batch.core.repository.JobRepository
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:597)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1095)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:990)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:504)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:475)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:302)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:228)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:298)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:706)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:762)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:482)
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:109)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:691)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:320)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:952)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:941)
at demo.Application.main(Application.java:35)
Caused by: org.springframework.beans.factory.BeanDefinitionStoreException: Factory method [public org.springframework.batch.core.configuration.annotation.JobBuilderFactory org.springframework.batch.core.configuration.annotation.AbstractBatchConfiguration.jobBuilders() throws java.lang.Exception] threw exception; nested exception is java.lang.ClassCastException: org.springframework.batch.core.repository.support.JobRepositoryFactoryBean$$EnhancerBySpringCGLIB$$49fa0273 cannot be cast to org.springframework.batch.core.repository.JobRepository
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:188)
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:586)
... 17 more
Caused by: java.lang.ClassCastException: org.springframework.batch.core.repository.support.JobRepositoryFactoryBean$$EnhancerBySpringCGLIB$$49fa0273 cannot be cast to org.springframework.batch.core.repository.JobRepository
at org.springframework.batch.core.configuration.annotation.SimpleBatchConfiguration$$EnhancerBySpringCGLIB$$b5c6eb04.jobRepository(<generated>)
at org.springframework.batch.core.configuration.annotation.AbstractBatchConfiguration.jobBuilders(AbstractBatchConfiguration.java:58)
at org.springframework.batch.core.configuration.annotation.SimpleBatchConfiguration$$EnhancerBySpringCGLIB$$b5c6eb04.CGLIB$jobBuilders$8(<generated>)
at org.springframework.batch.core.configuration.annotation.SimpleBatchConfiguration$$EnhancerBySpringCGLIB$$b5c6eb04$$FastClassBySpringCGLIB$$d88bd05f.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:228)
at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:312)
at org.springframework.batch.core.configuration.annotation.SimpleBatchConfiguration$$EnhancerBySpringCGLIB$$b5c6eb04.jobBuilders(<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:166)
... 18 more
My configuration is quite simple I have two configuration beans
#Configuration
#ImportResource({"classpath:/org/springframework/batch/admin/web/resources/servlet-config.xml",
"classpath:/org/springframework/batch/admin/web/resources/webapp-config.xml"})
public class BatchAdminConfiguration {
}
and
#Configuration
#EnableBatchProcessing
public class BatchImporterConfiguration {
}
When I remove #EnableBatchProcessing and try to create jobs with JobBuilderFactory and use #StepScope annotation I'm getting other ClassCastExceptions.
Now I'm using xml based configuration to create jobs, steps and other beans. It work well but I would actually preffer xml free configuration. Is there a way to easily integrate spring boot, spring batch and spring batch admin ?
Spring Batch Admin 2.0-BUILD-SNAPSHOT introduce a new Annoation #EnableBatchAdmin for easy to integrate with spring boot.
There is also a samples project https://github.com/spring-projects/spring-batch-admin-samples.
The short answer is that you won't want to use #EnableBatchProcessing with Spring Batch Admin. SBA provides a number of beans on a global scale that the #EnableBatchProcessing also provides. SBA 2.0 (currently in development) will probably fill the gaps between what is currently there and what #EnableBatchProcessing provides (specifically providing the JobBuilderFactory and StepBuilderFactory).
To get yourself running, you should be able to (I haven't tired this myself) configure in the META-INF/spring/batch/override/ directory a JobBuilderFactory and a StepBuilderFactory for global use. From there, you can use XML files in the META-INF/spring/batch/jobs directory that do nothing more than component scan for your #Configuration classes. However, leave off the #EnableBatchProcessing because of the duplication of beans.
For the record, this isn't an Spring Boot issue since #EnableBatchProcessing is a Spring Batch annotation, not a Boot one.
to complete the answer, here is the code to create the two beans once you disable the #EnableBatchProcessing annotation
#Autowired
JobRepository jobRepository;
#Autowired
PlatformTransactionManager transactionManager;
#Bean
public JobBuilderFactory jobBuilderFactory() {
return new JobBuilderFactory(jobRepository);
}
#Bean
public StepBuilderFactory stepBuilderFactory() {
return new StepBuilderFactory(jobRepository, transactionManager);
}
I've a working version here based on the same example (I forked the original one): https://github.com/vesperaba/spring-batch-admin-spring-boot.
I followed Michael Minella advice and I overwrote the SpringBatch property holder with a custom one.
I also added a job to check it's working now
This ClassCastException is caused by
classpath:/org/springframework/batch/admin/web/resources/servlet-config.xml
loading
META-INF/spring/batch/servlet/resources/resource-context.xml
which contains
<mvc:annotation-driven />
This conflicts with the mvc configuration in the Spring Java configuration class. The following class can be used to embed Spring Batch Admin within an existing application that uses Java configuration.
#Configuration
#EnableWebMvc
#ImportResource({"classpath*:/META-INF/spring/batch/bootstrap/**/*.xml"
, "classpath*:/META-INF/spring/batch/override/**/*.xml"
, "classpath*:/org/springframework/batch/admin/web/resources/webapp-config.xml"
, "classpath*:/META-INF/spring/batch/servlet/manager/**/*.xml"
, "classpath:base-menu-config.xml"
})
public class SpringBatchAdminConfig extends WebMvcConfigurerAdapter {
#Override
public void addResourceHandlers(final ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("classpath:/META-INF/");
}
#Bean
public SimpleControllerHandlerAdapter simpleControllerHandlerAdapter() {
return new SimpleControllerHandlerAdapter();
}
#Bean
public BeanNameUrlHandlerMapping beanNameUrlHandlerMapping() {
return new BeanNameUrlHandlerMapping();
}
#Bean
public BeanNameViewResolver beanNameViewResolver() {
return new BeanNameViewResolver();
}
#Bean(name = "defaultResources")
public PropertiesFactoryBean defaultResources() {
return new PropertiesFactoryBean();
}
#Bean(name = "jsonResources")
public PropertiesFactoryBean jsonResources() {
return new PropertiesFactoryBean();
}
#Bean
public HomeController homeController() throws IOException {
HomeController homeController = new HomeController();
homeController.setDefaultResources(defaultResources().getObject());
homeController.setJsonResources(jsonResources().getObject());
return homeController;
}
#Bean
public MenuManager menuManager() {
return new MenuManager();
}
#Bean(name = "freemarkerConfig")
public HippyFreeMarkerConfigurer hippyFreeMarkerConfigurer() {
HippyFreeMarkerConfigurer hippyFreeMarkerConfigurer = new HippyFreeMarkerConfigurer();
hippyFreeMarkerConfigurer.setTemplateLoaderPaths("/WEB-INF/web", "classpath:/org/springframework/batch/admin/web");
hippyFreeMarkerConfigurer.setPreferFileSystemAccess(false);
hippyFreeMarkerConfigurer.setFreemarkerVariables(Collections.singletonMap("menuManager", (Object) menuManager()));
Properties freemarkerSettings = new Properties();
freemarkerSettings.put("default_encoding", "UTF-8");
freemarkerSettings.put("output_encoding", "UTF-8");
hippyFreeMarkerConfigurer.setFreemarkerSettings(freemarkerSettings);
return hippyFreeMarkerConfigurer;
}
public AjaxFreeMarkerView parentLayout() {
AjaxFreeMarkerView ajaxFreeMarkerView = new AjaxFreeMarkerView();
FreeMarkerViewResolver freeMarkerViewResolver = new FreeMarkerViewResolver();
freeMarkerViewResolver.setExposeSpringMacroHelpers(false);
freeMarkerViewResolver.setAllowRequestOverride(true);
ajaxFreeMarkerView.setViewResolver(freeMarkerViewResolver);
Properties attributes = new Properties();
attributes.put("titleCode", "home.title");
attributes.put("titleText", "Spring Batch Admin");
ajaxFreeMarkerView.setAttributes(attributes);
return ajaxFreeMarkerView;
}
#Value("#{resourceService.servletPath}")
private String servletPath;
#Bean(name="standard")
public AjaxFreeMarkerView standard() {
AjaxFreeMarkerView standard = parentLayout();
standard.setUrl("/layouts/html/standard.ftl");
standard.setContentType("text/html;charset=UTF-8");
standard.getAttributesMap().put("body", "/layouts/html/home.ftl");
standard.getAttributesMap().put("servletPath", servletPath);
return standard;
}
#Bean(name="standard.rss")
public AjaxFreeMarkerView standardRss() {
AjaxFreeMarkerView standardRss = parentLayout();
standardRss.setUrl("/layouts/html/standard.ftl");
standardRss.setContentType("text/xml");
standardRss.getAttributesMap().put("body", "/layouts/rss/home.ftl");
standardRss.getAttributesMap().put("servletPath", servletPath);
return standardRss;
}
#Bean(name="standard.json")
public AjaxFreeMarkerView standardJson() {
AjaxFreeMarkerView standardJson = parentLayout();
standardJson.setUrl("/layouts/json/standard.ftl");
standardJson.setContentType("application/json");
standardJson.getAttributesMap().put("body", "/layouts/json/home.ftl");
standardJson.getAttributesMap().put("servletPath", servletPath);
return standardJson;
}
#Bean(name="home")
public AjaxFreeMarkerView home() {
return standard();
}
#Bean(name="home.json")
public AjaxFreeMarkerView homeJson() {
AjaxFreeMarkerView homeJson = standardJson();
homeJson.getAttributesMap().put("body", "/layouts/json/home.ftl");
return homeJson;
}
}
A single XML file is also required for the abstract base menu which is referenced elsewhere in the Spring Batch Admin project. This is required as abstract beans can not be provided from a Spring Java configuration.
<?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-2.5.xsd">
<bean id="baseMenu" abstract="true">
<property name="prefix" value="#{resourceService.servletPath}" />
</bean>
</beans>
Maven dependencies. Take care to ensure only a single version of the base Spring framework is pulled in by Maven.
<dependency>
<groupId>org.springframework.batch</groupId>
<artifactId>spring-batch-admin-manager</artifactId>
<version>1.3.1.RELEASE</version>
</dependency>
<dependency>
<groupId>hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<scope>runtime</scope>
<version>1.8.0.10</version>
</dependency>
Spring batch also expects in a default configuration for the following files to exist at the root of the classpath.
batch-default.properties
# Default placeholders for database platform independent features
batch.remote.base.url=http://localhost:8080/spring-batch-admin-sample
# Non-platform dependent settings that you might like to change
batch.job.configuration.file.dir=/tmp/config
build.artifactId=1
build.version=1
build.buildNumber=1
build.timestamp=1
log.enableConsole=true
batch-hsql.properties
# Placeholders batch.*
# for HSQLDB:
batch.jdbc.driver=org.hsqldb.jdbcDriver
batch.jdbc.url=jdbc:hsqldb:mem:testdb;sql.enforce_strict_size=true
# Override and use this one in for a separate server process so you can inspect
# the results (or add it to system properties with -D to override at run time).
# batch.jdbc.url=jdbc:hsqldb:hsql://localhost:9005/samples
batch.jdbc.user=sa
batch.jdbc.password=
batch.database.incrementer.class=org.springframework.jdbc.support.incrementer.HsqlMaxValueIncrementer
batch.schema.script=classpath*:/org/springframework/batch/core/schema-hsqldb.sql
batch.drop.script=classpath*:/org/springframework/batch/core/schema-drop-hsqldb.sql
batch.business.schema.script=classpath:/business-schema-hsqldb.sql
# Non-platform dependent settings that you might like to change
# batch.data.source.init=true
business-schedule-hsqldb.sql
DROP TABLE ERROR_LOG IF EXISTS;
CREATE TABLE ERROR_LOG (
JOB_NAME CHAR(20) ,
STEP_NAME CHAR(20) ,
MESSAGE VARCHAR(300) NOT NULL
) ;