1 /*
2 * $Id: DirectProtocol.java 19191 2010-08-25 21:05:23Z tcarlson $
3 * --------------------------------------------------------------------------------------
4 * Copyright (c) MuleSoft, Inc. All rights reserved. http://www.mulesoft.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 len, limit, 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 }