I have already created a simple tcp server with spring integration which keeps a connection alive and responses to each request during the connection.
In that requestMethod, I'm also able to read the MessageHeder to get the connectionId.
Now I want to send messages from the server to the client.
As far as i understood the documentation i need to put the connectionid in the MessageHeader and then send the message. But I can't figure out how to do the latter one. I have the Message ready but how do i send/push it out?
Here is my xml-configuration:
<bean id="lfSerializer" class="org.springframework.integration.ip.tcp.serializer.ByteArrayLfSerializer"/>
<int-ip:tcp-connection-factory
id="socketserver"
type="server"
port="30124"
using-nio="true"
deserializer="lfSerializer"
serializer="lfSerializer"
single-use="false"/>
<int-ip:tcp-inbound-channel-adapter id="inboundServer"
channel="inputChannel"
connection-factory="socketserver"/>
<int-ip:tcp-outbound-channel-adapter id="outboundServer"
channel="outputChannel"
connection-factory="socketserver"
/>
<int:channel id="inputChannel">
<int:interceptors>
<int:wire-tap channel="logger"/>
</int:interceptors>
</int:channel>
<int:channel id="outputChannel">
<int:interceptors>
<int:wire-tap channel="logger"/>
</int:interceptors>
</int:channel>
<int:logging-channel-adapter id="logger" level="DEBUG" log-full-message="true"/>
<int:service-activator input-channel="inputChannel"
output-channel="outputChannel"
ref="echoService"
method="test"/>
<bean id="echoService"
class="com.examples.EchoService" />
I also tried to create a bean and another serviceactivator for output, then autowired that bean and called it's "send" method, but I don't know what to implement in that send-method to send out a message.
If it's a simple request/response scenario use an inbound gateway instead of channel adapters and the framework will take care of the correlation for you. This is used in the sample app. Simply have your POJO method return the reply payload.
If you want to send arbitrary messages to the client (i.e. NOT request/reply but, say, in, out, out, in, out, out, out etc) then, yes, you need to build the messages yourself, inserting the ip_connectionId header.
To send them, there are several options:
Inject outputChannel into your code
#Autowired
private MessageChannel outputChannel;
Use a MessagingTemplate to send to the channel (or simply call its send(Message<?> message) method directly).
Or
Use a MessagingGateway with a void return method and inject the gateway into your code.
EDIT:
Note, that if you want to start sending messages before receiving anything, you can obtain the connection id via the connection opened event.
Related
I am new to spring integration and i want to write the below flow programmatically
I have below inbound channel adapter in which I query the DB and passing it to OutChannel
and from OutChannel to AccountOutputChannel. AccountOutputChannel has refernce of a class which calls onMessage when message is available on AccountOutputChannel
How can I do this all programmatically
<int-jdbc:inbound-channel-adapter id="jdbcInbound"
channel="OutChannel"
data-source="dataSource"
query="SELECT * FROM Accounts"
max-rows-per-poll="100"
row-mapper="AccountRowMapper">
<int:poller fixed-rate="1000"/>
</int-jdbc:inbound-channel-adapter>
<int:channel id="OutChannel"/>
<int:bridge input-channel="OutChannel" output-channel="AccountOutputChannel"/>
<int:channel id="AccountOutputChannel">
<int:dispatcher task-executor="executorPool"/>
</int:channel>
<int:service-activator input-channel="AccountOutputChannel" ref="AccountService" method="onMessage"/>
See similar question here: How to invoke Spring channel adapter from rest api?
The Inbound Channel Adapter is a thing by itself and it does its work via constant polling cycle. It just does not fit to your requirement.
Since you say you'd like to do something via REST call, then it is an event-driven by end-user action. Therefore you need to look into a <int-jdbc:outbound-gateway> instead which is going to receive a message via its input-channel and do some DB action and produce a reply for you.
See more in docs: https://docs.spring.io/spring-integration/reference/html/jdbc.html#jdbc-outbound-gateway.
In addition you may look into a #MessagingGateway contract to not deal with channels in your REST controller: https://docs.spring.io/spring-integration/reference/html/messaging-endpoints.html#gateway
We have a requirement where the external client are calling one of our spring integration inbound webservice gateway and we need to acknowledge them right away with a generic OK status. Meanwhile, the payload will be submitted to a channel for asynchronous processing and we don't need the response(email will be sent based on some business validation).
We tried using asynchronous gateway and executor channel(with task executor), but can't figure out how to make the gateway respond immediately. Both the cases it is working as a one way webservice with no response.
Configuration:
<context:component-scan base-package="com.myapp.springintegration" />
<channel id="helloWorldRequestChannel">
<dispatcher task-executor="taskExecutor"/>
</channel>
<channel id="helloWorldReplyChannel"/>
<task:executor id="taskExecutor" pool-size="2"/>
<gateway id="helloServiceGateway"
service-interface="com.myapp.springintegration.HelloService"
default-request-channel="helloWorldRequestChannel" default-reply-channel="helloWorldReplyChannel"/>
<service-activator input-channel="helloWorldRequestChannel" ref="helloServiceImpl" method="hello" />
I don't see any <int-ws:inbound-gateway> but the requirements may be implemented like this:
<int-ws:inbound-gateway request-channel="requestChannel"/>
<int:recipient-list-router input-channel="requestChannel">
<int:recipient channel="response" />
<int:recipient channel="process" />
</int:recipient-list-router>
<int:transformer input-channel="response" expression="'OK'"/>
<int:channel id="process">
<int:dispatcher task-executor="testExecutor"/>
</int:channel>
You send request to the recipient-list-router, that distributes your message to two other channels. The first one (response) just returns simple reply to the WS immediately. The second (process) shifts the message to the separate Thread, so the subscriber to that channel will do its work not blocking the WS Thread.
Hope I am clear.
I have a Spring-Integration TCP server with request and response and it works correctly. Well now I have to add a new layer to my application.
I have to put my message to an eh-cache db and then send back the ACK. Currently I have only a tcp clients but in the future I will have other sources, as the schema below.
Now the question is:
Can I configure this behavior using Spring-Integration?
I know that I can take the message on my ‘importService’ and put it on my eh-cache writing a code in this way:
public MyMessage handler(MyMessage message) {
try {
myCache.put(mykey, message)
} catch (Exception e) {
logger.error("unable to update" + e);
}
return message;
}
but I think it is not properly correct, and I was just wondering if I can configure my spring configuration file and add another end-point in order to create a chain.
My current config-file is:
<int-ip:tcp-connection-factory id="serverTcpConFact" type="server" port="5566" using-nio="false" single-use="false"
so-receive-buffer-size="8192"
so-send-buffer-size="8192"
so-tcp-no-delay="true"
task-executor="myTaskExecutor"
deserializer="serializer"
serializer="serializer"/>
<int-ip:tcp-inbound-channel-adapter id="tcpInboundAdapter"
channel="tcpInbound"
connection-factory="serverTcpConFact" />
<int:channel id="tcpInbound" />
<int:service-activator
output-channel="tcpOutbound"
input-channel="tcpInbound"
ref="importService"
method="handler" />
<bean id="importService" class="com.MyImportService" />
<int:channel id="tcpOutbound" />
<int-ip:tcp-inbound-gateway id="mygateway"
request-channel="tcpInbound"
reply-channel="tcpOutbound"
reply-timeout="6"/>
<int-ip:tcp-outbound-channel-adapter id="tcpOutboundAdapter"
channel="tcpOutbound"
connection-factory="serverTcpConFact" />
I was looking the public examples but I didn’t find an eh-cache example and a chain example.
Thank you !!
Well, looks like it just enough to move you Cache logic to the ChannelInterceptor:
<int:channel id="tcpInbound">
<int:interceptors>
<bean class="com.my.proj.si.CachePutChannelInterceptor"
</int:interceptors>
</int:channel>
And use this interceptor from any place when you need to use Cache.
How does I can achieve parallel processing in spring-integration with recipient-list-router.
My goal is the router has to be content based and sending messages to various channel on parallel processing just like multicast. I tried multicast in Camel with camel-spring-integration but couldn't configure it for content based
Please help if something cane be done
Thanks
If I'm understanding the question right, you just need to use publish subscribe channels as the output channels of the router. The router will direct the message to the right pubsub channel based on content, then all handlers subscribed to that channel will be executed in parallel, assuming the output channel task executor is configured to have multiple threads.
<int:publish-subscribe-channel id="channel1" task-executor="someExecutor"/>
<int:publish-subscribe-channel id="channel2" task-executor="someExecutor"/>
<int:recipient-list-router id="customRouter" input-channel="routingChannel">
<int:recipient channel="channel1" selector-expression="payload.equals('foo')"/>
<int:recipient channel="channel2" selector-expression="headers.containsKey('bar')"/>
</int:recipient-list-router>
The above recipient list router configuration is copied from section 5.1 of the Spring Integration reference manual.
I have achieved similar sort of requirements by extending the Spring-Integrations's RecipientListRouter as follows:
public class CententBasedRecipientListRouter extends RecipientListRouter {
#Override
protected void handleMessageInternal(final Message<?> message) {
......
}
}
in overridden method, you can implement any customized content based routing logic as per your requirements.
This custom router can be configured as follows:
<bean id="customRecipientListRouter" class="CententBasedRecipientListRouter">
<property name="channels">
<list>
<ref bean="parallelProcessingChannel1"/>
<ref bean="parallelProcessingChannel2"/>
<ref bean="parallelProcessingChannel3"/>
</list>
</property>
</bean>
<int:router ref="customRecipientListRouter"
input-channel="routingChannel"
default-output-channel="errorChannel" />
In order to achieve Parallel Processing, you can have Task Executor channels as follows:
<int:channel id="parallelProcessingChannel1">
<int:dispatcher task-executor="threadPoolExecutor"/>
</int:channel>
I have a Spring Integration project where I want to process a message concurrently through multiple actions. So I have set up a publish-subscribe-channel with a task-executor. However I want to wait for all processing to complete before moving on. How would I do this?
<publish-subscribe-channel id="myPubSub" task-executor="my10ThreadPool"/>
<channel id="myOutputChannel"/>
<service-activator input-channel="myPubSub" output-channel="myOutputChannel"
ref="beanA" method="blah"/>
<service-activator input-channel="myPubSub" output-channel="myOutputChannel"
ref="beanB" method="blah"/>
<service-activator id="afterThreadingProcessor" input-channel="myOutputChannel" .../>
So in the above case, I want my afterThreadingProcessor to be invoked only once after both beanA and beanB have completed their work. However, in the above afterThreadingProcessor will be invoked twice.
Add apply-sequence="true" to the pub-sub channel (this adds default correlation data to the messages, including correlationId, sequenceSize, and sequenceNumber and allows default strategies to be used on downstream components).
Add an <aggregator/> before afterThreadingProcessor and route the output from the two <service-activator/>s to it.
Add a <splitter/> after the aggregator - the default splitter will split the collection made by the aggregator into two messages.
afterThreadingProcessor will be invoked once for each message on the second thread that completes its work.
You can make the configuration easier by using a chain...
<chain input-channel="myOutputChannel">
<aggregator />
<splitter />
<service-activator id="afterThreadingProcessor" input-channel="myOutputChannel" .../>
</chain>
To make a single call to the final service, just change your service to take a Collection<?> instead of adding the splitter.
EDIT:
In order to do what you want in comment #3 (run the final service on the original thread), something this should work...
<int:channel id="foo" />
<int:service-activator ref="twoServicesGateway" input-channel="foo"
output-channel="myOutputChannel" />
<int:gateway id="twoServicesGateway" default-request-channel="myPubSub"/>
<int:publish-subscribe-channel id="myPubSub" task-executor="my10ThreadPool"
apply-sequence="true"/>
<int:service-activator input-channel="myPubSub" output-channel="aggregatorChannel"
ref="beanA" method="blah"/>
<int:service-activator input-channel="myPubSub" output-channel="aggregatorChannel"
ref="beanB" method="blah"/>
<int:aggregator input-channel="aggregatorChannel" />
<int:service-activator id="afterThreadingProcessor" input-channel="myOutputChannel" .../>
In this case, the gateway encapsulates the two other services and the aggregator; the default service-interface is a simple RequestReplyExchanger. The calling thread will wait for the output. Since the aggregator has no output-channel the framework will send the reply to the gateway, and the waiting thread will receive it, return to the <service-activator/> and the result will then be sent to the final service.
You would probably want to put a reply-timeout on the gateway because, by default, it will wait indefinitely and, if one of the services returns a null, no agreggated response will ever be received.
Note that I indented the gateway flow just to show it runs from the gateway, they are NOT child elements of the gateway.
Same kind of behavior can now be achieved using a more cleaner approach introduced in Spring Integration 4.1.0 as an implementation of EIP Scatter-Gather pattern.
Checkout Scatter-Gather example gist:
https://gist.github.com/noorulhaq/b13a19b9054941985109