View Javadoc

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