View Javadoc
1   /*
2    * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.com
3    * The software in this package is published under the terms of the CPAL v1.0
4    * license, a copy of which has been included with this distribution in the
5    * LICENSE.txt file.
6    */
7   package org.mule.transport.tcp.protocols;
8   
9   import java.io.IOException;
10  import java.io.InputStream;
11  import java.text.MessageFormat;
12  
13  import org.apache.commons.io.output.ByteArrayOutputStream;
14  import org.apache.commons.logging.Log;
15  import org.apache.commons.logging.LogFactory;
16  
17  /**
18   * The DirectProtocol class is an application level tcp protocol that does nothing.
19   * The socket is read until no more bytes are (momentarily) available
20   * (previously the transfer buffer also had to be full on the previous read, which made
21   * stronger requirements on the underlying network).  On slow networks
22   * {@link org.mule.transport.tcp.protocols.EOFProtocol} and
23   * {@link org.mule.transport.tcp.protocols.LengthProtocol} may be more reliable.
24   *
25   * <p>Writing simply writes the data to the socket.</p>
26   */
27  public class DirectProtocol extends AbstractByteProtocol
28  {
29  
30      protected static final int UNLIMITED = -1;
31  
32      private static final Log logger = LogFactory.getLog(DirectProtocol.class);
33      private static final int DEFAULT_BUFFER_SIZE = 8192;
34      
35      protected int bufferSize;
36  
37      public DirectProtocol()
38      {
39          this(STREAM_OK, DEFAULT_BUFFER_SIZE);
40      }
41  
42      public DirectProtocol(boolean streamOk, int bufferSize)
43      {
44          super(streamOk);
45          this.bufferSize = bufferSize;
46      }
47  
48      public Object read(InputStream is) throws IOException
49      {
50          return read(is, UNLIMITED);
51      }
52  
53      public Object read(InputStream is, int limit) throws IOException
54      {
55          // this can grow on repeated reads
56          ByteArrayOutputStream baos = new ByteArrayOutputStream(bufferSize);
57          
58          try
59          {
60              byte[] buffer = new byte[bufferSize];
61              int len;
62              int remain = remaining(limit, limit, 0);
63              boolean repeat;
64              do
65              {
66  
67                  len = copy(is, buffer, baos, remain);
68                  remain = remaining(limit, remain, len);
69                  repeat = EOF != len && remain > 0 && isRepeat(len, is.available());
70  
71                  if (logger.isDebugEnabled())
72                  {
73                      logger.debug(MessageFormat.format(
74                              "len/limit/repeat: {0}/{1}/{2}",
75                              len, limit, repeat));
76                  }
77              }
78              while (repeat);
79          }
80          finally
81          {
82              baos.flush();
83              baos.close();
84          }
85          return nullEmptyArray(baos.toByteArray());
86      }
87  
88      protected int remaining(int limit, int remain, int len)
89      {
90          if (UNLIMITED == limit)
91          {
92              return bufferSize;
93          }
94          else if (EOF != len)
95          {
96              return remain - len;
97          }
98          else
99          {
100             return remain;
101         }
102     }
103 
104     /**
105      * Decide whether to repeat transfer.  This implementation does so if
106      * more data are available.  Note that previously, while documented as such,
107      * there was also the additional requirement that the previous transfer
108      * completely used the transfer buffer.
109      *
110      * @param len Amount transferred last call (-1 on EOF or socket error)
111      * @param available Amount available
112      * @return true if the transfer should continue
113      */
114     protected boolean isRepeat(int len, int available)
115     {
116         // previous logic - less reliable on slow networks
117 //        return len == bufferSize && available > 0;
118         
119         return available > 0;
120     }
121 
122 }