Transfer how to deliver message to Gateway? - spring

https://github.com/spring-projects/spring-integration-samples/tree/master/intermediate/tcp-client-server-multiplex
I saw this exmaple. So, I was changed architecture.
send model
receive model
And I have a question.
I don't understand transfer's role in send model.
I understand Aggregator delivery message to Transfer.
But, I don't understand How to deliver message to gateway.
How to deliver?
That is my spring integration config.
It is Send app setting,
<!-- telegram bean -->
<bean id="byteArrayRawSerializer" class="org.springframework.integration.ip.tcp.serializer.ByteArrayRawSerializer">
<property name="maxMessageSize" value="2000"/>
</bean>
<bean id="myCorrelationStrategy" class="com.test.util.MyCorrelationStrategy"/>
<!-- online connection factory -->
<int-ip:tcp-connection-factory id="server" type="server" port="20001" single-use="false" lookup-host="false" so-timeout="60000" serializer="byteArrayRawSerializer" deserializer="byteArrayRawSerializer" />
<int-ip:tcp-connection-factory id="client" type="client" host="localhost" port="10001" single-use="false" so-timeout="60000" serializer="byteArrayRawSerializer" deserializer="byteArrayRawSerializer" />
<!-- Send -->
<int:gateway id="sendGateway"
service-interface="com.test.MySendGateway"
default-reply-timeout="20000"
default-request-channel="sendChannel"/>
<int:publish-subscribe-channel id="sendChannel" />
<int-ip:tcp-outbound-channel-adapter id="sendAdapter" order="2" channel="sendChannel" connection-factory="client" />
<int:bridge input-channel="batchSendChannel" output-channel="toSendAggregator" order="1"/>
<int:channel id="toSendAggregator" datatype="byte[]"/>
<int:aggregator input-channel="toSendAggregator"
output-channel="toSendTransformer"
expire-groups-upon-completion="true"
correlation-strategy="myCorrelationStrategy"
correlation-strategy-method="getCorrelationKey"
release-strategy-expression="size() == 2" />
<int:transformer input-channel="toSendTransformer" expression="payload.get(1)"/>
<int-ip:tcp-inbound-channel-adapter id="sendReplyAdapter" channel="toSendAggregator" connection-factory="client" />
<!-- Receive -->
<int-ip:tcp-inbound-channel-adapter id="inboundAdapter" channel="batchInboundChannel" connection-factory="batchReceiveServer" />
<int-ip:tcp-outbound-channel-adapter id="outboundAdapter" channel="batchOutboundChannel" connection-factory="batchReceiveServer"/>
<int:channel id="batchInboundChannel" />
<int:channel id="batchOutboundChannel"/>
<int:service-activator id="myReceiveServiceActivator" method="receive" input-channel="batchInboundChannel">
<bean class="com.test.endpoint.MyReceiveServiceActivator" />
</int:service-activator>
And, It is Delivery app setting(center of picture),
<!-- Bean load -->
<bean id="byteArrayRawSerializer" class="org.springframework.integration.ip.tcp.serializer.ByteArrayRawSerializer">
<property name="maxMessageSize" value="2000"/>
</bean>
<!-- Connection factory -->
<int-ip:tcp-connection-factory id="server" type="server" port="30001" using-nio="true" single-use="false" lookup-host="false" so-timeout="10000" serializer="byteArrayRawSerializer" deserializer="byteArrayRawSerializer" />
<int-ip:tcp-connection-factory id="client" type="client" host="${RemoteTarget.ip}" port="${RemoteTarget.port}" using-nio="true" single-use="false" so-timeout="10000" serializer="byteArrayRawSerializer" deserializer="byteArrayRawSerializer" />
<!-- Connection factory -->
<int-ip:tcp-connection-factory id="inboundServer" type="server" port="10001" using-nio="true" single-use="false" lookup-host="false" so-timeout="${server.outbound.connectionTimeout}" serializer="byteArrayRawSerializer" deserializer="byteArrayRawSerializer" />
<int-ip:tcp-connection-factory id="inboardClient" type="client" host="localhost" port="20001" using-nio="true" single-use="false" so-timeout="10000" serializer="byteArrayRawSerializer" deserializer="byteArrayRawSerializer" />
<int-ip:tcp-inbound-channel-adapter id="receiveAdapter" channel="receiveChannel" connection-factory="server" auto-startup="true"/>
<int-ip:tcp-inbound-channel-adapter id="sendReplyAdapter" channel="sendReplyChannel" connection-factory="client" auto-startup="true"/>
<int:channel id="receiveChannel"/>
<int:channel id="sendReplyChannel"/>
<int-ip:tcp-outbound-channel-adapter id="receiveAdapter.inboard" channel="receiveChannel" connection-factory="inboundServer" />
<int-ip:tcp-outbound-channel-adapter id="sendReplyAdapter.inboard" channel="sendReplyChannel" connection-factory="inboardClient" />
<int-ip:tcp-outbound-channel-adapter id="sendAdapter" channel="sendChannel" connection-factory="client" />
<int-ip:tcp-outbound-channel-adapter id="receiveReplyAdapter" channel="receiveReplyChannel" connection-factory="server" />
<int:channel id="sendChannel" />
<int:channel id="receiveReplyChannel"/>
<int:router id="outRouter" input-channel="toRouter" method="route" auto-startup="true">
<bean class="com.test.endpoint.MyRouter"/>
</int:router>
<int:channel id="toRouter"/>
<int-ip:tcp-inbound-channel-adapter id="sendAdapter.inboard" channel="toRouter" connection-factory="inboundServer" auto-startup="true"/>
<int-ip:tcp-inbound-channel-adapter id="receiveReplyAdapter.inboard" channel="toRouter" connection-factory="inboardClient" auto-startup="true"/>
But, When I call gw.send(msg), it is not work,
(exactly, message stop at the delivery machine's 'sendAdapter.inboard' until timeout and router get this message....

I an not sure what is transfer in your ar3chitecture either.
According the sample you show, we have:
gateway -> outbound-channel-adapter
|-> aggregator
inbound-channel-adapter->aggregator->transformer
Where gateway sends its request to both TCP Outbound Channel Adapter and Aggregator, just because of <publish-subscribe-channel id="input" />.
As we know gateway is a request/reply component. When it sends requests, it waits for reply, because of the contract:
public interface SimpleGateway {
String send(String text);
}
In this case the Gateway add TemporaryReplyChannel as a replyChannel header to wait for reply.
The reply is produced when we don't specify the output-channel on the last downstream flow consumer.
In our case it is exactly the <transformer> after <aggregator>:
<transformer input-channel="toTransformer.client"
expression="payload.get(1)"/> <!-- The response is always second -->
I think that is a trick what you are looking for. It is called replyChannel header in the Consumer logic.

Related

Spring Integration exception always not reaching errorChannel

<bean id="triggerFileScanner" class="abc.xyz">
<property name="triggerFile" value="value1" />
</bean>
<int-file:inbound-channel-adapter id="fileInbound" directory="somepath/directory" filter="acceptallFilter" scanner="triggerFileScanner"
auto-startup="true" channel="fileChannel">
<int:poller max-messages-per-poll="10" time-unit="SECONDS" fixed-delay="10" receive-timeout="30000" />
</int-file:inbound-channel-adapter>
<int:header-enricher id="headerEnricher" input-channel="fileChannel" output-channel="processChannel">
<int:header name="flowName" value="Name" />
<int:header name="flowID" method="uuidgenerate" ref="headerEnricherBean" />
<int:header name="flowStartTime" method="generateTimeString" ref="headerEnricherBean"></int:header>
<int:header name="fileName" method="deriveFileName" ref="headerEnricherBean" />
</int:header-enricher>
<int:channel id="processChannel">
<int:interceptors>
<int:wire-tap channel="copyChannel" id="copyTap" />
</int:interceptors>
</int:channel>
<int:channel id="copyChannel"></int:channel>
<int-file:outbound-channel-adapter id="fileCopier" channel="copyChannel" delete-source-files="false" filename-generator="dateSuffixFileNameGenerator"
directory="copy.path">
</int-file:outbound-channel-adapter>
<int:filter id="formatcheckFilter" ref="formatValidator" method="validateFile" input-channel="processChannel" output-channel="processDataChannel"
discard-channel="errorChannel" auto-startup="true">
</int:filter>
<int:service-activator id="converter" input-channel="processDataChannel" method="convert" ref="fileToQueryConverter" auto-startup="true"
output-channel="impChannel" />
<bean id="importer" class="testbean.import">
<property name="errorpath" value="path1" />
<property name="sourcepath" value="path2" />
</bean>
<int:service-activator input-channel="impChannel" ref="impeximporter" id="importProcess" method="import" auto-startup="true"
output-channel="archiveChannel" />
<int:channel id="archiveChannel">
<int:interceptors>
<int:wire-tap channel="logChannel" id="completionLogger" />
</int:interceptors>
</int:channel>
<int:channel id="logChannel"></int:channel>
<int-file:outbound-channel-adapter id="fileArchiver" channel="archiveChannel" delete-source-files="true" filename-generator="dateSuffixFileNameGenerator"
directory="archive.path">
</int-file:outbound-channel-adapter>
<int:service-activator id="flowLogger" input-channel="logChannel" ref="messageLogger" method="logMessage">
</int:service-activator>
Sometimes the exceptions from service activator are going to the error channel, however some times they are not going.
I have the error channel defined as below:
<int:channel id="errorChannel" />
<bean id="exceptionHandler" class=my.custom.ExceptionHandler">
</bean>
<int:service-activator id="errorLogger" input-channel="errorChannel" method="handle" ref="exceptionHandler">
</int:service-activator>
I have this error channel being used in many integrations and in my service activators i am just doing a throw Exception("Message")

pass message to producer through jms

How to pass a message to producer(a method defined to sent message to activemq) through spring integration.
Actual requirement is, i need insert data to database and that data to be moved to a queue in activemq,both the operations need to be happened parallely. How can i do it.
<jms:message-driven-channel-adapter id="helloWorldJMSAdapater" destination="helloWorldJMSQueue" connection-factory="jmsConnectionFactory"
channel="postChannel" />
<int:channel id="requestChannel" />
<int:channel id="outputChannel" />
<int-http:inbound-gateway request-channel="requestChannel"
reply-channel="outputChannel" supported-methods="GET" path="/register"
view-name="register">
<int-http:request-mapping />
</int-http:inbound-gateway>
<int-http:inbound-gateway request-channel="postChannel"
reply-channel="outputChannel" supported-methods="POST" path="/registerNew"
error-channel="errorChannel" view-name="login">
</int-http:inbound-gateway>
<int-jdbc:outbound-channel-adapter
query="insert into user_registration (USER_FSTNAME,USER_ADDRESS,USER_STATE,USER_CITY,USER_OCCUPATION,USER_EMAIL,USER_CONTACT,USER_PASSWORD)
values (:fstName,:addrss,:state,:city,:occupation,:email,:contact,:password)"
channel="postChannel" data-source="dataSource" id="sample" sql-parameter-source-factory="spelSource" />
<int:service-activator ref="userService" input-channel="requestChannel"
output-channel="outputChannel" method="message"/>
<bean id="spelSource"
class="org.springframework.integration.jdbc.ExpressionEvaluatingSqlParameterSourceFactory">
<property name="parameterExpressions">
<map>
<entry key="fstName" value="payload[firstName]" />
<entry key="lstName" value="payload[lastName]" />
<entry key="addrss" value="payload[address]" />
<entry key="state" value="payload[state]" />
<entry key="city" value="payload[city]" />
<entry key="occupation" value="payload[occupation]" />
<entry key="email" value="payload[email]"/>
<entry key="contact" value="payload[contact]"/>
<entry key="password" value="payload[password]"/>
</map>
</property>
</bean>
Use a <publish-subscribe-channel/> and subscribe both endpoints to it. They will be executed serially by default, or in parallel if you add a task-executor to the channel.

Spring Integration Aggregator + JDBC Message Store performance

The performance of aggregator to process JMS messages along with persistence message store is very low. Like for a simple example given below the messages processed are between 25-28 msgs per second.
Is this the normal behavior? Or am I doing something wrong here ?
<!-- ###################### Inbound Message Adapter ####################### -->
<int-jms:message-driven-channel-adapter
id="xmlInboundMessageAdapter"
channel="msgUnmarshallingChannel"
connection-factory="jmsConnectionFactory"
destination="messsageQueue"
acknowledge="transacted"
concurrent-consumers="1"
max-concurrent-consumers="5"
auto-startup="true"/>
<!-- ###################### MSG UN-MARSHALLER ####################### -->
<int:channel id="msgUnmarshallingChannel" />
<int:chain input-channel="msgUnmarshallingChannel" output-channel="msgHeaderEnricherChannel">
<int-xml:unmarshalling-transformer unmarshaller="msgUnmarshaller" />
</int:chain>
<bean id="msgUnmarshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
<property name="contextPath" value="com.msg.something" />
<property name="supportJaxbElementClass" value="true" />
</bean>
<int:channel id="msgHeaderEnricherChannel" />
<!-- ###################### SOME HEADER ENRICHMENT ####################### -->
<int:chain input-channel="msgHeaderEnricherChannel" output-channel="msgAggreggatorChannel">
<int:header-enricher>
<int:header name="CORRELATION_ID" expression="payload.notificationTypeId" />
</int:header-enricher>
</int:chain>
<int:channel id="msgAggreggatorChannel" />
<int:channel id="msgAggreggatorDiscardChannel" />
<!-- ###################### AGGREGATOR WITH PERSISTENCE MSG STORE ####################### -->
<int:aggregator
auto-startup="true"
send-timeout="-1"
message-store="messageStore"
input-channel="msgAggreggatorChannel"
output-channel="nullChannel"
discard-channel="msgAggreggatorDiscardChannel"
correlation-strategy="msgCorrelationStrategy"
release-strategy="msgReleaseStrategy"
expire-groups-upon-completion="true" />
<!-- ###################### MSG STORE ####################### -->
<bean id="messageStore" class="org.springframework.integration.jdbc.JdbcMessageStore">
<property name="dataSource" ref="dataSourceSPJDBC" />
<property name="lobHandler" ref="oracleLobHandler" />
</bean>
<bean id="oracleLobHandler" class="org.springframework.jdbc.support.lob.OracleLobHandler" />
<bean id="msgCorrelationStrategy" class="org.springframework.integration.aggregator.HeaderAttributeCorrelationStrategy">
<constructor-arg value="CORRELATION_ID" />
</bean>
<bean id="msgReleaseStrategy" class="org.springframework.integration.aggregator.MessageCountReleaseStrategy">
<constructor-arg value="10"/>
</bean>
It's a known problem for very large groups.
Which version of Spring Integration are you using? There have been a number of improvements made in this area, the latest being in 4.2.
The current version is 4.2.4; let us know if you're still seeing problems with that version.

Spring Integration queue is not getting message but channel is getting

Using Spring Integration for transferring message from one queue to other in Websphere MQ.
OutPut Channel shows message is going but I am not able to see in Queue from MQ Explorer.How the session commits ? and I am not able to stop the java application. How to gracefully stop with connection stop ?
where I am doing wrong ?
Here is the context config -
<int:logging-channel-adapter log-full-message="true" id="logger" level="INFO"/>
<bean id="jmsConnectionFactory" class="com.ibm.mq.jms.MQQueueConnectionFactory">
<property name="hostName" value="localhost" />
<property name="port" value="1414" />
<property name="queueManager" value="TEST" />
<property name="transportType" value="1" />
</bean>
<bean id="inQueue" class="com.ibm.mq.jms.MQQueue">
<constructor-arg value="TESTQ" />
</bean>
<bean id="outQueue" class="com.ibm.mq.jms.MQQueue">
<constructor-arg value="DEST_QUEUE" />
</bean>
<int:channel id="readFromChannel">
<int:interceptors>
<int:wire-tap channel="logger"/>
</int:interceptors>
</int:channel>
<int:channel id="sendToChannel" >
<int:queue/>
<int:interceptors>
<int:wire-tap channel="logger"/>
</int:interceptors>
</int:channel>
<int-jms:message-driven-channel-adapter id="jmsInAdapter"
connection-factory="cachingConnectionFactory"
destination="inQueue"
channel="readFromChannel" />
<int-jms:message-driven-channel-adapter id="jmsOutAdapter"
connection-factory="cachingConnectionFactory"
destination="outQueue"
channel="sendToChannel" />
<bean id="myMessenger" class="test.MyMessenger" />
<int:service-activator id="servAct" input-channel="readFromChannel" output-channel="sendToChannel" ref="myMessenger" method="transfer"/>
If I understand your use-case correctly, you want to shift messages from TESTQ to DEST_QUEUE. But you have <int-jms:message-driven-channel-adapter> for both to read messages from them, but no one to put messages to DEST_QUEUE.
Your <int:service-activator> get message from readFromChannel and it means 'get message from TESTQ', but it places message to the sendToChannel. But it doesn't say that you place a message to the DEST_QUEUE.
That is because <int-jms:message-driven-channel-adapter> is for reading messages from JMS (MQ in your case).
To send message to JMS (to the DEST_QUEUE in your case) you have to use <int-jms:outbound-channel-adapter> and there is no reason to mark sendToChannel as <queue>

Dynamically selecting a RabbitMq queue in Exchange using spring integration

From producer I have to send message to an RabbitMQ Exchange. this message will contain specific attribute, for example , queue name, based on this attribute, I have to dynamically decide the queue to send this message.[queue to bind from exchange, to send this particular message].
is there any way to intercept the message arriving to a RabbitMQ Exchange, using spring integration, At present , I have the following spring integration config file.
I don't know to how to create a bean to get Exchange Messages and route the message to smsQueue, emailQueue etc., queues.
thanks for you suggestions and replies.
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/rabbit
http://www.springframework.org/schema/rabbit/spring-rabbit-1.0.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/amqp
http://www.springframework.org/schema/integration/amqp/spring-integration-amqp.xsd
">
<context:annotation-config></context:annotation-config>
<context:component-scan base-package="com.rabbit"></context:component-scan>
<rabbit:connection-factory id="connectionFactory"
host="localhost" username="guest" password="guest" />
<rabbit:admin connection-factory="connectionFactory" />
<rabbit:template id="exchnageTemplate"
connection-factory="connectionFactory" exchange="COMMUNICATION-EXCHANGE" />
<rabbit:queue id="smsQueue" auto-delete="true" durable="false" />
<rabbit:queue id="emailQueue" auto-delete="true" durable="false" />
<rabbit:queue id="dvbQueue" auto-delete="true" durable="false" />
<rabbit:queue id="pbxQueue" auto-delete="true" durable="false" />
<rabbit:queue id="medsensorQueue" auto-delete="true"
durable="false" />
<int:gateway id="gateway" service-interface="com.rabbit.mq.ProducerGatewayInterface"
default-request-channel="producerChannel" />
<int:channel id="producerChannel" />
<int:channel id="errorChannel" />
<bean id="communicationInterface" class="com.rabbit.mq.CommunicationInterface" />
<amqp:outbound-channel-adapter channel="producerChannel"
amqp-template="exchnageTemplate" exchange-name="COMMUNICATION-EXCHANGE">
<int:service-activator input-channel="input"
ref="communicationInterface" method="optimalRoutingOfMessage" />
</amqp:outbound-channel-adapter>
With RabbitMQ (AMQP) you don't send to queues, you send to exchanges with a routing key, and bindings determine which queue(s) get the message.
<rabbit:direct-exchange name="si.test.exchange">
<rabbit:bindings>
<rabbit:binding queue="si_test_queue" key="si.test.binding" />
</rabbit:bindings>
</rabbit:direct-exchange>
<int-amqp:outbound-channel-adapter
channel="toRabbit" amqp-template="amqpTemplate" exchange-name="si.test.exchange"
routing-key="si.test.binding" />
Instead of routing-key you can use routing-key-expression with something like headers['foo'] or #someBean.determineRoutingKeyFor(payload).

Resources