Announcement Announcement Module
Collapse
No announcement yet.
Get session ID on server using spring integration tcp/ip Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Get session ID on server using spring integration tcp/ip

    Hi, I am new to spring integraton tcp/ip and i really loved it. Currently am facing one problem and hope you would be able to guide me.

    I have created one server, that basically listens on one port using channel, gateway.

    Now there is one client that I don't have any control over. Basically client sends out Login request to server and in turn server is suppose to send back <login_pass> response. Within this xml response string, their is one field session_id that needs to be filled out with the current session id.

    Is there any way of getting session id details somehow? Currently i did try to get that detail as below but no luck.

    CODE:
    final AbstractConnectionFactory acf = (AbstractServerConnectionFactory) GlobalContext.getContext()
    .getBean("serverConnectionFactory");
    return acf.getConnection().getConnectionId();

    P.S. Login request is made via sockets, so i have defined channel, inbound gateway that parses the request and calls LoginHandler where response is constructed using jaxb.

    Please let me know if you need more information.
    Last edited by Karan_Biawat; Mar 12th, 2013, 07:56 AM.

  • #2
    You can't use getConnection() on a server connection factory (it's a server so it might have lots of connections).

    Assuming the sessionid you want can be some arbitrary value that identifies the connection, then you can use the connection id - but the id is assigned to the connection itself.

    The connection id is available as a header in the message. You could do something like...

    Code:
    public String handleRequest(@Header(IpHeaders.CONNECTION_ID) String connectionId,
    		            @Payload String input) {
    
    ...
        if (inputIsALoginRequest) {
            ...
            return loginResponseWithConnectionid;             
        }
    ...
    }
    And invoke this with a <service-activator/>.
    Last edited by Gary Russell; Mar 12th, 2013, 08:39 AM.

    Comment


    • #3
      Thanks Gary, I will give it a try now.

      just one point wanted to mention, since am using 'serializer/deserializer' as part of int-ip:tcp-connection-factory tag within spring.

      I think, all the requests are meant to hit on my customized 'ControllerSerializerDeserializer' and this basically reads the input stream and method has a bit of code as

      Code:
      if (line.startsWith("<login"))
                  {
                      sb.append(line);
                      break;
                  }
      ...
      return sb.toString();
      I'm not sure <service-activator/> still going to hit your method defined in your post above rather than
      code:
      public static String process(final String reqMsg)

      I am going to give a try, thought of mentioning here.

      Thank you very much for your quick response.
      Last edited by Gary Russell; Mar 12th, 2013, 10:07 AM.

      Comment


      • #4
        This forum uses [ code ] ... [ /code ] tags (no spaces in brackets). I edited your post.

        It's not clear to me from your snippet why you have this logic in the deserializer. I would expect the deserializer to always append the data, regardless of the input.

        Regarding <service-activator/>, you can add a 'method' attribute if you have ambiguous methods.
        Last edited by Gary Russell; Mar 12th, 2013, 10:17 AM.

        Comment


        • #5
          The reason for doing that was,

          Earlier i was using it below fashion without deserializer

          Code:
          	<int:service-activator input-channel="toSA"
          		ref="echoService"
          		method="process"/>
          
          	<bean id="echoService"
          		class="org.springframework.integration.samples.tcpclientserver.EchoService" />
          
          	<int:transformer id="serverBytes2String"
          		input-channel="serverBytes2StringChannel"
          		output-channel="toSA"
          		expression="new String(payload)"/>
          code: below snippet was defined in EchoService, parsing reqMsg business and applying the logic etc...
          public static String process(final String reqMsg)

          When client was sending request, it was not able to hit my code though i could see via wireshark the request is hitting on same port. As a workaround i used 'deserialize(final InputStream input)' and as soon as i read <login onto that, forward that line to method defined in <service-activator/>. Obviously am not using any transformer or anything now.

          Code:
          	<!-- Server side connection factory-->
          	<int-ip:tcp-connection-factory id="serverConnectionFactory"
          		type="server"
          		port="${availableServerSocket}"
          		single-use="true"
          		so-linger="10000"
          		serializer="connectionSerializeDeserialize"
          		deserializer="connectionSerializeDeserialize"/>
          
          	<!-- inbound gateway for communication with trtn gateway -->	
          	<int-ip:tcp-inbound-gateway id="inGateway"
          		connection-factory="serverConnectionFactory"
          		request-channel="serverBytes2StringChannel"
          		error-channel="errorChannel"/>
          	
          	<!-- Serialize Deserialize messages --> 
          	<bean id="connectionSerializeDeserialize" class="com.my.springExample.ControllerSerializerDeserializer"/>	
          	
          	<!-- create channel-->
              <int:channel id="serverBytes2StringChannel"/>
              <int:channel id="errorChannel"/>
          	
          	<!-- service activator for incoming messages -->
          	<int:service-activator input-channel="serverBytes2StringChannel"
          		ref="delegator"
          		method="process"/>
          
          	<bean id="delegator"
          		class="com.my.springExample.Controller"/>
          EDITED ==

          I have implemented your change and it worked by updating the login_response with connection id.

          Though the original login response from server used to have different format of sessionid as "6a0pAaFfHCFdyaZmLnhRJPYI" and in this case "127.0.0.1:62755:93f21735-c8a8-4247-ad12-e872a7e4958f".By original means, i'm trying to create dummy server so comparing the login response with this. Anyways I don't think it should be any problem as long as it's only motive is to find the tunnel where the original request was sent out on.

          I'm just facing another small problem here.
          1. Client sends login request.
          2. server sends out login response with your implementation.

          as soon as server sends out response the below behavior in wireshark as.
          [FIN,ACK] - server to client
          [ACK] - client to server
          [FIN,ACK] - client to server
          [ACK] - server to client.

          I don't understand why would server sends out FIN packet after sending everything correctly (i tried using 'single-use="false/true" both but no change). Due to above TCP traces, I think client assumes that connection is no more alive. So it sends out another login request, server sends login response again... and this cycle keeps on continuing.

          Hence on server end all i can see login request coming all the time.

          I know this is diff issue than originally raised. If you have any vague idea please let me know, and you can close this ticket.

          Thanks for your help
          Last edited by Karan_Biawat; Mar 12th, 2013, 02:06 PM.

          Comment


          • #6
            I have implemented your change and it worked by updating the login_response with connection id.

            Though the original login response from server used to have different format of sessionid as "6a0pAaFfHCFdyaZmLnhRJPYI" and in this case "127.0.0.1:62755:93f21735-c8a8-4247-ad12-e872a7e4958f".By original means, i'm trying to create dummy server so comparing the login response with this. Anyways I don't think it should be any problem as long as it's only motive is to find the tunnel where the original request was sent out on.

            I'm just facing another small problem here.
            1. Client sends login request.
            2. server sends out login response with your implementation.

            as soon as server sends out response the below behavior in wireshark as.
            [FIN,ACK] - server to client
            [ACK] - client to server
            [FIN,ACK] - client to server
            [ACK] - server to client.

            I don't understand why would server sends out FIN packet after sending everything correctly (i tried using 'single-use="false/true" both but no change). Due to above TCP traces, I think client assumes that connection is no more alive. So it sends out another login request, server sends login response again... and this cycle keeps on continuing.

            Hence on server end all i can see login request coming all the time.

            I know this is diff issue than originally raised. If you have any vague idea please let me know, and you can close this ticket.

            Thanks for your help

            Comment


            • #7
              For some reason, your last post needed approval - I just approved it.

              The reason the server is immediately closing the socket after the reply is because you have single-use="true". This means the socket is only used for one request/reply.

              Set it to "false" and you should be good.

              I see you said you tried that, but the server won't close the socket. I still don't understand your custom serializer - can you post the source?

              Comment


              • #8
                Here is the source.

                CODE: ControllerSerializerDeserializer.java
                Code:
                 
                   public Object deserialize(final InputStream input) throws IOException
                    {
                  
                        final BufferedReader reader = new BufferedReader(new InputStreamReader(input));
                        final StringBuilder sb = new StringBuilder();
                        String line = null;
                        while ((line = reader.readLine()) != null)
                        {
                            if (line.startsWith("<login"))
                            {
                                sb.append(line);
                                break;
                            }
                
                            if (line.startsWith("<abc"))
                            {
                                sb.append(line);
                                break;
                            }
                
                            if (line.startsWith("<def"))
                            {
                                sb.append(line);
                                break;
                            }
                        }
                        // reader.close();
                        return sb.toString();
                    }
                
                    @Override
                    public void serialize(final Object obj, final OutputStream os) throws IOException
                    {
                       final PrintWriter pw = new PrintWriter(os, true);
                       pw.println(obj.toString());
                       pw.close();
                    }
                then it uses the same spring config as it was posted in above replies (with single-use="false" as well) and comes to below code

                CODE:Controller.java
                Code:
                    public static String process(@Header(IpHeaders.CONNECTION_ID) final String connectionId,
                            @Payload final String reqMsg)
                    {
                         // Use XMLParser
                        if (reqMsg != null && !reqMsg.isEmpty())
                        {
                            // get root element to decide the handler
                            final String msg = XMLParser.parse(reqMsg);
                
                            // delegate to login handler
                            if (msg.equalsIgnoreCase("login"))
                            {
                // construct login response with connection id as one of the field.
                                return LoginHandler.populateLoginResponseFields(connectionId,
                                        reqMsg);
                            }
                ...
                }
                So as per above, in theory i was expecting call to ControllerSerializerDeserializer which then sends to process method of Controller.java. It should send out the constructed login response. And that's what is happening as well. but the problem is server then sends out [FIN,ACK] for some reason that causes client to completely ignore the previous session (my guess) for further communication and sends a brand new login request. The same client.jar file works fine with actual server, so don't think their is any trouble with that.

                Comment


                • #9
                  Right, but what does your serialize() method do?

                  I see you have reader.close() commented out.

                  If you are doing something like writer.close() in serialize(), it will close the outputStream (and socket).

                  I assume, in your deserializer, you just want to simply discard anything but those 3 lines?

                  Comment


                  • #10
                    That's right am interested only in few messages so have to define accordingly in deserialize() method

                    Thank you so much for pointing that out, i don't really know how could i forget that. That was same reason for commenting out the reader.close() line.

                    After commenting out that writer line as well, it worked as expected.

                    Serialize method isn't doing much really, just writing the response coming from process method on to output stream. Is there any other way of doing that? Should i just ignore that serialize method completely? and would be taken care by spring itself, as soon as the method defined in "service-activator" finishes its job?

                    Comment


                    • #11
                      No, you need a Serializer of some kind. The default one (ByteArrayCrLfSerializer) will append CRLF to the end. If the client is just expecting LF, you can set the serializer to a ByteArrayLfSerializer.

                      Also, bear in mind your current deserializer will return an empty String when the socket is closed - this will result in a message with a zero length string payload.

                      You might want to consider returning null when there is no data.

                      Comment

                      Working...
                      X