1 /*
2 * $Id: DefaultProtocol.java 7976 2007-08-21 14:26:13Z 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 }