Java DSL Equivalent of Spring Integration Kafka Endpoint Configured in XML - java

I have the following XML configuration for a Kafka outbound channel adapter:
<int-kafka:outbound-channel-adapter id="kafkaOutboundChannelAdapter"
kafka-producer-context-ref="kafkaProducerContext"
auto-startup="true"
channel="activityOutputChannel">
<int:poller fixed-delay="1000" time-unit="MILLISECONDS" receive-timeout="0" task-executor="taskExecutor"/>
</int-kafka:outbound-channel-adapter>
<task:executor id="taskExecutor"
pool-size="5-25"
queue-capacity="20"
keep-alive="120"/>
This works just fine. I am trying to replicate this in the Java DSL, but I can't get too far. So far, I just have this:
.handle(Kafka.outboundChannelAdapter(kafkaConfig)
.addProducer(producerMetadata, brokerAddress)
.get());
I can't figure out how to add the taskExecutor and the poller with the DSL.
Any insight on how to incorporate these into my overall IntegrationFlow is appreciated.

The Spring Integration components (e.g. <int-kafka:outbound-channel-adapter>) consist with two beans: AbstractEndpoint to accept messages from the input-channel and MessageHandler to handle message.
So, Kafka.outboundChannelAdapter() is about MessageHandler. Any other endpoint-specific properties are up to the second Consumer<GenericEndpointSpec<H>> endpointConfigurer argument of .handle() EIP-method:
.handle(Kafka.outboundChannelAdapter(kafkaConfig)
.addProducer(producerMetadata, brokerAddress),
e -> e.id("kafkaOutboundChannelAdapter")
.poller(p -> p.fixedDelay(1000, TimeUnit.MILLISECONDS)
.receiveTimeout(0)
.taskExecutor(this.taskExecutor)));
See Reference Manual for more information.

Related

Converting Spring xml config to java

I've an XML config for mail service in spring, that I'd like to transform to JAVA config.
XML Looks like this
<int:chain id="chain"
input-channel="outMailError"
output-channel="outMailEntry">
<int:poller max-messages-per-poll="1" fixed-rate="20000" />
<int:transformer ref="mailSendErrorTransformer" />
</int:chain>
<int:channel id="outMailError">
<int:queue capacity="500" />
</int:channel>
<int:channel id="outboundMailEntry" />
I was able to convert the channels to
#Bean
public DirectChannel outboundMailEntry() {
return new DirectChannel();
}
#Bean
public QueueChannel outboundMailErrorChannel() {
return new QueueChannel(500);
}
But I don't know how to the same for int:chain. I was able to debug and find out what type of bean does spring instantiate for "chain" part of xml - it is PollingConsumer that takes 2 params PollableChannel inputChannel, MessageHandler handler.
The first one is not a problem since I already have that, it is the
#Qualifier("outMailError")
QueueChannel channel
But I do not know about the second one... Spring itself initializes some MessageHandlerChain but I was unable to to set the outMailEntry to it and also dont know about the poller and transformer.. any ídeas?
There is no chain equivalent in Java Config. It was designed especially for XML to let to minimize XML coding.
On the other hand it doesn't look like you need that <chain> at all: you have only one <int:transformer> over there.
In Java Config you would use a #Trasnoformer annotation on your mailSendErrorTransformer method with appropriate inputChannel and outputChannel attributes. The <int:poller> equivalent is also present over there as a poller attribute with resective #Poller configuration.
See more info in the docs starting from here: https://docs.spring.io/spring-integration/docs/current/reference/html/overview.html#configuration-enable-integration

How to solve exception with inbound-channel-adapter poller?

Сould not find an answer.
Spring version 5.0.6.
My config:
<int:channel id="data"/>
<int:inbound-channel-adapter
id="dataAdapter"
channel="data"
auto-startup="false"
ref="dataGetter"
method="myMessageSource">
<int:poller max-messages-per-poll="10"/>
</int:inbound-channel-adapter>
<beans:bean
class="org.endpoints.DataGetter"
id="dataGetter"/>
Throw exception:
Configuration problem: A <poller> must have one and only one trigger configuration.
If no poller:
No poller has been defined for channel-adapter 'dataAdapter', and no default poller is available within the context.
How to properly setup the poller?
Look at your config:
<int:poller max-messages-per-poll="10"/>
You don't meet the condition to have or fixed-delay, or fixed-rate, or cron, or just trigger reference: https://docs.spring.io/spring-integration/docs/5.0.6.RELEASE/reference/html/messaging-endpoints-chapter.html#endpoint-namespace

How to create channels with Spring 4 annotation based?

I want to create a socket channel with a rendezvous queue where a client and server can exchange a simple message.
But I already fail to convert the following xml to annotation based spring-4 configuration:
<int:channel id="rendezvousChannel"/>
<int:rendezvous-queue/>
</int:channel>
How would this look like in spring 4?
The short answer:
#Bean
public PollableChannel rendezvousChannel() {
return new RendezvousChannel();
}
Can you explain why it was an issue for you to find the solution from your side?
Any XML component is backed by some Java class anyway and most cases their names reflect the XML component names.

Spring Integration + Spring AMQP: How can I passing MessageProperties to int:service-activator?

Configs like this:
<int-amqp:inbound-channel-adapter connection-factory="connectionFactory" queue-names="#{prop['mq.queue.logging']}"
channel="emailLoggingChannel" message-converter="jsonMessageConverter" error-channel="errorChannel" />
<int:channel id="emailLoggingChannel"/>
<int:service-activator id="handleEmailLogging" input-channel="emailLoggingChannel"
ref="emailLoggingService" method="insertOrUpdate"/>
My question is:
How can I passing properties of AMQP message to int:service-activator?
Appreciated.
The AMQP MessageProperties are mepped to the MessageHeaders.
By default only standard AMQP properties (headers) are mepped.
To map all of them including any custom properties you should use this
mapped-request-headers="*"
for the <int-amqp:inbound-channel-adapter>.
See more info in the Reference Manual.

Launching Spring batch job

I have a problem where in I need to receive a series of messages from an MQ queue and write this to a file and initiate a spring batch job with the file as input. Right now I'm thinking of launching the job with wired #Autowired JobLauncher jobLauncher and #Autowired Job job; from the MDB itself.But I feel this is not a good approach as spring batch may create a series of threads and EJB as such doesnt support multi threading.
Is there any other effective way to do this ? I dont want to use quartz scheduler or anything else since it adds complexity. Is there any interface in spring batch itself which launches a job soon after a file comes in a directory ? Any leads in doing this better would be appreciated.
Thanks.
I have a problem where in I need to receive a series of messages from an MQ queue and write this to a file and initiate a spring batch job with the file as input
One way to do that would be engage a bit of Spring Integration, where you would have a file poller, that would poll for a new file:
<file:inbound-channel-adapter id="filePoller"
channel="filesAreComing"
directory="file:${input.directory}"
filename-pattern="test*" />
Adapt a file message ( java.io.File ) to a file name ( String ), since that is what Spring Batch needs. This can be done with a JobLauncher adapter, that is already available from Spring Batch Admin here:
#ServiceActivator
public JobLaunchRequest adapt(File file) throws NoSuchJobException {
JobParameters jobParameters = new JobParametersBuilder().addString(
"input.file", file.getAbsolutePath()).toJobParameters();
return new JobLaunchRequest(job, jobParameters);
}
wrap it to a JobLaunchRequest ( which is just a holder for a Job and JobParameters ) and send this request [as a message] to JobLaunchingMessageHandler:
<service-activator input-channel="jobLauncher">
<beans:bean class="org.springframework.batch.integration.launch.JobLaunchingMessageHandler">
<beans:constructor-arg ref="jobLauncher" />
</beans:bean>
</service-activator>
that would launch the job.
"input.file" is a parameter that is bound at runtime ( hence #{...} ):
<bean id="reader" class="org.springframework.batch.item.file.FlatFileItemReader" scope="step">
<property name="resource" value="#{jobParameters[input.file]}" />
... line mapper and other props
</bean>
I'm not sure I understand why you have a message queue, a message-driven POJO/EJB, AND a batch job.
One way to do it is to have the message driven POJO/EJB do the work. It's already an asynch process. You can pool the message driven beans so there are sufficient workers to handle the load. Why add complexity?
If you'd rather not do that, forget the queue and use Spring Batch on its own. I wouldn't do both.

Categories