Announcement Announcement Module
Collapse
No announcement yet.
gateway method with multiple parameters Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • #16
    Ok, I tried it with strings and it worked like a charm (I haven't tried the arraylist yet). Now I've upgraded the interface. Instead of strings the interface looks like this:

    Code:
    public Zoo request(Map<Foo, Collection<String>>, Bar)
    I am getting the following exception:

    HTML Code:
    Invalid header name [TYPE], name type must be String.
    Foo is an emum and TYPE is one of it's values.
    When I was working with one parameter I had no problem passing in a map with an enum as a key.
    What's the problem here?

    Thanks again you've really helped me a lot.
    Netta

    Comment


    • #17
      Also, I would not call it coupling since the expression you are providing is a "piece of code" after all. . . a script if you wish that needs to be executed, but since we give you ability to configure it you can inject a different script through placeholders in some other environment while keeping the same configuration.

      Also, you can use annotation support if you prefer
      Code:
      public interface Foo {
          String fooMethod(@Payload String foo, @Header("barHeader") String bar);
      }
      In the above case the gateway XML configuration is simple, however I would probably look at this one as more coupling that the XML version . . . but that is just me

      Comment


      • #18
        My personal preference in these configurations is xml so I'm with you on that . Just the thought of writing the argument names hardcoded bothers me...it's too fragile. Although, I agree that an approach like this should definitely be moved to a properties file.

        I'm still having the issue with the invalid header name (as described 2 posts above). Any thoughts? Am I doing something wrong or is it just not supported?

        Thanks again
        Netta

        Comment


        • #19
          Right, as the message states (Invalid header name [TYPE], name type must be String.). The message headers key must be String. That comes form the contract of the MessageHeaders http://static.springsource.org/sprin.../2.2.0.M2/api/
          Is that what you are asking?

          Comment


          • #20
            The Map isn't representing headers, the code just assumes it does. I just want one of the arguments to be a map.
            Before we were talking about multiple arguments as payloads and the arguments were just Strings. Now I want the payload to be a little more complicated.

            Code:
            public Zoo request(Map<Foo, Collection<String>>, Bar)
            This is just a map of values. I want to pass this map to the server. It doesn't represent headers.

            Taking your example and expanding it a bit:

            Code:
            public class Request {
            
            	private Map<Foo,Collection<String>> map;
            	
            	private Bar bar;
            
            	public Request(Map<Foo,Collection<String>> map, Bar bar) {
            		this.map = map;
            		this.bar = bar;
            	}
            
            	//getters
            }
            
            ...
            
            <int:method name="request" payload-expression="new com.foo.Request(#args[0], #args[1])" />
            Again, this is just a map of values that I want to pass to the server. From what I can tell when debugging, this map is automatically taken to represent headers when in fact, that was not my intention.

            Is there a way to tell spring integration not to treat these as headers; to treat them as it does bar or any other non-map argument?

            Comment


            • #21
              Ohh, got it.
              Well if its a Map and you want it to be payload instead you can annotate it with @Payload thus overriding the default conventions. However I see that there is another argument there. What would that be?
              In other words, gateway is nothing more than a proxy to a Messaging system so gateway arguments MUST map to a Message. We have default conventions as well as annotation way of managing it and that is why I am asking about that second argument.

              Comment


              • #22
                Originally posted by oleg.zhurakousky View Post
                Ohh, got it.
                Well if its a Map and you want it to be payload instead you can annotate it with @Payload thus overriding the default conventions. However I see that there is another argument there. What would that be?
                In other words, gateway is nothing more than a proxy to a Messaging system so gateway arguments MUST map to a Message. We have default conventions as well as annotation way of managing it and that is why I am asking about that second argument.
                The second argument is also part of the payload. That's why I was referring to the String solution we were talking about before. This whole thing started from me wanting to know how to implement a gateway with multiple parameters that are both payloads. I need the parameters to be Map<Enum,Collection<String>> and the other just a Pojo, but they are both payloads. Neither of them are headers. I prefer xml configuration. Don't want to use @Payload.

                This was my intended solution for the gateway but it doesn't work because the code tries to analyze the map as headers:

                arg[0]: Map<Enum,Collection<String>>
                arg[1]: POJO

                payloadUnifier.toList: returns List<Object>

                Code:
                <int:gateway service-interface="com.http.test.TestService"
                		default-request-channel="requestChannel">
                		  	<int:method name="send"
                			payload-expression="@payloadUnifier.toList(#args[0], #args[1])" />  
                	</int:gateway>
                I don't want the map analyzed as headers. I want both the map and the POJO as payloads as illustrated above.
                I hope that clarifies my intentions.

                Thanks
                Netta

                Comment


                • #23
                  Netta

                  I've investigated it further and we have a bug on our end. The problem is in GatewayMethodInboundMessageMapper which simply does this:
                  Code:
                  else if (Map.class.isAssignableFrom(methodParameter.getParameterType())) {
                  So we have to fix it.
                  What I propose now is for you to raise a JIRA and we can address it with high priority https://jira.springsource.org/browse/INT
                  Meanwhile we need to come up with workaround so the question is can you change the interface signature?

                  Comment


                  • #24
                    I opened a bug: https://jira.springsource.org/browse/INT-2610

                    Comment


                    • #25
                      Well there is already a lot of discussion done here and i know this post is a bit too late ,nevertheless, what i believe nettad was referring to is using say an interface X (with over loaded methods and having multiple method parameters) on the client side on which the client application will do invocations as a local bean, and have a service activator on the server side implementing perhaps the same interface which should get invoked in turn.

                      Just for your information, this might come handy something outside spring integration though, spring remoting does provide you with such feature too where you can have a service interface exposed which will invoke a remote bean implementing the same interface and uses JMS,RMI, WS or HTTP as the transport. The idea is that you have a invoker proxy factory bean on the client , you use the appropriate one based on the transport you want to use and on the server side you have a invoker service exporter, again an appropriate one based on the transport used.

                      See this for more information.
                      Last edited by Amol Nayak; Jun 11th, 2012, 10:31 AM.

                      Comment


                      • #26
                        @Netta

                        Here is what I have working as a workaround
                        Code:
                        public static void main(String... strings ) throws Exception{
                        		ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("config.xml", SpringIntegrationIntro.class);
                        		MyGateway gateway = context.getBean(MyGateway.class);
                        		Map<Integer, Object> map = new HashMap<Integer, Object>();
                        		map.put(1,  "Hello");
                        		gateway.send(map, new Foo());
                        }
                        
                        public static interface MyGateway {
                        	public void send(@Payload Map<Integer, Object> map, @Header("foo") Foo foo);
                        }
                        
                        public static class Foo{}
                        
                        <int:gateway service-interface="org.springframework.integration.util.SpringIntegrationIntro.MyGateway"
                        		default-request-channel="requestChannel"/>
                        
                        <int:logging-channel-adapter id="requestChannel" level="WARN" log-full-message="true"/>
                        And the output is


                        LoggingHandler: [Payload={1=Hello}][Headers={timestamp=1339426491423, id=88998d36-4f8d-4d3f-b89d-5a2ad697517a, foo=org.springframework.integration.util.SpringInt egrationIntro$Foo@42c4d04d}]


                        Can you please compare it to what you hve and see what is different?

                        Comment


                        • #27
                          Originally posted by oleg.zhurakousky View Post
                          @Netta

                          Here is what I have working as a workaround
                          Code:
                          public static void main(String... strings ) throws Exception{
                          		ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("config.xml", SpringIntegrationIntro.class);
                          		MyGateway gateway = context.getBean(MyGateway.class);
                          		Map<Integer, Object> map = new HashMap<Integer, Object>();
                          		map.put(1,  "Hello");
                          		gateway.send(map, new Foo());
                          }
                          
                          public static interface MyGateway {
                          	public void send(@Payload Map<Integer, Object> map, @Header("foo") Foo foo);
                          }
                          
                          public static class Foo{}
                          
                          <int:gateway service-interface="org.springframework.integration.util.SpringIntegrationIntro.MyGateway"
                          		default-request-channel="requestChannel"/>
                          
                          <int:logging-channel-adapter id="requestChannel" level="WARN" log-full-message="true"/>
                          And the output is


                          LoggingHandler: [Payload={1=Hello}][Headers={timestamp=1339426491423, id=88998d36-4f8d-4d3f-b89d-5a2ad697517a, foo=org.springframework.integration.util.SpringInt egrationIntro$Foo@42c4d04d}]


                          Can you please compare it to what you hve and see what is different?
                          That's exactly one-to-one the workaround I came up with (The only difference is my gateway interface has 2 headers) so:

                          Code:
                          public static interface MyGateway {
                          	public void send(@Payload Map<Integer, Object> map, @Header("foo") Foo foo, @Header("bar") Bar bar);
                          }
                          I used the loggingHandler and got exactly what you got. However, when I switched from the loggingHandler to my http:outbound-gateway I received an exception. I have spring integration in trace mode and I'm seeing the following:

                          HTML Code:
                          18:38:41,213    [http-bio-8443-exec-10] DEBUG    org.springframework.integration.http.support.DefaultHttpHeaderMapper -- headerName=[timeRange] WILL be mapped, matched pattern=timeRange
                          18:38:41,214    [http-bio-8443-exec-10] DEBUG    org.springframework.integration.http.support.DefaultHttpHeaderMapper -- setting headerName=[X-timeRange], value=<start=1339429113022,end=2678858226044>
                          18:38:42,821    [http-bio-8443-exec-10] WARN     org.springframework.integration.http.support.DefaultHttpHeaderMapper -- Header 'X-timeRange' with value '<start=1339429113022,end=2678858226044>' will not be set since it is not a String and no Converter is available. Consider registering a Converter with ConversionService (e.g., <int:converter>)
                          The exception is on the other side cause it can't find the headers. Obviously, they aren't being mapped so it's hard to find them .

                          Can you change your example to work with <int-http:outbound-gateway> to see what you get?

                          Comment


                          • #28
                            Well, now that's a whole other issue. So I am assuming that the annotation approach does provide a workaround to ensure that Gateway method's input arguments are properly mapped into a Message.

                            Now you have to send it over HTTP using HTTP Outbound Gateway. I hope you understand that its the limitation of HTTP protocol requiring that http headers can only have String as values and if you look at the WARN message it even tells you what to do to convert your POJOs to Strings. . . basically you need to register the appropriate Converter's with ConversionService and you can use <int:converter> to accomplish this. You can look at the example of how to register converter here http://static.springsource.org/sprin...ype-conversion
                            Even though it talks about the payload its the same for Headers

                            Comment


                            • #29
                              what do you write on the other side to convert back from String to POJO, another converter?

                              Comment


                              • #30
                                Yes, and that is actually the functionality that comes with Spring itself - the ability to convert types implicitly through the Convertered registered with the ConversionService. You can get more info here http://static.springsource.org/sprin...l#core-convert

                                Comment

                                Working...
                                X