INT-2419 Thread Starvation Detection
Previously, it was possible to run out of threads in a fixed thread pool, and this could cause an indefinite deadlock. With this change, the deadlock is detected causing the current message to fail, but freeing up the stuck threads. This was only seen with very small thread pools but the potential was there for the condition to occur under extreme conditions. INT-2419 Deprecate poolSize Property INT-2419 Polishing Add note about OOM possibility now that an unbounded task executor is used by default.
This commit is contained in:
committed by
Oleg Zhurakousky
parent
01225b8a48
commit
90fe92ae29
@@ -206,7 +206,6 @@
|
||||
using-nio="#{props['use.nio']}"
|
||||
single-use="true"
|
||||
task-executor="externalTE"
|
||||
pool-size="321"
|
||||
using-direct-buffers="true"
|
||||
interceptor-factory-chain="interceptors"
|
||||
/>
|
||||
@@ -232,11 +231,18 @@
|
||||
using-nio="true"
|
||||
single-use="true"
|
||||
task-executor="externalTE"
|
||||
pool-size="123"
|
||||
backlog="123"
|
||||
using-direct-buffers="true"
|
||||
interceptor-factory-chain="interceptors"
|
||||
/>
|
||||
|
||||
<ip:tcp-connection-factory
|
||||
id="serverBackwardsCompatible"
|
||||
type="server"
|
||||
port="#{client1.port}"
|
||||
pool-size="123"
|
||||
/>
|
||||
|
||||
<ip:tcp-connection-factory
|
||||
id="client2"
|
||||
type="client"
|
||||
@@ -254,7 +260,6 @@
|
||||
using-nio="false"
|
||||
single-use="true"
|
||||
task-executor="externalTE"
|
||||
pool-size="321"
|
||||
interceptor-factory-chain="interceptors"
|
||||
/>
|
||||
|
||||
@@ -275,7 +280,7 @@
|
||||
using-nio="false"
|
||||
single-use="true"
|
||||
task-executor="externalTE"
|
||||
pool-size="123"
|
||||
backlog="123"
|
||||
interceptor-factory-chain="interceptors"
|
||||
/>
|
||||
|
||||
|
||||
@@ -154,6 +154,9 @@ public class ParserUnitTests {
|
||||
@Autowired
|
||||
AbstractConnectionFactory server1;
|
||||
|
||||
@Autowired
|
||||
AbstractConnectionFactory serverBackwardsCompatible;
|
||||
|
||||
@Autowired
|
||||
AbstractConnectionFactory server2;
|
||||
|
||||
@@ -404,7 +407,6 @@ public class ParserUnitTests {
|
||||
assertEquals(true, dfa.getPropertyValue("soTcpNoDelay"));
|
||||
assertEquals(true, dfa.getPropertyValue("singleUse"));
|
||||
assertSame(taskExecutor, dfa.getPropertyValue("taskExecutor"));
|
||||
assertEquals(321, dfa.getPropertyValue("poolSize"));
|
||||
assertEquals(true, dfa.getPropertyValue("usingDirectBuffers"));
|
||||
assertNotNull(dfa.getPropertyValue("interceptorFactoryChain"));
|
||||
}
|
||||
@@ -424,11 +426,18 @@ public class ParserUnitTests {
|
||||
assertEquals(true, dfa.getPropertyValue("soTcpNoDelay"));
|
||||
assertEquals(true, dfa.getPropertyValue("singleUse"));
|
||||
assertSame(taskExecutor, dfa.getPropertyValue("taskExecutor"));
|
||||
assertEquals(123, dfa.getPropertyValue("poolSize"));
|
||||
assertEquals(123, dfa.getPropertyValue("backlog"));
|
||||
assertEquals(true, dfa.getPropertyValue("usingDirectBuffers"));
|
||||
assertNotNull(dfa.getPropertyValue("interceptorFactoryChain"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConnDeprecatedPoolSize() {
|
||||
assertTrue(serverBackwardsCompatible instanceof TcpNetServerConnectionFactory);
|
||||
DirectFieldAccessor dfa = new DirectFieldAccessor(serverBackwardsCompatible);
|
||||
assertEquals(123, dfa.getPropertyValue("backlog"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConnClient2() {
|
||||
assertTrue(client2 instanceof TcpNetClientConnectionFactory);
|
||||
@@ -445,7 +454,6 @@ public class ParserUnitTests {
|
||||
assertEquals(true, dfa.getPropertyValue("soTcpNoDelay"));
|
||||
assertEquals(true, dfa.getPropertyValue("singleUse"));
|
||||
assertSame(taskExecutor, dfa.getPropertyValue("taskExecutor"));
|
||||
assertEquals(321, dfa.getPropertyValue("poolSize"));
|
||||
assertNotNull(dfa.getPropertyValue("interceptorFactoryChain"));
|
||||
}
|
||||
|
||||
@@ -464,7 +472,7 @@ public class ParserUnitTests {
|
||||
assertEquals(true, dfa.getPropertyValue("soTcpNoDelay"));
|
||||
assertEquals(true, dfa.getPropertyValue("singleUse"));
|
||||
assertSame(taskExecutor, dfa.getPropertyValue("taskExecutor"));
|
||||
assertEquals(123, dfa.getPropertyValue("poolSize"));
|
||||
assertEquals(123, dfa.getPropertyValue("backlog"));
|
||||
assertNotNull(dfa.getPropertyValue("interceptorFactoryChain"));
|
||||
}
|
||||
|
||||
|
||||
@@ -37,7 +37,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import javax.net.ServerSocketFactory;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.core.serializer.DefaultDeserializer;
|
||||
import org.springframework.core.serializer.DefaultSerializer;
|
||||
import org.springframework.integration.Message;
|
||||
@@ -54,7 +53,7 @@ import org.springframework.integration.support.MessageBuilder;
|
||||
*/
|
||||
public class TcpOutboundGatewayTests {
|
||||
|
||||
@Test
|
||||
@Test
|
||||
public void testGoodNetSingle() throws Exception {
|
||||
final int port = SocketTestUtils.findAvailableServerSocket();
|
||||
AbstractConnectionFactory ccf = new TcpNetClientConnectionFactory("localhost", port);
|
||||
@@ -84,7 +83,6 @@ public class TcpOutboundGatewayTests {
|
||||
ccf.setDeserializer(new DefaultDeserializer());
|
||||
ccf.setSoTimeout(10000);
|
||||
ccf.setSingleUse(true);
|
||||
ccf.setPoolSize(10);
|
||||
ccf.start();
|
||||
assertTrue(latch.await(10000, TimeUnit.MILLISECONDS));
|
||||
TcpOutboundGateway gateway = new TcpOutboundGateway();
|
||||
@@ -98,7 +96,7 @@ public class TcpOutboundGatewayTests {
|
||||
gateway.handleMessage(MessageBuilder.withPayload("Test" + i).build());
|
||||
}
|
||||
Set<String> replies = new HashSet<String>();
|
||||
for (int i = 100; i < 200; i++) {
|
||||
for (int i = 100; i < 200; i++) {
|
||||
Message<?> m = replyChannel.receive(10000);
|
||||
assertNotNull(m);
|
||||
replies.add((String) m.getPayload());
|
||||
@@ -108,7 +106,7 @@ public class TcpOutboundGatewayTests {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@Test
|
||||
public void testGoodNetMultiplex() throws Exception {
|
||||
final int port = SocketTestUtils.findAvailableServerSocket();
|
||||
final CountDownLatch latch = new CountDownLatch(1);
|
||||
@@ -149,7 +147,7 @@ public class TcpOutboundGatewayTests {
|
||||
gateway.handleMessage(MessageBuilder.withPayload("Test" + i).build());
|
||||
}
|
||||
Set<String> replies = new HashSet<String>();
|
||||
for (int i = 100; i < 110; i++) {
|
||||
for (int i = 100; i < 110; i++) {
|
||||
Message<?> m = replyChannel.receive(10000);
|
||||
assertNotNull(m);
|
||||
replies.add((String) m.getPayload());
|
||||
@@ -160,7 +158,7 @@ public class TcpOutboundGatewayTests {
|
||||
done.set(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Test
|
||||
public void testGoodNetTimeout() throws Exception {
|
||||
final int port = SocketTestUtils.findAvailableServerSocket();
|
||||
final CountDownLatch latch = new CountDownLatch(1);
|
||||
@@ -212,11 +210,11 @@ public class TcpOutboundGatewayTests {
|
||||
}
|
||||
Set<String> replies = new HashSet<String>();
|
||||
int timeouts = 0;
|
||||
for (int i = 0; i < 2; i++) {
|
||||
for (int i = 0; i < 2; i++) {
|
||||
try {
|
||||
results[i].get();
|
||||
} catch (InterruptedException e) {
|
||||
|
||||
|
||||
} catch (ExecutionException e) {
|
||||
if (timeouts > 0) {
|
||||
fail("Unexpected " + e.getMessage());
|
||||
|
||||
@@ -151,7 +151,7 @@ public class TcpReceivingChannelAdapterTests {
|
||||
TcpNioServerConnectionFactory scf = new TcpNioServerConnectionFactory(port);
|
||||
ByteArrayCrLfSerializer serializer = new ByteArrayCrLfSerializer();
|
||||
scf.setSerializer(serializer);
|
||||
scf.setDeserializer(serializer);
|
||||
scf.setDeserializer(serializer);
|
||||
scf.setSoTimeout(5000);
|
||||
TcpReceivingChannelAdapter adapter = new TcpReceivingChannelAdapter();
|
||||
adapter.setConnectionFactory(scf);
|
||||
@@ -168,7 +168,7 @@ public class TcpReceivingChannelAdapterTests {
|
||||
Socket socket = SocketFactory.getDefault().createSocket("localhost", port);
|
||||
for (int i = 0; i < 1000; i++) {
|
||||
socket.getOutputStream().write(("Test" + i + "\r\n").getBytes());
|
||||
}
|
||||
}
|
||||
Set<String> results = new HashSet<String>();
|
||||
for (int i = 0; i < 1000; i++) {
|
||||
Message<?> message = channel.receive(10000);
|
||||
@@ -210,14 +210,14 @@ public class TcpReceivingChannelAdapterTests {
|
||||
handler.handleMessage(message);
|
||||
message = channel.receive(10000);
|
||||
assertNotNull(message);
|
||||
handler.handleMessage(message);
|
||||
handler.handleMessage(message);
|
||||
byte[] b = new byte[6];
|
||||
readFully(socket.getInputStream(), b);
|
||||
assertEquals("Test\r\n", new String(b));
|
||||
readFully(socket.getInputStream(), b);
|
||||
assertEquals("Test\r\n", new String(b));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testNioShared() throws Exception {
|
||||
final int port = SocketTestUtils.findAvailableServerSocket();
|
||||
@@ -248,14 +248,14 @@ public class TcpReceivingChannelAdapterTests {
|
||||
handler.handleMessage(message);
|
||||
message = channel.receive(10000);
|
||||
assertNotNull(message);
|
||||
handler.handleMessage(message);
|
||||
handler.handleMessage(message);
|
||||
byte[] b = new byte[6];
|
||||
readFully(socket.getInputStream(), b);
|
||||
assertEquals("Test\r\n", new String(b));
|
||||
readFully(socket.getInputStream(), b);
|
||||
assertEquals("Test\r\n", new String(b));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testNetSingleNoOutbound() throws Exception {
|
||||
final int port = SocketTestUtils.findAvailableServerSocket();
|
||||
@@ -316,7 +316,7 @@ public class TcpReceivingChannelAdapterTests {
|
||||
socket.getOutputStream().write("Test1\r\n".getBytes());
|
||||
socket = SocketFactory.getDefault().createSocket("localhost", port);
|
||||
socket.getOutputStream().write("Test2\r\n".getBytes());
|
||||
Message<?> message = channel.receive(10000);
|
||||
Message<?> message = channel.receive(60000);
|
||||
assertNotNull(message);
|
||||
// with single use, results may come back in a different order
|
||||
Set<String> results = new HashSet<String>();
|
||||
@@ -371,15 +371,15 @@ public class TcpReceivingChannelAdapterTests {
|
||||
handler.handleMessage(message);
|
||||
message = channel.receive(10000);
|
||||
assertNotNull(message);
|
||||
handler.handleMessage(message);
|
||||
handler.handleMessage(message);
|
||||
byte[] b = new byte[7];
|
||||
readFully(socket1.getInputStream(), b);
|
||||
assertEquals("Test1\r\n", new String(b));
|
||||
readFully(socket2.getInputStream(), b);
|
||||
assertEquals("Test2\r\n", new String(b));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@Test
|
||||
public void testNioSingleShared() throws Exception {
|
||||
final int port = SocketTestUtils.findAvailableServerSocket();
|
||||
TcpNioServerConnectionFactory scf = new TcpNioServerConnectionFactory(port);
|
||||
@@ -412,15 +412,15 @@ public class TcpReceivingChannelAdapterTests {
|
||||
handler.handleMessage(message);
|
||||
message = channel.receive(10000);
|
||||
assertNotNull(message);
|
||||
handler.handleMessage(message);
|
||||
handler.handleMessage(message);
|
||||
byte[] b = new byte[7];
|
||||
readFully(socket1.getInputStream(), b);
|
||||
assertEquals("Test1\r\n", new String(b));
|
||||
readFully(socket2.getInputStream(), b);
|
||||
assertEquals("Test2\r\n", new String(b));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@Test
|
||||
public void testNioSingleSharedMany() throws Exception {
|
||||
final int port = SocketTestUtils.findAvailableServerSocket();
|
||||
TcpNioServerConnectionFactory scf = new TcpNioServerConnectionFactory(port);
|
||||
@@ -428,12 +428,12 @@ public class TcpReceivingChannelAdapterTests {
|
||||
scf.setSerializer(serializer);
|
||||
scf.setDeserializer(serializer);
|
||||
scf.setSingleUse(true);
|
||||
scf.setPoolSize(100);
|
||||
scf.setBacklog(100);
|
||||
TcpSendingMessageHandler handler = new TcpSendingMessageHandler();
|
||||
handler.setConnectionFactory(scf);
|
||||
TcpReceivingChannelAdapter adapter = new TcpReceivingChannelAdapter();
|
||||
adapter.setConnectionFactory(scf);
|
||||
Executor te = Executors.newFixedThreadPool(10);
|
||||
Executor te = Executors.newCachedThreadPool();
|
||||
scf.setTaskExecutor(te);
|
||||
scf.start();
|
||||
QueueChannel channel = new QueueChannel();
|
||||
@@ -453,17 +453,17 @@ public class TcpReceivingChannelAdapterTests {
|
||||
sockets.add(socket1);
|
||||
}
|
||||
for (int i = 100; i < 200; i++) {
|
||||
Message<?> message = channel.receive(10000);
|
||||
Message<?> message = channel.receive(60000);
|
||||
assertNotNull(message);
|
||||
handler.handleMessage(message);
|
||||
}
|
||||
byte[] b = new byte[9];
|
||||
for (int i = 100; i < 200; i++) {
|
||||
for (int i = 100; i < 200; i++) {
|
||||
readFully(sockets.remove(0).getInputStream(), b);
|
||||
assertEquals("Test" + i + "\r\n", new String(b));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testNetInterceptors() throws Exception {
|
||||
final int port = SocketTestUtils.findAvailableServerSocket();
|
||||
@@ -484,7 +484,7 @@ public class TcpReceivingChannelAdapterTests {
|
||||
AbstractServerConnectionFactory scf = new TcpNetServerConnectionFactory(port);
|
||||
singleSharedInterceptorsGuts(port, scf);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testNioInterceptors() throws Exception {
|
||||
final int port = SocketTestUtils.findAvailableServerSocket();
|
||||
@@ -509,11 +509,11 @@ public class TcpReceivingChannelAdapterTests {
|
||||
private void interceptorsGuts(final int port, AbstractServerConnectionFactory scf) throws Exception {
|
||||
scf.setSerializer(new DefaultSerializer());
|
||||
scf.setDeserializer(new DefaultDeserializer());
|
||||
scf.setSingleUse(false);
|
||||
scf.setSingleUse(false);
|
||||
TcpReceivingChannelAdapter adapter = new TcpReceivingChannelAdapter();
|
||||
adapter.setConnectionFactory(scf);
|
||||
TcpConnectionInterceptorFactoryChain fc = new TcpConnectionInterceptorFactoryChain();
|
||||
fc.setInterceptors(new TcpConnectionInterceptorFactory[]
|
||||
fc.setInterceptors(new TcpConnectionInterceptorFactory[]
|
||||
{new HelloWorldInterceptorFactory(),
|
||||
new HelloWorldInterceptorFactory()});
|
||||
scf.setInterceptorFactoryChain(fc);
|
||||
@@ -553,7 +553,7 @@ public class TcpReceivingChannelAdapterTests {
|
||||
scf.setSingleUse(true);
|
||||
scf.setSoTimeout(10000);
|
||||
TcpConnectionInterceptorFactoryChain fc = new TcpConnectionInterceptorFactoryChain();
|
||||
fc.setInterceptors(new TcpConnectionInterceptorFactory[]
|
||||
fc.setInterceptors(new TcpConnectionInterceptorFactory[]
|
||||
{new HelloWorldInterceptorFactory(),
|
||||
new HelloWorldInterceptorFactory()});
|
||||
scf.setInterceptorFactoryChain(fc);
|
||||
@@ -576,7 +576,7 @@ public class TcpReceivingChannelAdapterTests {
|
||||
new ObjectOutputStream(socket.getOutputStream()).writeObject("Hello");
|
||||
assertEquals("world!", new ObjectInputStream(socket.getInputStream()).readObject());
|
||||
new ObjectOutputStream(socket.getOutputStream()).writeObject("Test1");
|
||||
|
||||
|
||||
socket = SocketFactory.getDefault().createSocket("localhost", port);
|
||||
new ObjectOutputStream(socket.getOutputStream()).writeObject("Hello");
|
||||
assertEquals("world!", new ObjectInputStream(socket.getInputStream()).readObject());
|
||||
@@ -601,7 +601,7 @@ public class TcpReceivingChannelAdapterTests {
|
||||
scf.setSingleUse(true);
|
||||
scf.setSoTimeout(60000);
|
||||
TcpConnectionInterceptorFactoryChain fc = new TcpConnectionInterceptorFactoryChain();
|
||||
fc.setInterceptors(new TcpConnectionInterceptorFactory[]
|
||||
fc.setInterceptors(new TcpConnectionInterceptorFactory[]
|
||||
{new HelloWorldInterceptorFactory(),
|
||||
new HelloWorldInterceptorFactory()});
|
||||
scf.setInterceptorFactoryChain(fc);
|
||||
@@ -641,7 +641,7 @@ public class TcpReceivingChannelAdapterTests {
|
||||
message = channel.receive(10000);
|
||||
assertNotNull(message);
|
||||
handler.handleMessage(message);
|
||||
|
||||
|
||||
assertEquals("Test1", new ObjectInputStream(socket1.getInputStream()).readObject());
|
||||
assertEquals("Test2", new ObjectInputStream(socket2.getInputStream()).readObject());
|
||||
}
|
||||
|
||||
@@ -51,7 +51,6 @@ import org.springframework.integration.Message;
|
||||
import org.springframework.integration.MessageChannel;
|
||||
import org.springframework.integration.channel.QueueChannel;
|
||||
import org.springframework.integration.core.PollableChannel;
|
||||
import org.springframework.integration.ip.IpHeaders;
|
||||
import org.springframework.integration.ip.tcp.connection.AbstractConnectionFactory;
|
||||
import org.springframework.integration.ip.tcp.connection.HelloWorldInterceptorFactory;
|
||||
import org.springframework.integration.ip.tcp.connection.TcpConnectionInterceptorFactory;
|
||||
@@ -80,7 +79,7 @@ public class TcpSendingMessageHandlerTests {
|
||||
buff[i] = (byte) is.read();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testNetCrLf() throws Exception {
|
||||
final int port = SocketTestUtils.findAvailableServerSocket();
|
||||
@@ -111,7 +110,7 @@ public class TcpSendingMessageHandlerTests {
|
||||
ByteArrayCrLfSerializer serializer = new ByteArrayCrLfSerializer();
|
||||
ccf.setSerializer(serializer);
|
||||
ccf.setDeserializer(serializer);
|
||||
ccf.setSoTimeout(10000);
|
||||
ccf.setSoTimeout(10000);
|
||||
ccf.start();
|
||||
TcpSendingMessageHandler handler = new TcpSendingMessageHandler();
|
||||
handler.setConnectionFactory(ccf);
|
||||
@@ -119,7 +118,7 @@ public class TcpSendingMessageHandlerTests {
|
||||
adapter.setConnectionFactory(ccf);
|
||||
QueueChannel channel = new QueueChannel();
|
||||
adapter.setOutputChannel(channel);
|
||||
assertTrue(latch.await(10, TimeUnit.SECONDS));
|
||||
assertTrue(latch.await(10, TimeUnit.SECONDS));
|
||||
handler.handleMessage(MessageBuilder.withPayload("Test").build());
|
||||
handler.handleMessage(MessageBuilder.withPayload("Test").build());
|
||||
Message<?> mOut = channel.receive(10000);
|
||||
@@ -239,7 +238,7 @@ public class TcpSendingMessageHandlerTests {
|
||||
assertTrue(results.remove("Reply2"));
|
||||
done.set(true);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testNetStxEtx() throws Exception {
|
||||
final int port = SocketTestUtils.findAvailableServerSocket();
|
||||
@@ -277,7 +276,7 @@ public class TcpSendingMessageHandlerTests {
|
||||
adapter.setConnectionFactory(ccf);
|
||||
QueueChannel channel = new QueueChannel();
|
||||
adapter.setOutputChannel(channel);
|
||||
assertTrue(latch.await(10, TimeUnit.SECONDS));
|
||||
assertTrue(latch.await(10, TimeUnit.SECONDS));
|
||||
handler.handleMessage(MessageBuilder.withPayload("Test").build());
|
||||
handler.handleMessage(MessageBuilder.withPayload("Test").build());
|
||||
Message<?> mOut = channel.receive(10000);
|
||||
@@ -381,7 +380,7 @@ public class TcpSendingMessageHandlerTests {
|
||||
adapter.setConnectionFactory(ccf);
|
||||
QueueChannel channel = new QueueChannel();
|
||||
adapter.setOutputChannel(channel);
|
||||
assertTrue(latch.await(10, TimeUnit.SECONDS));
|
||||
assertTrue(latch.await(10, TimeUnit.SECONDS));
|
||||
handler.handleMessage(MessageBuilder.withPayload("Test").build());
|
||||
handler.handleMessage(MessageBuilder.withPayload("Test").build());
|
||||
Message<?> mOut = channel.receive(10000);
|
||||
@@ -484,7 +483,7 @@ public class TcpSendingMessageHandlerTests {
|
||||
adapter.setConnectionFactory(ccf);
|
||||
QueueChannel channel = new QueueChannel();
|
||||
adapter.setOutputChannel(channel);
|
||||
assertTrue(latch.await(10, TimeUnit.SECONDS));
|
||||
assertTrue(latch.await(10, TimeUnit.SECONDS));
|
||||
handler.handleMessage(MessageBuilder.withPayload("Test").build());
|
||||
handler.handleMessage(MessageBuilder.withPayload("Test").build());
|
||||
Message<?> mOut = channel.receive(10000);
|
||||
@@ -679,7 +678,7 @@ public class TcpSendingMessageHandlerTests {
|
||||
assertTrue(latch.await(10, TimeUnit.SECONDS));
|
||||
handler.handleMessage(MessageBuilder.withPayload("Test").build());
|
||||
handler.handleMessage(MessageBuilder.withPayload("Test").build());
|
||||
assertTrue(semaphore.tryAcquire(2, 10000, TimeUnit.MILLISECONDS));
|
||||
assertTrue(semaphore.tryAcquire(2, 10000, TimeUnit.MILLISECONDS));
|
||||
Set<String> replies = new HashSet<String>();
|
||||
for (int i = 0; i < 2; i++) {
|
||||
Message<?> mOut = channel.receive(10000);
|
||||
@@ -736,7 +735,7 @@ public class TcpSendingMessageHandlerTests {
|
||||
assertTrue(latch.await(10, TimeUnit.SECONDS));
|
||||
handler.handleMessage(MessageBuilder.withPayload("Test").build());
|
||||
handler.handleMessage(MessageBuilder.withPayload("Test").build());
|
||||
assertTrue(semaphore.tryAcquire(2, 10000, TimeUnit.MILLISECONDS));
|
||||
assertTrue(semaphore.tryAcquire(2, 10000, TimeUnit.MILLISECONDS));
|
||||
Set<String> replies = new HashSet<String>();
|
||||
for (int i = 0; i < 2; i++) {
|
||||
Message<?> mOut = channel.receive(10000);
|
||||
@@ -859,9 +858,9 @@ public class TcpSendingMessageHandlerTests {
|
||||
AbstractConnectionFactory ccf = new TcpNetClientConnectionFactory("localhost", port);
|
||||
ccf.setSerializer(new DefaultSerializer());
|
||||
ccf.setDeserializer(new DefaultDeserializer());
|
||||
ccf.setSoTimeout(10000);
|
||||
ccf.setSoTimeout(10000);
|
||||
TcpConnectionInterceptorFactoryChain fc = new TcpConnectionInterceptorFactoryChain();
|
||||
fc.setInterceptors(new TcpConnectionInterceptorFactory[]
|
||||
fc.setInterceptors(new TcpConnectionInterceptorFactory[]
|
||||
{new HelloWorldInterceptorFactory(),
|
||||
new HelloWorldInterceptorFactory()});
|
||||
ccf.setInterceptorFactoryChain(fc);
|
||||
@@ -872,7 +871,7 @@ public class TcpSendingMessageHandlerTests {
|
||||
adapter.setConnectionFactory(ccf);
|
||||
QueueChannel channel = new QueueChannel();
|
||||
adapter.setOutputChannel(channel);
|
||||
assertTrue(latch.await(10, TimeUnit.SECONDS));
|
||||
assertTrue(latch.await(10, TimeUnit.SECONDS));
|
||||
handler.handleMessage(MessageBuilder.withPayload("Test").build());
|
||||
handler.handleMessage(MessageBuilder.withPayload("Test").build());
|
||||
Message<?> mOut = channel.receive(10000);
|
||||
@@ -921,7 +920,7 @@ public class TcpSendingMessageHandlerTests {
|
||||
AbstractConnectionFactory ccf = new TcpNioClientConnectionFactory("localhost", port);
|
||||
ccf.setSerializer(new DefaultSerializer());
|
||||
ccf.setDeserializer(new DefaultDeserializer());
|
||||
ccf.setSoTimeout(10000);
|
||||
ccf.setSoTimeout(10000);
|
||||
TcpConnectionInterceptorFactoryChain fc = new TcpConnectionInterceptorFactoryChain();
|
||||
fc.setInterceptors(new TcpConnectionInterceptorFactory[] {new HelloWorldInterceptorFactory()});
|
||||
ccf.setInterceptorFactoryChain(fc);
|
||||
@@ -932,7 +931,7 @@ public class TcpSendingMessageHandlerTests {
|
||||
adapter.setConnectionFactory(ccf);
|
||||
QueueChannel channel = new QueueChannel();
|
||||
adapter.setOutputChannel(channel);
|
||||
assertTrue(latch.await(10, TimeUnit.SECONDS));
|
||||
assertTrue(latch.await(10, TimeUnit.SECONDS));
|
||||
for (int i = 0; i < 1000; i++) {
|
||||
handler.handleMessage(MessageBuilder.withPayload("Test").build());
|
||||
}
|
||||
@@ -991,9 +990,9 @@ public class TcpSendingMessageHandlerTests {
|
||||
AbstractConnectionFactory ccf = new TcpNetClientConnectionFactory("localhost", port);
|
||||
ccf.setSerializer(new DefaultSerializer());
|
||||
ccf.setDeserializer(new DefaultDeserializer());
|
||||
ccf.setSoTimeout(10000);
|
||||
ccf.setSoTimeout(10000);
|
||||
TcpConnectionInterceptorFactoryChain fc = new TcpConnectionInterceptorFactoryChain();
|
||||
fc.setInterceptors(new TcpConnectionInterceptorFactory[]
|
||||
fc.setInterceptors(new TcpConnectionInterceptorFactory[]
|
||||
{new HelloWorldInterceptorFactory(),
|
||||
new HelloWorldInterceptorFactory()});
|
||||
ccf.setInterceptorFactoryChain(fc);
|
||||
@@ -1001,7 +1000,7 @@ public class TcpSendingMessageHandlerTests {
|
||||
ccf.start();
|
||||
TcpSendingMessageHandler handler = new TcpSendingMessageHandler();
|
||||
handler.setConnectionFactory(ccf);
|
||||
assertTrue(latch.await(10, TimeUnit.SECONDS));
|
||||
assertTrue(latch.await(10, TimeUnit.SECONDS));
|
||||
handler.handleMessage(MessageBuilder.withPayload("Test").build());
|
||||
done.set(true);
|
||||
}
|
||||
@@ -1047,9 +1046,9 @@ public class TcpSendingMessageHandlerTests {
|
||||
AbstractConnectionFactory ccf = new TcpNioClientConnectionFactory("localhost", port);
|
||||
ccf.setSerializer(new DefaultSerializer());
|
||||
ccf.setDeserializer(new DefaultDeserializer());
|
||||
ccf.setSoTimeout(10000);
|
||||
ccf.setSoTimeout(10000);
|
||||
TcpConnectionInterceptorFactoryChain fc = new TcpConnectionInterceptorFactoryChain();
|
||||
fc.setInterceptors(new TcpConnectionInterceptorFactory[]
|
||||
fc.setInterceptors(new TcpConnectionInterceptorFactory[]
|
||||
{new HelloWorldInterceptorFactory(),
|
||||
new HelloWorldInterceptorFactory()});
|
||||
ccf.setInterceptorFactoryChain(fc);
|
||||
@@ -1057,7 +1056,7 @@ public class TcpSendingMessageHandlerTests {
|
||||
ccf.start();
|
||||
TcpSendingMessageHandler handler = new TcpSendingMessageHandler();
|
||||
handler.setConnectionFactory(ccf);
|
||||
assertTrue(latch.await(10, TimeUnit.SECONDS));
|
||||
assertTrue(latch.await(10, TimeUnit.SECONDS));
|
||||
handler.handleMessage(MessageBuilder.withPayload("Test").build());
|
||||
done.set(true);
|
||||
}
|
||||
|
||||
@@ -32,7 +32,6 @@ import java.util.concurrent.TimeUnit;
|
||||
import javax.net.SocketFactory;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.integration.Message;
|
||||
import org.springframework.integration.ip.tcp.serializer.AbstractByteArraySerializer;
|
||||
import org.springframework.integration.ip.tcp.serializer.ByteArrayCrLfSerializer;
|
||||
@@ -47,12 +46,12 @@ import org.springframework.integration.ip.util.SocketTestUtils;
|
||||
public class TcpNioConnectionReadTests {
|
||||
|
||||
private CountDownLatch latch = new CountDownLatch(1);
|
||||
|
||||
|
||||
private AbstractServerConnectionFactory getConnectionFactory(int port,
|
||||
AbstractByteArraySerializer serializer, TcpListener listener) throws Exception {
|
||||
return getConnectionFactory(port, serializer, listener, null);
|
||||
}
|
||||
|
||||
|
||||
private AbstractServerConnectionFactory getConnectionFactory(int port,
|
||||
AbstractByteArraySerializer serializer, TcpListener listener, TcpSender sender) throws Exception {
|
||||
AbstractServerConnectionFactory scf = new TcpNioServerConnectionFactory(port);
|
||||
@@ -72,7 +71,7 @@ public class TcpNioConnectionReadTests {
|
||||
}
|
||||
return scf;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test method for {@link org.springframework.integration.ip.tcp.NioSocketReader}.
|
||||
*/
|
||||
@@ -90,17 +89,17 @@ public class TcpNioConnectionReadTests {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// Fire up the sender.
|
||||
|
||||
|
||||
SocketTestUtils.testSendLength(port, latch);
|
||||
latch.countDown();
|
||||
assertTrue(semaphore.tryAcquire(1, 10000, TimeUnit.MILLISECONDS));
|
||||
assertTrue(semaphore.tryAcquire(1, 10000, TimeUnit.MILLISECONDS));
|
||||
assertEquals("Did not receive data", 2, responses.size());
|
||||
assertEquals("Data", SocketTestUtils.TEST_STRING + SocketTestUtils.TEST_STRING,
|
||||
assertEquals("Data", SocketTestUtils.TEST_STRING + SocketTestUtils.TEST_STRING,
|
||||
new String(((Message<byte[]>) responses.get(0)).getPayload()));
|
||||
assertEquals("Data", SocketTestUtils.TEST_STRING + SocketTestUtils.TEST_STRING,
|
||||
assertEquals("Data", SocketTestUtils.TEST_STRING + SocketTestUtils.TEST_STRING,
|
||||
new String(((Message<byte[]>) responses.get(1)).getPayload()));
|
||||
scf.close();
|
||||
}
|
||||
@@ -124,20 +123,20 @@ public class TcpNioConnectionReadTests {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
int howMany = 2;
|
||||
scf.setPoolSize(howMany + 5);
|
||||
scf.setBacklog(howMany + 5);
|
||||
// Fire up the sender.
|
||||
SocketTestUtils.testSendFragmented(port, howMany, false);
|
||||
assertTrue(semaphore.tryAcquire(howMany, 20000, TimeUnit.MILLISECONDS));
|
||||
assertEquals("Expected", howMany, responses.size());
|
||||
for (int i = 0; i < howMany; i++) {
|
||||
assertEquals("Data", "xx",
|
||||
assertEquals("Data", "xx",
|
||||
new String(((Message<byte[]>) responses.get(0)).getPayload()));
|
||||
}
|
||||
scf.close();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test method for {@link org.springframework.integration.ip.tcp.NioSocketReader}.
|
||||
*/
|
||||
@@ -155,17 +154,17 @@ public class TcpNioConnectionReadTests {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// Fire up the sender.
|
||||
|
||||
|
||||
SocketTestUtils.testSendStxEtx(port, latch);
|
||||
latch.countDown();
|
||||
assertTrue(semaphore.tryAcquire(1, 10000, TimeUnit.MILLISECONDS));
|
||||
assertTrue(semaphore.tryAcquire(1, 10000, TimeUnit.MILLISECONDS));
|
||||
assertEquals("Did not receive data", 2, responses.size());
|
||||
assertEquals("Data", SocketTestUtils.TEST_STRING + SocketTestUtils.TEST_STRING,
|
||||
assertEquals("Data", SocketTestUtils.TEST_STRING + SocketTestUtils.TEST_STRING,
|
||||
new String(((Message<byte[]>) responses.get(0)).getPayload()));
|
||||
assertEquals("Data", SocketTestUtils.TEST_STRING + SocketTestUtils.TEST_STRING,
|
||||
assertEquals("Data", SocketTestUtils.TEST_STRING + SocketTestUtils.TEST_STRING,
|
||||
new String(((Message<byte[]>) responses.get(1)).getPayload()));
|
||||
scf.close();
|
||||
}
|
||||
@@ -187,17 +186,17 @@ public class TcpNioConnectionReadTests {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// Fire up the sender.
|
||||
|
||||
|
||||
SocketTestUtils.testSendCrLf(port, latch);
|
||||
latch.countDown();
|
||||
assertTrue(semaphore.tryAcquire(1, 10000, TimeUnit.MILLISECONDS));
|
||||
assertTrue(semaphore.tryAcquire(1, 10000, TimeUnit.MILLISECONDS));
|
||||
assertEquals("Did not receive data", 2, responses.size());
|
||||
assertEquals("Data", SocketTestUtils.TEST_STRING + SocketTestUtils.TEST_STRING,
|
||||
assertEquals("Data", SocketTestUtils.TEST_STRING + SocketTestUtils.TEST_STRING,
|
||||
new String(((Message<byte[]>) responses.get(0)).getPayload()));
|
||||
assertEquals("Data", SocketTestUtils.TEST_STRING + SocketTestUtils.TEST_STRING,
|
||||
assertEquals("Data", SocketTestUtils.TEST_STRING + SocketTestUtils.TEST_STRING,
|
||||
new String(((Message<byte[]>) responses.get(1)).getPayload()));
|
||||
scf.close();
|
||||
}
|
||||
@@ -229,9 +228,9 @@ public class TcpNioConnectionReadTests {
|
||||
semaphore.release();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// Fire up the sender.
|
||||
|
||||
|
||||
SocketTestUtils.testSendLengthOverflow(port);
|
||||
whileOpen(semaphore, added);
|
||||
assertEquals(1, added.size());
|
||||
@@ -268,9 +267,9 @@ public class TcpNioConnectionReadTests {
|
||||
semaphore.release();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// Fire up the sender.
|
||||
|
||||
|
||||
SocketTestUtils.testSendStxEtxOverflow(port);
|
||||
whileOpen(semaphore, added);
|
||||
assertEquals(1, added.size());
|
||||
@@ -307,9 +306,9 @@ public class TcpNioConnectionReadTests {
|
||||
semaphore.release();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// Fire up the sender.
|
||||
|
||||
|
||||
SocketTestUtils.testSendCrLfOverflow(port);
|
||||
whileOpen(semaphore, added);
|
||||
assertEquals(1, added.size());
|
||||
@@ -320,7 +319,7 @@ public class TcpNioConnectionReadTests {
|
||||
|
||||
/**
|
||||
* Tests socket closure when no data received.
|
||||
*
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
@@ -359,7 +358,7 @@ public class TcpNioConnectionReadTests {
|
||||
|
||||
/**
|
||||
* Tests socket closure when no data received.
|
||||
*
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
@@ -399,7 +398,7 @@ public class TcpNioConnectionReadTests {
|
||||
|
||||
/**
|
||||
* Tests socket closure when mid-message
|
||||
*
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
@@ -407,10 +406,10 @@ public class TcpNioConnectionReadTests {
|
||||
ByteArrayCrLfSerializer serializer = new ByteArrayCrLfSerializer();
|
||||
testClosureMidMessageGuts(serializer, "xx");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Tests socket closure when mid-message
|
||||
*
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
|
||||
@@ -422,7 +421,7 @@ public class TcpNioConnectionReadTests {
|
||||
|
||||
/**
|
||||
* Tests socket closure when mid-message
|
||||
*
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
|
||||
|
||||
@@ -19,15 +19,19 @@ package org.springframework.integration.ip.tcp.connection;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.net.SocketTimeoutException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.SelectionKey;
|
||||
import java.nio.channels.Selector;
|
||||
import java.nio.channels.SocketChannel;
|
||||
@@ -36,19 +40,30 @@ import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.net.ServerSocketFactory;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.invocation.InvocationOnMock;
|
||||
import org.mockito.stubbing.Answer;
|
||||
import org.springframework.integration.Message;
|
||||
import org.springframework.integration.ip.tcp.serializer.ByteArrayCrLfSerializer;
|
||||
import org.springframework.integration.ip.util.SocketTestUtils;
|
||||
import org.springframework.integration.support.MessageBuilder;
|
||||
import org.springframework.integration.test.util.TestUtils;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
import org.springframework.util.ReflectionUtils.FieldCallback;
|
||||
import org.springframework.util.ReflectionUtils.FieldFilter;
|
||||
import org.springframework.util.ReflectionUtils.MethodCallback;
|
||||
import org.springframework.util.ReflectionUtils.MethodFilter;
|
||||
|
||||
|
||||
/**
|
||||
@@ -84,7 +99,7 @@ public class TcpNioConnectionTests {
|
||||
TcpConnection connection = factory.getConnection();
|
||||
connection.send(MessageBuilder.withPayload(new byte[1000000]).build());
|
||||
} catch (Exception e) {
|
||||
assertTrue("Expected SocketTimeoutException, got " + e.getClass().getSimpleName() +
|
||||
assertTrue("Expected SocketTimeoutException, got " + e.getClass().getSimpleName() +
|
||||
":" + e.getMessage(), e instanceof SocketTimeoutException);
|
||||
}
|
||||
}
|
||||
@@ -102,7 +117,7 @@ public class TcpNioConnectionTests {
|
||||
ServerSocket server = ServerSocketFactory.getDefault().createServerSocket(port);
|
||||
latch.countDown();
|
||||
Socket socket = server.accept();
|
||||
byte[] b = new byte[6];
|
||||
byte[] b = new byte[6];
|
||||
readFully(socket.getInputStream(), b);
|
||||
// block to cause timeout on read.
|
||||
server.accept();
|
||||
@@ -127,7 +142,7 @@ public class TcpNioConnectionTests {
|
||||
fail("Unexpected exception " + e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testMemoryLeak() throws Exception {
|
||||
final int port = SocketTestUtils.findAvailableServerSocket();
|
||||
@@ -234,10 +249,108 @@ public class TcpNioConnectionTests {
|
||||
assertEquals(0, TestUtils.getPropertyValue(factory, "connections", List.class).size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInsufficientThreads() throws Exception {
|
||||
final ExecutorService exec = Executors.newFixedThreadPool(2);
|
||||
Future<Object> future = exec.submit(new Callable<Object>() {
|
||||
public Object call() throws Exception {
|
||||
SocketChannel channel = mock(SocketChannel.class);
|
||||
Socket socket = mock(Socket.class);
|
||||
Mockito.when(channel.socket()).thenReturn(socket);
|
||||
doAnswer(new Answer<Integer>() {
|
||||
public Integer answer(InvocationOnMock invocation) throws Throwable {
|
||||
ByteBuffer buffer = (ByteBuffer) invocation.getArguments()[0];
|
||||
buffer.position(1025);
|
||||
return 1025;
|
||||
}
|
||||
}).when(channel).read(Mockito.any(ByteBuffer.class));
|
||||
final TcpNioConnection connection = new TcpNioConnection(channel, false, false);
|
||||
connection.setTaskExecutor(exec);
|
||||
connection.setPipeTimeout(200);
|
||||
ReflectionUtils.doWithMethods(TcpNioConnection.class, new MethodCallback() {
|
||||
public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
|
||||
method.setAccessible(true);
|
||||
try {
|
||||
method.invoke(connection, (Object[]) null);
|
||||
}
|
||||
catch (InvocationTargetException e) {
|
||||
throw (RuntimeException) e.getCause();
|
||||
}
|
||||
}
|
||||
}, new MethodFilter() {
|
||||
public boolean matches(Method method) {
|
||||
return method.getName().equals("doRead");
|
||||
}
|
||||
});
|
||||
return null;
|
||||
}
|
||||
});
|
||||
try {
|
||||
Object o = future.get(10, TimeUnit.SECONDS);
|
||||
fail("Expected exception, got " + o);
|
||||
}
|
||||
catch (ExecutionException e) {
|
||||
assertEquals("Timed out writing to pipe, probably due to insufficient threads in " +
|
||||
"a fixed thread pool; consider increasing this task executor pool size", e.getCause()
|
||||
.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSufficientThreads() throws Exception {
|
||||
final ExecutorService exec = Executors.newFixedThreadPool(3);
|
||||
final CountDownLatch messageLatch = new CountDownLatch(1);
|
||||
Future<Object> future = exec.submit(new Callable<Object>() {
|
||||
public Object call() throws Exception {
|
||||
SocketChannel channel = mock(SocketChannel.class);
|
||||
Socket socket = mock(Socket.class);
|
||||
Mockito.when(channel.socket()).thenReturn(socket);
|
||||
doAnswer(new Answer<Integer>() {
|
||||
public Integer answer(InvocationOnMock invocation) throws Throwable {
|
||||
ByteBuffer buffer = (ByteBuffer) invocation.getArguments()[0];
|
||||
buffer.position(1025);
|
||||
buffer.put((byte) '\r');
|
||||
buffer.put((byte) '\n');
|
||||
return 1027;
|
||||
}
|
||||
}).when(channel).read(Mockito.any(ByteBuffer.class));
|
||||
final TcpNioConnection connection = new TcpNioConnection(channel, false, false);
|
||||
connection.setTaskExecutor(exec);
|
||||
connection.registerListener(new TcpListener(){
|
||||
public boolean onMessage(Message<?> message) {
|
||||
System.out.println(message);
|
||||
messageLatch.countDown();
|
||||
return false;
|
||||
}
|
||||
});
|
||||
connection.setMapper(new TcpMessageMapper());
|
||||
connection.setDeserializer(new ByteArrayCrLfSerializer());
|
||||
ReflectionUtils.doWithMethods(TcpNioConnection.class, new MethodCallback() {
|
||||
public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
|
||||
method.setAccessible(true);
|
||||
try {
|
||||
method.invoke(connection, (Object[]) null);
|
||||
}
|
||||
catch (InvocationTargetException e) {
|
||||
throw (RuntimeException) e.getCause();
|
||||
}
|
||||
}
|
||||
}, new MethodFilter() {
|
||||
public boolean matches(Method method) {
|
||||
return method.getName().equals("doRead");
|
||||
}
|
||||
});
|
||||
return null;
|
||||
}
|
||||
});
|
||||
future.get(60, TimeUnit.SECONDS);
|
||||
assertTrue(messageLatch.await(10, TimeUnit.SECONDS));
|
||||
}
|
||||
|
||||
private void readFully(InputStream is, byte[] buff) throws IOException {
|
||||
for (int i = 0; i < buff.length; i++) {
|
||||
buff[i] = (byte) is.read();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user