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 }