I am working on a high-volume integration with using spring integration tcp and I only send a request and receive more than millions of data over one connection and the time between two receiving message is lower than 100 milliseconds.
Here is my context xml and I am using TCPOutboundGateway.
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns:int="http://www.springframework.org/schema/integration"
xmlns:int-ip="http://www.springframework.org/schema/integration/ip"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/integration https://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/integration/ip https://www.springframework.org/schema/integration/ip/spring-integration-ip.xsd">
<bean class="org.springframework.integration.samples.tcpclientserver.EchoService"
id="echoService"/>
<bean class="org.springframework.integration.samples.tcpclientserver.ByteArrayToStringConverter"
id="javaDeserializer"/>
<int-ip:tcp-connection-factory
apply-sequence="true" deserializer="javaDeserializer"
host="127.0.0.1"
id="TCPClientFactory1"
port="443"
single-use="false"
type="client"
/>
<int-ip:tcp-outbound-gateway
async="true" close-stream-after-send="false" connection-factory="TCPClientFactory1"
id="outGateway"
remote-timeout="10000"
reply-channel="serverBytes2StringChannel"
reply-timeout="10000"
request-channel="input"
request-timeout="10"
/>
<int:channel id="input"/>
<int:channel id="toSA"/>
<int:gateway default-request-channel="input"
id="gw"
service-interface="org.springframework.integration.samples.tcpclientserver.SimpleGateway"/>
<int:object-to-string-transformer auto-startup="true" id="serverBytes2String"
input-channel="serverBytes2StringChannel"
output-channel="toSA"/>
<int:service-activator
input-channel="toSA"
method="test"
ref="echoService"
/>
<int:transformer expression="payload.failedMessage.payload + ':' + payload.cause.message"
id="errorHandler"
input-channel="errorChannel"/>
</beans>
I took an example from github.
My issue is; I can successfully handle and process first received message. But the rest is got below exception.
20:21:34.550 [pool-1-thread-1] ERROR org.springframework.integration.ip.tcp.TcpOutboundGateway - Cannot correlate response - no pending reply for 127.0.0.1:443:57385:e164052f-64e5-4d41-9d46-4a12bad12cd4
I read the source code of TcpOutboundGateway and also read caching client connection factory document but could not found a proper way to achieve solution.
The gateway is not designed for that scenarion it only supports 1 reply per request.
You can use a pair of outbound/inbound channel adapters, instead of the gateway, for scenarios like this.
The upcoming 5.4 release has an enhancement to the gateway to support this scenario.
Related
Currently we are using Spring Integration 2.1.0 Release in our application.
Application flow is as below:
Some operation is performed in application and we got the output string in String via Active MQ.
I have used message-driven-channel-adapter and service-activator to read the data from queue.
That data is displayed successfully on Server(application is working as client) using tcp-outbound-gateway.
Problem is while getting the acknowledgement from server.
Created a new channel and entered in reply-channel in tcp-outbound-gateway
Passing the same channel in service-activator as input channel.
It is showing below error:
[task-scheduler-5] 2017-10-05 18:32:20,732 ERROR org.springframework.integration.handler.LoggingHandler - org.springframework.integration.MessageDeliveryException: Dispatcher has no subscribers.
at org.springframework.integration.dispatcher.UnicastingDispatcher.doDispatch(UnicastingDispatcher.java:108)
at org.springframework.integration.dispatcher.UnicastingDispatcher.dispatch(UnicastingDispatcher.java:101)
at org.springframework.integration.channel.AbstractSubscribableChannel.doSend(AbstractSubscribableChannel.java:61)
at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:157)
at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:128)
at org.springframework.integration.core.MessagingTemplate.doSend(MessagingTemplate.java:288)
at org.springframework.integration.core.MessagingTemplate.send(MessagingTemplate.java:149)
Code is as below
<context:property-placeholder />
<!-- Gateway and connection factory setting -->
<int:channel id="telnetLandingChannel" />
<int:channel id="telnetReplyChannel" />
<beans:bean id="clientCustomSerializer"
class="com.telnet.core.serializer.CustomSerializer">
<beans:property name="terminatingChar" value="10" />
<beans:property name="maxLength" value="65535" />
</beans:bean>
<int:gateway id="gw" default-reply-channel="telnetReplyChannel" default-reply-timeout="100000"
service-interface="com.telnet.core.integration.connection.ParseTcpConfiguration$SimpleGateway"
default-request-channel="telnetLandingChannel"/>
<ip:tcp-connection-factory id="clientFactory"
type="client" host="localhost" port="7777" single-use="false" using-nio="false"
serializer="${client.serializer}" deserializer="${client.serializer}" />
<ip:tcp-outbound-gateway id="clientInGw"
request-channel="telnetLandingChannel"
connection-factory="clientFactory"
reply-channel="telnetReplyChannel"
reply-timeout="100000"/>
<!-- To send the messege over server via JMS and serviceActivator -->
<int:channel id="incidentDispatchMessageChannel" />
<int:channel id="jmsChannel" />
<beans:bean id="customClientServiceActivator"
class= "com.telnet.core.integration.CustomClientServiceActivator">
</beans:bean>
<int-jms:message-driven-channel-adapter id="incidentDispatchMessageChannelAdapter" error-channel="errorChannel"
connection-factory="mqConnectionFactory"
destination-name="${incident.processing.messaging.dispatch.queues}"
channel="incidentDispatchMessageChannel"/>
<int:service-activator id="incidentMessageActivator"
input-channel="incidentDispatchMessageChannel"
output-channel="jmsChannel"
ref="customClientServiceActivator" method="getOutboundMessage">
</int:service-activator>
<int:object-to-string-transformer id="clientBytes2String"
input-channel="jmsChannel"
output-channel="telnetLandingChannel"/>
<!-- To receive the acknowledgement message on server via serviceActivator -->
<int:service-activator id="incidentAck"
input-channel="telnetReplyChannel"
ref="customClientServiceActivator" method="getAck">
</int:service-activator>
I have studied various article on stackverFlow but not able to get any solution
Yeah... That isn't clear by the error what channel is guilty.
On the other hand you really use very old Spring Integration version.
Would be great to consider to upgrade to the latest: http://projects.spring.io/spring-integration/.
However I think that issue is somehow around exactly that reply-channel, which you use not only for the <service-activator> but for the <int:gateway> as well.
I suggest you to remove default-reply-channel="telnetReplyChannel" from the gateway definition, remove reply-channel="telnetReplyChannel" from the <ip:tcp-outbound-gateway> definition. And let them communicate via replyChannel header populated by the gateway during request.
Regarding your <int-jms:message-driven-channel-adapter> flow which leads to the same <ip:tcp-outbound-gateway>, I would suggest to still stay with the replyChannel header but here populate it via <header-enricher> before sending message to the telnetLandingChannel. That replyChannel via <header-enricher> would be exactly an input-channel for the subsequent <int:service-activator> to handle ack from the <ip:tcp-outbound-gateway>.
I got the solution of this issue, there are multiple xmls in our code but i have added the code in one to show flow in stackOverflow.
Issue was i had defined in a xml which has only configuration part like Outbound adapter connection factory where as it should be defined in another xml where I am using service activator. Changed the place of channel definition and it worked.
I want to disconnect the TCP (as server) the moment i got the response message. As of now I am using so-timeout, so my TCP server will gets timedout after the time given in so-timeout, but requirement is to disconnect the connection the moment TCP print/display the acknowledgement. Please suggest how can I implement this.
I'm trying to learn Spring Integration and for this i would like to create an application like this:
From Oracle i send messages (on Oracle Queue), this message will be intercepted from a Java application (build with Spring Integration) and the application will send an email based on message received. The message will contain To: - Cc: and the text to send.
To make this kind of communication i've decided to use JMS (i think in Oracle this is made with Oracle AQ).
In the database i've already created the Queue and now i'm trying to create a simple applicationContext.xml to start this handshake.
Looking on the net i've found really few articles about this (Spring Integration + Oracle AQ) and i'm getting some error. The main error is this: java.lang.ClassNotFoundException: oracle.jms.AQjmsFactory
Right now this is my applicationContext.xml
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:int="http://www.springframework.org/schema/integration"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:orcl="http://www.springframework.org/schema/data/orcl"
xmlns:int-jms="http://www.springframework.org/schema/integration/jms"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/integration/jms http://www.springframework.org/schema/integration/jms/spring-integration-jms.xsd
http://www.springframework.org/schema/data/orcl http://www.springframework.org/schema/data/orcl/spring-data-orcl-1.0.xsd">
<int:channel id="inbound" />
<int:channel id="outbound" />
<bean id="simpleMessageListener" class="it.dirimo.SimpleMessageListener" />
<int-jms:inbound-channel-adapter
channel="inbound"
connection-factory="connectionFactory"
destination-name="Q1">
<int:poller fixed-delay="1000" />
</int-jms:inbound-channel-adapter>
<int:service-activator input-channel="inbound" output-channel="outbound" ref="simpleMessageListener" method="onMessage" />
<int-jms:outbound-channel-adapter id="jmsOut"
channel="outbound"
connection-factory="connectionFactory"
destination-name="sampleQueue" />
<int:poller id="poller" default="true" fixed-delay="10000" />
<orcl:aq-jms-connection-factory id="connectionFactory"
data-source="dataSource"
use-local-data-source-transaction="true"/>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" lazy-init="false">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
<property name="url" value="jdbc:oracle:thin:#localhost:1521:ORCL" />
<property name="username" value="user" />
<property name="password" value="password" />
</bean>
</beans>
Maybe i'm using "old" technologies (for example i've seen for the first time this org.apache.commons.dbcp.BasicDataSource)
Unfortunally i'm so new about Spring Integration and i've seen for the first time Oracle Queue (i'm using Oracle for work but never used any kind of Queue).
Some advice of how to proceed will be apreciated :)
EDIT 1
To solve the problem about the AQjmsFactory need to include aqapi.jar
java.lang.ClassNotFoundException: oracle.jms.AQjmsFactory
This simply means you are missing the jar that contains that class from the classpath.
Oracle, typically, requires that you manually download their jars from them directly.
After my poller fetches data from DB, I am calling an external service.
After getting response from that service, I want to do call another systems in a separate thread. Means, after getting response, my poller should take another record and send.In addition calling other systems should work in parallel.
For this I used a direct channel for receiving the data from DB. Used a service activator for sending request to external service. The response is passed to an executer channel.can anyone please tell me whether the below configuration is correct for the scenario ?
For clarity I am sharing the poller.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:int="http://www.springframework.org/schema/integration"
xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:int-jdbc="http://www.springframework.org/schema/integration/jdbc"
xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
xmlns:task="http://www.springframework.org/schema/task" xmlns:int-http="http://www.springframework.org/schema/integration/http"
xmlns:stream="http://www.springframework.org/schema/integration/stream"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.1.xsd
http://www.springframework.org/schema/integration
http://www.springframework.org/schema/integration/spring-integration-4.1.xsd
http://www.springframework.org/schema/integration/stream
http://www.springframework.org/schema/integration/stream/spring-integration-stream-4.1.xsd
http://www.springframework.org/schema/integration/http
http://www.springframework.org/schema/integration/http/spring-integration-http-4.1.xsd
http://www.springframework.org/schema/integration/jdbc
http://www.springframework.org/schema/integration/jdbc/spring-integration-jdbc-4.1.xsd
http://www.springframework.org/schema/jdbc
http://www.springframework.org/schema/jdbc/spring-jdbc-4.1.xsd">
<!-- <import resource="persistence-config.xml" /> <int:channel id="inchannel">
</int:channel> <int:channel id="outchannel"> <int:dispatcher task-executor="taskExecutor"/>
</int:channel> <task:executor id="taskExecutor" pool-size="2"/> <bean id="poller"
class="main.java.com.as.poller.PollerService" /> <int:service-activator input-channel="inchannel"
output-channel="outchannel" ref="poller" method="sendMessage" /> -->
<int-jdbc:inbound-channel-adapter id="dataChannel"
query="select loyalty_id, process_id,mobile_uid from TBL_RECEIPT where r_cre_time=(select min(r_cre_time) from TBL_RECEIPT where receipt_status=0)"
data-source="dataSource" max-rows-per-poll="1"
update="update TBL_RECEIPT set receipt_status=11 where loyalty_id in (:loyalty_id)">
<int:poller fixed-rate="5000">
</int:poller>
</int-jdbc:inbound-channel-adapter>
<bean id="poller" class="main.java.com.as.poller.PollerService" />
<int:channel id="executerchannel">
<int:dispatcher task-executor="taskExecutor"/>
</int:channel>
<task:executor id="taskExecutor" pool-size="20"/>
<int:service-activator input-channel="dataChannel"
output-channel="executerchannel" ref="poller" method="processMessage" />
<int:service-activator input-channel="executerchannel" ref="poller" method="processTpg">
</int:service-activator>
<stream:stdout-channel-adapter id="executerchannel"/>
No; it's not correct (it is almost correct).
<stream:stdout-channel-adapter id="executerchannel"/>
this overrides your executor channel definition (an outbound adapter with no channel attribute creates a channel with that id).
You will end up with a simple direct channel with 2 subscribers (stdout and your service activator) - they will get alternate messages.
I am not sure why you added that element; remove it or subscribe it to some other channel.
If you want it to go to both places; change the channel to a <publish-subscribe-channel/> with an executor.
I've been asked to do a prototype, converting a working web service that uses a Spring enabled JAX-WS endpoint to using Spring Integration instead, and I've been told to use xml configuration as much as possible. I stripped down the application until just the relevant web service elements remain, and I've created a couple of new spring xml config files as needed. While it compiles fine, when I deploy to a JBoss container and then try to invoke it using SoapUI, I get a HTTP 405 response, and there's nothing in the JBoss console to indicate that the request was even received, though the server log indicates the new gateway and service activator was setup correctly and is running. I can't find anything remotely relevant in any of the Spring documentation I've read, and none of the code examples I've pulled from Github address configuring the web service to run in an actual J2EE server.
I'm at a complete loss as to what I should be looking at. Here are my spring config files:
springContext-main.xml (I can't use applicationContext.xml in the real app due to pre-existing contraints)
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:annotation-config/>
<!-- <bean class="com.bofa.ecom.intfacade.web.ApplicationConfiguration"/> -->
<bean id="reconDao" class="com.bofa.ecom.intfacade.snf.recon.dao.ReconDAOImpl">
<!-- <property name="dataSource" ref="dataSource"/> -->
</bean>
<bean id="reconServiceHelper" class="com.bofa.ecom.intfacade.snf.recon.service.helper.ReconServiceHelperImpl">
<constructor-arg ref="reconDao"/>
</bean>
<import resource="classpath:/META-INF/spring/recon-ws.xml"/>
</beans>
recon-ws.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:sws="http://www.springframework.org/schema/web-services"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.5.xsd
http://www.springframework.org/schema/oxm http://www.springframework.org/schema/oxm/spring-oxm-1.5.xsd
http://www.springframework.org/schema/web-services http://www.springframework.org/schema/web-services/web-services-2.0.xsd">
<bean id="messageFactory" class="org.springframework.ws.soap.saaj.SaajSoapMessageFactory"/>
<import resource="classpath:/META-INF/spring/inbound-gateway-config.xml" />
<sws:dynamic-wsdl id="reconWsdl" portTypeName="reconGateway" locationUri="/reconService"
targetNamespace="http://intfacade.cpm.ecom.bofa.com/">
<sws:xsd location="/WEB-INF/recon.xsd"/>
</sws:dynamic-wsdl>
<bean
class="org.springframework.ws.server.endpoint.mapping.UriEndpointMapping">
<property name="defaultEndpoint" ref="reconGateway"></property>
</bean>
</beans>
inbound-gateway-config.xml
<?xml version="1.0" encoding="utf-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:int-ws="http://www.springframework.org/schema/integration/ws"
xmlns:int="http://www.springframework.org/schema/integration"
xsi:schemaLocation="http://www.springframework.org/schema/integration/ws http://www.springframework.org/schema/integration/ws/spring-integration-ws.xsd
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<int:channel id="recon-input"/>
<int-ws:inbound-gateway id="reconGateway" request-channel="recon-input"/>
<int:service-activator input-channel="recon-input" method="saveArrangementApplicationDetails">
<bean id="arrangementApplicationReconService" class="com.bofa.ecom.intfacade.snf.recon.service.ArrangementApplicationReconServiceImpl">
<constructor-arg ref="reconServiceHelper"/>
</bean>
</int:service-activator>
</beans>
Any pointers in the right direction would be greatly appreciated.
Edit: I've narrowed it down to what I think is a configuration problem with either SI or Spring-ws. I can't find a complete SI + Spring-ws example that uses XML configuration to figure out what I'm missing or doing wrong. I've added my spring ws config file above.
405 is Method Not Allowed - it appears you are doing a GET (or something else) rather than a POST.
If you believe you are POSTing, take a look with a network monitor (wireshark, or the built-in tcp/ip monitor in eclipse).
You may also be hitting the wrong URL; I suggest you turn on DEBUG logging on the server.
If you still can't figure it out, post the log someplace such as a gist.
The below code is using Spring Integration 3.0.1
Client side integration XML:
<int:channel id="serviceTWeb"></int:channel>
<int:gateway id="serviceTGW" default-request-channel="serviceTWeb"
service-interface="com.test.ServiceTWeb">
</int:gateway>
<int-http:outbound-gateway
url="http://testserver:8080/service-webapp/service"
http-method="POST" id="RequestTNHTTP" reply-timeout="2000"
request-channel="serviceTWeb" message-converters="conv>
</int-http:outbound-gateway>
<bean id="conv" class="org.springframework.integration.http.converter.SerializingHttpMessageConverter">
</bean>
Web side integration XML:
<!-- The following uses a ServiceActivator on service -->
<bean id="stweb" class="test.poc.si.ServiceTWeb"></bean>
<bean id="conv" class="org.springframework.integration.http.converter.SerializingHttpMessageConverter">
</bean>
<int:channel id="requestChannel"></int:channel>
<int:channel id="replyChannel"></int:channel>
<int:service-activator input-channel="requestChannel" ref="stweb"
method="service" requires-reply="true" id="webserv"
output-channel="replyChannel">
</int:service-activator>
<int-http:inbound-gateway request-channel="requestChannel"
supported-methods="POST" path="/service" message-converters="conv"
reply-channel="replyChannel">
</int-http:inbound-gateway>
The client makes the request out to the server, the server side get the code
and processes the Request object, but the server tosses the following when sending the
reply message:
SEVERE: Servlet.service() for servlet [Multipart] in context with path [/service-webapp] threw exception [Request processing failed; nested exception is org.springframework.integration.MessagingException: Could not convert reply: no suitable HttpMessageConverter found for type [com.myobject.MReply] and accept types [[text/html, image/gif, image/jpeg, /;q=.2, /;q=.2]]] with root cause
org.springframework.integration.MessagingException: Could not convert reply: no suitable HttpMessageConverter found for type [com.myobject.MReply] and accept types [[text/html, image/gif, image/jpeg, /;q=.2, /;q=.2]
Any help would be welcome!
Assuming com.myobject.MReply is Serializable, try setting expected-response-type="com.myobject.MReply" on the outbound gateway. It should cause the accept header to be set to application/x-java-serialized-object.
EDIT:
Or, set expected-response-type="java.io.Serializable" if you don't want to tie it to a specific type.