Results 1 to 4 of 4

Thread: Custom message header did not pass to server

  1. #1

    Default Custom message header did not pass to server

    Hi,

    I tried to add a custom header to the message on the client side.

    Code:
    	<context:component-scan base-package="com.barnesandnoble.message"/>
    
        <beans:bean id="tcpSerializer"
              class="org.springframework.integration.ip.tcp.serializer.ByteArrayLengthHeaderSerializer">
                <beans:property name="maxMessageSize" value="20480"/>
        </beans:bean>
    
        <beans:bean id="tcpDeserializer"
              class="org.springframework.integration.ip.tcp.serializer.ByteArrayLengthHeaderSerializer">
            <beans:property name="maxMessageSize" value="20480"/>
        </beans:bean>
    
    	<ip:tcp-connection-factory id="connectionFactory"
            serializer="tcpSerializer"
            deserializer="tcpDeserializer"
    		type="client"
    		host="${dev.message.client.message.bus.host}"
    		port="${dev.message.client.message.bus.port}"
            using-nio="true"
            single-use="true"
    		so-timeout="10000"/>
    
    	<channel id="requestChannel"/>
        <channel id="replyChannel"/>
    
     	<ip:tcp-outbound-gateway id="outGateway"
    		request-channel="requestChannel"
    		reply-channel="replyChannel"
    		connection-factory="connectionFactory"
    		request-timeout="10000"
    		reply-timeout="10000"/>
    
     	<gateway id="productGateway"
    			default-request-channel="requestChannel"
                default-reply-channel="replyChannel"
    			service-interface="com.barnesandnoble.message.server.iface.ProductService">
    	</gateway>
    and the product service is defined as

    Code:
    public interface ProductService {
    
       @Gateway(requestChannel="requestChannel")
        void post(String productsInJSON, @Header(MessageHeader.STAGE) String stage);
    
    }
    The client sent the message with the custom header

    Code:
        productService.post(request, StageType.BASE.name());
    I can see the custom header in the log

    DEBUG: com.barnesandnoble.message.server.impl.ProductMess ageClient - Send request: {"products":[{"type":"BOOKS","ean":"2111251351325"}]}
    DEBUG: org.springframework.integration.channel.DirectChan nel - preSend on channel 'requestChannel', message: [Payload={"products":[{"type":"BOOKS","ean":"2111251351325"}]}][Headers={timestamp=1297966333904, id=f1b8c089-1ea4-450d-ab85-1c6c531a3021, stage=BASE}]
    DEBUG: org.springframework.integration.ip.tcp.TcpOutbound Gateway - org.springframework.integration.ip.tcp.TcpOutbound Gateway#0 received message: [Payload={"products":[{"type":"BOOKS","ean":"2111251351325"}]}][Headers={timestamp=1297966333904, id=f1b8c089-1ea4-450d-ab85-1c6c531a3021, stage=BASE}]
    DEBUG: org.springframework.integration.ip.tcp.connection. TcpNioClientConnectionFactory - Opening new socket channel connection to localhost:8888
    DEBUG: org.springframework.integration.ip.tcp.TcpOutbound Gateway - Added localhost:8888:1517879698
    DEBUG: org.springframework.integration.ip.tcp.connection. TcpNioConnection - Message sent [Payload={"products":[{"type":"BOOKS","ean":"2111251351325"}]}][Headers={timestamp=1297966333904, id=f1b8c089-1ea4-450d-ab85-1c6c531a3021, stage=BASE}]
    But the problem is the server always complained there is no header stage.

    DEBUG - _initHandlerFor_stageRouter received message: [Payload=Products{Product{ean='2111251351325', type='BOOKS'} }][Headers={timestamp=1297966333924, id=a1defcec-7fe5-48f3-a6da-fef8d2c24e79, errorChannel=org.springframework.integration.core. MessagingTemplate$TemporaryReplyChannel@11613fe7, history=tcpProductGateway,requestChannel,productPu blishChannel, ip_address=127.0.0.1, replyChannel=org.springframework.integration.core. MessagingTemplate$TemporaryReplyChannel@11613fe7, ip_connection_seq=1, ip_hostname=localhost.localdomain, ip_tcp_remote_port=48629, ip_connection_id=localhost.localdomain:48629:43077 1672}]
    2011-02-17 13:12:13,926 (pool-1-thread-15) [TcpInboundGateway.doSendAndReceive]
    WARN - failure occurred in gateway sendAndReceive
    org.springframework.integration.MessageHandlingExc eption: java.lang.IllegalArgumentException: required header not available: stage
    at org.springframework.integration.handler.MethodInvo kingMessageProcessor.processMessage(MethodInvoking MessageProcessor.java:76)
    The server configuration is as follows.

    Code:
        <beans:bean id="tcpSerializer"
              class="org.springframework.integration.ip.tcp.serializer.ByteArrayLengthHeaderSerializer">
                <beans:property name="maxMessageSize" value="${message.bus.max.message.size}"/>
        </beans:bean>
    
        <beans:bean id="tcpDeserializer"
              class="org.springframework.integration.ip.tcp.serializer.ByteArrayLengthHeaderSerializer">
            <beans:property name="maxMessageSize" value="${message.bus.max.message.size}"/>
        </beans:bean>
    
        <message-history tracked-components="*Gateway, *Channel, *Adapter"/>
    
    	<ip:tcp-connection-factory id="gatewayConnectionFactory"
            serializer="tcpSerializer"
            deserializer="tcpDeserializer"
    		type="server"
            pool-size="${message.bus.server.gateway.connection.pool.size}"
            using-nio="true"
            single-use="true"
    		port="${message.bus.server.gateway.tcp.port}"/>
    
    	<ip:tcp-inbound-gateway id="tcpProductGateway"
    		connection-factory="gatewayConnectionFactory"
    		request-channel="requestChannel"
            reply-channel="replyChannel"
    		error-channel="errorChannel"/>
    BTW, I used Wireshark to check the tcp stream, but could not find any header information.

    Do you know what was wrong here?

    Thanks,

    John

  2. #2
    Join Date
    Mar 2010
    Location
    Gtr Philadelphia, PA
    Posts
    2,028

    Default

    Yes, only the payload is transferred over TCP; this is mentioned in the documentation several times, including in the section 'TCP Message Correlation'...

    One goal of the IP Endpoints is to provide communication with systems other than another Spring
    Integration application. For this reason, only message payloads are sent and received.
    You have several options:

    1. Enhance the payload on the client...

    Code:
    	<transformer input-channel="input" output-channel="toTcp"
    		expression="headers.STAGE + ':' + payload"/>
    ..and strip it on the server...

    Code:
    	<chain input-channel="serverBytes2StringChannel" output-channel="toSA">
    		<transformer expression="new String(payload)"/>
    		<header-enricher>
    			<header name="STAGE" expression="payload.substring(0, payload.indexOf(':'))"/>
    		</header-enricher>
    		<transformer expression="payload.substring(payload.indexOf(':')+1)"/>
    	</chain>
    2. Make your payload an object that contains your actual payload and any custom headers you want; the objects would need to be Serializable and you'd use the java serialization (De)Serializers.

    HTH
    Last edited by Gary Russell; Feb 17th, 2011 at 02:27 PM.
    Gary P. Russell
    Spring Integration Team
    SpringSource, a division of VMware

  3. #3

    Default

    Quote Originally Posted by Gary Russell View Post
    Yes, only the payload is transferred over TCP; this is mentioned in the documentation several times, including in the section 'TCP Message Correlation'...
    That sounds a bit surprise to me. Socket communication is a light weight way to integrate systems because I don't want http servlet and JMS. I really question about the assumption in the document.

    Anyway, I add the header information to the request object and it should work now.

  4. #4
    Join Date
    Mar 2010
    Location
    Gtr Philadelphia, PA
    Posts
    2,028

    Default

    Yes, tcp is lightweight; but there are two reasons we took this approach.

    1. We couldn't make any assumptions that the collaborating service is a Spring Integration application.
    2. We certainly didn't want to require java serialization, which is needed for any complex object graph serialization (or OXM or similar).

    If you don't care about these restrictions, it's easy to do what you want, and we maintain flexibility for those that do care.

    Here's another solution...

    Code:
    @SuppressWarnings("serial")
    public class MessageWrapper implements Serializable {
    	
    	private Message<?> message;
    
    	public MessageWrapper(Message<?> message) {
    		this.message = message;
    	}
    
    	public Message<?> getMessage() {
    		return message;
    	}
    
    }
    Code:
    <transformer input-channel="input" output-channel="toTcp"
      expression="new org.springframework.integration.samples.tcpclientserver.MessageWrapper(#root)"/>
    Code:
    <chain input-channel="serverBytes2StringChannel" output-channel="toSA">
    	<header-enricher>
    		<header name="STAGE" expression="payload.message.headers['STAGE']"/>
    	</header-enricher>
    	<transformer expression="payload.message.payload"/>		
    </chain>
    SpEL is a wonderful thing :-)

    You need to configure the java (de)serializers for it to work.

    We could consider some formalized way to send a subset of headers with the payload; if you feel strongly about it enter a new feature JIRA and if it gets some votes, we'll consider it.
    Gary P. Russell
    Spring Integration Team
    SpringSource, a division of VMware

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •