Announcement Announcement Module
Collapse
No announcement yet.
How not to send message? Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • How not to send message?

    Hello all =)

    I use Tcp from receiving massages from device. Sometimes device open Tcp connect and close without any payload.

    I use deserializer in tcp-connection-factory.
    deserializer tryes to read anything from Stream, if there is something - it return founded thing...
    But when nothing are come - i return null, and Spring Integrations throws exception "can not send message: null".

    How can i correctly say to Spring that NO MESSAGE EXIST, so no processing shold be done.

  • #2
    Could you post your configuration?
    The message is correct, we don't allow messages with the 'null' payload, however, i am curious to see why it even attempts to create a Message with 'null' payload. We may need to improve there.

    Comment


    • #3
      Which deserializer are you using?

      If it's a custom one, you need to throw a SoftEndOfStreamException to signal a 'clean' close.

      For example, in the ByteArrayCrLfSerializer...

      Code:
      if (bite < 0 && n == 0) {
      	throw new SoftEndOfStreamException("Stream closed between payloads");
      }
      If you are using one of our deserializers, please attach a debug log showing the error.

      Comment


      • #4
        2 Oleg:

        <int-ip:tcp-connection-factory
        id="tcpInFactory-Device"
        type="server"
        port="***"
        using-nio="false"
        serializer="byteArrayLfConverter"
        deserializer="byteArrayLfConverter"

        pool-size="200"
        so-keep-alive="false"
        so-timeout="10000"
        />

        <int-ip:tcp-inbound-channel-adapter
        id="tcpInAdapter-Device"
        channel="inChannel-Device"
        connection-factory="tcpInFactory-Device"
        />

        <int:channel id="inChannel-Device" />
        byteArrayLfConverter is similar to ByteArrayCrLfSerializer written by Spring.

        Comment


        • #5
          "The message is correct, we don't allow messages with the 'null' payload, however, i am curious to see why it even attempts to create a Message with 'null' payload. We may need to improve there"

          TCP channel is opened, but NO payload are come. And channel are closed. Whay should i do in deserializer?

          SoftEndOfStreamException -is not correct solution. It's an exception and it will be written to logs and admins will receive email that "SOMETHING BAD APPEARED - WE GOT EXCEPTION".

          Comment


          • #6
            2 Gary:

            Hi, how are you? I use your code with modifications:

            Code:
            public byte[] deserialize(InputStream inputStream) throws IOException {
                    try {
                        byte[] buffer = new byte[this.maxMessageSize];
                        int n = 0;
                        int bite;
                        if (LOG.isDebugEnabled()) {
                            LOG.debug("Some data arrived");
                        }
                        while (true) {
                            try {
                                bite = inputStream.read();
                                if (bite < 0 && n == 0) {
                                    throw new SoftEndOfStreamException("Stream closed between payloads");
                                }
                                checkClosure(bite);
                                //if message has non zero elements - end of message
                                if (n > 0 && bite == '\n') {
                                    break;
                                }
                                //skipping \n data, because some devices send \n as TCP connection "heat beats"
                                if (bite != '\n') {
                                    buffer[n++] = (byte) bite;
                                    if (n >= this.maxMessageSize) {
                                        throw new IOException("CRLF not found before max message length: "
                                                + this.maxMessageSize);
                                    }
                                }
                            } catch (SocketTimeoutException timeoutException) {
                                break;      //on timeout we trying to continue with all already read data
                            }
                        }
                        //if n is ZERO - mean socket closed without any payload
                        if (n == 0) {
                            // HERE IS PROBLEM!!! What should i do to correctly say to Spring - no message exist, continue work without Exceptions
                            throw new SoftEndOfStreamException("No data are readed from channel");
                        }
                        byte[] assembledData = new byte[n];
                        System.arraycopy(buffer, 0, assembledData, 0, n);
                        LOG.debug("some data readed, size {}", n);
                        return assembledData;
                    } catch (RuntimeException re) {
                        LOG.error("error during data reading", re);
                        throw re;
                    } catch (IOException e) {
                        LOG.error("IOException during data reading", e);
                        throw e;
                    }
                }

            Comment


            • #7
              Hello,
              I think, SoftEndOfStreamException - is the best solution.
              Your can define on your tcp-adapter an error-channel. And in the end you must write simple ErrorUnwrapper. That one checks Exception from message via instanceof SoftEndOfStreamException and doesn't send outbound message to reply-channel.

              Is it suitable?

              Artem

              Comment


              • #8
                2 Cleric:

                AFAIK Exception is UBNORMAL situation. And no data in socket is normal for my application.
                Also AFAIK Exception handling is much more consuming than work without Exception

                for example
                Code:
                        if(obj == null) {
                            doSomeStuff();
                        }
                will be much faster than
                Code:
                        try {
                            obj.getSomething()
                        } catch (NullPointerException ex) {
                            doSomeStuff();
                        }
                is not it?

                And in my case possible that for one piece of cake i will receive ten empty connections.

                Comment


                • #9
                  if(obj == null) {
                  doSomeStuff();
                  }
                  But it's not logic of deserializer...

                  Comment


                  • #10
                    I mean that no sense to use Exception in logically normal situation.


                    Code:
                    readData() {
                    ...
                                //if n is ZERO - mean socket closed without any payload
                                if (n == 0) {
                                    // HERE IS PROBLEM!!! What should i do to correctly say to Spring - no message exist, continue work without Exceptions
                                    throw new SoftEndOfStreamException("No data are readed from channel");
                                }
                    ...
                    }
                    
                    try { 
                        readData();
                    } catch (SoftEndOfStreamException ex) { 
                        //just skip message
                    }

                    Comment


                    • #11
                      Ok.
                      Maybe it's enough:

                      Code:
                       if (n == 0) {
                                      // HERE IS PROBLEM!!! What should i do to correctly say to Spring - no message exist, continue work without Exceptions
                                      // throw new SoftEndOfStreamException("No data are readed from channel");
                                      return "NO MESSAGE EXIST".getBytes();
                                  }

                      Comment


                      • #12
                        // HERE IS PROBLEM!!! What should i do to correctly say to Spring - no message exist, continue work without Exceptions
                        I couldn't disagree more!

                        Using an exception to convey information to something further down the stack is entirely legitimate.

                        Otherwise, you'd have to pass and test some 'special' return value (such as null) in *every* stack frame on the way down. In this case, the exception tells the framework that the socket was closed in an orderly fashion, and we can clean up properly. The intervening frames don't care about the condition.

                        We don't incur any additional overhead because we have to catch IOExceptions anyway (SEOSE is a subclass of IOException).

                        You don't need to worry about it being logged; we consume the exception at the appropriate stack frame; it is not logged; as I said it is used to convey information. Aside from not having to worry about the condition in all the stack frames between convert() in the connection and the low-level code in the deserializer; I feel it conveys more semantic value than, say, returning something like null or some other special value.

                        It is clearly documented in the javadoc for the exception as well as in the javadoc for the deserialize() method in our serializers.

                        If you used our serializer as a base, I don't see why you didn't use that part of the code.

                        You can disagree if you like, but if you want to avoid the 'can't send null' message, you need to throw the exception if the socket is closed before any part of a message is received.

                        HTH

                        Comment


                        • #13
                          Yes, it's possible but it's bad decision.

                          Data from TCP channel goes to JMS and stores until processing service. So this "NO MESSAGE EXIST" will be stored in JMS saved to log file, to HDD... then readed from HDD and send to JMS-receiver.

                          Also possbile situation that for one package of real data will be 10 "NO MESSAGE EXIST". This mean that JMS server will store huge amounts of useless messages, cunsuming CPU and IO resources.

                          Comment


                          • #14
                            Re: How not to send message?

                            I have to agree with Gary, and he's given you a good solution. The serializer's job is to make sense of what's on the channel, it shouldn't be making business decisions as to whether what it gets is sensible (cf Separation of Concerns). At the (low) level of abstraction of a serializer, receiving null is exceptional. You may want to use it elsewhere when your solution wouldn't make sense.

                            Cleric's earlier answer ("Your can define on your tcp-adapter an error-channel.") may give you a way to avoid the waste of JMS resources, otherwise it seems a problem with your stream rather than with Spring; presumably you've looked into improving that already.

                            David

                            Comment

                            Working...
                            X