I am trying to create a Integration flow :
Connection A : [ ActiveMq (queue1) ---> TCP Server (1111) ](spring boot Application) ---> [ExternalApplication (client connected to Server running on port (1111))] (Application on different Technology (VB))
Connection B : [ ActiveMq (queue2) ---> TCP Server (2222) ](spring boot Application) ---> [ExternalApplication (client connected to Server running on port (2222))] (Application on different Technology (VB))
So Above flow depicts following scenario:
I have a spring boot application (say springUtility) which connect with external application(say externalutility) on some other technology.
The connection between springutility and externalUtility is through TCP protocol.
There will be more than one connection between both the utilities as in above flow diagram connection A and connection B.
The flow of message will be from springUtilty to externalutility (One way)
Now, the externalutility can run in client Mode or server mode. so, if the externalUtility run in server Mode then my springutility will be in client mode (Done) also to create more than one connection I run this below code in for loop code :
Code:
flow = IntegrationFlows
.from(Jms.inboundAdapter(ConnectionFactory())
.destination("rec"))
.channel(directChannel()).handle(Tcp.outboundAdapter(Tcp.nioClient("172.18.11.22",5555)
.serializer(customSerializer)
.deserializer(customSerializer)
.id(hostConnection.getConnectionNumber()).soTimeout(10000)))
.get();
flowRegistration = this.flowContext.registration(flow).id("in.flow").register();
Issue : When the externalutility run in client mode then spring utility should able to create a server on which the external utility will get connected and then it start receiving messsages from spring utility: which I tried to implement in a wrong way.
So, finally I have to Implement the above connection as a test case to validate the flow, means spring utility has opened server port (1111 and 2222) the external application connect with these two port and start receiving the message from spring utility from queue1 and queue2 repectively. Both the connection will have there seperate flow (Once a single flow will be created then we can use a for loop to create no of connection we need).
Code:
flow = IntegrationFlows
.from(Jms.inboundAdapter(ConnectionFactory())
.destination("rec"))
.channel(directChannel()).handle(Tcp.outboundAdapter(Tcp.netServer(5555)
.serializer(customSerializer)
.deserializer(customSerializer)
.id(hostConnection.getConnectionNumber()).soTimeout(10000)))
.get();
flowRegistration = this.flowContext.registration(flow).id("in.flow").register();
` code:
2018-05-30 17:39:39.171 INFO 15776 --- [nio-8080-exec-1] o.s.i.endpoint.EventDrivenConsumer : Adding {jms:outbound-channel-adapter} as a subscriber to the 'Conn1311out.flow.channel#0' channel
2018-05-30 17:39:39.172 INFO 15776 --- [nio-8080-exec-1] o.s.integration.channel.DirectChannel : Channel 'application.Conn1311out.flow.channel#0' has 1 subscriber(s).
2018-05-30 17:39:39.172 INFO 15776 --- [nio-8080-exec-1] o.s.i.endpoint.EventDrivenConsumer : started org.springframework.integration.config.ConsumerEndpointFactoryBean#3
2018-05-30 17:39:41.965 INFO 15776 --- [nio-8080-exec-1] o.s.i.endpoint.EventDrivenConsumer : Adding {ip:tcp-outbound-channel-adapter} as a subscriber to the 'Conn1311in.flow.channel#0' channel
2018-05-30 17:39:41.965 INFO 15776 --- [nio-8080-exec-1] o.s.integration.channel.DirectChannel : Channel 'application.Conn1311in.flow.channel#0' has 1 subscriber(s).
2018-05-30 17:39:41.966 INFO 15776 --- [nio-8080-exec-1] .s.i.i.t.c.TcpNetServerConnectionFactory : started Conn1311, port=3333
2018-05-30 17:39:41.966 INFO 15776 --- [nio-8080-exec-1] o.s.i.endpoint.EventDrivenConsumer : started org.springframework.integration.config.ConsumerEndpointFactoryBean#4
2018-05-30 17:39:41.966 INFO 15776 --- [pool-1-thread-1] .s.i.i.t.c.TcpNetServerConnectionFactory : Conn1311, port=3333 No listener bound to server connection factory; will not read; exiting...
2018-05-30 17:39:41.971 INFO 15776 --- [nio-8080-exec-1] o.s.i.e.SourcePollingChannelAdapter : started org.springframework.integration.config.SourcePollingChannelAdapterFactoryBean#0
It first create the server on the provided port but exit with following message
No listener bound to server connection factory; will not read; exiting...
When I am creating the client it is working fine but in case of creating server it is giving error
EDIT:
I have use the following approach to create dynamically different server and send message to connected client from its respective activemq client
I have created an inbound adapter as below :
IntegrationFlow flow; CustomSerializer customSerializer = getCustomSerializer(String.valueOf(hostConnection.getMaxMessageLength()), hostConnection.getTerminatorChar()); TcpSendingMessageHandler handler = new TcpSendingMessageHandler(); TcpNetServerConnectionFactory cf = new TcpNetServerConnectionFactory(1234)); cf.setSerializer(customSerializer); cf.setDeserializer(customSerializer); handler.setConnectionFactory(cf); flow = IntegrationFlows .from(Tcp.inboundAdapter(cf).id("adapter")).handle(handler) .get(); this.flowContext.registration(flow).id("inflow") .addBean(hostConnection.getConnectionNumber(),cf) .addBean(hostConnection.getConnectionNumber()+"handler",handler) .register();
I have created a Jmsflow in which the message from the queue is send to a router as below:
flow = IntegrationFlows .from(Jms.inboundAdapter(activeMQConnectionFactory) .destination(hostConnection.getConnectionNumber() +"rec")) .channel(directChannel()).route(new ServerRouter()) .get();
when the client got connected to my server then I create a flow from the listener
handleTcpConnectionCloseEvent(TcpConnectionOpenEvent event)
and create a flow as:void createServerFlow(TcpConnectionOpenEvent event) { String connectionNumber = event.getConnectionFactoryName(); TcpNetConnection server = (TcpNetConnection) event.getSource(); TcpSendingMessageHandler handler = (TcpSendingMessageHandler) ac.getBean(connectionNumber + "handler"); IntegrationFlow flow = f -> f.enrichHeaders(e -> e.header(IpHeaders.CONNECTION_ID, event.getConnectionId())) .handle(handler); IntegrationFlowRegistration flowregister = this.flowContext.registration(flow).id("outclient").register(); MessageChannel channel = flowregister.getInputChannel(); this.subFlows.put(connectionNumber + "server", channel); }
My ServerRouter find the channel and send to the target channel
protected Collection<MessageChannel> determineTargetChannels(Message<?> message) { String serverChannel = (String) message.getHeaders().get("connectionnumber"); MessageChannel channel = HostConnectionRepository.subFlows .get(serverChannel+"server"); return Collections.singletonList(channel);
}
when I got disconnected then I remove the flow from flowContext created in
step 3
.
Issue : When I remove the flow the bean associated with the flow also get removed as its written in the docs that related beans will also discard.
This remove my handler bean which close the TCP adapter also the connectionfactory hence once it get disconnected it can't connect again
How can i discard the outclientflow without discarding the handler bean?