Announcement Announcement Module
Collapse
No announcement yet.
Accessing correlation ID with a service activaor Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Accessing correlation ID with a service activaor

    Is there a way to access message headers (specifically correlation ID) when using a service activator. I have a scenario where I need asynchronous communication between two software components and I need to correlate the response with it's request. I make use of 2 service activators at either end of the system...one to process a request that has made it through the system and one to process the response at the other end of the system.

    In an attempt to access the message headers instead of just the payload, the service activator's service method accepts an SI message (instead of an object representing the payload). I seem able to retrieve the message ID header while processing the request and set that to be the correlation ID on the response. However, the correlation ID is always null when trying to process the response. Does service activator do something under the covers with correlation ID that I am missing?

    Thanks

  • #2
    In a request-response scenario we have built in features you can use. If you add a simplified code sample here you will get a nudge in the right direction.

    You could think about using a RendezvousChannel, MessageChannelTemplate or have a look at the jms outbound gateway for an example.

    It is possible that there is a bug in your code or ours. With your sample we can analyze that.

    Comment


    • #3
      Thanks for the reply.

      I actually got the correlation ID working yesterday, so I assume the bug was in my code.

      What I am seeing now is that when I create a message to send, that message's ID is different than the ID of the message that is received at the other end of our system. Without matching IDs I cannot match a response to a request. Thus I went a different route for now...wrapping an XML message in an envelope that contains IDs that my application sets. Not what I was hoping to do, but it works.

      As far as my request-response scenario, it needs to be asynchronous (and the services are actually running in different JVMs). That is why I did not use something like a JMS gateway. From the documentation I got the feeling that the JMS gateway is used for synchronous communication...is that correct? This is the same reason I did not use the RendezvousChannel. I did not think about the MessageChannelTemplate, I will look into that.

      What I have now seems to be working, but does not seem very clean and I keep thinking there has got to be a better way to do things. Any guidance would be appreciated.

      If a code sample would still be helpful, I would be glad to post.

      Comment


      • #4
        Please do post some sample code. Even some excerpts from the part that you have had to customize would be really helpful in understanding the limitations that you've encountered.

        Comment


        • #5
          Originally posted by adstro View Post
          Thanks for the reply.
          I actually got the correlation ID working yesterday, so I assume the bug was in my code.

          What I am seeing now is that when I create a message to send, that message's ID is different than the ID of the message that is received at the other end of our system. Without matching IDs I cannot match a response to a request. Thus I went a different route for now...wrapping an XML message in an envelope that contains IDs that my application sets. Not what I was hoping to do, but it works.
          I'm not sure, but I get the feeling that you're mixing up the Id of the message with its correlationId. Anyway, if you post the code those mistakes should be revealed too.

          Comment


          • #6
            Here is the code that creates and sends the message:

            Code:
            public boolean produce(String request)
            {
            	ChannelResolver channelResolver =
            		new BeanFactoryChannelResolver(context);
            	
            	MessageChannel requestChannel =
            		channelResolver.resolveChannelName("producerRequestChannel");
            	
            	Message<String> message =
            		MessageBuilder.withPayload(request).build();
            	
            	Object requestId = message.getHeaders().getId().toString();
            
            	boolean messageSentStatus = requestChannel.send(message);
            	
            	if (messageSentStatus)
            	{
            		correlationIdMap.put(requestId.toString(), request);
            		logger.debug("Sent request with ID " + requestId);
            	}
            	else
            	{
            		logger.warn("Unable to send message");
            	}
            	
            	return messageSentStatus;
            }
            Here is the code that receives the message, processes the message and sends the response (in a seperate JVM from the requester):
            Code:
            public Message<String> processRequest(Message<String> message)
            {	
            	Object requestId = message.getHeaders().getId();
            
            	logger.info("Processing request with ID " + requestId);
            	
            	String response =
            		consumer.consume(message.getPayload().toString());
            	
            	Message<String> responseMessage =
            		MessageBuilder.withPayload(response).setCorrelationId(requestId.toString()).build();
            	
            	return responseMessage;
            }
            Here is the log from the producer:
            Code:
            DEBUG [main] Sent request with ID d135ad34-7202-4381-9c27-b6196cf586c5 (sandbox.ProducerGateway.java:48)
             INFO [main] Sent 1 messages (sandbox.MessagingTest.java:34)
             WARN [org.springframework.jms.listener.DefaultMessageListenerContainer#0-1] Unable to find request 18b3ed44-6c3e-4d6a-bcaf-082f137c52e5 (sandbox.ProducerGateway.java:73)
            And the log from the consumer:
            Code:
             INFO [main] Starting Consumer (sandbox.Consumer.java:18)
             INFO [main] Consumer started (sandbox.Consumer.java:22)
             INFO [org.springframework.jms.listener.DefaultMessageListenerContainer#0-1] Processing request with ID 18b3ed44-6c3e-4d6a-bcaf-082f137c52e5 (sandbox.ConsumerGateway.java:26)
             INFO [org.springframework.jms.listener.DefaultMessageListenerContainer#0-1] Consumer 8a52af99-56bc-4ae5-a5ea-d8df69f59eda sleeping for 10 sec (sandbox.Consumer.java:39)
             INFO [org.springframework.jms.listener.DefaultMessageListenerContainer#0-1] Done processing request (sandbox.Consumer.java:32)
            What I found interesting is that the message IDs of the message that was sent from the producer is different than the message ID of the message that the consumer received. With those IDs being different, I cannot match the response to the request.

            I have also attached the XML config files. I can post more code if needed.

            Thanks

            Comment


            • #7
              One quick thing you should try is setting 'extract-payload' to false for the outbound message. Then it will send the Spring Integration Message instance as the body of the JMS Message. Otherwise, it is sending only the payload as the body and the headers as JMS properties. When it creates a new Message from those on the receiving side, a new ID is created. Let me know if that brief description makes sense... if not, I can elaborate.

              Comment


              • #8
                Thanks for the reply!

                I tried the following line in Producer.xml:

                Code:
                <jms:outbound-channel-adapter id="producerRequestChannelAdapter" destination="requestQueue" channel="producerRequestChannel" extract-payload="false" />
                and got the same results. Did i implement your suggestion correctly, or did I misinterpret something?

                Comment


                • #9
                  Actually, the Message ID for the received Message will be different even in that case, because a new Message is always created from the existing Message. Even when the Spring Integration Message is passed as the body of the JMS ObjectMessage, the default header-mapper is doing the following:
                  Code:
                  if (conversionResult instanceof Message) {
                      builder = MessageBuilder.fromMessage((Message<?>) conversionResult);
                  }
                  The reason is that the header-mapper also writes any JMS properties to the headers and writing headers requires the creation of a new Message (the existing Message's header map is immutable).

                  You could provide your own MessageConverter reference for the inbound channel adapter. However, I need to explore your use-case in more detail in order to decide if there is a way to avoid relying on the Message ID for the correlation.

                  Comment


                  • #10
                    Fair enough...do you need any more info from me?

                    Comment

                    Working...
                    X