Exception while running spring integration with zookeeper - spring-integration

when i am running spring integration SFTP with zookeeper: Facing issue while file metada put in metadatastore. i have mention below code.
Below is my configuration
<beans:bean id="compositeFilter"
class="org.springframework.integration.file.filters.ChainFileListFilter">
<beans:constructor-arg >
<beans:set>
<beans:bean
class="org.springframework.integration.sftp.filters.SftpRegexPatternFileListFilter">
<beans:constructor-arg value="^.*\.(dat|DAT)$" />
</beans:bean>
<beans:bean
class="org.springframework.integration.sftp.filters.SftpPersistentAcceptOnceFileListFilter">
<beans:constructor-arg name="store"
ref="metadataStore" />
<beans:constructor-arg value="filterprefix" />
</beans:bean>
</beans:set>
</beans:constructor-arg>
</beans:bean>
<beans:bean id="zookeeperClient"
class="org.springframework.integration.zookeeper.config.CuratorFrameworkFactoryBean">
<beans:constructor-arg value="${zookeeper.server.uri}" />
</beans:bean>
<beans:bean id="metadataStore"
class="org.springframework.integration.zookeeper.metadata.ZookeeperMetadataStore">
<beans:constructor-arg ref="zookeeperClient" />
<beans:property name="root" value="/metaDataStore" />
</beans:bean>
Below are the exception trace which I am getting. when i run above program i am getting following error.
Caused by:
Caused by: java.lang.IllegalArgumentException: Invalid path string "/AtdFaureciaMetaDataStore/.." caused by relative paths not allowed #27
at org.apache.curator.utils.PathUtils.validatePath(PathUtils.java:102)
at org.apache.curator.utils.PathUtils.validatePath(PathUtils.java:37)
at org.apache.curator.utils.ZKPaths.fixForNamespace(ZKPaths.java:105)
at org.apache.curator.framework.imps.NamespaceImpl.fixForNamespace(NamespaceImpl.java:104)
at org.apache.curator.framework.imps.CuratorFrameworkImpl.fixForNamespace(CuratorFrameworkImpl.java:599)
at org.apache.curator.framework.imps.CreateBuilderImpl.forPath(CreateBuilderImpl.java:458)
at org.apache.curator.framework.imps.CreateBuilderImpl.forPath(CreateBuilderImpl.java:44)
at org.springframework.integration.zookeeper.metadata.ZookeeperMetadataStore.createNode(ZookeeperMetadataStore.java:257)
at org.springframework.integration.zookeeper.metadata.ZookeeperMetadataStore.putIfAbsent(ZookeeperMetadataStore.java:119)

Consider to use ChainFileListFilter instead of CompositeFileListFilter:
**
* The {#link CompositeFileListFilter} extension which chains the result
* of the previous filter to the next one. If a filter in the chain returns
* an empty list, the remaining filters are not invoked.
*
* #param <F> The type that will be filtered.
*
* #author Artem Bilan
* #author Gary Russell
*
* #since 4.3.7
*
*/
public class ChainFileListFilter<F> extends CompositeFileListFilter<F> {
It doesn’t pass discarded files to the next filters in chain.
On the other hand really consider some non-empty prefix for the SftpPersistentAcceptOnceFileListFilter to avoid that relative path error.

Related

sftp:inbound-streaming-channel-adapter with zookeeper is not working when i use CompositeFileListFilter

i have used sftp:inbound-streaming-channel-adapter with zookeeper.but it is giving me exception : java.lang.ClassCastException: com.jcraft.jsch.ChannelSftp$LsEntry cannot be cast to java.io.File. I am using the following code
<int-sftp:inbound-streaming-channel-adapter
id="sftpAdapter" channel="receiveChannel"
session-factory="cachingSessionFactory"
remote-file-separator="/" remote-directory-expression="'${ftpServerLoc}'" filter="compositeFilter"
auto-startup="true">
<int:poller fixed-rate="${pollarInterval}"
max-messages-per-poll="1" />
</int-sftp:inbound-streaming-channel-adapter>
<beans:bean id="compositeFilter"
class="org.springframework.integration.file.filters.CompositeFileListFilter">
<beans:constructor-arg>
<beans:list>
<beans:bean
class="org.springframework.integration.file.filters.RegexPatternFileListFilter">
<beans:constructor-arg value="^.*\.(dat|DAT)$" />
</beans:bean>
<beans:bean
class="org.springframework.integration.sftp.filters.SftpPersistentAcceptOnceFileListFilter">
<beans:constructor-arg name="store"
ref="metadataStore" />
<beans:constructor-arg value="" />
</beans:bean>
</beans:list>
</beans:constructor-arg>
</beans:bean>
The org.springframework.integration.file.filters.RegexPatternFileListFilter should be org.springframework.integration.sftp.filters.SftpRegexPatternFileListFilter.
The one you have applies to java.io.File; the sftp version applies to LsEntry (Jsch's representation of the remote file).

Configuration not to loose messages

I have spring xd component called throttle where i store the messages and post are and throttle them and send them slowly.I am running my xd in 3 containers.I have holding delay for delayer as 0.When one container goes down.I loose messages.Below is my configuration.Looks like its not storing to postgre and loosing in memory or cache.
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/integration"
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:int-groovy="http://www.springframework.org/schema/integration/groovy"
xmlns:task="http://www.springframework.org/schema/task"
xmlns:int-jdbc="http://www.springframework.org/schema/integration/jdbc"
xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xmlns:ehcache="http://www.springframework.org/schema/cache"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/integration
http://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd
http://www.springframework.org/schema/integration/jdbc
http://www.springframework.org/schema/integration/jdbc/spring-integration-jdbc.xsd
http://www.springframework.org/schema/integration/groovy
http://www.springframework.org/schema/integration/groovy/spring-integration-groovy.xsd
http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache-4.1.xsd">
<ehcache:annotation-driven cache-manager="cacheManager" />
<context:property-placeholder
location="classpath*:dms-security-${region}.properties, classpath*:dms-jms-${region}.properties, classpath*:dms-mongo-${region}.properties" />
<context:component-scan base-package="com.testhrottle.api.dms.*"
use-default-filters="false">
<context:include-filter type="annotation"
expression="org.springframework.context.annotation.Configuration" />
</context:component-scan>
<channel id="input">
<!-- <interceptors>
<ref bean="messageInterceptor" />
</interceptors> -->
</channel>
<channel id="output" />
<channel id="sms" />
<channel id="eml" />
<channel id="del" />
<!-- <header-value-router input-channel="input" header-name="Channel-Type" >
<mapping value="PHN" channel="sms" />
<mapping value="EML" channel="eml" />
<mapping value="DEL" channel="del" />
</header-value-router> -->
<router input-channel="input">
<beans:bean name="messageRouter" class="com.testhrottle.xd.util.MessageRouter">
<beans:property name="cache" ref="configCache" />
</beans:bean>
</router>
<service-activator input-channel="del" ref="delete" method="delete"/>
<filter input-channel="eml" output-channel="output">
<beans:bean class="com.testhrottle.xd.throttle.Throttle">
<beans:constructor-arg value="${tpsThreshold}" />
<beans:constructor-arg value="${spanSeconds}" />
<beans:property name="cache" ref="configCache" />
<beans:property name="dailyLimitCounter" ref="dailyLimitCounter" />
<beans:property name="errorPublishing" ref="errorPublishing" />
</beans:bean>
</filter>
<filter input-channel="sms" output-channel="output">
<beans:bean class="com.testhrottle.xd.throttle.SmsThrottle">
<beans:constructor-arg value="${smsTpsThreshold}" />
<beans:constructor-arg value="${smsSpanSeconds}" />
<beans:property name="cache" ref="configCache" />
<beans:property name="dailyLimitCounter" ref="dailyLimitCounter" />
<beans:property name="errorPublishing" ref="errorPublishing" />
</beans:bean>
</filter>
<channel id="requeue">
<dispatcher task-executor="taskExecutor" />
</channel>
<task:executor id="taskExecutor" pool-size="1" />
<delayer id="delayer" input-channel="requeue" default-delay="${holdingDelay}"
expression="headers['delay']" message-store="messageStore"
output-channel="input" />
<!-- <int-jdbc:message-store id="messageStore" data-source="dataSource" /> -->
<beans:bean id="messageStore" class="com.testhrottle.xd.util.CustomJdbcMessageStore">
<beans:constructor-arg ref="dataSource"/>
</beans:bean>
<!-- <beans:bean name="messageInterceptor" class="com.testhrottle.xd.util.MessageInterceptor">
<beans:property name="cache" ref="configCache" />
</beans:bean> -->
<beans:bean name="configCache"
class="com.testhrottle.xd.cache.ConfigCache">
<beans:property name="jdbcTemplate" ref="jdbcTemplate" />
<beans:property name="holdRetryIntervelInSeconds" value="${holdRetryIntervelInSeconds}" />
<beans:property name="configQuery" value="select alrt_type_cd alertType,dlvry_days_of_week daysOfWeek,DLVRY_STRT_TM startTime,DLVRY_END_TM endTime,DLVRY_STRT_DT startDate,DLVRY_END_DT endDate,hold_ind holdFlag, max_msgs_per_day maxMsgPerDay,purge_ind purge from ${schema}.alrt_type where alrt_type_cd = ?" />
</beans:bean>
<beans:bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<beans:property name="driverClassName" value="org.postgresql.Driver"/>
<beans:property name="url" value="${dbURL}"/>
<beans:property name="username" value="${userName}"/>
<beans:property name="password" value="#{encryptedDatum.decryptBase64Encoded('${passWord}')}"/>
</beans:bean>
<beans:bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<beans:property name="dataSource">
<beans:ref bean="dataSource" />
</beans:property>
</beans:bean>
<beans:bean id="encryptedDatum" class="com.testhrottle.api.dms.core.security.EncryptedSecuredDatum"/>
<!-- <beans:bean id="rabbitTemplate" class="org.springframework.amqp.rabbit.core.RabbitTemplate"/> -->
<beans:bean id="errorPublishing" class="com.testhrottle.xd.util.ErrorPublishing">
<!-- <beans:property name="rabbitTemplate" ref="rabbitTemplate" /> -->
</beans:bean>
<beans:bean id="delete" class="com.testhrottle.xd.util.Delete"/>
<!--
<beans:bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<beans:property name="driverClassName" value="org.postgresql.Driver"/>
<beans:property name="url" value="jdbc:postgresql://localhost:5432/postgres"/>
<beans:property name="username" value="postgres"/>
<beans:property name="password" value="postgres"/>
</beans:bean>
<beans:bean name="configCache"
class="com.testhrottle.xd.cache.ConfigCache">
<beans:property name="jdbcTemplate" ref="jdbcTemplate" />
<beans:property name="holdRetryIntervelInSeconds" value="10" />
<beans:property name="configQuery" value="select alrt_type_cd alertType,dlvry_days_of_week daysOfWeek,DLVRY_STRT_TM startTime,DLVRY_END_TM endTime,DLVRY_STRT_DT startDate,DLVRY_END_DT endDate,hold_ind holdFlag, max_msgs_per_day maxMsgPerDay from dms_wb.alrt_type where alrt_type_cd = ?;
" />
</beans:bean>
<beans:bean name="cacheTest"
class="com.testhrottle.xd.cache.CacheTest">
<beans:property name="cache" ref="configCache" />
</beans:bean> -->
<beans:bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/>
<beans:bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager">
<beans:property name="cacheManager" ref="ehcache" />
</beans:bean>
<beans:bean id="ehcache"
class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
<beans:property name="configLocation" value="classpath:ehcache.xml" />
<beans:property name="shared" value="true" />
</beans:bean>
<beans:bean name="dailyLimitCounter" class="com.testhrottle.xd.throttle.DailyLimitCounter"/>
<task:scheduler id="taskSchedulerInbound" pool-size="10" />
<task:scheduled-tasks>
<task:scheduled ref="dailyLimitCounter" method="clearAlertDailyCount" cron="59 59 23 * * *" />
</task:scheduled-tasks>
</beans:beans>
so if i remove this it should work in same thread.
<channel id="requeue">
<dispatcher task-executor="taskExecutor" />
</channel>
<task:executor id="taskExecutor" pool-size="1" />
Looks like your <dispatcher task-executor="taskExecutor" /> is guilty.
Since you jump out of the Message Bus thread, that acks (commits) the message on the Broker, but the crash of the node doesn't effect that already (rallback), because your message has been moved to different thread. And there it hasn't reached your DB to be commited there, too.
In general it would be better to do everything in the Spring XD withing container's (XD) threads and rely on the Message Bus persistent mechanism.
Or commit messages to DB manually, but in the same XD thread.
Makes sense?

http outbound gateway not converting french characters

I have my spring integration http outbound gateway something like this.I am using my own rest template for pooling connection with ssl.I was getting 500 with french character hence I am injecting both UTF-8 and supported media type to message converter.Now Before I was injecting my own request factory and default rest template After injecting both then it started accepting french characters.Now when i changed to use my own rest template it don't accept message converter and when i try to inject this to my rest template I get this exception
Cause is - Could not write request: no suitable HttpMessageConverter found for request type [java.lang.String] and content type [text/plain;charset=UTF-8]
This worked for all request
<int-http:outbound-gateway id='batch-http' header-mapper="headerMapper"
request-channel='toHttp'
request-factory="requestFactory"
message-converters="batchHTTPConverter"
url-expression="payload.contains('${filterAttribute}') ? '${url1}' : '${url2}'" http-method="${httpMethod}"
expected-response-type='java.lang.String' charset='${charset}'
reply-timeout='${replyTimeout}' reply-channel='output'>
</int-http:outbound-gateway>
<beans:bean id="batchHTTPConverter" class="org.springframework.http.converter.StringHttpMessageConverter">
<beans:constructor-arg index="0" value="UTF-8"/>
<beans:property name="supportedMediaTypes" value = "application/json;UTF-8" />
</beans:bean>
<beans:bean id="requestFactory" class="test.batch.httpclient.CustomClientHttpRequestFactory">
<beans:constructor-arg ref="verifier"/>
</beans:bean>
<beans:bean id="verifier"
class="batch.NullHostnameVerifier">
</beans:bean>
This is not working for french or any input request
<header-filter input-channel="input"
output-channel="inputX" header-names="x-death"/>
<service-activator input-channel="inputX" ref="gw" />
<gateway id="gw" default-request-channel="toHttp" default-reply-timeout="0" error-channel="errors" />
<beans:bean id="inputfields" class="testbatch.httpclient.HTTPInputProperties">
<beans:property name="nonRetryErrorCodes" value="${nonRetryErrorCodes}"/>
</beans:bean>
<beans:bean id="responseInterceptor" class="testbatch.httpclient.ResponseInterceptor">
<beans:property name="inputProperties" ref="inputfields" />
</beans:bean>
<chain input-channel="errors" output-channel="output">
<!-- examine payload.cause (http status code etc) and decide whether
to throw an exception or return the status code for sending to output -->
<header-filter header-names="replyChannel, errorChannel" />
<transformer ref="responseInterceptor" />
</chain>
<int-http:outbound-gateway id='batch-http' header-mapper="headerMapper"
request-channel='toHttp'
rest-template="batchRestTemplate"
url-expression="payload.contains('${filterAttribute}') ? '${url1}' : '${url2}'" http-method="${httpMethod}"
expected-response-type='java.lang.String' charset='${charset}'
reply-timeout='${replyTimeout}' reply-channel='output'>
</int-http:outbound-gateway>
<beans:bean id="batchHTTPConverter" class="org.springframework.http.converter.StringHttpMessageConverter" >
<beans:constructor-arg index="0" value="UTF-8"/>
<beans:property name="supportedMediaTypes" value = "application/json;UTF-8" />
</beans:bean>
<beans:bean id="batchRestTemplate" class="testbatch.httpclient.BatchRestTemplate" >
<beans:property name="batchHTTPConverter" ref="batchHTTPConverter"/>
</beans:bean>
<beans:bean id="requestFactory"
class="testbatch.httpclient.CustomClientHttpRequestFactory">
<beans:constructor-arg ref="verifier"/>
</beans:bean>
<beans:bean id="verifier"
class="testbatch.httpclient.NullHostnameVerifier">
</beans:bean>
<beans:bean id="headerMapper" class="org.springframework.integration.http.support.DefaultHttpHeaderMapper"
factory-method="outboundMapper">
<beans:property name="outboundHeaderNames" value="${mapHeaders}"/>
<beans:property name="userDefinedHeaderPrefix" value=""/>
</beans:bean>
<channel id="output" />
<channel id="input" />
<channel id="inputX" />
<channel id="toHttp" />
</beans:beans>
My rest template
public class BatchRestTemplate extends RestTemplate{
private static final Logger LOGGER = LoggerFactory
.getLogger(BatchRestTemplate.class);
private StringHttpMessageConverter batchHTTPConverter;
public StringHttpMessageConverter getBatchHTTPConverter() {
return batchHTTPConverter;
}
public void setBatchHTTPConverter(StringHttpMessageConverter batchHTTPConverter) {
this.batchHTTPConverter = batchHTTPConverter;
}
public BatchRestTemplate() {
super(createBatchHttpRequestFactory());
List<HttpMessageConverter<?>> messageConverters= new ArrayList<HttpMessageConverter<?>>();
messageConverters.addAll(getMessageConverters());
messageConverters.add(getBatchHTTPConverter());
super.setMessageConverters(messageConverters);
}
private static ClientHttpRequestFactory createBatchHttpRequestFactory() {
CloseableHttpClient httpClient;
HttpComponentsClientHttpRequestFactory httpRequestFactory;
final int timeout = 3000;
SSLConnectionSocketFactory socketFactory;
try {
socketFactory = new SSLConnectionSocketFactory(
SSLContext.getDefault(),
new String[] {"TLSv1"},
null,
SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
.register("http", PlainConnectionSocketFactory.getSocketFactory())
.register("https", socketFactory)
.build();
PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
cm.setMaxTotal(700);
cm.setDefaultMaxPerRoute(300);
cm.closeExpiredConnections();
RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(timeout)
.setConnectionRequestTimeout(timeout).setSocketTimeout(timeout).build();
httpClient = HttpClients.custom().setDefaultRequestConfig(requestConfig).setConnectionManager(cm).build();
httpRequestFactory = new HttpComponentsClientHttpRequestFactory(httpClient);
return httpRequestFactory;
}
catch (Exception e) {
LOGGER.debug("error exception", e);
}
return null;
}
}
You have a bug in your own code:
public BatchRestTemplate() {
..........
messageConverters.add(getBatchHTTPConverter());
..........
}
But... There is no batchHTTPConverter yet!. It will appear there only after setBatchHTTPConverter().
In other words you can't use the property from the constructor because setters are called latter after the object instantiating.

Spring: Accessing JPA repository from TaskExecutor thread

I'm using JPA and Hibernate for persistence, with some autoconfiguration help from Spring Boot. I'm running a JUnit test which saves some record in the JPA Repository. Then it instantiates a new Spring-managed-thread, and it's run by ThreadPoolTaskExecutor. That thread will try to get that previously added record with no success.
Here is the relevant code of the test and the runnable thread:
public class RtmpSpyingTests extends AbstractTransactionalJUnit4SpringContextTests {
#Autowired
ThreadPoolTaskExecutor rtmpSpyingTaskExecutor;
#Autowired
ApplicationContext ctx;
#Autowired
RtmpSourceRepository rtmpRep;
#Test
public void test() {
RtmpSource rtmpSourceSample = new RtmpSource("test");
rtmpRep.save(rtmpSourceSample);
rtmpRep.flush();
List<RtmpSource> rtmpSourceList = rtmpRep.findAll(); // Here I get a list containing rtmpSourceSample
RtmpSpyingTask rtmpSpyingTask = ctx.getBean(RtmpSpyingTask.class,
"arg1","arg2");
rtmpSpyingTaskExecutor.execute(rtmpSpyingTask);
}
}
public class RtmpSpyingTask implements Runnable {
#Autowired
RtmpSourceRepository rtmpRep;
String nameIdCh;
String rtmpUrl;
public RtmpSpyingTask(String nameIdCh, String rtmpUrl) {
this.nameIdCh = nameIdCh;
this.rtmpUrl = rtmpUrl;
}
public void run() {
// Here I should get a list containing rtmpSourceSample, but instead of that
// I get an empty list
List<RtmpSource> rtmpSource = rtmpRep.findAll();
}
}
So, after I have inserted the rtmpSourceSample object, I can check it's been inserted from the test method, it is indeed on the rtmpSourceList list. However, when I do the same from the thread, what I get is an empty list.
Here is the JPA/Hibernate configuration in my spring-context.xml configuration file:
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.h2.Driver" />
<property name="url" value="jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1;MVCC=true" />
<property name="username" value="user" />
<property name="password" value="user" />
</bean>
<!-- Define the JPA transaction manager -->
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<constructor-arg ref="entityManagerFactory" />
</bean>
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter" ref="vendorAdaptor" />
<property name="packagesToScan" value="guiatv.persistence.domain" />
</bean>
<bean id="abstractVendorAdaptor" abstract="true">
<property name="generateDdl" value="true" />
<property name="database" value="H2" />
<property name="showSql" value="false" />
</bean>
<bean id="entityManager"
class="org.springframework.orm.jpa.support.SharedEntityManagerBean">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<bean id="vendorAdaptor"
class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"
parent="abstractVendorAdaptor">
</bean>
<context:annotation-config />
<tx:annotation-driven />
<context:component-scan base-package="guiatv.persistence" />
Note that the persistence-unit.xml is not needed since I'm using Spring Boot.
And finally this is the xml configuration of the taskexecutor bean and the runnable thread:
<bean id="rtmpSpyingTaskExecutor"
class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
<property name="corePoolSize" value="5" />
<property name="maxPoolSize" value="5" />
<property name="queueCapacity" value="5" />
</bean>
<bean id="rtmpSpyingTask" class="guiatv.realtime.rtmpspying.RtmpSpyingTask"
scope="prototype">
<constructor-arg ref="rtmpSpyingTaskExecutor" />
</bean>
I've been looking for topics about this problematic Spring's persistence and threading combination. One of the solutions I've found so far is to create some #Service annotated class with a #Transactional method, which I am supposed to call from my run() method. It does not work for me.
Some other solutions involve the use of the EntityManager or some other Hibernate dependent bean, instead of querying the JPA Repository directly. Doesn't work too.
So, any solution that could fit my needs? Thank you!
SOLUTION (from cproinger):
Create a #Service annotated class:
#Service
public class AsyncTransactionService {
#Autowired
RtmpSourceRepository rtmpRep;
#Transactional(readOnly = true)
public List<RtmpSource> getRtmpSources() {
return rtmpRep.findAll();
}
#Transactional(propagation = Propagation.REQUIRES_NEW)
public void insertRtmpSource(RtmpSource rtmpSource) {
rtmpRep.save(rtmpSource);
}
}
Then, I autowire that AsyncTransactionService from both the JUnit test, and the Runnable class. In order to insert the record from JUnit test I invoke insertRtmpSource(), and then I get the records from my thread by calling getRtmpSources().
I tried to do it without the #Service. This is, by putting an annotated insertRtmpSource() method on my JUnit class and a getRtmpSources() method on my Runnable class, but it did not work.
Thank you for you quick response cproinger!
the thread does not see the record because the test runs inside a transaction that is not committed yet. since the transaction is bound to the executing thread the task that is forked does not use the same transaction. in order for this to work the insert must run in a method that is annotated with #Transactional(propagation = REQUIRES_NEW). please note that transactional rollback will not work then though

SwitchUserFilter with password-encoder not working

I have a <password-encoder> and CustomDetailService refered in AuthenticationManager. I added the following bean in spring-security after all the other security filters (concurrency, customLogoutFilter, etc.,) and <http auto-config="false" ..>:
<?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.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.0.xsd">
<!-- Disable annotation-based method security -->
<global-method-security secured-annotations="disabled" />
<beans:bean id="sessionRegistry"
class="org.springframework.security.core.session.SessionRegistryImpl" />
<!-- Service that provides user credentials for use by the authentication provider -->
<beans:bean id="customDetailService" class="xxx.security.CustomDetailService" />
<!-- Assign the user details service to the default authentication provider -->
<beans:bean class="xxx.security.XyzPasswordEncoder" id="passwordEncoder" />
<!-- Get an alias to the default authentication manager -->
<authentication-manager alias="authenticationManager">
<authentication-provider user-service-ref="customDetailService">
<password-encoder ref="passwordEncoder" />
</authentication-provider>
</authentication-manager>
<!-- Register an exception filter that takes an entry point -->
<beans:bean id="exceptionTranslationFilter"
class="org.springframework.security.web.access.ExceptionTranslationFilter">
<beans:property name="authenticationEntryPoint" ref="authenticationEntryPoint" />
<beans:property name="accessDeniedHandler" ref="accessDeniedHandler" />
</beans:bean>
<beans:bean id="authenticationEntryPoint"
class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
<beans:property name="loginFormUrl" value="/public/auth/login.htmlx" />
</beans:bean>
<beans:bean id="accessDeniedHandler"
class="org.springframework.security.web.access.AccessDeniedHandlerImpl">
<beans:property name="errorPage" value="/error/access-denied.jsp" />
</beans:bean>
<!-- Register a custom authentication filter and register success/failure
handlers -->
<beans:bean id="customAuthenticationFilter"
class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter">
<beans:property name="authenticationManager" ref="authenticationManager" />
<beans:property name="sessionAuthenticationStrategy"
ref="concurrentSessionControlStrategy" />
<beans:property name="authenticationSuccessHandler"
ref="loginSuccessHandler" />
<beans:property name="authenticationFailureHandler"
ref="loginFailureHandler" />
</beans:bean>
<beans:bean id="concurrentSessionControlStrategy"
class="org.springframework.security.web.authentication.session.ConcurrentSessionControlStrategy">
<beans:constructor-arg name="sessionRegistry"
ref="sessionRegistry" />
</beans:bean>
<beans:bean id="loginSuccessHandler"
class="org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler">
<beans:property name="defaultTargetUrl" value="/LoginSuccess" />
</beans:bean>
<beans:bean id="loginFailureHandler"
class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">
<beans:property name="defaultFailureUrl" value="/LoginFailed" />
</beans:bean>
<!-- Register a custom logout filter -->
<beans:bean id="customLogoutFilter" class="xxx.security.LogoutFilterWrapper">
<beans:property name="logoutSuccessfulUrl" value="/public/auth/login.htmlx" />
<beans:property name="logoutSuccessfulUrlAdmin" value="/public/auth/admlogin.htmlx" />
<beans:property name="logoutSuccessfulUrlInactivity"
value="/public/auth/timedout.htmlx" />
</beans:bean>
<!-- Register a concurrent session filter. This will limit the number of
sessions a user can have -->
<beans:bean id="concurrencyFilter"
class="org.springframework.security.web.session.ConcurrentSessionFilter">
<beans:property name="sessionRegistry" ref="sessionRegistry" />
<beans:property name="expiredUrl"
value="/public/error/multi-login-not-supported.htmlx" />
</beans:bean>
<!-- Register a filter to log in as a different user -->
<beans:bean id="switchUserProcessingFilter" class="org.springframework.security.web.authentication.switchuser.SwitchUserFilter">
<beans:property name="userDetailsService" ref="customDetailService" />
<beans:property name="switchUserUrl" value="/j_spring_security_switch_user" />
<beans:property name="exitUserUrl" value="/j_spring_security_exit_user" />
<beans:property name="targetUrl" value="/" />
</beans:bean>
<http auto-config="false" entry-point-ref="authenticationEntryPoint">
<custom-filter position="FORM_LOGIN_FILTER" ref="customAuthenticationFilter" />
<custom-filter position="LOGOUT_FILTER" ref="customLogoutFilter" />
<custom-filter position="CONCURRENT_SESSION_FILTER" ref="concurrencyFilter" />
<custom-filter position="SWITCH_USER_FILTER" ref="switchUserProcessingFilter" />
<session-management session-fixation-protection="none" />
<!-- Configure the filter security interceptor. URL patterns default to
Apache Ant path syntax -->
<intercept-url pattern="/**/xyz_product*" access="ROLE_XYZ_PRODUCT" />
<intercept-url pattern="/root/user/index.htmlx" access="ROLE_XYZ_PRODUCT" />
<!-- Allow unrestrictricted access to assets -->
<intercept-url pattern="/assets/**" filters="none" />
<!-- Allow unrestrictricted access to public areas -->
<intercept-url pattern="/public/**" filters="none" />
<!-- Allow unrestrictricted access to generated resources -->
<intercept-url pattern="/faces/**" filters="none" />
<!-- Enforce role-based access for login success servlet -->
<intercept-url pattern="/LoginSuccess"
access="ROLE_RESTRICTED,ROLE_ADMIN,ROLE_ADMIN_APP,ROLE_PHYSICIAN,ROLE_NURSE" />
<!-- Enforce role-based access for user area -->
<intercept-url pattern="/root/user/**" access="ROLE_PHYSICIAN,ROLE_NURSE" />
<!-- Enforce role-based access for admin area -->
<intercept-url pattern="/root/admin/*" access="ROLE_ADMIN,ROLE_ADMIN_APP" />
<intercept-url pattern="/root/admin/user/**" access="ROLE_ADMIN,ROLE_ADMIN_APP" />
// ommitted ...
</http>
</beans:beans>
Here's my facelets page:
<h:form>
<h:inputText id="j_username" value="" styleClass="textInput" size="50"/>
<p>Click <h:commandLink value="here" action="/j_spring_security_switch_user"/> to switch to
user </p>
</h:form>
Error in the logs:
org.springframework.security.web.access.intercept.FilterSecurityInterceptor
- RunAsManager did not change Authentication object
I was able to fix this. The problem was with my jsf page not sending j_username to SwitchUserFilter when I bind the jsf action to '/j_spring_security_switch_user'. However, a passthrough through a controller binding works.
I blogged my experience here:
http://www.reverttoconsole.com/blog/spring/switch-user-su-like-behavior-in-spring/

Resources