View Javadoc

1   /*
2    * $Id: DirectProtocol.java 10489 2008-01-23 17:53:38Z dfeist $
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.transport.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 DirectProtocol class is an application level tcp protocol that does nothing.
23   * The socket is read until no more bytes are (momentarily) 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.transport.tcp.protocols.EOFProtocol} and
27   * {@link org.mule.transport.tcp.protocols.LengthProtocol} may be more reliable.
28   *
29   * <p>Writing simply writes the data to the socket.</p>
30   */
31  public class DirectProtocol extends AbstractByteProtocol
32  {
33  
34      protected static final int UNLIMITED = -1;
35  
36      private static final Log logger = LogFactory.getLog(DirectProtocol.class);
37      private static final int DEFAULT_BUFFER_SIZE = 8192;
38      
39      protected int bufferSize;
40  
41      public DirectProtocol()
42      {
43          this(STREAM_OK, DEFAULT_BUFFER_SIZE);
44      }
45  
46      public DirectProtocol(boolean streamOk, int bufferSize)
47      {
48          super(streamOk);
49          this.bufferSize = bufferSize;
50      }
51  
52      public Object read(InputStream is) throws IOException
53      {
54          return read(is, UNLIMITED);
55      }
56  
57      public Object read(InputStream is, int limit) throws IOException
58      {
59          // this can grow on repeated reads
60          ByteArrayOutputStream baos = new ByteArrayOutputStream(bufferSize);
61          
62          try
63          {
64              byte[] buffer = new byte[bufferSize];
65              int len;
66              int remain = remaining(limit, limit, 0);
67              boolean repeat;
68              do
69              {
70  
71                  len = copy(is, buffer, baos, remain);
72                  remain = remaining(limit, remain, len);
73                  repeat = EOF != len && remain > 0 && isRepeat(len, is.available());
74  
75                  if (logger.isDebugEnabled())
76                  {
77                      logger.debug(MessageFormat.format(
78                              "len/limit/repeat: {0}/{1}/{2}",
79                              new Object[] {new Integer(len), new Integer(limit), Boolean.valueOf(repeat)}));
80                  }
81              }
82              while (repeat);
83          }
84          finally
85          {
86              baos.flush();
87              baos.close();
88          }
89          return nullEmptyArray(baos.toByteArray());
90      }
91  
92      protected int remaining(int limit, int remain, int len)
93      {
94          if (UNLIMITED == limit)
95          {
96              return bufferSize;
97          }
98          else if (EOF != len)
99          {
100             return remain - len;
101         }
102         else
103         {
104             return remain;
105         }
106     }
107 
108     /**
109      * Decide whether to repeat transfer.  This implementation does so if
110      * more data are available.  Note that previously, while documented as such,
111      * there was also the additional requirement that the previous transfer
112      * completely used the transfer buffer.
113      *
114      * @param len Amount transferred last call (-1 on EOF or socket error)
115      * @param available Amount available
116      * @return true if the transfer should continue
117      */
118     protected boolean isRepeat(int len, int available)
119     {
120         // previous logic - less reliable on slow networks
121 //        return len == bufferSize && available > 0;
122         
123         return available > 0;
124     }
125 
126 }