Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
LengthProtocol |
|
| 0.0;0 |
1 | /* | |
2 | * $Id: LengthProtocol.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.DataInputStream; | |
14 | import java.io.DataOutputStream; | |
15 | import java.io.IOException; | |
16 | import java.io.InputStream; | |
17 | import java.io.OutputStream; | |
18 | ||
19 | import org.apache.commons.logging.Log; | |
20 | import org.apache.commons.logging.LogFactory; | |
21 | ||
22 | /** | |
23 | * The LengthProtocol is an application level tcp protocol that can be used to | |
24 | * transfer large amounts of data without risking some data to be loss. The protocol | |
25 | * is defined by sending / reading an integer (the packet length) and then the data | |
26 | * to be transferred. | |
27 | * | |
28 | * <p>Note that use of this protocol must be symmetric - both the sending and receiving | |
29 | * connectors must use the same protocol.</p> | |
30 | */ | |
31 | public class LengthProtocol extends DirectProtocol | |
32 | { | |
33 | ||
34 | 0 | private static final Log logger = LogFactory.getLog(LengthProtocol.class); |
35 | // TODO - can we not get this from the API somewhere? | |
36 | private static final int SIZE_INT = 4; | |
37 | public static final int NO_MAX_LENGTH = -1; | |
38 | private int maxMessageLength; | |
39 | ||
40 | public LengthProtocol() | |
41 | { | |
42 | 0 | this(NO_MAX_LENGTH); |
43 | 0 | } |
44 | ||
45 | public LengthProtocol(int maxMessageLength) | |
46 | { | |
47 | 0 | super(NO_STREAM, SIZE_INT); |
48 | 0 | this.setMaxMessageLength(maxMessageLength); |
49 | 0 | } |
50 | ||
51 | public Object read(InputStream is) throws IOException | |
52 | { | |
53 | // original comments indicated that we need to use read(byte[]) rather than readInt() | |
54 | // to avoid socket timeouts - don't understand, but don't want to risk change. | |
55 | ||
56 | // first read the data necessary to know the length of the payload | |
57 | 0 | DataInputStream dis = new DataInputStream(is); |
58 | 0 | dis.mark(SIZE_INT); |
59 | // this pulls through SIZE_INT bytes | |
60 | 0 | if (null == super.read(dis, SIZE_INT)) |
61 | { | |
62 | 0 | return null; // eof |
63 | } | |
64 | ||
65 | // reset and read the integer | |
66 | 0 | dis.reset(); |
67 | 0 | int length = dis.readInt(); |
68 | 0 | if (logger.isDebugEnabled()) |
69 | { | |
70 | 0 | logger.debug("length: " + length); |
71 | } | |
72 | ||
73 | 0 | if (length < 0 || (getMaxMessageLength() > 0 && length > getMaxMessageLength())) |
74 | { | |
75 | 0 | throw new IOException("Length " + length + " exceeds limit: " + getMaxMessageLength()); |
76 | } | |
77 | ||
78 | // finally read the rest of the data | |
79 | 0 | byte[] buffer = new byte[length]; |
80 | 0 | dis.readFully(buffer); |
81 | 0 | if (logger.isDebugEnabled()) |
82 | { | |
83 | 0 | logger.debug("length read: " + buffer.length); |
84 | } | |
85 | ||
86 | 0 | return buffer; |
87 | } | |
88 | ||
89 | @Override | |
90 | protected void writeByteArray(OutputStream os, byte[] data) throws IOException | |
91 | { | |
92 | // Write the length and then the data. | |
93 | 0 | DataOutputStream dos = new DataOutputStream(os); |
94 | 0 | dos.writeInt(data.length); |
95 | 0 | dos.write(data); |
96 | // DataOutputStream size is SIZE_INT + the byte length, due to the writeInt call | |
97 | // this should fix EE-1494 | |
98 | 0 | if (dos.size() != data.length + SIZE_INT) |
99 | { | |
100 | // only flush if the sizes don't match up | |
101 | 0 | dos.flush(); |
102 | } | |
103 | 0 | } |
104 | ||
105 | /** | |
106 | * Read all four bytes for initial integer (limit is set in read) | |
107 | * | |
108 | * @param len Amount transferred last call (-1 on EOF or socket error) | |
109 | * @param available Amount available | |
110 | * @return true if the transfer should continue | |
111 | */ | |
112 | @Override | |
113 | protected boolean isRepeat(int len, int available) | |
114 | { | |
115 | 0 | return true; |
116 | } | |
117 | ||
118 | public int getMaxMessageLength() | |
119 | { | |
120 | 0 | return maxMessageLength; |
121 | } | |
122 | ||
123 | public void setMaxMessageLength(int maxMessageLength) | |
124 | { | |
125 | 0 | this.maxMessageLength = maxMessageLength; |
126 | 0 | } |
127 | ||
128 | } |