Spring MVC - Annotation based controller failed to find request handler method - rest

This has stopped working after I added a Spring Security filter.
Spring 3.1.4.RELEASE
Spring Security 3.1.2.RELEASE
Tomcat 7.0.37
The mapping is configured as expected when the app is deployed
INFO annotation.RequestMappingHandlerMapping: Mapped "{[/countries],methods=[GET],params=[!countryCode],headers=[],consumes=[],produces=[application/json],custom=[]}" onto public com.purpleleaf.proxy.rest.data.ProxyResponse com.purpleleaf.proxy.rest.service.reference.DefaultCountry.findAll()
The GET request is submitted.
GET http://localhost:8081/purpleleaf-admin-1.0.0/countries?page=1&start=0&limit=25
The request parameters are added by ExtJS and it is not an issue as it was working without security.
The log for the GET request
DEBUG util.AntPathRequestMatcher: Checking match of request : '/countries'; against '/*'
DEBUG web.FilterChainProxy: /countries?page=1&start=0&limit=25 has an empty filter list
DEBUG servlet.DispatcherServlet: DispatcherServlet with name 'admin-spring' processing GET request for [//purpleleaf-admin-1.0.0/countries]
DEBUG annotation.RequestMappingHandlerMapping: Looking up handler method for path //purpleleaf-admin-1.0.0/countries
DEBUG annotation.RequestMappingHandlerMapping: Did not find handler method for [//purpleleaf-admin-1.0.0/countries]
DEBUG handler.SimpleUrlHandlerMapping: Matching patterns for request [//purpleleaf-admin-1.0.0/countries] are [/**]
DEBUG handler.SimpleUrlHandlerMapping: URI Template variables for request [//purpleleaf-admin-1.0.0/countries] are {}
DEBUG handler.SimpleUrlHandlerMapping: Mapping [//purpleleaf-admin-1.0.0/countries] to HandlerExecutionChain with handler [org.springframework.web.servlet.resource.DefaultServletHttpRequestHandler#3f8050cf] and 1 interceptor
DEBUG servlet.DispatcherServlet: Last-Modified value for [//purpleleaf-admin-1.0.0/countries] is: -1
DEBUG servlet.DispatcherServlet: Null ModelAndView returned to DispatcherServlet with name 'admin-spring': assuming HandlerAdapter completed request handling
DEBUG servlet.DispatcherServlet: Successfully completed request
When the request is processed by web.filterChainProxy it is /countries but when it is process by annotation.RequestMappingHandlerMapping it is //purpleleaf-admin-1.0.0/countires
purpleleaf-admin-1.0.0 is the folder where war file is unpaked.
web.xml has following servlet and filter mapping
<servlet-mapping>
<servlet-name>admin-spring</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Any suggestion on how I can resolve this mapping?
Edit 1: Spring Security Configuration File
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="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-3.1.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd">
<beans:import resource="classpath*:applicationContext-CrowdClient.xml" />
<beans:bean id="crowdUserDetailsService" class="com.atlassian.crowd.integration.springsecurity.user.CrowdUserDetailsServiceImpl">
<beans:property name="authenticationManager" ref="crowdAuthenticationManager"/>
<beans:property name="groupMembershipManager" ref="crowdGroupMembershipManager"/>
<beans:property name="userManager" ref="crowdUserManager"/>
<beans:property name="authorityPrefix" value="ROLE_"/>
</beans:bean>
<beans:bean id="crowdAuthenticationProvider" class="com.atlassian.crowd.integration.springsecurity.RemoteCrowdAuthenticationProvider">
<beans:constructor-arg ref="crowdAuthenticationManager"/>
<beans:constructor-arg ref="httpAuthenticator"/>
<beans:constructor-arg ref="crowdUserDetailsService"/>
</beans:bean>
<authentication-manager alias="authenticationManager">
<authentication-provider ref='crowdAuthenticationProvider' />
</authentication-manager>
<beans:bean id="crowdAuthenticationProcessingFilterEntryPoint" class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
<beans:constructor-arg value="/login.jsp" />
</beans:bean>
<beans:bean id="crowdAuthenticationProcessingFilter" class="com.atlassian.crowd.integration.springsecurity.CrowdSSOAuthenticationProcessingFilter">
<beans:property name="httpAuthenticator" ref="httpAuthenticator"/>
<beans:property name="authenticationManager" ref="authenticationManager"/>
<beans:property name="filterProcessesUrl" value="/j_security_check"/>
<beans:property name="authenticationFailureHandler">
<beans:bean class="com.atlassian.crowd.integration.springsecurity.UsernameStoringAuthenticationFailureHandler">
<beans:property name="defaultFailureUrl" value="/login.jsp?error=true"/>
</beans:bean>
</beans:property>
<beans:property name="authenticationSuccessHandler">
<beans:bean class="org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler">
<beans:property name="defaultTargetUrl" value="/"/>
</beans:bean>
</beans:property>
</beans:bean>
<beans:bean id="crowdLogoutHandler" class="com.atlassian.crowd.integration.springsecurity.CrowdLogoutHandler">
<beans:property name="httpAuthenticator" ref="httpAuthenticator"/>
</beans:bean>
<beans:bean id="securityContextLogoutHandler" class="org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler" />
<beans:bean id="logoutFilter" class="org.springframework.security.web.authentication.logout.LogoutFilter">
<beans:constructor-arg index="0" value="/index.html"/>
<beans:constructor-arg index="1">
<beans:list>
<beans:ref bean="crowdLogoutHandler"/>
<beans:ref bean="securityContextLogoutHandler"/>
</beans:list>
</beans:constructor-arg>
<beans:property name="filterProcessesUrl" value="/logout.html"/>
</beans:bean>
<http pattern='/*' security='none'/>
<!--http pattern='/scripts/*' security='none'/-->
<http auto-config="false" entry-point-ref="crowdAuthenticationProcessingFilterEntryPoint">
<custom-filter position="FORM_LOGIN_FILTER" ref='crowdAuthenticationProcessingFilter'/>
<custom-filter position="LOGOUT_FILTER" ref='logoutFilter'/>
<!--intercept-url pattern="/admin/*" access="ROLE_application-administrators"/-->
<!--intercept-url pattern="/passwordHint.html" access="ROLE_ANONYMOUS,ROLE_ADMIN,ROLE_USER"/-->
<!--security:intercept-url pattern="/**/*.html*" access="IS_AUTHENTICATED_FULLY"/-->
</http>
</beans:beans>

The root cause was the purpleleaf-admin-1.0.0 on the url. util.AntPathRequestMatcher could not resolve the path correctly when it contains a dot(.).
The class was not in the path until the security filter was added.

Related

OAuth with Spring Security in RESTful web service WITHOUT hard-coded username and password (should use MongoDB database)

I just implemented OAuth with Spring Security in RESTful web service WITH hard-coded username and password,for that i just added,one spring-security file,
spring-security.xml
<beans:beans xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:oauth="http://www.springframework.org/schema/security/oauth2"
xmlns:sec="http://www.springframework.org/schema/security"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.2.xsd
http://www.springframework.org/schema/security/oauth2
http://www.springframework.org/schema/security/spring-security-oauth2-1.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.1.6.xsd">
<!-- Definition of the Authentication Service -->
<http pattern="/oauth/token" create-session="stateless" authentication-manager-ref="clientAuthenticationManager"
xmlns="http://www.springframework.org/schema/security">
<intercept-url pattern="/oauth/token" access="IS_AUTHENTICATED_FULLY"/>
<anonymous enabled="false"/>
<http-basic entry-point-ref="clientAuthenticationEntryPoint"/>
<!-- include this only if you need to authenticate clients via request parameters -->
<custom-filter ref="clientCredentialsTokenEndpointFilter" after="BASIC_AUTH_FILTER"/>
<access-denied-handler ref="oauthAccessDeniedHandler"/>
</http>
<!-- Protected resources -->
<http pattern="/admin/**"
create-session="never"
entry-point-ref="oauthAuthenticationEntryPoint"
access-decision-manager-ref="accessDecisionManager"
xmlns="http://www.springframework.org/schema/security">
<anonymous enabled="false"/>
<intercept-url pattern="/admin/**"
access="ROLE_USER"/>
<custom-filter ref="resourceServerFilter"
before="PRE_AUTH_FILTER"/>
<access-denied-handler
ref="oauthAccessDeniedHandler"/>
</http>
<beans:bean id="oauthAuthenticationEntryPoint"
class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
<beans:property name="realmName" value="dstest"/>
</beans:bean>
<beans:bean id="clientAuthenticationEntryPoint"
class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
<beans:property name="realmName" value="dstest/client"/>
<beans:property name="typeName" value="Basic"/>
</beans:bean>
<beans:bean id="oauthAccessDeniedHandler"
class="org.springframework.security.oauth2.provider.error.OAuth2AccessDeniedHandler"/>
<beans:bean id="clientCredentialsTokenEndpointFilter"
class="org.springframework.security.oauth2.provider.client.ClientCredentialsTokenEndpointFilter">
<beans:property name="authenticationManager" ref="clientAuthenticationManager"/>
</beans:bean>
<bean id="accessDecisionManager" class="org.springframework.security.access.vote.UnanimousBased"
xmlns="http://www.springframework.org/schema/beans">
<constructor-arg>
<list>
<bean class="org.springframework.security.oauth2.provider.vote.ScopeVoter"/>
<bean class="org.springframework.security.access.vote.RoleVoter"/>
<bean class="org.springframework.security.access.vote.AuthenticatedVoter"/>
</list>
</constructor-arg>
</bean>
<!-- Authentication in config file -->
<authentication-manager id="clientAuthenticationManager" xmlns="http://www.springframework.org/schema/security">
<authentication-provider user-service-ref="clientDetailsUserService"/>
</authentication-manager>
<authentication-manager alias="authenticationManager" xmlns="http://www.springframework.org/schema/security">
<authentication-provider>
<user-service id="userDetailsService">
<user name="shree" password="pass" authorities="ROLE_USER"/>
</user-service>
</authentication-provider>
</authentication-manager>
<beans:bean id="clientDetailsUserService"
class="org.springframework.security.oauth2.provider.client.ClientDetailsUserDetailsService">
<beans:constructor-arg ref="clientDetails"/>
</beans:bean>
<!-- Token Store -->
<beans:bean id="tokenStore" class="org.springframework.security.oauth2.provider.token.InMemoryTokenStore"/>
<beans:bean id="tokenServices" class="org.springframework.security.oauth2.provider.token.DefaultTokenServices">
<beans:property name="tokenStore" ref="tokenStore"/>
<beans:property name="supportRefreshToken" value="true"/>
<beans:property name="clientDetailsService" ref="clientDetails"/>
<!-- VIV -->
<beans:property name="accessTokenValiditySeconds" value="10"/>
</beans:bean>
<beans:bean id="userApprovalHandler"
class="org.springframework.security.oauth2.provider.approval.TokenServicesUserApprovalHandler">
<beans:property name="tokenServices" ref="tokenServices"/>
</beans:bean>
<!-- Token management -->
<oauth:authorization-server client-details-service-ref="clientDetails" token-services-ref="tokenServices"
user-approval-handler-ref="userApprovalHandler">
<oauth:authorization-code/>
<oauth:implicit/>
<oauth:refresh-token/>
<oauth:client-credentials/>
<oauth:password/>
</oauth:authorization-server>
<oauth:resource-server id="resourceServerFilter"
resource-id="dstest"
token-services-ref="tokenServices"/>
<!-- Client Definition -->
<oauth:client-details-service id="clientDetails">
<oauth:client client-id="my-trusted-client"
authorized-grant-types="password,authorization_code,refresh_token,implicit,redirect"
authorities="ROLE_CLIENT, ROLE_TRUSTED_CLIENT"
redirect-uri="/web"
scope="read,write,trust"
access-token-validity="10"
refresh-token-validity="30"/>
</oauth:client-details-service>
<sec:global-method-security pre-post-annotations="enabled" proxy-target-class="true">
<sec:expression-handler ref="oauthExpressionHandler"/>
</sec:global-method-security>
<oauth:expression-handler id="oauthExpressionHandler"/>
<oauth:web-expression-handler id="oauthWebExpressionHandler"/>
</beans:beans>
means we no need to goto .java file currently,but now I want to check username and password from MongoDB database.I tried searching for this but either I am not understanding because code is different or their different database confuse me,I am not getting some website which really explain flow & use of code.
So my question is How to simply make above code accessible to MongoDB database
and check username,password from their.
are you asking about authentication? spring security oauth use spring security for authentication. that means you could configure this with WebSecurityConfigurerAdapter. like this
#Configuration
#EnableWebSecurity
public class SecurityCfg extends WebSecurityConfigurerAdapter {
#Autowired
public vodie globalUserDetails(AuthenticationManagerBuilder auth)
{
auth.mongoDBAuthentication().dataSource(dataSource)
.passwordEncoder(passwordEncoder());
}
}
you've to look for or implement mongoDBAuthentication class which implements UserDetailsManager. and setup a datasource bean.
would be much easier to use jdbcAuthentication with MySQL or postgresQL.
maybe this would help https://github.com/caelwinner/spring-security-mongo

spring batch remote chunking doesn't queue messages but runs it locally?

Below is my configuration for spring batch remote chunking. My steps are running locally instead of remotely. I cant see messages in rabbitmq.
<beans:bean id="importExchangesChunkItemWriter"
class="org.springframework.batch.integration.chunk.ChunkMessageChannelItemWriter"
scope="step" p:messagingOperations-ref="importExchangesMessagingTemplate"
p:replyChannel-ref="importExchangesReplyChannel">
</beans:bean>
<beans:bean id="importExchangesChunkHandler"
class="org.springframework.batch.integration.chunk.RemoteChunkHandlerFactoryBean"
p:chunkWriter-ref="importExchangesChunkItemWriter" p:step-ref="importExchangesStep">
</beans:bean>
<job id="importExchangesJob" restartable="true">
<step id="importExchangesStep" next="importEclsStep">
<tasklet transaction-manager="transactionManager">
<chunk reader="importExchangesFileItemReader" writer="importExchangesItemWriter"
commit-interval="${import.exchanges.commit.interval}" />
</tasklet>
</step>
</job>
<beans:bean id="passThroughItemProcessor" class="org.springframework.batch.item.support.PassThroughItemProcessor" />
<rabbit:connection-factory id="connectionFactory"
port="${rabbitmq.port}" host="${rabbitmq.host}" username="${rabbitmq.username}"
password="${rabbitmq.password}" />
<rabbit:template id="amqpTemplate" connection-factory="connectionFactory" />
<rabbit:admin id="rmqAdmin" connection-factory="connectionFactory" />
<rabbit:queue name="${import.exchanges.queue}" />
<rabbit:queue name="${import.exchanges.reply.queue}" />
<int:channel id="importExchangesChannel" />
<int:channel id="importExchangesReplyChannel" />
<beans:bean id="importExchangesMessagingTemplate"
class="org.springframework.integration.core.MessagingTemplate"
p:defaultChannel-ref="importExchangesChannel" p:receiveTimeout="${import.exchanges.reply.timeout}" />
<amqp:outbound-channel-adapter id="importExchangesOutboundAdapter"
channel="importExchangesChannel" />
<amqp:inbound-channel-adapter id="importExchangesInboundAdapter"
connection-factory="connectionFactory" channel="importExchangesReplyChannel"
queue-names="${import.exchanges.reply.queue}" />
<amqp:inbound-channel-adapter id="importExchangesSlaveInboundAdapter"
connection-factory="connectionFactory" channel="importExchangesChannel"
queue-names="${import.exchanges.queue}" />
<amqp:outbound-channel-adapter id="importExchangesSlaveOutboundAdapter"
channel="importExchangesReplyChannel" />
<int:service-activator id="serviceActivatorExchanges"
input-channel="importExchangesChannel" output-channel="importExchangesReplyChannel"
ref="chunkProcessorChunkHandlerExchanges" method="handleChunk" />
<beans:bean id="importExchangesItemWriter"
class="com.st.batch.foundation.ImportExchangesItemWriter" p:symfony-ref="symfony" p:replyTimeout="${import.exchanges.reply.timeout}"/>
<beans:bean id="chunkProcessorExchanges"
class="org.springframework.batch.core.step.item.SimpleChunkProcessor"
p:itemWriter-ref="importExchangesItemWriter" p:itemProcessor-ref="passThroughItemProcessor"/>
<beans:bean id="chunkProcessorChunkHandlerExchanges"
class="org.springframework.batch.integration.chunk.ChunkProcessorChunkHandler"
p:chunkProcessor-ref="chunkProcessorExchanges" />
Changed configuration to this, now it queue single message at a time and doesn't process multiple (should process number of messages equal to listener concurrency).
<beans:bean id="simpleThreadScope"
class="org.springframework.context.support.SimpleThreadScope" />
<util:map id="scopesMap">
<beans:entry key="thread" value-ref="simpleThreadScope" />
</util:map>
<beans:bean
class="org.springframework.beans.factory.config.CustomScopeConfigurer"
p:scopes-ref="scopesMap" />
<int:channel id="importExchangesChannel" />
<int:channel id="importExchangesReplyChannel" scope="thread">
<int:queue />
</int:channel>
<beans:bean id="importExchangesMessagingTemplate"
class="org.springframework.integration.core.MessagingTemplate"
p:defaultChannel-ref="importExchangesChannel" p:receiveTimeout="${import.exchanges.reply.timeout}" />
<amqp:outbound-channel-adapter
amqp-template="amqpTemplate" channel="importExchangesChannel"
exchange-name="${import.exchanges.exchange}" routing-key="${import.exchanges.routing.key}" />
<rabbit:listener-container
connection-factory="rabbitConnectionFactory" concurrency="${import.exchanges.listener.concurrency}"
requeue-rejected="false" prefetch="1">
<rabbit:listener queues="${import.exchanges.queue}"
ref="importExchangesChunkHandler" method="handleChunk" />
</rabbit:listener-container>
<int:channel id="importEclsChannel" />
<int:channel id="importEclsReplyChannel" scope="thread">
<int:queue />
</int:channel>
<beans:bean id="importEclsMessagingTemplate"
class="org.springframework.integration.core.MessagingTemplate"
p:defaultChannel-ref="importEclsChannel" p:receiveTimeout="${import.ecls.reply.timeout}" />
<amqp:outbound-channel-adapter
amqp-template="amqpTemplate" channel="importEclsChannel"
exchange-name="${import.ecls.exchange}" routing-key="${import.ecls.routing.key}" />
<rabbit:listener-container
connection-factory="rabbitConnectionFactory" concurrency="${import.ecls.listener.concurrency}"
requeue-rejected="false" prefetch="1">
<rabbit:listener queues="${import.ecls.queue}"
ref="importEclsChunkHandler" method="handleChunk" />
</rabbit:listener-container>
<beans:bean id="importExchangesItemWriter"
class="com.st.batch.foundation.ImportExchangesItemWriter"
p:symfony-ref="symfony" p:replyTimeout="${import.exchanges.reply.timeout}" />
<beans:bean id="importExchangesChunkItemWriter"
class="org.springframework.batch.integration.chunk.ChunkMessageChannelItemWriter"
scope="step" p:messagingOperations-ref="importExchangesMessagingTemplate"
p:replyChannel-ref="importExchangesReplyChannel">
</beans:bean>
<beans:bean id="importExchangesChunkHandler"
class="org.springframework.batch.integration.chunk.RemoteChunkHandlerFactoryBean"
p:chunkWriter-ref="importExchangesChunkItemWriter" p:step-ref="importExchangesStep">
</beans:bean>
<rabbit:queue name="${import.exchanges.queue}" />
<rabbit:queue name="${import.exchanges.reply.queue}" />
<rabbit:direct-exchange name="${import.exchanges.exchange}">
<rabbit:bindings>
<rabbit:binding queue="${import.exchanges.queue}"
key="${import.exchanges.routing.key}" />
</rabbit:bindings>
</rabbit:direct-exchange>
I can see only 1 message in queue at a time. I should sent messages = ${import.exchanges.commit.interval} and all should be picked up by concurrent listeners and processed parallely.
I am not sure what you mean by "running locally" but you don't have any routing information on the outbound adapters; if rabbit doesn't know how to route messages, he simply drops them.
You need to add routing-key="${import.exchanges.queue}" and routing-key="${import.exchanges.reply.queue}" to the adapters. This will use the default exchange ("") where the queues are bound using their names.
Also, you can't use the same channel name on both sides (importExchangesChannel). That way, the outbound adapter and service activator will both be subscribed and messages will be distributed in round-robin fashion.
So, some chunks will run locally; others will be dropped because of the routing key problem.
You need to fix the routing key and use a different channel on service side.

Where to store authentication token in RESTful API?

I want to secure the REST URL. For that I have decided to go with token based authentication. In that, how can I create the token with expiration time and where can I store it for later validation token check ?
Thanks in advance.
This is my security.xml
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:sec="http://www.springframework.org/schema/security"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd">
<beans:import resource="applicationContext.xml"/>
<http pattern="/jaxrs/employess/**" create-session="stateless" entry-point-ref="myAuthenticationEntryPoint">
<intercept-url pattern='/jaxrs/employess/**' />
<custom-filter position="PRE_AUTH_FILTER" ref="myAuthenticationFilter" />
</http>
<beans:bean id="myAuthenticationEntryPoint" class="restservice.security.MyAuthenticationEntryPoint"/>
<global-method-security secured-annotations="enabled" />
<beans:bean id="myAuthenticationFilter" class="restservice.security.MyAuthenticationFilter">
<beans:property name="authenticationManager" ref="authenticationManager"/>
</beans:bean>
<authentication-manager alias="authenticationManager">
<authentication-provider ref="myAuthenticationProvider"/>
</authentication-manager>
<!--<beans:bean id="restTemplate" class="org.springframework.web.client.RestTemplate"/>-->
<beans:bean id="restTemplate" class="org.springframework.web.client.RestTemplate">
<!-- <beans:property name="errorHandler" ref="customErrorHandler" /> -->
</beans:bean>
<beans:bean id="myAuthenticationProvider" class="restservice.security.MyAuthenticationProvider" >
<beans:property name="restTemplate" ref="restTemplate"/>
</beans:bean>
<!-- <beans:bean id="customErrorHandler" class="com.AuthenticationResponseErrorHandler"/> -->
</beans:beans>*
You shouldn't store it anywhere, since that would imply storing some session state on the server.
Instead, the token itself should be a signed encoded string with the information you need to identify the user. You verify its authenticity by checking the signature. If you need to expire it, just append a time stamp to it before signing and calculate the token age based on the current time.

Configuring SpringMVC with Hibernate using JPA

Can someone please tell what am I doing wrong here. All I'm trying to do is hit the mysql database using Spring MVC with JPA configuration. I'm greeted with error every time I'm running the program.
servlet-context.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-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/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
<context:property-placeholder location="classpath:hibernate.properties" />
<!-- DispatcherServlet Context: defines this servlet's request-processing
infrastructure -->
<!-- Enables the Spring MVC #Controller programming model -->
<annotation-driven />
<!-- Handles HTTP GET requests for /resources/** by efficiently serving
up static resources in the ${webappRoot}/resources directory -->
<resources mapping="/resources/**" location="/resources/" />
<!-- Resolves views selected for rendering by #Controllers to .jsp resources
in the /WEB-INF/views directory -->
<beans:bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<beans:property name="prefix" value="/WEB-INF/views/" />
<beans:property name="suffix" value=".jsp" />
</beans:bean>
<context:component-scan base-package="com.logicalideasJPA" />
<!-- Enables the Spring MVC #Controller programming model -->
<tx:annotation-driven transaction-manager="transactionManager" />
<!-- Declare a JPA entityManagerFactory -->
<beans:bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<beans:property name="dataSource" ref="dataSource" />
<beans:property name="loadTimeWeaver">
<beans:bean
class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver" />
</beans:property>
<beans:property name="jpaVendorAdapter">
<beans:bean
class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<beans:property name="showSql" value="true" />
</beans:bean>
</beans:property>
</beans:bean>
<!-- Declare a transaction manager -->
<beans:bean id="transactionManager"
class="org.springframework.orm.jpa.JpaTransactionManager">
<beans:property name="entityManagerFactory" ref="entityManagerFactory" />
<beans:property name="dataSource" ref="dataSource" />
</beans:bean>
<beans:bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<beans:property name="driverClassName" value="${database.driver}" />
<beans:property name="url" value="${database.url}" />
<beans:property name="username" value="${database.user}" />
<beans:property name="password" value="${database.password}" />
</beans:bean>
</beans:beans>
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping#0': Initialization of bean failed; nested exception is java.lang.NoClassDefFoundError: com/logicalideas/persistence/Contacts
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:527)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:294)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:225)
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.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:585)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:913)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:464)
at org.springframework.web.servlet.FrameworkServlet.configureAndRefreshWebApplicationContext(FrameworkServlet.java:631)
at org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:588)
at org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:645)
at org.springframework.web.servlet.FrameworkServlet.initWebApplicationContext(FrameworkServlet.java:508)
at org.springframework.web.servlet.FrameworkServlet.initServletBean(FrameworkServlet.java:449)
at org.springframework.web.servlet.HttpServletBean.init(HttpServletBean.java:133)
at javax.servlet.GenericServlet.init(GenericServlet.java:160)
at org.apache.catalina.core.StandardWrapper.initServlet(StandardWrapper.java:1266)
at org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1185)
at org.apache.catalina.core.StandardWrapper.load(StandardWrapper.java:1080)
at org.apache.catalina.core.StandardContext.loadOnStartup(StandardContext.java:5001)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5289)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1525)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1515)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
at java.util.concurrent.FutureTask.run(FutureTask.java:138)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
In your entityManagerFactory bean, you have to set the packages to scan in order to hibernate can find your entities:
<beans:bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
...
<beans:property name="packagesToScan" value="com.logicalideas.persistence"/>
...
</beans:bean>
You can find more information here.
Looks like you are scanning for com.logicalideasJPA,
<context:component-scan base-package="com.logicalideasJPA" />
while your JPA classes are expected to be at com.logicalideas.persistence, based on the exception you are getting. Try changing scanning package name.

Database to File program query

I have a spring batch program which reads from a database and writes to a file.
Job is:
<job id="MyTransactionJob" job-repository="jobRepository" incrementer="dynamicJobParameters">
<step id="TransactionfileGenerator">
<tasklet transaction-manager="jobRepository-transactionManager">
<chunk reader="MyItemReader" writer="MyItemWriter" commit-interval="1000" skip-policy="skipPolicy"/>
</tasklet>
<listeners>
<listener ref="MySkipListener"/>
</listeners>
</step>
</job>
Item Reader is:
<beans:bean id="MyItemReader" class="org.springframework.batch.item.database.JdbcCursorItemReader">
<beans:property name="dataSource" ref="jobRepository-dataSource" />
<beans:property name="sql" value="${dbTofileDataReadSQL}"/>
<beans:property name="rowMapper">
<beans:bean class="com.mypackage.MyRowMapper" />
</beans:property>
</beans:bean>
dbTofileDataReadSQL is a simple select sql based on some condition. So if condition is not satisfied, 0 rows will be returned.
Item writer is:
<beans:bean id="MyItemWriter" class="com.mypackage.MyDbToFileItemWriter">
<beans:property name="delegate">
<beans:bean class="org.springframework.batch.item.file.FlatFileItemWriter">
<beans:property name="resource" value="file:c:\output.dat" />
<beans:property name="shouldDeleteIfExists" value="true"/>
<beans:property name="lineAggregator">
<beans:bean class="org.springframework.batch.item.file.transform.PassThroughLineAggregator" />
</beans:property>
</beans:bean>
</beans:property>
</beans:bean>
Issue is even if the number of rows returned are 0 an empty file will be created as the writer will always run.
Is it possible to put in a condition such that the file should be created if and only if there is atleast one row to be written. Else just skip the ItemWriter part completely.
Thanks for reading!!
the file will be opened when the step starts, you can
create a custom FlatFileItemWriter which uses the file in a lazy manner
create an afterstep which deletes the file if there are no written lines, this could be a more general solution, if you use a flow
use a simple shell script which checks the file after the job and deletes it if it is empty