Consider the following code which configures the polling of some SFTP servers. The configuration comes from a database.
@Bean
@RefreshScope
RotatingServerAdvice advice(DelegatingSessionFactory<LsEntry> delegatingSessionFactory) {
List<RotationPolicy.KeyDirectory> keyDirectories = interfaceRepo.findAll().stream()
.filter(Interface::isReceivingData)
.map(x -> new RotationPolicy.KeyDirectory(
new SessionFactoryKey(x.getHostname(), x.getPort(), x.getUsername()),
x.getDirectory()()))
.toList();
return keyDirectories.isEmpty() ? null : new RotatingServerAdvice(delegatingSessionFactory, keyDirectories);
}
@Bean
ConcurrentMetadataStore store() {
return new PropertiesPersistingMetadataStore();
}
@Bean
public IntegrationFlow flow(ObjectProvider<RotatingServerAdvice> adviceProvider,
DelegatingSessionFactory<LsEntry> delegatingSessionFactory, ConcurrentMetadataStore store) {
RotatingServerAdvice advice = adviceProvider.getIfAvailable();
return advice == null ? null
: IntegrationFlows
.from(Sftp.inboundAdapter(delegatingSessionFactory)
.filter(new SftpPersistentAcceptOnceFileListFilter(store, "rotate_"))
.localDirectory(new File("C:\\tmp\\sftp"))
.localFilenameExpression("#remoteDirectory + T(java.io.File).separator + #root")
.remoteDirectory("."), e -> e.poller(Pollers.fixedDelay(1).advice(advice)))
.channel(MessageChannels.queue("files")).get();
}
I'm trying to handle the case when the database is empty. I can't create a RotatingServerAdvice
with an empty List<RotationPolicy.KeyDirectory>
because there is an Assert.notNull
in Spring's code, so I'm returning null
instead of a RotatingServerAdvice
instance.
In flow
I tried to handle the null
case with ObjectProvider
when I call getIfAvailable
on it it just returns me a CGLib proxy backed with what I suspect to be a NullBean
(because toString()
returns "null"
).
I have no solution to test if that bean is a NullBean
or an actual instance of RotatingServerAdvice
because of the proxy that hides the internal implementation.
Also there is no @Conditional
annotation that would allow me to query the database.
How do I solve this?
This works for me in some my projects:
@Autowired(required = false) RotatingServerAdvice rotatingServerAdvice
However the IntegrationFlow
is not designed for refreshing: it is a composite logical component to populated Spring Integration beans according to the provided config.
I would suggest to implement some delegating MessageSourceMutator
which would use that RotatingServerAdvice
if that is not null, otherwise default method impls. This way you always can inject it into your flow and can mark it with the @RefreshScope
to be able to re-initialize with newly created RotatingServerAdvice
delegate. Same @Autowired(required = false)
injection still applies.