I am trying to poll ftp server for file and process them. I want to do it without xml configuration. I am using spring boot(1.2.5) and spring integration ftp (4.1.5)
I created a bean for session factory
#Bean
public DefaultFtpSessionFactory ftpSessionFactory() {
DefaultFtpSessionFactory ftpSessionFactory = new DefaultFtpSessionFactory();
ftpSessionFactory.setHost(ftpProperties.ftpHost);
ftpSessionFactory.setPort(Integer.parseInt(ftpProperties.ftpPort));
ftpSessionFactory.setUsername(ftpProperties.ftpUser);
ftpSessionFactory.setPassword(ftpProperties .ftpPassword);
return ftpSessionFactory;
}
I am trying to configure ftp server polling as follows.
#Bean
#InboundChannelAdapter(value = "receiveChannel", poller = #Poller(fixedRate="1000"))
public MessageSource pollFtpForFiles() {
File localDirectory = new File(sftpProperties.localDirectory);
System.err.println("LocalDirectory::"+localDirectory.getAbsolutePath()+"::exists::"+localDirectory.isDirectory());
FtpInboundFileSynchronizer ftpInboundFileSynchronizer = new FtpInboundFileSynchronizer(ftpSessionFactory());
ftpInboundFileSynchronizer.setRemoteDirectory(sftpProperties.remoteDirectory);
ftpInboundFileSynchronizer.synchronizeToLocalDirectory(localDirectory);
return new FtpInboundFileSynchronizingMessageSource(ftpInboundFileSynchronizer);
}
But I am getting following exception when I run the app.
Not sure what I am doing wrong. Can somebody help me. (I tried with sftp also with same result)
LocalDirectory::localDirForSftpTransfer::exists::true
Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sftpInboundSetup' defined in file [/Users/rsamban/Documents/workspace/Second/target/classes/com/yesVin/integration/sftp/SftpInboundSetup.class]: Initialization of bean failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'pollFtpForFiles' defined in class path resource [com/yesVin/integration/sftp/SftpInboundSetup.class]: **Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: localDirectory must not be null**
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:547)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:476)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:303)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:299)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:755)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:757)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:480)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:686)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:320)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:957)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:946)
at com.yesVin.integration.SecondApplication.main(SecondApplication.java:16)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'pollFtpForFiles' defined in class path resource [com/yesVin/integration/sftp/SftpInboundSetup.class]: **Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: localDirectory must not be null**
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1574)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:539)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:476)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:303)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:299)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
at org.springframework.integration.config.annotation.AbstractMethodAnnotationPostProcessor.resolveTargetBeanFromMethodWithBeanAnnotation(AbstractMethodAnnotationPostProcessor.java:362)
at org.springframework.integration.config.annotation.InboundChannelAdapterAnnotationPostProcessor.createMessageSource(InboundChannelAdapterAnnotationPostProcessor.java:76)
at org.springframework.integration.config.annotation.InboundChannelAdapterAnnotationPostProcessor.postProcess(InboundChannelAdapterAnnotationPostProcessor.java:62)
at org.springframework.integration.config.annotation.MessagingAnnotationPostProcessor$1.doWith(MessagingAnnotationPostProcessor.java:151)
at org.springframework.util.ReflectionUtils.doWithMethods(ReflectionUtils.java:495)
at org.springframework.integration.config.annotation.MessagingAnnotationPostProcessor.postProcessAfterInitialization(MessagingAnnotationPostProcessor.java:131)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsAfterInitialization(AbstractAutowireCapableBeanFactory.java:422)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1579)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:539)
... 13 more
**Caused by: java.lang.IllegalArgumentException: localDirectory must not be null**
at org.springframework.util.Assert.notNull(Assert.java:112)
at org.springframework.integration.file.remote.synchronizer.AbstractInboundFileSynchronizingMessageSource.afterPropertiesSet(AbstractInboundFileSynchronizingMessageSource.java:132)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1633)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1570)
... 28 more
thanks
-Ramesh
The operation:
ftpInboundFileSynchronizer.synchronizeToLocalDirectory(localDirectory);
isn't for your responsibility.
I'm sure you meant exactly this setter:
FtpInboundFileSynchronizingMessageSource.setLocalDirectory(localDirectory);
In other words your #InboundChannelAdapter should look like this:
#Bean
#InboundChannelAdapter(value = "receiveChannel", poller = #Poller(fixedRate="1000"))
public MessageSource pollFtpForFiles() {
File localDirectory = new File(sftpProperties.localDirectory);
System.err.println("LocalDirectory::"+localDirectory.getAbsolutePath()+"::exists::"+localDirectory.isDirectory());
FtpInboundFileSynchronizer ftpInboundFileSynchronizer = new FtpInboundFileSynchronizer(ftpSessionFactory());
ftpInboundFileSynchronizer.setRemoteDirectory(sftpProperties.remoteDirectory);
FtpInboundFileSynchronizingMessageSource messageSource = new FtpInboundFileSynchronizingMessageSource(ftpInboundFileSynchronizer);
messageSource.setLocalDirectory(localDirectory);
return messageSource;
}
Related
I have got this error in my 'normal' code and was able to reproduce it in one simple junit test.
This error is thrown by using .route(...)..subFlowMapping(...)
If I comment .route(..) code out then test runs successful.
Could please someone explain why does Spring Integration try to find 'true' channel instead to route to true subflow?
#Test
public void testDynaSubFlowCreation() {
Flux<Message<?>> messageFlux = Flux.just("1,2,3,4").map(v -> v.split(",")).flatMapIterable(Arrays::asList)
.map(Integer::parseInt).map(GenericMessage<Integer>::new);
QueueChannel resultChannel = new QueueChannel();
IntegrationFlow integrationFlow = IntegrationFlows
.from(messageFlux)
.<Integer, Boolean>route(p->p % 2 == 0, m->m
.subFlowMapping(true, sf-> sf.<Integer, String>transform(em->{return "even:"+em;}).log())
.subFlowMapping(false, sf-> sf.<Integer, String>transform(em->{return "odd:"+em;}).log())
.defaultOutputToParentFlow()
)
.log(l -> "!!!!!!!!!!!!!!!!!!!!!!! end int="+l)
.channel(resultChannel)
.get();
this.flowContext.registration(integrationFlow).register();
int queueSize = resultChannel.getQueueSize();
assertThat(queueSize).as("queueSize").isEqualTo(4);
}
2018-02-21 17:33:27,541 [main] DEBUG reactor.util.Loggers$LoggerFactory - Using Slf4j logging framework
2018-02-21 17:33:28,184 [main] DEBUG o.s.i.handler.LoggingHandler - _org.springframework.integration.errorLogger.handler received message: ErrorMessage [payload=org.springframework.messaging.MessagingException: failed to resolve channel name 'false'; nested exception is org.springframework.messaging.core.DestinationResolutionException: failed to look up MessageChannel with name 'false' in the BeanFactory.; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'false' available, failedMessage=GenericMessage [payload=1, headers={id=684db1df-ee6e-f35e-8332-168cee2a1681, timestamp=1519230808175}], headers={id=621649c0-b8a0-4573-9220-c38891544043, timestamp=1519230808181}]
2018-02-21 17:33:28,188 [main] ERROR o.s.i.handler.LoggingHandler - org.springframework.messaging.MessagingException: failed to resolve channel name 'false'; nested exception is org.springframework.messaging.core.DestinationResolutionException: failed to look up MessageChannel with name 'false' in the BeanFactory.; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'false' available, failedMessage=GenericMessage [payload=1, headers={id=684db1df-ee6e-f35e-8332-168cee2a1681, timestamp=1519230808175}]
at org.springframework.integration.router.AbstractMappingMessageRouter.resolveChannelForName(AbstractMappingMessageRouter.java:227)
at org.springframework.integration.router.AbstractMappingMessageRouter.addChannelFromString(AbstractMappingMessageRouter.java:258)
at org.springframework.integration.router.AbstractMappingMessageRouter.addToCollection(AbstractMappingMessageRouter.java:296)
at org.springframework.integration.router.AbstractMappingMessageRouter.determineTargetChannels(AbstractMappingMessageRouter.java:186)
at org.springframework.integration.router.AbstractMessageRouter.handleMessageInternal(AbstractMessageRouter.java:171)
at org.springframework.integration.handler.AbstractMessageHandler.handleMessage(AbstractMessageHandler.java:141)
at org.springframework.integration.handler.AbstractMessageHandler.onNext(AbstractMessageHandler.java:165)
at org.springframework.integration.handler.AbstractMessageHandler.onNext(AbstractMessageHandler.java:51)
at org.springframework.integration.endpoint.ReactiveStreamsConsumer$1.hookOnNext(ReactiveStreamsConsumer.java:138)
at org.springframework.integration.endpoint.ReactiveStreamsConsumer$1.hookOnNext(ReactiveStreamsConsumer.java:127)
at reactor.core.publisher.BaseSubscriber.onNext(BaseSubscriber.java:158)
at reactor.core.publisher.FluxRetry$RetrySubscriber.onNext(FluxRetry.java:79)
at reactor.core.publisher.FluxPeek$PeekSubscriber.onNext(FluxPeek.java:185)
at reactor.core.publisher.FluxPublish$PublishSubscriber.drain(FluxPublish.java:457)
at reactor.core.publisher.FluxPublish$PublishSubscriber.onNext(FluxPublish.java:263)
at reactor.core.publisher.FluxCreate$IgnoreSink.next(FluxCreate.java:571)
at reactor.core.publisher.FluxCreate$SerializedSink.next(FluxCreate.java:146)
at org.springframework.integration.channel.FluxMessageChannel.doSend(FluxMessageChannel.java:65)
at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:438)
at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:388)
at reactor.core.publisher.FluxPeekFuseable$PeekFuseableSubscriber.poll(FluxPeekFuseable.java:310)
at reactor.core.publisher.FluxPublish$PublishSubscriber.drain(FluxPublish.java:411)
at reactor.core.publisher.FluxPublish$PublishSubscriber.onSubscribe(FluxPublish.java:224)
at reactor.core.publisher.FluxPeekFuseable$PeekFuseableSubscriber.onSubscribe(FluxPeekFuseable.java:172)
at reactor.core.publisher.FluxPeekFuseable$PeekFuseableSubscriber.onSubscribe(FluxPeekFuseable.java:172)
at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onSubscribe(FluxMapFuseable.java:90)
at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onSubscribe(FluxMapFuseable.java:90)
at reactor.core.publisher.FluxFlattenIterable$FlattenIterableSubscriber.onSubscribe(FluxFlattenIterable.java:206)
at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onSubscribe(FluxMapFuseable.java:90)
at reactor.core.publisher.FluxJust.subscribe(FluxJust.java:68)
at reactor.core.publisher.FluxMapFuseable.subscribe(FluxMapFuseable.java:63)
at reactor.core.publisher.FluxFlattenIterable.subscribe(FluxFlattenIterable.java:107)
at reactor.core.publisher.FluxMapFuseable.subscribe(FluxMapFuseable.java:63)
at reactor.core.publisher.FluxMapFuseable.subscribe(FluxMapFuseable.java:63)
at reactor.core.publisher.FluxPeekFuseable.subscribe(FluxPeekFuseable.java:86)
at reactor.core.publisher.FluxPeekFuseable.subscribe(FluxPeekFuseable.java:86)
at reactor.core.publisher.FluxPublish.connect(FluxPublish.java:99)
at reactor.core.publisher.ConnectableFlux.connect(ConnectableFlux.java:99)
at java.util.concurrent.ConcurrentHashMap$ValuesView.forEach(ConcurrentHashMap.java:4707)
at org.springframework.integration.channel.FluxMessageChannel.subscribe(FluxMessageChannel.java:77)
at org.springframework.integration.endpoint.ReactiveStreamsConsumer.doStart(ReactiveStreamsConsumer.java:127)
at org.springframework.integration.endpoint.AbstractEndpoint.start(AbstractEndpoint.java:162)
at org.springframework.integration.config.ConsumerEndpointFactoryBean.start(ConsumerEndpointFactoryBean.java:349)
at org.springframework.integration.dsl.StandardIntegrationFlow.start(StandardIntegrationFlow.java:102)
at org.springframework.integration.dsl.context.IntegrationFlowRegistration.start(IntegrationFlowRegistration.java:136)
at org.springframework.integration.dsl.context.IntegrationFlowContext.register(IntegrationFlowContext.java:108)
at org.springframework.integration.dsl.context.IntegrationFlowContext.access$500(IntegrationFlowContext.java:66)
at org.springframework.integration.dsl.context.IntegrationFlowContext$IntegrationFlowRegistrationBuilder.register(IntegrationFlowContext.java:238)
at com.lr.m3integration.DynaFlowTests.testDynaSubFlowCreation(DynaFlowTests.java:124)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.springframework.test.context.junit4.statements.RunBeforeTestExecutionCallbacks.evaluate(RunBeforeTestExecutionCallbacks.java:73)
at org.springframework.test.context.junit4.statements.RunAfterTestExecutionCallbacks.evaluate(RunAfterTestExecutionCallbacks.java:83)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:251)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:97)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:190)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:538)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:760)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:460)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:206)
Caused by: org.springframework.messaging.core.DestinationResolutionException: failed to look up MessageChannel with name 'false' in the BeanFactory.; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'false' available
at org.springframework.integration.support.channel.BeanFactoryChannelResolver.resolveDestination(BeanFactoryChannelResolver.java:117)
at org.springframework.integration.support.channel.BeanFactoryChannelResolver.resolveDestination(BeanFactoryChannelResolver.java:46)
at org.springframework.integration.router.AbstractMappingMessageRouter.resolveChannelForName(AbstractMappingMessageRouter.java:223)
... 80 more
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'false' available
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:687)
at org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:1205)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:292)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:205)
at org.springframework.integration.support.channel.BeanFactoryChannelResolver.resolveDestination(BeanFactoryChannelResolver.java:89)
... 82 more
#artem-bilan:
I'm not completely sure that dynamically registration is a root of a problem.
I configured the same flow statically, like this:
#EnableIntegration
#Configuration
public class IntegrationTestConfig {
#Bean
public QueueChannel resultChannel() {
return new QueueChannel();
}
#Bean
public Flux<Message<?>> messageFlux(){
return Flux.just("1,2,3,4").map(v -> v.split(",")).flatMapIterable(Arrays::asList)
.map(Integer::parseInt).map(GenericMessage<Integer>::new);
}
#Bean
public MessageChannel inputChannel() {
return MessageChannels.direct().get();
}
#Bean
public IntegrationFlow withSubFlows() {
return IntegrationFlows
// .from(inputChannel())
.from(messageFlux())
.<Integer, Boolean>route(p->p % 2 == 0, m->m
.subFlowMapping(true, sf-> sf.<Integer, String>transform(em->{return "even:"+em;}).log().bridge())
.subFlowMapping(false, sf-> sf.<Integer, String>transform(em->{return "odd:"+em;}).log().bridge())
.defaultOutputToParentFlow()
)
.log(l -> "!!!!!!!!!!!!!!!!!!!!!!! end int="+l)
.channel(resultChannel())
.get();
}
}
#RunWith(SpringRunner.class)
#SpringIntegrationTest
#SpringBootTest
#Autowired
public QueueChannel resultChannel;
#Autowired
public MessageChannel inputChannel;
#Test
public void testSubFlowCreation() {
// fill input channel
IntStream.range(0,4).forEach(i-> inputChannel.send(MessageBuilder.withPayload(i).build()));
// receive results after flow processing
assertThat(resultChannel.getReceiveCount()).as("receiveCount").isEqualTo(0);
assertThat(resultChannel.receive(1000)).as("message").isNotNull();
assertThat(resultChannel.getQueueSize()).as("queueSize").isEqualTo(3);
}
}
By executing with input=messageFlux() you will get the same error.
By executing with input=inputChannel() junit test runs green.
Confirmed. This is a bug in the RouterSpec. We can't use subFlowMapping() for dynamically registered flows for now. Just because the logic there is based on the ContextRefreshedEvent, which happens only once in the application context startup: https://jira.spring.io/browse/INT-4411
The below class is used to poll for a file in a directory and trigger the spring batch once a file is received in a directory. I am getting some error, which I am not able to figure out. please advice.
Also, if there is some sample code example to do the same, please refer me to that location.
#Configuration
class FilePollingIntegrationFlow {
#Autowired
private ApplicationContext applicationContext;
// this is the integration flow that foirst polls for messages and then trigger the spring batch job
#Bean
public IntegrationFlow inboundFileIntegration(#Value("${inbound.file.poller.fixed.delay}") long period,
#Value("${inbound.file.poller.max.messages.per.poll}") int maxMessagesPerPoll,
TaskExecutor taskExecutor,
MessageSource<File> fileReadingMessageSource,
JobLaunchingGateway jobLaunchingGateway) {
return IntegrationFlows.from(fileReadingMessageSource,
c -> c.poller(Pollers.fixedDelay(period)
.taskExecutor(taskExecutor)
.maxMessagesPerPoll(maxMessagesPerPoll)))
.transform(Transformers.fileToString())
.channel(ApplicationConfiguration.INBOUND_CHANNEL)
.handle((p, h) -> {
System.out.println("Testing:::::"+p);
return p;
})
.handle(fileMessageToJobRequest())
.handle(jobLaunchingGateway(),"toRequest")
.channel(MessageChannels.queue())
.get();
}
#Bean
public FileMessageToJobRequest fileMessageToJobRequest() {
FileMessageToJobRequest fileMessageToJobRequest = new FileMessageToJobRequest();
fileMessageToJobRequest.setFileParameterName("input.file.name");
// fileMessageToJobRequest.setJob(personJob());
System.out.println("FilePollingIntegrationFlow::fileMessageToJobRequest::::Job launched successfully!!!");
return fileMessageToJobRequest;
}
#Bean
public JobLaunchingGateway jobLaunchingGateway() {
SimpleJobLauncher simpleJobLauncher = new SimpleJobLauncher();
// simpleJobLauncher.setJobRepository(jobRepository);
simpleJobLauncher.setTaskExecutor(new SyncTaskExecutor());
JobLaunchingGateway jobLaunchingGateway = new JobLaunchingGateway(simpleJobLauncher);
System.out.println("FilePollingIntegrationFlow::jobLaunchingGateway::::Job launched successfully!!!");
return jobLaunchingGateway;
}
//This is another class used for batch job trigger
public class FileMessageToJobRequest {
private Job job;
private String fileParameterName;
public void setFileParameterName(String fileParameterName) {
this.fileParameterName = fileParameterName;
}
public void setJob(Job job) {
this.job = job;
}
#Transformer
public JobLaunchRequest toRequest(Message<File> message) {
JobParametersBuilder jobParametersBuilder =
new JobParametersBuilder();
jobParametersBuilder.addString(fileParameterName,
message.getPayload().getAbsolutePath());
return new JobLaunchRequest(job, jobParametersBuilder.toJobParameters());
}
}
I am getting the below error:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'inboundFileIntegration' defined in class path resource [com/porterhead/integration/file/FilePollingIntegrationFlow.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.integration.dsl.IntegrationFlow]: Factory method 'inboundFileIntegration' threw exception; nested exception is java.lang.IllegalArgumentException: Target object of type [class org.springframework.batch.integration.launch.JobLaunchingGateway] has no eligible methods for handling Messages.
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:599)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1123)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1018)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:510)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:772)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:839)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:538)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:766)
at org.springframework.boot.SpringApplication.createAndRefreshContext(SpringApplication.java:361)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:307)
at org.springframework.boot.builder.SpringApplicationBuilder.run(SpringApplicationBuilder.java:134)
at com.porterhead.Application.main(Application.java:23)
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.integration.dsl.IntegrationFlow]: Factory method 'inboundFileIntegration' threw exception; nested exception is java.lang.IllegalArgumentException: Target object of type [class org.springframework.batch.integration.launch.JobLaunchingGateway] has no eligible methods for handling Messages.
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:189)
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:588)
... 16 common frames omitted
Caused by: java.lang.IllegalArgumentException: Target object of type [class org.springframework.batch.integration.launch.JobLaunchingGateway] has no eligible methods for handling Messages.
at org.springframework.integration.util.MessagingMethodInvokerHelper.findHandlerMethodsForTarget(MessagingMethodInvokerHelper.java:494)
at org.springframework.integration.util.MessagingMethodInvokerHelper.<init>(MessagingMethodInvokerHelper.java:226)
at org.springframework.integration.util.MessagingMethodInvokerHelper.<init>(MessagingMethodInvokerHelper.java:135)
at org.springframework.integration.util.MessagingMethodInvokerHelper.<init>(MessagingMethodInvokerHelper.java:139)
at org.springframework.integration.handler.MethodInvokingMessageProcessor.<init>(MethodInvokingMessageProcessor.java:52)
at org.springframework.integration.handler.ServiceActivatingHandler.<init>(ServiceActivatingHandler.java:45)
at org.springframework.integration.dsl.IntegrationFlowDefinition.handle(IntegrationFlowDefinition.java:982)
at org.springframework.integration.dsl.IntegrationFlowDefinition.handle(IntegrationFlowDefinition.java:964)
at com.porterhead.integration.file.FilePollingIntegrationFlow.inboundFileIntegration(FilePollingIntegrationFlow.java:85)
at com.porterhead.integration.file.FilePollingIntegrationFlow$$EnhancerBySpringCGLIB$$c1cfa1e9.CGLIB$inboundFileIntegration$1(<generated>)
at com.porterhead.integration.file.FilePollingIntegrationFlow$$EnhancerBySpringCGLIB$$c1cfa1e9$$FastClassBySpringCGLIB$$4ce6110e.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:228)
at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:356)
at com.porterhead.integration.file.FilePollingIntegrationFlow$$EnhancerBySpringCGLIB$$c1cfa1e9.inboundFileIntegration(<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:162)
... 17 common frames omitted
Please advice.
Since your FileMessageToJobRequest.toRequest() is marked with the #Transformer you should consider to use .transform() instead.
Also I see that you use that toRequest method name for the JobLaunchingGateway what is definitely wrong. So, the proper way to go is like this:
.transform(fileMessageToJobRequest())
.handle(jobLaunchingGateway())
The sample you are looking for is in the Spring Batch Reference Manual.
I am getting InstanceAlreadyExistsException while trying to deploy in tomcat 8 in linux server the code with Spring Integration having 2 separate flows. I referred several forums and still not able to find a solution for this. But am not getting this exception while testing in my local tomcat 8 in windows platform. Any input is appreciated.
Stacktrace -
2016-08-30 14:27:40 ERROR SpringApplication:838 - Application startup failed
org.springframework.jmx.export.UnableToRegisterMBeanException: Unable to register MBean [getCities.channel#0] with key 'org.springframework.integration:type=MessageChannel,name=getCities.channel#0'; nested exception is javax.management.InstanceAlreadyExistsException: org.springframework.integration:type=MessageChannel,name=getCities.channel#0
at org.springframework.jmx.export.MBeanExporter.registerBeanNameOrInstance(MBeanExporter.java:625) ~[spring-context-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.integration.monitor.IntegrationMBeanExporter.registerChannels(IntegrationMBeanExporter.java:675) ~[spring-integration-jmx-4.3.1.RELEASE.jar:4.3.1.RELEASE]
at org.springframework.integration.monitor.IntegrationMBeanExporter.afterSingletonsInstantiated(IntegrationMBeanExporter.java:271) ~[spring-integration-jmx-4.3.1.RELEASE.jar:4.3.1.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:796) ~[spring-beans-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:861) ~[spring-context-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:541) ~[spring-context-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:122) ~[spring-boot-1.4.0.RELEASE.jar:1.4.0.RELEASE]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:759) [spring-boot-1.4.0.RELEASE.jar:1.4.0.RELEASE]
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:369) [spring-boot-1.4.0.RELEASE.jar:1.4.0.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:313) [spring-boot-1.4.0.RELEASE.jar:1.4.0.RELEASE]
at org.springframework.boot.web.support.SpringBootServletInitializer.run(SpringBootServletInitializer.java:150) [spring-boot-1.4.0.RELEASE.jar:1.4.0.RELEASE]
at org.springframework.boot.web.support.SpringBootServletInitializer.createRootApplicationContext(SpringBootServletInitializer.java:130) [spring-boot-1.4.0.RELEASE.jar:1.4.0.RELEASE]
at org.springframework.boot.web.support.SpringBootServletInitializer.onStartup(SpringBootServletInitializer.java:86) [spring-boot-1.4.0.RELEASE.jar:1.4.0.RELEASE]
at org.springframework.web.SpringServletContainerInitializer.onStartup(SpringServletContainerInitializer.java:169) [spring-web-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5261) [catalina.jar:8.0.35]
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:147) [catalina.jar:8.0.35]
at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:725) [catalina.jar:8.0.35]
at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:701) [catalina.jar:8.0.35]
at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:717) [catalina.jar:8.0.35]
at org.apache.catalina.startup.HostConfig.deployWAR(HostConfig.java:940) [catalina.jar:8.0.35]
at org.apache.catalina.startup.HostConfig$DeployWar.run(HostConfig.java:1816) [catalina.jar:8.0.35]
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) [?:1.8.0_91]
at java.util.concurrent.FutureTask.run(FutureTask.java:266) [?:1.8.0_91]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [?:1.8.0_91]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [?:1.8.0_91]
at java.lang.Thread.run(Thread.java:745) [?:1.8.0_91]
Caused by: javax.management.InstanceAlreadyExistsException: org.springframework.integration:type=MessageChannel,name=getCities.channel#0
at com.sun.jmx.mbeanserver.Repository.addMBean(Repository.java:437) ~[?:1.8.0_91]
at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.registerWithRepository(DefaultMBeanServerInterceptor.java:1898) ~[?:1.8.0_91]
at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.registerDynamicMBean(DefaultMBeanServerInterceptor.java:966) ~[?:1.8.0_91]
at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.registerObject(DefaultMBeanServerInterceptor.java:900) ~[?:1.8.0_91]
at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.registerMBean(DefaultMBeanServerInterceptor.java:324) ~[?:1.8.0_91]
at com.sun.jmx.mbeanserver.JmxMBeanServer.registerMBean(JmxMBeanServer.java:522) ~[?:1.8.0_91]
at org.springframework.jmx.support.MBeanRegistrationSupport.doRegister(MBeanRegistrationSupport.java:195) ~[spring-context-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.jmx.export.MBeanExporter.registerBeanInstance(MBeanExporter.java:678) ~[spring-context-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.jmx.export.MBeanExporter.registerBeanNameOrInstance(MBeanExporter.java:615) ~[spring-context-4.3.2.RELEASE.jar:4.3.2.RELEASE]
The configuration is given below -
#Configuration
#EnableAutoConfiguration(exclude = JmxAutoConfiguration.class)
#EnableMBeanExport(registration = RegistrationPolicy.IGNORE_EXISTING)
#EnableAspectJAutoProxy
#EnableAsync
#EnableWebMvc
#ComponentScan(basePackages = "foobar")
#PropertySource("classpath:environments/dev.properties")
#Import({SecurityConfig.class, IntegrationConfig.class})
public class AppConfig extends WebMvcConfigurerAdapter {
#Autowired
Environment environment;
#Bean
#Scope(BeanScopes.SINGLETON)
public Logger getLogger() {
return LoggerFactory.getLogger("SampleService");
}
#Bean
public LoggerAspect loggerAspect() {
return new LoggerAspect(getLogger(), jsonMapper());
}
}
#EnableIntegration
#IntegrationComponentScan(basePackages = "fooBar")
#Import({FirstConfig.class, SecondConfig.class})
public class IntegrationConfig {
}
#MessagingGateway
public interface FirstGateway {
#Gateway(requestChannel = "getCitiesChannel")
CityModel[] getCities(Message<FirstPayload> message);
}
public class FirstConfig {
#Bean
public MessageChannel getCitiesChannel() {
return MessageChannels.direct().get();
}
#Bean
public IntegrationFlow sdsGetCities() {
return IntegrationFlows
.from("input")
.channel("getCitiesChannel")
.handle(foobar)
.get();
}
}
#MessagingGateway
public interface SecondGateway {
#Gateway(requestChannel = "getProductDetailsChannel")
ProductModel getProductDetails(Message<SecondPayload> message);
}
public class SecondConfig {
#Bean
public MessageChannel getProductDetailsChannel() {
return MessageChannels.direct().get();
}
#Bean
public IntegrationFlow getProductDetails() {
return IntegrationFlows
.from("input")
.channel("getProductDetailsChannel")
.handle(foobar)
.get();
}
}
You don't show your #EnableIntegrationMBeanExport; if you are deploying 2 apps with similar flows, you need to put each app in a different domain #EnableIntegrationMBeanExport(defaultDomain="foo") and #EnableIntegrationMBeanExport(defaultDomain="bar"), so
org.springframework.integration:type=MessageChannel,name=getCities.channel#0
becomes
foo:type=MessageChannel,name=getCities.channel#0
and
bar:type=MessageChannel,name=getCities.channel#0
If it's only one app (which it looks like) then it means the previous deployment didn't shut down properly.
try this
<context:mbean-export registration="replaceExisting"/>
I got this error when using an abstract base class for my integration tests.
I added #DirtiesContext to my base class, so that the application context would be flushed between each test.
I have a Sftp inbound flow and I got the session information from DefaultSftpSessionFactory. But I need to implement mulitple session information dynamically which I will get from database table. That means I have multiple number of Sftp server details that I need to implement in my integration flow. Now I have done with file transfer from single source to single destination but I need to implement multiple source to multiple destination. So can any one provide some pointer on this.
This is my session Factory...Here I have a single Sftp server information but how to configure multiple server details.
#Autowired
private DefaultSftpSessionFactory sftpSessionFactory;
#Bean
public DefaultSftpSessionFactory sftpSessionFactory() {
DefaultSftpSessionFactory factory = new DefaultSftpSessionFactory(
true);
factory.setHost("111.11.12.143");
factory.setPort(22);
factory.setUser("sftp");
factory.setPassword("*******");
return factory;
}
and this is my Sftp Inbound flow..
#Bean
public IntegrationFlow sftpInboundFlow() {
System.out.println("enter sftpInboundFlow....."
+ sftpSessionFactory.getSession());
return IntegrationFlows
.from(Sftp.inboundAdapter(this.sftpSessionFactory)
.preserveTimestamp(true).remoteDirectory(remDir)
.regexFilter(".*\\.txt$")
.localFilenameExpression("#this.toUpperCase()")
.localDirectory(new File(localDir))
.remoteFileSeparator("/"),
new Consumer<SourcePollingChannelAdapterSpec>() {
#Override
public void accept(SourcePollingChannelAdapterSpec e) {
e.id("sftpInboundAdapter")
.autoStartup(true)
.poller(Pollers.fixedRate(1000)
.maxMessagesPerPoll(1));
}
})
//.channel(MessageChannels.queue("sftpInboundResultChannel"))
.channel(sftpInboundResultChannel())
.get();
}
As suggested by Gary I am editing my post....
Hi Gary,
I am taking the reference from Github dynamic FTP example.
Through the ChannelResolver class I need to call my above DSL class. and set the dynamic value in context property without using XML.
In my ChannelResolver class I want some thing like this
StandardEnvironment env = new StandardEnvironment();
Properties props = new Properties();
props.setProperty("inbound.host", host); //I am getting the value of 'host' from a DB table.
PropertiesPropertySource pps = new PropertiesPropertySource("sftpprop", props);
env.getPropertySources().addLast(pps);
context.setEnvironment(env);
And my DSL class I need to use like this.
#Value("${inbound.host}")
private String host;
So in this way can I set dynamic value for String 'host' ?
I am editing my original post...........
In my Outbound dynamic resolver class I am doing like this
StandardEnvironment env = new StandardEnvironment();
Properties props = new Properties();
props.setProperty("outbound.host", host);
props.setProperty("outbound.port", String.valueOf(port));
props.setProperty("outbound.user", user);
props.setProperty("outbound.password", password);
props.setProperty("outbound.remote.directory", remoteDir);
props.setProperty("outbound.local.directory", localDir);
PropertiesPropertySource pps = new PropertiesPropertySource("ftpprops", props);
env.getPropertySources().addLast(pps);
ctx.setEnvironment(env);
And this is my dsl class....
#Autowired
private DefaultSftpSessionFactory sftpSessionFactory;
#Bean
public DefaultSftpSessionFactory sftpSessionFactory(#Value("${outbound.host}") String host, #Value("${outbound.port}") int port,
#Value("${outbound.user}") String user, #Value("${outbound.password}") String password
) {
DefaultSftpSessionFactory factory = new DefaultSftpSessionFactory(true);
factory.setHost(host);
factory.setPort(port);
factory.setUser(user);
factory.setPassword(password);
return factory;
}
#Bean
public IntegrationFlow fileInboundFlow(#Value("${outbound.local.directory}") String localDir)
{
return IntegrationFlows
.from(Files.inboundAdapter(new File(localDir)),
new Consumer<SourcePollingChannelAdapterSpec>() {
#Override
public void accept(SourcePollingChannelAdapterSpec e) {
e.autoStartup(true).poller(
Pollers.fixedDelay(5000)
.maxMessagesPerPoll(1));
}
})
.channel(sftpSendChannel())
.get();
}
#Bean
public IntegrationFlow sftpOutboundFlow(#Value("${outbound.remote.directory}") String remDir) {
return IntegrationFlows
.from(sftpSendChannel())
.handle(Sftp.outboundAdapter(this.sftpSessionFactory)
.useTemporaryFileName(false)
.remoteDirectory(remDir))
.get();
}
#Bean
public MessageChannel sftpSendChannel() {
return new DirectChannel();
}
#Bean
public static PropertySourcesPlaceholderConfigurer configurer1() {
return new PropertySourcesPlaceholderConfigurer();
}
And this the error log from console...
Aug 03, 2015 7:50:25 PM org.apache.catalina.core.StandardContext listenerStart
SEVERE: Exception sending context initialized event to listener instance of class org.springframework.web.context.ContextLoaderListener
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sftpOutBoundDsl': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private org.springframework.integration.sftp.session.DefaultSftpSessionFactory com.tcs.iux.ieg.sftp.dynamic.SftpOutBoundDsl.sftpSessionFactory; nested exception is java.lang.IllegalArgumentException: Could not resolve placeholder 'outbound.host' in string value "${outbound.host}"
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:334)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1204)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:538)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:476)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:302)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:229)
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:725)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:757)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:480)
at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:403)
at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:306)
at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:106)
at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4973)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5467)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1559)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1549)
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:744)
Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: private org.springframework.integration.sftp.session.DefaultSftpSessionFactory com.tcs.iux.ieg.sftp.dynamic.SftpOutBoundDsl.sftpSessionFactory; nested exception is java.lang.IllegalArgumentException: Could not resolve placeholder 'outbound.host' in string value "${outbound.host}"
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:555)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:87)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:331)
... 22 more
Caused by: java.lang.IllegalArgumentException: Could not resolve placeholder 'outbound.host' in string value "${outbound.host}"
at org.springframework.util.PropertyPlaceholderHelper.parseStringValue(PropertyPlaceholderHelper.java:174)
at org.springframework.util.PropertyPlaceholderHelper.replacePlaceholders(PropertyPlaceholderHelper.java:126)
at org.springframework.core.env.AbstractPropertyResolver.doResolvePlaceholders(AbstractPropertyResolver.java:204)
at org.springframework.core.env.AbstractPropertyResolver.resolveRequiredPlaceholders(AbstractPropertyResolver.java:178)
at org.springframework.context.support.PropertySourcesPlaceholderConfigurer$2.resolveStringValue(PropertySourcesPlaceholderConfigurer.java:175)
at org.springframework.beans.factory.support.AbstractBeanFactory.resolveEmbeddedValue(AbstractBeanFactory.java:800)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:917)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:904)
at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:815)
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:743)
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:466)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1113)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1008)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:505)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:476)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:302)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:229)
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.findAutowireCandidates(DefaultListableBeanFactory.java:1088)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1006)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:904)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:527)
... 24 more
It is currently not supported.
We have an open JIRA to add support for dynamic server selection but it's unlikely to be done in time for the upcoming 4.2 release.
You could work around it by writing your own custom delegating session factory that uses some criteria (e.g. a ThreadLocal) to determine which delegate factory to use.
EDIT:
As with the XML, you need a PropertySourcesPlaceholderConfigurer bean.
You should also use factory-method injection because the #Configuration class is created too early to have the #Value injected...
#Configuration
public class FooConfig {
#Bean
public DefaultSftpSessionFactory factory(
#Value("${inbound.host}") String host,
#Value("${inbound.port}") int port) {
DefaultSftpSessionFactory sf = new DefaultSftpSessionFactory();
sf.setHost(host);
sf.setPort(port);
return sf;
}
#Bean
public PropertySourcesPlaceholderConfigurer configurer() {
return new PropertySourcesPlaceholderConfigurer();
}
}
.
public class Testing {
#Test
public void test() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.register(FooConfig.class);
StandardEnvironment env = new StandardEnvironment();
Properties props = new Properties();
props.setProperty("inbound.host", "bar");
props.setProperty("inbound.port", "23");
PropertiesPropertySource pps = new PropertiesPropertySource("sftpprop", props);
env.getPropertySources().addLast(pps);
context.setEnvironment(env);
context.refresh();
DefaultSftpSessionFactory sessionFactory = context.getBean(DefaultSftpSessionFactory.class);
assertEquals("bar", TestUtils.getPropertyValue(sessionFactory, "host"));
context.close();
}
}
By the way, the delegating session factory will be in 4.2 after all.
EDIT2:
You can avoid the early instantiation of the config class and use global #Value injection, as long as you make the PSPC bean static...
#Configuration
public class FooConfig {
#Value("${foo}")
public String foo;
#Bean
public String earlyFoo() {
return this.foo;
}
#Bean
public String foo(#Value("${foo}") String foo) {
return foo;
}
#Bean
public static PropertySourcesPlaceholderConfigurer configurer() {
return new PropertySourcesPlaceholderConfigurer();
}
}
In this case, earlyFoo is populated as expected.
I haven't been able to find a way to force a JAXBException when marshalling for a JUnit test. Does anyone have any ideas?
Here is my marshalling code:
public String toXml() {
log.debug("Entered toXml method");
String result = null;
try {
JAXBContext jaxbContext = JAXBContext.newInstance(Config.class);
Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
StringWriter writer = new StringWriter();
jaxbMarshaller.marshal(this, writer);
result = writer.toString();
} catch (JAXBException e) {
log.error(e);
}
log.debug("Exiting toXml method");
return result;
}
There are different ways to create a JAXBException during a marshal operation:
1 - Marshal an Invalid Object
You can generate a JAXBException during a marshal operation by marshalling an instance of a class that the JAXBContext isn't aware of (i.e. Take your example and use it to marshal an instance of Foo). This will produce the following exception.
Exception in thread "main" javax.xml.bind.JAXBException: class forum13389277.Foo nor any of its super class is known to this context.
at com.sun.xml.bind.v2.runtime.JAXBContextImpl.getBeanInfo(JAXBContextImpl.java:594)
at com.sun.xml.bind.v2.runtime.XMLSerializer.childAsRoot(XMLSerializer.java:482)
at com.sun.xml.bind.v2.runtime.MarshallerImpl.write(MarshallerImpl.java:315)
at com.sun.xml.bind.v2.runtime.MarshallerImpl.marshal(MarshallerImpl.java:244)
at javax.xml.bind.helpers.AbstractMarshallerImpl.marshal(AbstractMarshallerImpl.java:95)
at forum13272288.Demo.main(Demo.java:27)
2 - Marshal to Invalid Output
If you try to marshal to an invalid output such as an OutputStream that has been closed:
FileOutputStream closedStream = new FileOutputStream("src/foo.xml");
closedStream.close();
jaxbMarshaller.marshal(this, closedStream);
Then you will get a MarshalException which is a subclass of JAXBException.
Exception in thread "main" javax.xml.bind.MarshalException
- with linked exception:
[java.io.IOException: Stream Closed]
at com.sun.xml.bind.v2.runtime.MarshallerImpl.write(MarshallerImpl.java:320)
at com.sun.xml.bind.v2.runtime.MarshallerImpl.marshal(MarshallerImpl.java:244)
at javax.xml.bind.helpers.AbstractMarshallerImpl.marshal(AbstractMarshallerImpl.java:95)
at forum13272288.Demo.main(Demo.java:27)
Caused by: java.io.IOException: Stream Closed
at java.io.FileOutputStream.writeBytes(Native Method)
at java.io.FileOutputStream.write(FileOutputStream.java:318)
at com.sun.xml.bind.v2.runtime.output.UTF8XmlOutput.flushBuffer(UTF8XmlOutput.java:413)
at com.sun.xml.bind.v2.runtime.output.UTF8XmlOutput.endDocument(UTF8XmlOutput.java:137)
at com.sun.xml.bind.v2.runtime.output.IndentingUTF8XmlOutput.endDocument(IndentingUTF8XmlOutput.java:165)
at com.sun.xml.bind.v2.runtime.XMLSerializer.endDocument(XMLSerializer.java:852)
at com.sun.xml.bind.v2.runtime.MarshallerImpl.postwrite(MarshallerImpl.java:369)
at com.sun.xml.bind.v2.runtime.MarshallerImpl.write(MarshallerImpl.java:316)
... 3 more