Package nexj.core.rpc.tcp

Source Code of nexj.core.rpc.tcp.MLLPMessageInputStream

package nexj.core.rpc.tcp;

import java.io.IOException;
import java.io.InputStream;
import java.net.SocketTimeoutException;

import nexj.core.integration.MessageInputStream;
import nexj.core.rpc.RPCException;
import nexj.core.rpc.TransferObject;
import nexj.core.rpc.tcp.ra.TCPTimeoutException;
import nexj.core.util.IOUtil;

/**
* An MLLP input stream.
*/
public class MLLPMessageInputStream extends MessageInputStream
{
   // constants

   /**
    * The initial size of the buffer.
    * It will grow as needed.
    */
   protected final static int INITIAL_BUFFER_SIZE = IOUtil.BUFFER_SIZE;

   // attributes

   /**
    * Array to buffer the message body.
    */
   protected byte[] m_nBuffer;

   /**
    * The current buffer position.
    * While reading: The next byte returned will be m_nBuffer[m_nBufReadPos].
    */
   protected int m_nBufReadPos;

   /**
    * The position in the buffer where the current message starts.
    */
   protected int m_nBufStartPos;

   /**
    * The position in the buffer that holds the last byte of the current message.
    */
   protected int m_nBufEndPos;

   /**
    * The position in the buffer just past the last byte read from the socket.
    */
   protected int m_nLastIndex;

   // associations

   /**
    * The MLLP message stream factory.
    */
   protected MLLPMessageStreamFactory m_factory;

   // constructors

   /**
    * @param istream The underlying input stream.
    * @param factory The message stream factory (caller).
    */
   public MLLPMessageInputStream(InputStream istream, MLLPMessageStreamFactory factory)
   {
      super(istream);

      m_factory = factory;

      // initialize buffer
      m_nBuffer = new byte[Math.min(INITIAL_BUFFER_SIZE, m_factory.getMaxReadBufferSize())];
   }

   // operations

   /**
    * @see nexj.core.integration.MessageInputStream#next(nexj.core.rpc.TransferObject)
    */
   public boolean next(TransferObject raw) throws IOException, TCPTimeoutException
   {
      // next byte will be read into m_nBuffer[nPos]
      int nPos = (m_nLastIndex == 0 ? 0 : m_nBufEndPos + 3);
      int n = 0;
      boolean bFoundEB = false;
      boolean bFoundSB = false;

      // resize buffer if necessary
      nPos = checkAndResizeBuffer(nPos, bFoundSB);

      for (;;)
      {
         if (nPos >= m_nLastIndex)
         {
            // read a chunk of data
            int nNewByteCount = readChunk(m_nBuffer, nPos, m_nBuffer.length - nPos);

            // end-of-file?
            if (nNewByteCount == -1)
            {
               if (bFoundSB)
               {
                  throw new RPCException("err.rpc.tcp.mllp.unexpectedEOF");
               }
               else
               {
                  return false;
               }
            }

            m_nLastIndex = nPos + nNewByteCount;
         }

         if (!bFoundSB)
         {
            for (; nPos < m_nLastIndex; ++nPos)
            {
               // read and discard until
               // we find the start byte
               n = m_nBuffer[nPos];

               // start byte?
               if (n == m_factory.getStartBlock())
               {
                  bFoundSB = true;

                  break;
               }
            }

            // resize buffer if necessary
            nPos = checkAndResizeBuffer(nPos, bFoundSB);

            if (!bFoundSB)
            {
               continue;
            }

            m_nBufStartPos = ++nPos;
         }

         // read until we get an end byte followed by message separator
         for (; nPos < m_nLastIndex; ++nPos)
         {
            n = m_nBuffer[nPos];

            // start byte?
            if (n == m_factory.getStartBlock())
            {
               // ignore all currently buffered bytes
               m_nBufStartPos = nPos + 1;

               continue;
            }

            // message separator?
            if (bFoundEB)
            {
               if (n == m_factory.getMessageSeparator())
               {
                  // We've read (and buffered) a complete message
                  m_nBufEndPos = nPos - 2;
                  m_nBufReadPos = m_nBufStartPos;

                  return true;
               }

               throw new RPCException("err.rpc.tcp.mllp.noCRAfterEB",
                  new Object[] { new Integer(m_factory.getMessageSeparator()), new Integer(n) });
            }

            // end byte?
            if (n == m_factory.getEndBlock())
            {
               bFoundEB = true;

               continue;
            }

            // invalid byte?
            if (!m_factory.isValidByte(n))
            {
               throw new RPCException("err.rpc.tcp.mllp.invalidByte",
                  new Object[] { new Integer(n), new Integer(m_factory.getMinByte()) });
            }

            // resize buffer if necessary
            nPos = checkAndResizeBuffer(nPos, bFoundSB);

            if (nPos == 0)
            {
               break;
            }
         }
      }
   }

   /**
    * The buffer will be re-sized or the existing bytes shifted to
    * the beginning if necessary.
    * @param nPos The current byte position in the buffer.
    * @param bFoundSB True iff we have found the start byte for the current message.
    * @return The new nPos value.
    */
   protected int checkAndResizeBuffer(int nPos, boolean bFoundSB)
   {
      // Do we need to increase the buffer size?
      // or shift array elements down?
      if (nPos >= m_nBuffer.length - 1)
      {
         if (!bFoundSB)
         {
            // we haven't found a start byte yet, so no need to increase
            // the buffer size, just reset it.
            m_nLastIndex = 0;
            m_nBufStartPos = 0;
            m_nBufEndPos = 0;
            nPos = 0;
         }
         else if (m_nBufStartPos >= m_nBuffer.length >> 1)
         {
            // shift bytes down
            System.arraycopy(m_nBuffer, m_nBufStartPos, m_nBuffer, 0, m_nLastIndex - m_nBufStartPos);
            nPos = nPos - m_nBufStartPos;
            m_nLastIndex = m_nLastIndex - m_nBufStartPos;
            m_nBufStartPos = 0;
         }
         else
         {
            // increase buffer size
            int nNewSize;

            // buffer length already greater than half the max?
            if (m_nBuffer.length > m_factory.getMaxReadBufferSize() >> 1)
            {
               // new size will be the maximum
               nNewSize = m_factory.getMaxReadBufferSize();
            }
            else
            {
               // double the current size
               nNewSize = m_nBuffer.length << 1;
            }

            if (nNewSize <= m_nBuffer.length)
            {
               // We can't continue, since we've reached the
               // maximum buffer size (according to the settings).
               throw new RPCException("err.rpc.tcp.mllp.noBufferSpace");
            }

            byte[] newBuffer = new byte[nNewSize];
            System.arraycopy(m_nBuffer, 0, newBuffer, 0, m_nBuffer.length);
            m_nBuffer = newBuffer;
         }
      }

      return nPos;
   }

   /**
    * @see java.io.InputStream#read()
    */
   public int read() throws IOException
   {
      assert m_nBufReadPos >= m_nBufStartPos;

      // Have we read everything?
      if (m_nBufReadPos > m_nBufEndPos)
      {
         return -1;
      }

      return (int)m_nBuffer[m_nBufReadPos++] & 0xFF;
   }

   /**
    * @see java.io.InputStream#read(byte[], int, int)
    */
   public int read(byte[] nArray, int nOffset, int nLength) throws IOException
   {
      assert m_nBufReadPos >= m_nBufStartPos;

      // Have we read everything?
      if (m_nBufReadPos > m_nBufEndPos)
      {
         return -1;
      }

      int nNumToCopy = Math.min(nLength, m_nBufEndPos - m_nBufReadPos + 1);

      System.arraycopy(m_nBuffer, m_nBufReadPos, nArray, nOffset, nNumToCopy);
      m_nBufReadPos += nNumToCopy;

      return nNumToCopy;
   }

   /**
    * Performs a read() call on the underlying input stream.
    * Catches SocketTimeoutException's and re-throws them as TCPTimeoutException's
    * after resetting the position variables.
    * @param nArray The destination buffer.
    * @param nOffset The start index into the destination buffer.
    * @param nLength The length of the destination buffer.
    * @return The number of bytes read into the buffer, or -1 if the end of the stream is reached.
    * @throws IOException, TCPTimeoutException
    */
   protected int readChunk(byte[] nArray, int nOffset, int nLength) throws IOException, TCPTimeoutException
   {
      try
      {
         return m_istream.read(nArray, nOffset, nLength);
      }
      catch (SocketTimeoutException e)
      {
         m_nLastIndex = 0;
         m_nBufStartPos = 0;
         m_nBufEndPos = 0;

         throw new TCPTimeoutException(e);
      }
   }
}
TOP

Related Classes of nexj.core.rpc.tcp.MLLPMessageInputStream

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.