Avoid throws Exception where possible - Phase I

* Polishing - PR Comments
This commit is contained in:
Gary Russell
2019-03-07 12:53:52 -05:00
committed by Artem Bilan
parent 005bc80680
commit b187bca36e
130 changed files with 992 additions and 784 deletions

View File

@@ -19,7 +19,6 @@ package org.springframework.integration.ip.config;
import java.util.concurrent.Executor;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.config.AbstractFactoryBean;
import org.springframework.context.ApplicationEventPublisher;
@@ -58,7 +57,7 @@ import org.springframework.util.Assert;
* @since 2.0.5
*/
public class TcpConnectionFactoryFactoryBean extends AbstractFactoryBean<AbstractConnectionFactory>
implements Lifecycle, BeanNameAware, BeanFactoryAware, ApplicationEventPublisherAware {
implements Lifecycle, BeanNameAware, ApplicationEventPublisherAware {
private volatile AbstractConnectionFactory connectionFactory;
@@ -151,7 +150,7 @@ public class TcpConnectionFactoryFactoryBean extends AbstractFactoryBean<Abstrac
}
@Override
protected AbstractConnectionFactory createInstance() throws Exception {
protected AbstractConnectionFactory createInstance() {
if (!this.mapperSet) {
this.mapper.setBeanFactory(this.beanFactory);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2001-2018 the original author or authors.
* Copyright 2001-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -41,6 +41,7 @@ import org.springframework.integration.ip.tcp.connection.TcpListener;
import org.springframework.integration.ip.tcp.connection.TcpSender;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.MessageHandlingException;
import org.springframework.messaging.MessagingException;
import org.springframework.messaging.support.ErrorMessage;
import org.springframework.util.Assert;
@@ -138,26 +139,9 @@ public class TcpOutboundGateway extends AbstractReplyProducingMessageHandler
TcpConnection connection = null;
String connectionId = null;
try {
if (!this.isSingleUse) {
logger.debug("trying semaphore");
if (!this.semaphore.tryAcquire(this.requestTimeout, TimeUnit.MILLISECONDS)) {
throw new MessageTimeoutException(requestMessage, "Timed out waiting for connection");
}
haveSemaphore = true;
if (logger.isDebugEnabled()) {
logger.debug("got semaphore");
}
}
haveSemaphore = acquireSemaphoreIfNeeded(requestMessage);
connection = this.connectionFactory.getConnection();
Long remoteTimeout = this.remoteTimeoutExpression.getValue(this.evaluationContext, requestMessage,
Long.class);
if (remoteTimeout == null) {
remoteTimeout = DEFAULT_REMOTE_TIMEOUT;
if (logger.isWarnEnabled()) {
logger.warn("remoteTimeoutExpression evaluated to null; falling back to default for message "
+ requestMessage);
}
}
Long remoteTimeout = getRemoteTimeout(requestMessage);
AsyncReply reply = new AsyncReply(remoteTimeout);
connectionId = connection.getConnectionId();
this.pendingReplies.put(connectionId, reply);
@@ -165,42 +149,83 @@ public class TcpOutboundGateway extends AbstractReplyProducingMessageHandler
logger.debug("Added pending reply " + connectionId);
}
connection.send(requestMessage);
Message<?> replyMessage = reply.getReply();
if (replyMessage == null) {
if (logger.isDebugEnabled()) {
logger.debug("Remote Timeout on " + connectionId);
}
// The connection is dirty - force it closed.
this.connectionFactory.forceClose(connection);
throw new MessageTimeoutException(requestMessage, "Timed out waiting for response");
}
if (logger.isDebugEnabled()) {
logger.debug("Response " + replyMessage);
}
return replyMessage;
return getReply(requestMessage, connection, connectionId, reply);
}
catch (Exception e) {
catch (RuntimeException e) {
logger.error("Tcp Gateway exception", e);
if (e instanceof MessagingException) {
throw (MessagingException) e;
}
throw new MessagingException("Failed to send or receive", e);
}
catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new MessageHandlingException(requestMessage, "Interrupted", e);
}
finally {
if (connectionId != null) {
this.pendingReplies.remove(connectionId);
if (logger.isDebugEnabled()) {
logger.debug("Removed pending reply " + connectionId);
}
if (this.isSingleUse) {
connection.close();
}
cleanUp(haveSemaphore, connection, connectionId);
}
}
private boolean acquireSemaphoreIfNeeded(Message<?> requestMessage) throws InterruptedException {
if (!this.isSingleUse) {
logger.debug("trying semaphore");
if (!this.semaphore.tryAcquire(this.requestTimeout, TimeUnit.MILLISECONDS)) {
throw new MessageTimeoutException(requestMessage, "Timed out waiting for connection");
}
if (haveSemaphore) {
this.semaphore.release();
if (logger.isDebugEnabled()) {
logger.debug("released semaphore");
}
if (logger.isDebugEnabled()) {
logger.debug("got semaphore");
}
return true;
}
return false;
}
private Long getRemoteTimeout(Message<?> requestMessage) {
Long remoteTimeout = this.remoteTimeoutExpression.getValue(this.evaluationContext, requestMessage,
Long.class);
if (remoteTimeout == null) {
remoteTimeout = DEFAULT_REMOTE_TIMEOUT;
if (logger.isWarnEnabled()) {
logger.warn("remoteTimeoutExpression evaluated to null; falling back to default for message "
+ requestMessage);
}
}
return remoteTimeout;
}
private Message<?> getReply(Message<?> requestMessage, TcpConnection connection, String connectionId,
AsyncReply reply) {
Message<?> replyMessage = reply.getReply();
if (replyMessage == null) {
if (logger.isDebugEnabled()) {
logger.debug("Remote Timeout on " + connectionId);
}
// The connection is dirty - force it closed.
this.connectionFactory.forceClose(connection);
throw new MessageTimeoutException(requestMessage, "Timed out waiting for response");
}
if (logger.isDebugEnabled()) {
logger.debug("Response " + replyMessage);
}
return replyMessage;
}
private void cleanUp(boolean haveSemaphore, TcpConnection connection, String connectionId) {
if (connectionId != null) {
this.pendingReplies.remove(connectionId);
if (logger.isDebugEnabled()) {
logger.debug("Removed pending reply " + connectionId);
}
if (this.isSingleUse) {
connection.close();
}
}
if (haveSemaphore) {
this.semaphore.release();
if (logger.isDebugEnabled()) {
logger.debug("released semaphore");
}
}
}
@@ -334,13 +359,13 @@ public class TcpOutboundGateway extends AbstractReplyProducingMessageHandler
* @return The return message or null if we time out
* @throws Exception
*/
public Message<?> getReply() throws Exception {
public Message<?> getReply() {
try {
if (!this.latch.await(this.remoteTimeout, TimeUnit.MILLISECONDS)) {
return null;
}
}
catch (InterruptedException e) {
catch (@SuppressWarnings("unused") InterruptedException e) {
Thread.currentThread().interrupt();
}
boolean waitForMessageAfterError = true;
@@ -351,19 +376,31 @@ public class TcpOutboundGateway extends AbstractReplyProducingMessageHandler
* before the reply, on a different thread.
*/
logger.debug("second chance");
this.secondChanceLatch.await(TcpOutboundGateway.this.secondChanceDelay, TimeUnit.SECONDS); // NOSONAR
try {
this.secondChanceLatch.await(TcpOutboundGateway.this.secondChanceDelay, TimeUnit.SECONDS); // NOSONAR
}
catch (@SuppressWarnings("unused") InterruptedException e) {
Thread.currentThread().interrupt();
doThrowErrorMessagePayload();
}
waitForMessageAfterError = false;
}
else if (this.reply.getPayload() instanceof MessagingException) {
throw (MessagingException) this.reply.getPayload();
}
else {
throw new MessagingException("Exception while awaiting reply", (Throwable) this.reply.getPayload());
doThrowErrorMessagePayload();
}
}
return this.reply;
}
private void doThrowErrorMessagePayload() {
if (this.reply.getPayload() instanceof MessagingException) {
throw (MessagingException) this.reply.getPayload();
}
else {
throw new MessagingException("Exception while awaiting reply", (Throwable) this.reply.getPayload());
}
}
/**
* We have a race condition when a socket is closed right after the reply is received. The close "error"
* might arrive before the actual reply. Overwrite an error with a good reply, but not vice-versa.

View File

@@ -63,14 +63,15 @@ public abstract class AbstractClientConnectionFactory extends AbstractConnection
* Obtains a connection - if {@link #setSingleUse(boolean)} was called with
* true, a new connection is returned; otherwise a single connection is
* reused for all requests while the connection remains open.
* @throws InterruptedException if interrupted.
*/
@Override
public TcpConnectionSupport getConnection() throws Exception {
this.checkActive();
public TcpConnectionSupport getConnection() throws InterruptedException {
checkActive();
return obtainConnection();
}
protected TcpConnectionSupport obtainConnection() throws Exception {
protected TcpConnectionSupport obtainConnection() throws InterruptedException {
if (!this.isSingleUse()) {
TcpConnectionSupport connection = obtainSharedConnection();
if (connection != null) {
@@ -92,11 +93,10 @@ public abstract class AbstractClientConnectionFactory extends AbstractConnection
finally {
this.theConnectionLock.readLock().unlock();
}
return null;
}
protected final TcpConnectionSupport obtainNewConnection() throws Exception {
protected final TcpConnectionSupport obtainNewConnection() throws InterruptedException {
boolean singleUse = this.isSingleUse();
if (!singleUse) {
this.theConnectionLock.writeLock().lockInterruptibly();
@@ -115,14 +115,14 @@ public abstract class AbstractClientConnectionFactory extends AbstractConnection
logger.debug("Opening new socket connection to " + this.getHost() + ":" + this.getPort());
}
connection = this.buildNewConnection();
connection = buildNewConnection();
if (!singleUse) {
this.setTheConnection(connection);
}
connection.publishConnectionOpenEvent();
return connection;
}
catch (Exception e) {
catch (RuntimeException e) {
ApplicationEventPublisher applicationEventPublisher = getApplicationEventPublisher();
if (applicationEventPublisher != null) {
applicationEventPublisher.publishEvent(new TcpConnectionFailedEvent(this, e));
@@ -136,7 +136,7 @@ public abstract class AbstractClientConnectionFactory extends AbstractConnection
}
}
protected TcpConnectionSupport buildNewConnection() throws Exception {
protected TcpConnectionSupport buildNewConnection() {
throw new UnsupportedOperationException("Factories that don't override this class' obtainConnection() must implement this method");
}

View File

@@ -18,6 +18,7 @@ package org.springframework.integration.ip.tcp.connection;
import java.io.EOFException;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.net.Socket;
import java.net.SocketException;
import java.net.SocketTimeoutException;
@@ -62,6 +63,8 @@ import org.springframework.util.Assert;
public abstract class AbstractConnectionFactory extends IntegrationObjectSupport
implements ConnectionFactory, ApplicationEventPublisherAware {
private static final String UNUSED = "unused";
protected static final int DEFAULT_REPLY_TIMEOUT = 10000;
private static final int DEFAULT_NIO_HARVEST_INTERVAL = 2000;
@@ -351,24 +354,24 @@ public abstract class AbstractConnectionFactory extends IntegrationObjectSupport
/**
* Registers a TcpListener to receive messages after
* the payload has been converted from the input data.
* @param listener the TcpListener.
* @param listenerToRegister the TcpListener.
*/
public void registerListener(TcpListener listener) {
public void registerListener(TcpListener listenerToRegister) {
Assert.isNull(this.listener, this.getClass().getName() +
" may only be used by one inbound adapter");
this.listener = listener;
this.listener = listenerToRegister;
}
/**
* Registers a TcpSender; for server sockets, used to
* provide connection information so a sender can be used
* to reply to incoming messages.
* @param sender The sender
* @param senderToRegister The sender
*/
public void registerSender(TcpSender sender) {
public void registerSender(TcpSender senderToRegister) {
Assert.isNull(this.sender, this.getClass().getName() +
" may only be used by one outbound adapter");
this.sender = sender;
this.sender = senderToRegister;
}
/**
@@ -557,7 +560,7 @@ public abstract class AbstractConnectionFactory extends IntegrationObjectSupport
}
}
}
catch (InterruptedException e) {
catch (@SuppressWarnings(UNUSED) InterruptedException e) {
executorService.shutdownNow();
Thread.currentThread().interrupt();
}
@@ -572,7 +575,7 @@ public abstract class AbstractConnectionFactory extends IntegrationObjectSupport
}
}
protected TcpConnectionSupport wrapConnection(TcpConnectionSupport connectionArg) throws Exception {
protected TcpConnectionSupport wrapConnection(TcpConnectionSupport connectionArg) {
TcpConnectionSupport connection = connectionArg;
try {
if (this.interceptorFactoryChain == null) {
@@ -611,12 +614,11 @@ public abstract class AbstractConnectionFactory extends IntegrationObjectSupport
* @param selectionCount Number of IO Events, if 0 we were probably woken up by a close.
* @param selector The selector.
* @param server The server socket channel.
* @param connections Map of connections.
* @throws IOException Any IOException.
* @param connectionMap Map of connections.
*/
protected void processNioSelections(int selectionCount, final Selector selector,
@Nullable ServerSocketChannel server,
Map<SocketChannel, TcpNioConnection> connections) throws IOException {
Map<SocketChannel, TcpNioConnection> connectionMap) {
final long now = System.currentTimeMillis();
rescheduleDelayedReads(selector, now);
@@ -624,7 +626,7 @@ public abstract class AbstractConnectionFactory extends IntegrationObjectSupport
now >= this.nextCheckForClosedNioConnections ||
selectionCount == 0) {
this.nextCheckForClosedNioConnections = now + this.nioHarvestInterval;
Iterator<Entry<SocketChannel, TcpNioConnection>> it = connections.entrySet().iterator();
Iterator<Entry<SocketChannel, TcpNioConnection>> it = connectionMap.entrySet().iterator();
while (it.hasNext()) {
SocketChannel channel = it.next().getKey();
if (!channel.isOpen()) {
@@ -632,7 +634,7 @@ public abstract class AbstractConnectionFactory extends IntegrationObjectSupport
it.remove();
}
else if (this.soTimeout > 0) {
TcpNioConnection connection = connections.get(channel);
TcpNioConnection connection = connectionMap.get(channel);
if (now - connection.getLastRead() >= this.soTimeout) {
/*
* For client connections, we have to wait for 2 timeouts if the last
@@ -650,7 +652,7 @@ public abstract class AbstractConnectionFactory extends IntegrationObjectSupport
if (logger.isWarnEnabled()) {
logger.warn("Timing out TcpNioConnection " + connection.getConnectionId());
}
SocketTimeoutException exception = new SocketTimeoutException("Timing out connection");
Exception exception = new SocketTimeoutException("Timing out connection");
connection.publishConnectionExceptionEvent(exception);
connection.timeout();
connection.sendExceptionToListener(exception);
@@ -689,7 +691,7 @@ public abstract class AbstractConnectionFactory extends IntegrationObjectSupport
try {
connection.readPacket();
}
catch (RejectedExecutionException e1) {
catch (@SuppressWarnings(UNUSED) RejectedExecutionException e1) {
delayRead(selector, now, key);
delayed = true;
}
@@ -715,7 +717,7 @@ public abstract class AbstractConnectionFactory extends IntegrationObjectSupport
}
});
}
catch (RejectedExecutionException e) {
catch (@SuppressWarnings(UNUSED) RejectedExecutionException e) {
delayRead(selector, now, key);
}
}
@@ -731,7 +733,7 @@ public abstract class AbstractConnectionFactory extends IntegrationObjectSupport
logger.error("Unexpected key: " + key);
}
}
catch (CancelledKeyException e) {
catch (@SuppressWarnings(UNUSED) CancelledKeyException e) {
if (logger.isDebugEnabled()) {
logger.debug("Selection key " + key + " cancelled");
}
@@ -787,7 +789,7 @@ public abstract class AbstractConnectionFactory extends IntegrationObjectSupport
}
}
}
catch (InterruptedException e) {
catch (@SuppressWarnings(UNUSED) InterruptedException e) {
Thread.currentThread().interrupt();
}
finally {
@@ -801,9 +803,8 @@ public abstract class AbstractConnectionFactory extends IntegrationObjectSupport
* @param selector The selector.
* @param server The server socket channel.
* @param now The current time.
* @throws IOException Any IOException.
*/
protected void doAccept(final Selector selector, ServerSocketChannel server, long now) throws IOException {
protected void doAccept(final Selector selector, ServerSocketChannel server, long now) {
throw new UnsupportedOperationException("Nio server factory must override this method");
}
@@ -874,9 +875,9 @@ public abstract class AbstractConnectionFactory extends IntegrationObjectSupport
this.active = active;
}
protected void checkActive() throws IOException {
protected void checkActive() {
if (!this.isActive()) {
throw new IOException(this + " connection factory has not been started");
throw new UncheckedIOException(new IOException(this + " connection factory has not been started"));
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2001-2018 the original author or authors.
* Copyright 2001-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -214,7 +214,7 @@ public abstract class AbstractServerConnectionFactory extends AbstractConnection
try {
taskScheduler.schedule((Runnable) () -> eventPublisher.publishEvent(event), new Date());
}
catch (TaskRejectedException e) {
catch (@SuppressWarnings("unused") TaskRejectedException e) {
eventPublisher.publishEvent(event);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -133,7 +133,7 @@ public class CachingClientConnectionFactory extends AbstractClientConnectionFact
}
@Override
public TcpConnectionSupport obtainConnection() throws Exception {
public TcpConnectionSupport obtainConnection() {
return new CachedConnection(this.pool.getItem(), getListener());
}

View File

@@ -34,7 +34,7 @@ public class DefaultTcpNetConnectionSupport extends AbstractTcpConnectionSupport
@Override
public TcpNetConnection createNewConnection(Socket socket, boolean server, boolean lookupHost,
ApplicationEventPublisher applicationEventPublisher, String connectionFactoryName) throws Exception {
ApplicationEventPublisher applicationEventPublisher, String connectionFactoryName) {
if (isPushbackCapable()) {
return new PushBackTcpNetConnection(socket, server, lookupHost, applicationEventPublisher,
connectionFactoryName, getPushbackBufferSize());

View File

@@ -38,7 +38,7 @@ public class DefaultTcpNioConnectionSupport extends AbstractTcpConnectionSupport
@Override
public TcpNioConnection createNewConnection(SocketChannel socketChannel, boolean server, boolean lookupHost,
ApplicationEventPublisher applicationEventPublisher, String connectionFactoryName) throws Exception {
ApplicationEventPublisher applicationEventPublisher, String connectionFactoryName) {
if (isPushbackCapable()) {
return new PushBackTcpNioConnection(socketChannel, server, lookupHost, applicationEventPublisher,
connectionFactoryName, getPushbackBufferSize());
@@ -61,7 +61,7 @@ public class DefaultTcpNioConnectionSupport extends AbstractTcpConnectionSupport
PushBackTcpNioConnection(SocketChannel socketChannel, boolean server, boolean lookupHost,
ApplicationEventPublisher applicationEventPublisher, @Nullable String connectionFactoryName,
int bufferSize) throws Exception {
int bufferSize) {
super(socketChannel, server, lookupHost, applicationEventPublisher, connectionFactoryName);
this.pushbackBufferSize = bufferSize;

View File

@@ -75,7 +75,7 @@ public class DefaultTcpNioSSLConnectionSupport extends AbstractTcpConnectionSupp
*/
@Override
public TcpNioConnection createNewConnection(SocketChannel socketChannel, boolean server, boolean lookupHost,
ApplicationEventPublisher applicationEventPublisher, String connectionFactoryName) throws Exception {
ApplicationEventPublisher applicationEventPublisher, String connectionFactoryName) {
SSLEngine sslEngine = this.sslContext.createSSLEngine();
postProcessSSLEngine(sslEngine);
@@ -120,7 +120,8 @@ public class DefaultTcpNioSSLConnectionSupport extends AbstractTcpConnectionSupp
PushBackTcpNioSSLConnection(SocketChannel socketChannel, boolean server, boolean lookupHost,
ApplicationEventPublisher applicationEventPublisher, String connectionFactoryName, SSLEngine sslEngine,
int bufferSize) throws Exception {
int bufferSize) {
super(socketChannel, server, lookupHost, applicationEventPublisher, connectionFactoryName, sslEngine);
this.pushbackBufferSize = bufferSize;
this.connectionId = "pushback:" + super.getConnectionId();

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -92,7 +92,7 @@ public class FailoverClientConnectionFactory extends AbstractClientConnectionFac
}
@Override
protected TcpConnectionSupport obtainConnection() throws Exception {
protected TcpConnectionSupport obtainConnection() throws InterruptedException {
TcpConnectionSupport connection = this.getTheConnection();
if (connection != null && connection.isOpen()) {
((FailoverTcpConnection) connection).incrementEpoch();
@@ -146,7 +146,7 @@ public class FailoverClientConnectionFactory extends AbstractClientConnectionFac
*/
private final class FailoverTcpConnection extends TcpConnectionSupport implements TcpListener {
private final List<AbstractClientConnectionFactory> factories;
private final List<AbstractClientConnectionFactory> connectionFactories;
private final String connectionId;
@@ -160,8 +160,8 @@ public class FailoverClientConnectionFactory extends AbstractClientConnectionFac
private final AtomicLong epoch = new AtomicLong();
private FailoverTcpConnection(List<AbstractClientConnectionFactory> factories) throws Exception {
this.factories = factories;
private FailoverTcpConnection(List<AbstractClientConnectionFactory> factories) throws InterruptedException {
this.connectionFactories = factories;
this.factoryIterator = factories.iterator();
findAConnection();
this.connectionId = UUID.randomUUID().toString();
@@ -177,14 +177,14 @@ public class FailoverClientConnectionFactory extends AbstractClientConnectionFac
* This allows for the condition where the current connection is closed,
* the current factory can serve up a new connection, but all other
* factories are down.
* @throws Exception if an exception occurs
* @throws InterruptedException if interrupted.
*/
private synchronized void findAConnection() throws Exception {
private synchronized void findAConnection() throws InterruptedException {
boolean success = false;
AbstractClientConnectionFactory lastFactoryToTry = this.currentFactory;
AbstractClientConnectionFactory nextFactory = null;
if (!this.factoryIterator.hasNext()) {
this.factoryIterator = this.factories.iterator();
this.factoryIterator = this.connectionFactories.iterator();
}
boolean retried = false;
while (!success) {
@@ -198,7 +198,7 @@ public class FailoverClientConnectionFactory extends AbstractClientConnectionFac
this.currentFactory = nextFactory;
success = this.delegate.isOpen();
}
catch (Exception e) {
catch (RuntimeException e) {
if (logger.isDebugEnabled()) {
logger.debug(nextFactory + " failed with "
+ e.toString()
@@ -213,7 +213,7 @@ public class FailoverClientConnectionFactory extends AbstractClientConnectionFac
this.open = false;
throw e;
}
this.factoryIterator = this.factories.iterator();
this.factoryIterator = this.connectionFactories.iterator();
retried = true;
}
}
@@ -237,7 +237,7 @@ public class FailoverClientConnectionFactory extends AbstractClientConnectionFac
* If send fails on a connection from every factory, we give up.
*/
@Override
public synchronized void send(Message<?> message) throws Exception {
public synchronized void send(Message<?> message) {
boolean success = false;
AbstractClientConnectionFactory lastFactoryToTry = this.currentFactory;
AbstractClientConnectionFactory lastFactoryTried = null;
@@ -248,7 +248,7 @@ public class FailoverClientConnectionFactory extends AbstractClientConnectionFac
this.delegate.send(message);
success = true;
}
catch (Exception e) {
catch (RuntimeException e) {
if (retried && lastFactoryTried == lastFactoryToTry) {
logger.error("All connection factories exhausted", e);
this.open = false;
@@ -259,7 +259,12 @@ public class FailoverClientConnectionFactory extends AbstractClientConnectionFac
logger.debug("Send to " + this.delegate.getConnectionId() + " failed; attempting failover", e);
}
this.delegate.close();
findAConnection();
try {
findAConnection();
}
catch (@SuppressWarnings("unused") InterruptedException e1) {
Thread.currentThread().interrupt();
}
if (logger.isDebugEnabled()) {
logger.debug("Failing over to " + this.delegate.getConnectionId());
}
@@ -268,7 +273,7 @@ public class FailoverClientConnectionFactory extends AbstractClientConnectionFac
}
@Override
public Object getPayload() throws Exception {
public Object getPayload() {
return this.delegate.getPayload();
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2001-2018 the original author or authors.
* Copyright 2001-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -47,18 +47,16 @@ public interface TcpConnection extends Runnable {
/**
* Converts and sends the message.
* @param message The message,
* @throws Exception Any Exception.
*/
void send(Message<?> message) throws Exception;
void send(Message<?> message);
/**
* Uses the deserializer to obtain the message payload
* from the connection's input stream.
* @return The payload.
* @throws Exception Any Exception.
*/
@Nullable
Object getPayload() throws Exception;
Object getPayload();
/**
* @return the host name

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -60,7 +60,7 @@ public abstract class TcpConnectionInterceptorSupport extends TcpConnectionSuppo
}
@Override
public Object getPayload() throws Exception {
public Object getPayload() {
return this.theConnection.getPayload();
}
@@ -165,7 +165,7 @@ public abstract class TcpConnectionInterceptorSupport extends TcpConnectionSuppo
}
@Override
public void send(Message<?> message) throws Exception {
public void send(Message<?> message) {
this.theConnection.send(message);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,8 +17,8 @@
package org.springframework.integration.ip.tcp.connection;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.net.Socket;
import java.net.SocketException;
import org.springframework.util.Assert;
@@ -45,16 +45,21 @@ public class TcpNetClientConnectionFactory extends
}
@Override
protected TcpConnectionSupport buildNewConnection() throws IOException, SocketException, Exception {
Socket socket = createSocket(this.getHost(), this.getPort());
setSocketAttributes(socket);
TcpConnectionSupport connection = this.tcpNetConnectionSupport.createNewConnection(socket, false, isLookupHost(),
getApplicationEventPublisher(), getComponentName());
connection = wrapConnection(connection);
initializeConnection(connection, socket);
this.getTaskExecutor().execute(connection);
this.harvestClosedConnections();
return connection;
protected TcpConnectionSupport buildNewConnection() {
try {
Socket socket = createSocket(this.getHost(), this.getPort());
setSocketAttributes(socket);
TcpConnectionSupport connection = this.tcpNetConnectionSupport.createNewConnection(socket, false, isLookupHost(),
getApplicationEventPublisher(), getComponentName());
connection = wrapConnection(connection);
initializeConnection(connection, socket);
this.getTaskExecutor().execute(connection);
this.harvestClosedConnections();
return connection;
}
catch (IOException e) {
throw new UncheckedIOException(e);
}
}
/**

View File

@@ -20,9 +20,11 @@ import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UncheckedIOException;
import java.net.Socket;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.util.function.Supplier;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;
@@ -85,7 +87,7 @@ public class TcpNetConnection extends TcpConnectionSupport implements Scheduling
try {
this.socket.close();
}
catch (Exception e) {
catch (@SuppressWarnings("unused") Exception e) {
}
super.close();
}
@@ -97,23 +99,24 @@ public class TcpNetConnection extends TcpConnectionSupport implements Scheduling
@Override
@SuppressWarnings("unchecked")
public synchronized void send(Message<?> message) throws Exception {
if (this.socketOutputStream == null) {
int writeBufferSize = this.socket.getSendBufferSize();
this.socketOutputStream = new BufferedOutputStream(this.socket.getOutputStream(),
writeBufferSize > 0 ? writeBufferSize : 8192);
}
Object object = getMapper().fromMessage(message);
Assert.state(object != null, "Mapper mapped the message to 'null'.");
this.lastSend = System.currentTimeMillis();
public synchronized void send(Message<?> message) {
try {
if (this.socketOutputStream == null) {
int writeBufferSize = this.socket.getSendBufferSize();
this.socketOutputStream = new BufferedOutputStream(this.socket.getOutputStream(),
writeBufferSize > 0 ? writeBufferSize : 8192);
}
Object object = getMapper().fromMessage(message);
Assert.state(object != null, "Mapper mapped the message to 'null'.");
this.lastSend = System.currentTimeMillis();
((Serializer<Object>) getSerializer()).serialize(object, this.socketOutputStream);
this.socketOutputStream.flush();
}
catch (Exception e) {
publishConnectionExceptionEvent(new MessagingException(message, "Failed TCP serialization", e));
MessagingException mex = new MessagingException(message, "Send Failed", e);
publishConnectionExceptionEvent(mex);
closeConnection(true);
throw e;
throw mex;
}
if (logger.isDebugEnabled()) {
logger.debug(getConnectionId() + " Message sent " + message);
@@ -121,9 +124,14 @@ public class TcpNetConnection extends TcpConnectionSupport implements Scheduling
}
@Override
public Object getPayload() throws Exception {
return getDeserializer()
.deserialize(inputStream());
public Object getPayload() {
try {
return getDeserializer()
.deserialize(inputStream());
}
catch (IOException e) {
throw new UncheckedIOException(e);
}
}
@Override
@@ -137,7 +145,7 @@ public class TcpNetConnection extends TcpConnectionSupport implements Scheduling
try {
return inputStream();
}
catch (Exception e) {
catch (@SuppressWarnings("unused") Exception e) {
return null;
}
}
@@ -198,7 +206,7 @@ public class TcpNetConnection extends TcpConnectionSupport implements Scheduling
}
listener.onMessage(message);
}
catch (NoListenerException nle) { // could also be thrown by an interceptor
catch (@SuppressWarnings("unused") NoListenerException nle) { // could also be thrown by an interceptor
if (logger.isWarnEnabled()) {
logger.warn("Unexpected message - no endpoint registered with connection interceptor: "
+ getConnectionId()
@@ -213,12 +221,33 @@ public class TcpNetConnection extends TcpConnectionSupport implements Scheduling
}
}
protected boolean handleReadException(Exception e) {
protected boolean handleReadException(Exception exception) {
Exception e = exception instanceof UncheckedIOException ? (Exception) exception.getCause() : exception;
if (checkTimeout(e)) {
boolean readErrorOnClose = !isNoReadErrorOnClose();
closeConnection(true);
if (!(e instanceof SoftEndOfStreamException)) {
if (e instanceof SocketTimeoutException) {
if (logger.isDebugEnabled()) {
logger.debug("Closed socket after timeout:" + getConnectionId());
}
}
else {
logOtherExceptions(e, readErrorOnClose);
}
sendExceptionToListener(e);
}
return true;
}
return false;
}
/*
* For client connections, we have to wait for 2 timeouts if the last
* send was within the current timeout.
*/
private boolean checkTimeout(Exception e) {
boolean doClose = true;
/*
* For client connections, we have to wait for 2 timeouts if the last
* send was within the current timeout.
*/
if (!isServer() && e instanceof SocketTimeoutException) {
long now = System.currentTimeMillis();
try {
@@ -234,43 +263,26 @@ public class TcpNetConnection extends TcpConnectionSupport implements Scheduling
logger.error("Error accessing soTimeout", e1);
}
}
if (doClose) {
boolean noReadErrorOnClose = isNoReadErrorOnClose();
closeConnection(true);
if (!(e instanceof SoftEndOfStreamException)) {
if (e instanceof SocketTimeoutException) {
if (logger.isDebugEnabled()) {
logger.debug("Closed socket after timeout:" + getConnectionId());
}
}
else {
if (noReadErrorOnClose) {
if (logger.isTraceEnabled()) {
logger.trace("Read exception " +
getConnectionId(), e);
}
else if (logger.isDebugEnabled()) {
logger.debug("Read exception " +
getConnectionId() + " " +
e.getClass().getSimpleName() +
":" + (e.getCause() != null ? e.getCause() + ":" : "") + e.getMessage());
}
}
else if (logger.isTraceEnabled()) {
logger.error("Read exception " +
getConnectionId(), e);
}
else {
logger.error("Read exception " +
getConnectionId() + " " +
e.getClass().getSimpleName() +
":" + (e.getCause() != null ? e.getCause() + ":" : "") + e.getMessage());
}
}
sendExceptionToListener(e);
}
}
return doClose;
}
private void logOtherExceptions(Exception e, boolean readErrorOnClose) {
if (this.logger.isErrorEnabled()) {
String messagePrefix = "Read exception " + getConnectionId();
Supplier<String> summaryMessageSupplier = () -> messagePrefix + " " + e.getClass().getSimpleName() + ":"
+ (e.getCause() != null ? e.getCause() + ":" : "") + e.getMessage();
if (logger.isTraceEnabled()) {
logger.trace(messagePrefix, e);
}
else if (readErrorOnClose) {
logger.error(summaryMessageSupplier.get());
}
else {
if (logger.isDebugEnabled()) {
logger.debug(summaryMessageSupplier.get());
}
}
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2017 the original author or authors.
* Copyright 2017-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -41,11 +41,10 @@ public interface TcpNetConnectionSupport {
* @param connectionFactoryName the name of the connection factory creating this connection; used
* during event publishing, may be null, in which case "unknown" will be used.
* @return the TcpNetConnection
* @throws Exception Any exception.
*/
TcpNetConnection createNewConnection(Socket socket,
boolean server, boolean lookupHost,
ApplicationEventPublisher applicationEventPublisher,
String connectionFactoryName) throws Exception;
String connectionFactoryName);
}

View File

@@ -135,7 +135,7 @@ public class TcpNetServerConnectionFactory extends AbstractServerConnectionFacto
socket = this.serverSocket.accept();
}
}
catch (SocketTimeoutException ste) {
catch (@SuppressWarnings("unused") SocketTimeoutException ste) {
if (logger.isDebugEnabled()) {
logger.debug("Timed out on accept; continuing");
}
@@ -164,20 +164,20 @@ public class TcpNetServerConnectionFactory extends AbstractServerConnectionFacto
harvestClosedConnections();
connection.publishConnectionOpenEvent();
}
catch (Exception e) {
catch (RuntimeException e) {
this.logger.error("Failed to create and configure a TcpConnection for the new socket: "
+ socket.getInetAddress().getHostAddress() + ":" + socket.getPort(), e);
try {
socket.close();
}
catch (IOException e1) {
catch (@SuppressWarnings("unused") IOException e1) {
// empty
}
}
}
}
}
catch (Exception e) {
catch (IOException e) { // NOSONAR flow control via exceptions
// don't log an error if we had a good socket once and now it's closed
if (e instanceof SocketException && theServerSocket != null) {
logger.info("Server Socket closed");
@@ -224,7 +224,7 @@ public class TcpNetServerConnectionFactory extends AbstractServerConnectionFacto
try {
this.serverSocket.close();
}
catch (IOException e) {
catch (@SuppressWarnings("unused") IOException e) {
}
this.serverSocket = null;
super.stop();

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,6 +17,7 @@
package org.springframework.integration.ip.tcp.connection;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.net.InetSocketAddress;
import java.nio.channels.CancelledKeyException;
import java.nio.channels.ClosedChannelException;
@@ -63,43 +64,48 @@ public class TcpNioClientConnectionFactory extends
}
@Override
protected void checkActive() throws IOException {
protected void checkActive() {
super.checkActive();
int n = 0;
while (this.selector == null) {
try {
Thread.sleep(100);
}
catch (InterruptedException e) {
catch (@SuppressWarnings("unused") InterruptedException e) {
Thread.currentThread().interrupt();
}
if (n++ > 600) {
throw new IOException("Factory failed to start");
throw new UncheckedIOException(new IOException("Factory failed to start"));
}
}
}
@Override
protected TcpConnectionSupport buildNewConnection() throws Exception {
SocketChannel socketChannel = SocketChannel.open(new InetSocketAddress(getHost(), getPort()));
setSocketAttributes(socketChannel.socket());
TcpNioConnection connection = this.tcpNioConnectionSupport.createNewConnection(
socketChannel, false, this.isLookupHost(), this.getApplicationEventPublisher(), getComponentName());
connection.setUsingDirectBuffers(this.usingDirectBuffers);
connection.setTaskExecutor(this.getTaskExecutor());
if (getSslHandshakeTimeout() != null && connection instanceof TcpNioSSLConnection) {
((TcpNioSSLConnection) connection).setHandshakeTimeout(getSslHandshakeTimeout());
protected TcpConnectionSupport buildNewConnection() {
try {
SocketChannel socketChannel = SocketChannel.open(new InetSocketAddress(getHost(), getPort()));
setSocketAttributes(socketChannel.socket());
TcpNioConnection connection = this.tcpNioConnectionSupport.createNewConnection(
socketChannel, false, this.isLookupHost(), this.getApplicationEventPublisher(), getComponentName());
connection.setUsingDirectBuffers(this.usingDirectBuffers);
connection.setTaskExecutor(this.getTaskExecutor());
if (getSslHandshakeTimeout() != null && connection instanceof TcpNioSSLConnection) {
((TcpNioSSLConnection) connection).setHandshakeTimeout(getSslHandshakeTimeout());
}
TcpConnectionSupport wrappedConnection = wrapConnection(connection);
initializeConnection(wrappedConnection, socketChannel.socket());
socketChannel.configureBlocking(false);
if (this.getSoTimeout() > 0) {
connection.setLastRead(System.currentTimeMillis());
}
this.channelMap.put(socketChannel, connection);
this.newChannels.add(socketChannel);
this.selector.wakeup();
return wrappedConnection;
}
TcpConnectionSupport wrappedConnection = wrapConnection(connection);
initializeConnection(wrappedConnection, socketChannel.socket());
socketChannel.configureBlocking(false);
if (this.getSoTimeout() > 0) {
connection.setLastRead(System.currentTimeMillis());
catch (IOException e) {
throw new UncheckedIOException(e);
}
this.channelMap.put(socketChannel, connection);
this.newChannels.add(socketChannel);
this.selector.wakeup();
return wrappedConnection;
}
/**
@@ -164,7 +170,7 @@ public class TcpNioClientConnectionFactory extends
}
selectionCount = this.selector.select(timeout);
}
catch (CancelledKeyException cke) {
catch (@SuppressWarnings("unused") CancelledKeyException cke) {
if (logger.isDebugEnabled()) {
logger.debug("CancelledKeyException during Selector.select()");
}
@@ -173,7 +179,7 @@ public class TcpNioClientConnectionFactory extends
try {
newChannel.register(this.selector, SelectionKey.OP_READ, this.channelMap.get(newChannel));
}
catch (ClosedChannelException cce) {
catch (@SuppressWarnings("unused") ClosedChannelException cce) {
if (logger.isDebugEnabled()) {
logger.debug("Channel closed before registering with selector for reading");
}

View File

@@ -20,6 +20,7 @@ import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UncheckedIOException;
import java.net.SocketTimeoutException;
import java.nio.ByteBuffer;
import java.nio.channels.ClosedChannelException;
@@ -57,6 +58,10 @@ import org.springframework.util.Assert;
*/
public class TcpNioConnection extends TcpConnectionSupport {
private static final String UNUSED = "unused";
private static final int SIXTY = 60;
private static final long DEFAULT_PIPE_TIMEOUT = 60000;
private static final byte[] EOF = new byte[0]; // EOF marker buffer
@@ -123,12 +128,12 @@ public class TcpNioConnection extends TcpConnectionSupport {
try {
this.channelInputStream.close();
}
catch (IOException e) {
catch (@SuppressWarnings(UNUSED) IOException e) {
}
try {
this.socketChannel.close();
}
catch (Exception e) {
catch (@SuppressWarnings(UNUSED) Exception e) {
}
super.close();
}
@@ -140,24 +145,25 @@ public class TcpNioConnection extends TcpConnectionSupport {
@Override
@SuppressWarnings("unchecked")
public void send(Message<?> message) throws Exception {
public void send(Message<?> message) {
synchronized (this.socketChannel) {
if (this.bufferedOutputStream == null) {
int writeBufferSize = this.socketChannel.socket().getSendBufferSize();
this.bufferedOutputStream = new BufferedOutputStream(getChannelOutputStream(),
writeBufferSize > 0 ? writeBufferSize : 8192);
}
Object object = getMapper().fromMessage(message);
Assert.state(object != null, "Mapper mapped the message to 'null'.");
this.lastSend = System.currentTimeMillis();
try {
if (this.bufferedOutputStream == null) {
int writeBufferSize = this.socketChannel.socket().getSendBufferSize();
this.bufferedOutputStream = new BufferedOutputStream(getChannelOutputStream(),
writeBufferSize > 0 ? writeBufferSize : 8192);
}
Object object = getMapper().fromMessage(message);
Assert.state(object != null, "Mapper mapped the message to 'null'.");
this.lastSend = System.currentTimeMillis();
((Serializer<Object>) getSerializer()).serialize(object, this.bufferedOutputStream);
this.bufferedOutputStream.flush();
}
catch (Exception e) {
publishConnectionExceptionEvent(new MessagingException(message, "Failed TCP serialization", e));
MessagingException mex = new MessagingException(message, "Send Failed", e);
publishConnectionExceptionEvent(mex);
closeConnection(true);
throw e;
throw mex;
}
if (logger.isDebugEnabled()) {
logger.debug(getConnectionId() + " Message sent " + message);
@@ -166,9 +172,14 @@ public class TcpNioConnection extends TcpConnectionSupport {
}
@Override
public Object getPayload() throws Exception {
return getDeserializer()
.deserialize(inputStream());
public Object getPayload() {
try {
return getDeserializer()
.deserialize(inputStream());
}
catch (IOException e) {
throw new UncheckedIOException(e);
}
}
@Override
@@ -240,7 +251,7 @@ public class TcpNioConnection extends TcpConnectionSupport {
try {
this.taskExecutor.execute2(this);
}
catch (RejectedExecutionException e) {
catch (@SuppressWarnings(UNUSED) RejectedExecutionException e) {
this.executionControl.decrementAndGet();
if (logger.isInfoEnabled()) {
logger.info(getConnectionId()
@@ -288,40 +299,35 @@ public class TcpNioConnection extends TcpConnectionSupport {
// Final check in case new data came in and the
// timing was such that we were the last assembler and
// a new one wasn't run
try {
if (dataAvailable()) {
synchronized (this.executionControl) {
if (this.executionControl.incrementAndGet() <= 1) {
// only continue if we don't already have another assembler running
this.executionControl.set(1);
moreDataAvailable = true;
if (dataAvailable()) {
synchronized (this.executionControl) {
if (this.executionControl.incrementAndGet() <= 1) {
// only continue if we don't already have another assembler running
this.executionControl.set(1);
moreDataAvailable = true;
}
else {
this.executionControl.decrementAndGet();
}
}
}
if (moreDataAvailable) {
if (logger.isTraceEnabled()) {
logger.trace(getConnectionId() + " Nio message assembler continuing...");
}
}
else {
if (logger.isTraceEnabled()) {
logger.trace(getConnectionId() + " Nio message assembler exiting... avail: "
+ this.channelInputStream.available());
else {
this.executionControl.decrementAndGet();
}
}
}
catch (IOException e) {
logger.error("Exception when checking for assembler", e);
if (moreDataAvailable) {
if (logger.isTraceEnabled()) {
logger.trace(getConnectionId() + " Nio message assembler continuing...");
}
}
else {
if (logger.isTraceEnabled()) {
logger.trace(getConnectionId() + " Nio message assembler exiting... avail: "
+ this.channelInputStream.available());
}
}
}
}
}
private boolean dataAvailable() throws IOException {
private boolean dataAvailable() {
if (logger.isTraceEnabled()) {
logger.trace(getConnectionId() + " checking data avail: " + this.channelInputStream.available() +
" pending: " + (this.writingToPipe));
@@ -343,7 +349,7 @@ public class TcpNioConnection extends TcpConnectionSupport {
}
if (this.channelInputStream.available() <= 0) {
try {
if (this.writingLatch.await(60, TimeUnit.SECONDS)) {
if (this.writingLatch.await(SIXTY, TimeUnit.SECONDS)) {
if (this.channelInputStream.available() <= 0) {
return null;
}
@@ -352,7 +358,7 @@ public class TcpNioConnection extends TcpConnectionSupport {
throw new IOException("Timed out waiting for IO");
}
}
catch (InterruptedException e) {
catch (@SuppressWarnings(UNUSED) InterruptedException e) {
Thread.currentThread().interrupt();
throw new IOException("Interrupted waiting for IO");
}
@@ -451,13 +457,13 @@ public class TcpNioConnection extends TcpConnectionSupport {
}
}
protected void sendToPipe(ByteBuffer rawBuffer) throws IOException {
Assert.notNull(rawBuffer, "rawBuffer cannot be null");
protected void sendToPipe(ByteBuffer rawBufferToSend) throws IOException {
Assert.notNull(rawBufferToSend, "rawBuffer cannot be null");
if (logger.isTraceEnabled()) {
logger.trace(getConnectionId() + " Sending " + rawBuffer.limit() + " to pipe");
logger.trace(getConnectionId() + " Sending " + rawBufferToSend.limit() + " to pipe");
}
this.channelInputStream.write(rawBuffer);
rawBuffer.clear();
this.channelInputStream.write(rawBufferToSend);
rawBufferToSend.clear();
}
private void checkForAssembler() {
@@ -496,7 +502,7 @@ public class TcpNioConnection extends TcpConnectionSupport {
try {
doRead();
}
catch (ClosedChannelException cce) {
catch (@SuppressWarnings(UNUSED) ClosedChannelException cce) {
if (logger.isDebugEnabled()) {
logger.debug(getConnectionId() + " Channel is closed");
}
@@ -593,12 +599,12 @@ public class TcpNioConnection extends TcpConnectionSupport {
}
@Override
public void close() throws IOException {
public void close() {
doClose();
}
@Override
public void flush() throws IOException {
public void flush() {
}
@Override
@@ -767,7 +773,7 @@ public class TcpNioConnection extends TcpConnectionSupport {
try {
this.buffers.offer(EOF, TcpNioConnection.this.pipeTimeout, TimeUnit.SECONDS);
}
catch (InterruptedException e) {
catch (@SuppressWarnings(UNUSED) InterruptedException e) {
Thread.currentThread().interrupt();
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -42,11 +42,10 @@ public interface TcpNioConnectionSupport {
* @param connectionFactoryName the name of the connection factory creating this connection; used
* during event publishing, may be null, in which case "unknown" will be used.
* @return the TcpNioConnection
* @throws Exception Any exception.
*/
TcpNioConnection createNewConnection(SocketChannel socketChannel,
boolean server, boolean lookupHost,
ApplicationEventPublisher applicationEventPublisher,
String connectionFactoryName) throws Exception;
String connectionFactoryName);
}

View File

@@ -17,6 +17,7 @@
package org.springframework.integration.ip.tcp.connection;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.util.concurrent.Semaphore;
@@ -82,7 +83,7 @@ public class TcpNioSSLConnection extends TcpNioConnection {
public TcpNioSSLConnection(SocketChannel socketChannel, boolean server, boolean lookupHost,
ApplicationEventPublisher applicationEventPublisher, @Nullable String connectionFactoryName,
SSLEngine sslEngine) throws Exception {
SSLEngine sslEngine) {
super(socketChannel, server, lookupHost, applicationEventPublisher, connectionFactoryName);
this.sslEngine = sslEngine;
@@ -252,14 +253,17 @@ public class TcpNioSSLConnection extends TcpNioConnection {
/**
* Initializes the SSLEngine and sets up the encryption/decryption buffers.
*
* @throws IOException Any IOException.
*/
public void init() throws IOException {
public void init() {
if (this.decoded == null) {
this.decoded = allocateEncryptionBuffer(2048);
this.encoded = allocateEncryptionBuffer(2048);
initilizeEngine();
try {
initilizeEngine();
}
catch (IOException e) {
throw new UncheckedIOException(e);
}
}
}

View File

@@ -17,6 +17,7 @@
package org.springframework.integration.ip.tcp.connection;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
@@ -80,6 +81,7 @@ public class TcpNioServerConnectionFactory extends AbstractServerConnectionFacto
}
}
catch (IOException e) {
logger.error("Error getting port", e);
}
}
return port;
@@ -93,6 +95,7 @@ public class TcpNioServerConnectionFactory extends AbstractServerConnectionFacto
return this.serverChannel.getLocalAddress();
}
catch (IOException e) {
logger.error("Error getting local address", e);
}
}
return null;
@@ -161,10 +164,10 @@ public class TcpNioServerConnectionFactory extends AbstractServerConnectionFacto
* schedules a call to doRead which reads all available data. When the read
* is complete, the socket is again registered for read interest.
* @param server the ServerSocketChannel to select
* @param selector the Selector multiplexor
* @param selectorToSelect the Selector multiplexor
* @throws IOException
*/
private void doSelect(ServerSocketChannel server, final Selector selector) throws IOException {
private void doSelect(ServerSocketChannel server, final Selector selectorToSelect) throws IOException {
while (isActive()) {
int soTimeout = getSoTimeout();
int selectionCount = 0;
@@ -176,10 +179,10 @@ public class TcpNioServerConnectionFactory extends AbstractServerConnectionFacto
if (logger.isTraceEnabled()) {
logger.trace("Delayed reads: " + getDelayedReads().size() + " timeout " + timeout);
}
selectionCount = selector.select(timeout);
processNioSelections(selectionCount, selector, server, this.channelMap);
selectionCount = selectorToSelect.select(timeout);
processNioSelections(selectionCount, selectorToSelect, server, this.channelMap);
}
catch (CancelledKeyException cke) {
catch (@SuppressWarnings("unused") CancelledKeyException cke) {
logger.debug("CancelledKeyException during Selector.select()");
}
catch (ClosedSelectorException cse) {
@@ -193,47 +196,51 @@ public class TcpNioServerConnectionFactory extends AbstractServerConnectionFacto
}
/**
* @param selector The selector.
* @param selectorForNewSocket The selector.
* @param server The server socket channel.
* @param now The current time.
* @throws IOException Any IOException.
*/
@Override
protected void doAccept(final Selector selector, ServerSocketChannel server, long now) throws IOException {
protected void doAccept(final Selector selectorForNewSocket, ServerSocketChannel server, long now) {
logger.debug("New accept");
SocketChannel channel = server.accept();
if (isShuttingDown()) {
if (logger.isInfoEnabled()) {
logger.info("New connection from " + channel.socket().getInetAddress().getHostAddress()
+ ":" + channel.socket().getPort()
+ " rejected; the server is in the process of shutting down.");
}
channel.close();
}
else {
try {
channel.configureBlocking(false);
Socket socket = channel.socket();
setSocketAttributes(socket);
TcpNioConnection connection = createTcpNioConnection(channel);
if (connection == null) {
return;
try {
SocketChannel channel = server.accept();
if (isShuttingDown()) {
if (logger.isInfoEnabled()) {
logger.info("New connection from " + channel.socket().getInetAddress().getHostAddress()
+ ":" + channel.socket().getPort()
+ " rejected; the server is in the process of shutting down.");
}
connection.setTaskExecutor(getTaskExecutor());
connection.setLastRead(now);
if (getSslHandshakeTimeout() != null && connection instanceof TcpNioSSLConnection) {
((TcpNioSSLConnection) connection).setHandshakeTimeout(getSslHandshakeTimeout());
}
this.channelMap.put(channel, connection);
channel.register(selector, SelectionKey.OP_READ, connection);
connection.publishConnectionOpenEvent();
}
catch (Exception e) {
logger.error("Exception accepting new connection from "
+ channel.socket().getInetAddress().getHostAddress()
+ ":" + channel.socket().getPort(), e);
channel.close();
}
else {
try {
channel.configureBlocking(false);
Socket socket = channel.socket();
setSocketAttributes(socket);
TcpNioConnection connection = createTcpNioConnection(channel);
if (connection == null) {
return;
}
connection.setTaskExecutor(getTaskExecutor());
connection.setLastRead(now);
if (getSslHandshakeTimeout() != null && connection instanceof TcpNioSSLConnection) {
((TcpNioSSLConnection) connection).setHandshakeTimeout(getSslHandshakeTimeout());
}
this.channelMap.put(channel, connection);
channel.register(selectorForNewSocket, SelectionKey.OP_READ, connection);
connection.publishConnectionOpenEvent();
}
catch (IOException e) {
logger.error("Exception accepting new connection from "
+ channel.socket().getInetAddress().getHostAddress()
+ ":" + channel.socket().getPort(), e);
channel.close();
}
}
}
catch (IOException e) {
throw new UncheckedIOException(e);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2017 the original author or authors.
* Copyright 2017-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -61,7 +61,7 @@ public class ThreadAffinityClientConnectionFactory extends AbstractClientConnect
}
@Override
public TcpConnectionSupport getConnection() throws Exception {
public TcpConnectionSupport getConnection() throws InterruptedException {
TcpThreadConnection connection = this.connections.get();
if (connection == null || !connection.isOpen()) {
TcpConnectionSupport delegate = this.connectionFactory.getConnection();
@@ -380,7 +380,7 @@ public class ThreadAffinityClientConnectionFactory extends AbstractClientConnect
}
@Override
public void send(Message<?> message) throws Exception {
public void send(Message<?> message) {
this.connection.send(message);
}
@@ -390,7 +390,7 @@ public class ThreadAffinityClientConnectionFactory extends AbstractClientConnect
}
@Override
public Object getPayload() throws Exception {
public Object getPayload() {
return this.connection.getPayload();
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -39,6 +39,7 @@ import org.springframework.lang.Nullable;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHandlingException;
import org.springframework.messaging.MessageHeaders;
import org.springframework.messaging.MessagingException;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
@@ -133,7 +134,7 @@ public class DatagramPacketMessageMapper implements InboundMessageMapper<Datagra
* Raw byte[] from message, possibly with a length field up front.
*/
@Override
public DatagramPacket fromMessage(Message<?> message) throws Exception {
public DatagramPacket fromMessage(Message<?> message) {
if (this.acknowledge) {
return fromMessageWithAck(message);
}
@@ -152,23 +153,28 @@ public class DatagramPacketMessageMapper implements InboundMessageMapper<Datagra
/**
* Prefix raw byte[] from message with 'acknowledge to' and 'message id' "headers".
*/
private DatagramPacket fromMessageWithAck(Message<?> message) throws Exception {
private DatagramPacket fromMessageWithAck(Message<?> message) {
Assert.state(StringUtils.hasText(this.ackAddress), "'ackAddress' must not be empty");
byte[] bytes = getPayloadAsBytes(message);
ByteBuffer buffer = ByteBuffer.allocate(100 + bytes.length);
if (this.lengthCheck) {
buffer.putInt(0); // placeholder for length
}
buffer.put(IpHeaders.ACK_ADDRESS.getBytes(this.charset));
buffer.put((byte) '=');
buffer.put(this.ackAddress.getBytes(this.charset));
buffer.put((byte) ';');
UUID id = message.getHeaders().getId();
if (id != null) {
buffer.put(MessageHeaders.ID.getBytes(this.charset));
try {
buffer.put(IpHeaders.ACK_ADDRESS.getBytes(this.charset));
buffer.put((byte) '=');
buffer.put(id.toString().getBytes(this.charset));
buffer.put(this.ackAddress.getBytes(this.charset));
buffer.put((byte) ';');
UUID id = message.getHeaders().getId();
if (id != null) {
buffer.put(MessageHeaders.ID.getBytes(this.charset));
buffer.put((byte) '=');
buffer.put(id.toString().getBytes(this.charset));
buffer.put((byte) ';');
}
}
catch (UnsupportedEncodingException e) {
throw new MessagingException(message, "Failed to get headers", e);
}
int headersLength = buffer.position() - 4;
buffer.put(bytes);
@@ -203,13 +209,13 @@ public class DatagramPacketMessageMapper implements InboundMessageMapper<Datagra
@Override
@Nullable
public Message<byte[]> toMessage(DatagramPacket object) throws Exception {
public Message<byte[]> toMessage(DatagramPacket object) {
return toMessage(object, null);
}
@Override
@Nullable
public Message<byte[]> toMessage(DatagramPacket packet, @Nullable Map<String, Object> headers) throws Exception {
public Message<byte[]> toMessage(DatagramPacket packet, @Nullable Map<String, Object> headers) {
int offset = packet.getOffset();
int length = packet.getLength();
byte[] payload;

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2001-2018 the original author or authors.
* Copyright 2001-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -21,6 +21,7 @@ import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.MulticastSocket;
import java.net.URISyntaxException;
import org.springframework.expression.Expression;
import org.springframework.messaging.Message;
@@ -190,7 +191,7 @@ public class MulticastSendingMessageHandler extends UnicastSendingMessageHandler
}
@Override
protected void convertAndSend(Message<?> message) throws Exception {
protected void convertAndSend(Message<?> message) throws IOException, URISyntaxException {
super.convertAndSend(message);
if (logger.isDebugEnabled()) {
logger.debug("Sent packet to " + this.multicastSocket.getInterface());

View File

@@ -217,7 +217,7 @@ public class UnicastReceivingChannelAdapter extends AbstractInternetProtocolRece
}
}
protected DatagramPacket receive() throws Exception {
protected DatagramPacket receive() throws IOException {
final byte[] buffer = new byte[this.getReceiveBufferSize()];
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
getSocket().receive(packet);

View File

@@ -24,6 +24,7 @@ import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.net.SocketException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
@@ -278,7 +279,7 @@ public class UnicastSendingMessageHandler extends
+ this.ackTimeout + " millis");
}
}
catch (InterruptedException e) {
catch (@SuppressWarnings("unused") InterruptedException e) {
Thread.currentThread().interrupt();
}
}
@@ -312,7 +313,7 @@ public class UnicastSendingMessageHandler extends
try {
this.ackLatch.await(10000, TimeUnit.MILLISECONDS);
}
catch (InterruptedException e) {
catch (@SuppressWarnings("unused") InterruptedException e) {
Thread.currentThread().interrupt();
}
}
@@ -320,7 +321,7 @@ public class UnicastSendingMessageHandler extends
}
}
protected void convertAndSend(Message<?> message) throws Exception {
protected void convertAndSend(Message<?> message) throws IOException, URISyntaxException {
DatagramSocket datagramSocket;
if (this.socketExpression != null) {
datagramSocket = this.socketExpression.getValue(this.evaluationContext, message, DatagramSocket.class);

View File

@@ -139,10 +139,12 @@ public final class TestingUtilities {
* of connections.
* @param factory The factory.
* @param n The required number of connections.
* @throws Exception IllegalStateException if the count does not match.
* @throws InterruptedException if interrupted.
* @throws IllegalStateException if the count does not match.
*/
public static void waitUntilFactoryHasThisNumberOfConnections(AbstractConnectionFactory factory, int n)
throws Exception {
throws InterruptedException {
int timer = 0;
while (timer < 10000) {
if (factory.getOpenConnectionIds().size() == n) {

View File

@@ -653,7 +653,7 @@ public class ParserUnitTests {
public static class FooAdvice extends AbstractRequestHandlerAdvice {
@Override
protected Object doInvoke(ExecutionCallback callback, Object target, Message<?> message) throws Exception {
protected Object doInvoke(ExecutionCallback callback, Object target, Message<?> message) {
adviceCalled.countDown();
return null;
}

View File

@@ -17,6 +17,7 @@
package org.springframework.integration.ip.tcp;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.catchThrowable;
import static org.assertj.core.api.Assertions.fail;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
@@ -27,6 +28,7 @@ import java.io.EOFException;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.UncheckedIOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketTimeoutException;
@@ -74,6 +76,8 @@ import org.springframework.integration.test.rule.Log4j2LevelAdjuster;
import org.springframework.integration.test.support.LongRunningIntegrationTest;
import org.springframework.integration.test.util.TestUtils;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHandlingException;
import org.springframework.messaging.MessagingException;
import org.springframework.messaging.PollableChannel;
import org.springframework.messaging.support.ErrorMessage;
import org.springframework.messaging.support.GenericMessage;
@@ -485,7 +489,8 @@ public class TcpOutboundGatewayTests {
AbstractClientConnectionFactory factory1 = mock(AbstractClientConnectionFactory.class);
TcpConnectionSupport mockConn1 = makeMockConnection();
when(factory1.getConnection()).thenReturn(mockConn1);
doThrow(new IOException("fail")).when(mockConn1).send(Mockito.any(Message.class));
doThrow(new UncheckedIOException(new IOException("fail")))
.when(mockConn1).send(Mockito.any(Message.class));
AbstractClientConnectionFactory factory2 = new TcpNetClientConnectionFactory("localhost",
serverSocket.get().getLocalPort());
@@ -567,7 +572,8 @@ public class TcpOutboundGatewayTests {
TcpConnectionSupport mockConn1 = makeMockConnection();
when(factory1.getConnection()).thenReturn(mockConn1);
when(factory1.isSingleUse()).thenReturn(true);
doThrow(new IOException("fail")).when(mockConn1).send(Mockito.any(Message.class));
doThrow(new UncheckedIOException(new IOException("fail")))
.when(mockConn1).send(Mockito.any(Message.class));
CachingClientConnectionFactory cachingFactory1 = new CachingClientConnectionFactory(factory1, 1);
AbstractClientConnectionFactory factory2 = new TcpNetClientConnectionFactory("localhost",
@@ -727,13 +733,10 @@ public class TcpOutboundGatewayTests {
gateway.setBeanFactory(mock(BeanFactory.class));
gateway.afterPropertiesSet();
gateway.start();
try {
gateway.handleMessage(MessageBuilder.withPayload("Test").build());
fail("expected failure");
}
catch (Exception e) {
assertThat(e.getCause().getCause()).isInstanceOf(EOFException.class);
}
Throwable thrown = catchThrowable(() -> gateway.handleMessage(MessageBuilder.withPayload("Test").build()));
assertThat(thrown).isInstanceOf(MessageHandlingException.class);
assertThat(thrown.getCause()).isInstanceOf(MessagingException.class);
assertThat(thrown.getCause().getCause()).isInstanceOf(EOFException.class);
assertThat(TestUtils.getPropertyValue(gateway, "pendingReplies", Map.class).size()).isEqualTo(0);
Message<?> reply = replyChannel.receive(0);
assertThat(reply).isNull();
@@ -837,13 +840,10 @@ public class TcpOutboundGatewayTests {
gateway.setBeanFactory(mock(BeanFactory.class));
gateway.afterPropertiesSet();
gateway.start();
try {
gateway.handleMessage(MessageBuilder.withPayload("Test").build());
fail("expected failure");
}
catch (Exception e) {
assertThat(e.getCause().getCause()).isInstanceOf(SocketTimeoutException.class);
}
Throwable thrown = catchThrowable(() -> gateway.handleMessage(MessageBuilder.withPayload("Test").build()));
assertThat(thrown).isInstanceOf(MessageHandlingException.class);
assertThat(thrown.getCause()).isInstanceOf(MessagingException.class);
assertThat(thrown.getCause().getCause()).isInstanceOf(SocketTimeoutException.class);
assertThat(TestUtils.getPropertyValue(gateway, "pendingReplies", Map.class).size()).isEqualTo(0);
Message<?> reply = replyChannel.receive(0);
assertThat(reply).isNull();

View File

@@ -17,7 +17,7 @@
package org.springframework.integration.ip.tcp.connection;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.fail;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
@@ -32,6 +32,7 @@ import static org.mockito.Mockito.when;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UncheckedIOException;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
@@ -73,6 +74,7 @@ import org.springframework.integration.test.util.TestUtils;
import org.springframework.integration.util.PoolItemNotAvailableException;
import org.springframework.integration.util.SimplePool;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessagingException;
import org.springframework.messaging.PollableChannel;
import org.springframework.messaging.SubscribableChannel;
import org.springframework.messaging.support.ErrorMessage;
@@ -363,13 +365,8 @@ public class CachingClientConnectionFactoryTests {
private void doTestCloseOnSendError(TcpConnection conn1, TcpConnection conn2,
CachingClientConnectionFactory cccf) throws Exception {
TcpConnection cached1 = cccf.getConnection();
try {
cached1.send(new GenericMessage<String>("foo"));
fail("Expected IOException");
}
catch (IOException e) {
assertThat(e.getMessage()).isEqualTo("Foo");
}
assertThatExceptionOfType(MessagingException.class)
.isThrownBy(() -> cached1.send(new GenericMessage<String>("foo")));
// Before INT-3163 this failed with a timeout - connection not returned to pool after failure on send()
TcpConnection cached2 = cccf.getConnection();
assertThat(cached1.getConnectionId().contains(conn1.getConnectionId())).isTrue();
@@ -550,7 +547,7 @@ public class CachingClientConnectionFactoryTests {
when(factory2.getConnection()).thenReturn(mockConn2);
when(factory1.isActive()).thenReturn(true);
when(factory2.isActive()).thenReturn(true);
doThrow(new IOException("fail")).when(mockConn1).send(Mockito.any(Message.class));
doThrow(new UncheckedIOException(new IOException("fail"))).when(mockConn1).send(Mockito.any(Message.class));
doAnswer(invocation -> null).when(mockConn2).send(Mockito.any(Message.class));
FailoverClientConnectionFactory failoverFactory = new FailoverClientConnectionFactory(factories);
failoverFactory.start();

View File

@@ -27,6 +27,7 @@ import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import java.io.OutputStream;
import java.io.UncheckedIOException;
import java.net.BindException;
import java.net.ServerSocket;
import java.net.Socket;
@@ -258,13 +259,7 @@ public class ConnectionEventTests {
}
private void testServerExceptionGuts(AbstractServerConnectionFactory factory) throws Exception {
ServerSocket ss = null;
try {
ss = ServerSocketFactory.getDefault().createServerSocket(0);
}
catch (Exception e) {
fail("Failed to get a server socket");
}
ServerSocket ss = ServerSocketFactory.getDefault().createServerSocket(0);
factory.setPort(ss.getLocalPort());
final AtomicReference<TcpConnectionServerExceptionEvent> theEvent =
new AtomicReference<TcpConnectionServerExceptionEvent>();
@@ -315,8 +310,8 @@ public class ConnectionEventTests {
}
@Override
protected TcpConnectionSupport buildNewConnection() throws Exception {
throw new UnknownHostException("Mocking for test ");
protected TcpConnectionSupport buildNewConnection() {
throw new UncheckedIOException(new UnknownHostException("Mocking for test "));
}
};
@@ -340,7 +335,7 @@ public class ConnectionEventTests {
fail("expected exception");
}
catch (Exception e) {
assertThat(e).isInstanceOf(UnknownHostException.class);
assertThat(e.getCause()).isInstanceOf(UnknownHostException.class);
TcpConnectionFailedEvent event = (TcpConnectionFailedEvent) failEvent.get();
assertThat(event.getCause()).isSameAs(e);
}

View File

@@ -171,7 +171,7 @@ public class ConnectionTimeoutTests {
connection.send(MessageBuilder.withPayload("foo").build());
Thread.sleep(1400);
assertThat(connection.isOpen()).isTrue();
assertThat(clientCloseLatch.await(2000, TimeUnit.SECONDS)).isTrue();
assertThat(clientCloseLatch.await(5, TimeUnit.SECONDS)).isTrue();
assertThat(reply.get()).isNull();
assertThat(connection.isOpen()).isFalse();
server.stop();

View File

@@ -17,7 +17,7 @@
package org.springframework.integration.ip.tcp.connection;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.fail;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
@@ -25,6 +25,7 @@ import static org.mockito.Mockito.times;
import static org.mockito.Mockito.when;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.net.Socket;
import java.nio.channels.SocketChannel;
import java.util.ArrayList;
@@ -100,7 +101,8 @@ public class FailoverClientConnectionFactoryTests {
when(factory2.getConnection()).thenReturn(conn2);
when(factory1.isActive()).thenReturn(true);
when(factory2.isActive()).thenReturn(true);
doThrow(new IOException("fail")).when(conn1).send(Mockito.any(Message.class));
doThrow(new UncheckedIOException(new IOException("fail")))
.when(conn1).send(Mockito.any(Message.class));
doAnswer(invocation -> null).when(conn2).send(Mockito.any(Message.class));
FailoverClientConnectionFactory failoverFactory = new FailoverClientConnectionFactory(factories);
failoverFactory.start();
@@ -109,7 +111,7 @@ public class FailoverClientConnectionFactoryTests {
Mockito.verify(conn2).send(message);
}
@Test(expected = IOException.class)
@Test(expected = UncheckedIOException.class)
public void testFailoverAllDead() throws Exception {
AbstractClientConnectionFactory factory1 = mock(AbstractClientConnectionFactory.class);
AbstractClientConnectionFactory factory2 = mock(AbstractClientConnectionFactory.class);
@@ -122,8 +124,10 @@ public class FailoverClientConnectionFactoryTests {
when(factory2.getConnection()).thenReturn(conn2);
when(factory1.isActive()).thenReturn(true);
when(factory2.isActive()).thenReturn(true);
doThrow(new IOException("fail")).when(conn1).send(Mockito.any(Message.class));
doThrow(new IOException("fail")).when(conn2).send(Mockito.any(Message.class));
doThrow(new UncheckedIOException(new IOException("fail")))
.when(conn1).send(Mockito.any(Message.class));
doThrow(new UncheckedIOException(new IOException("fail")))
.when(conn2).send(Mockito.any(Message.class));
FailoverClientConnectionFactory failoverFactory = new FailoverClientConnectionFactory(factories);
failoverFactory.start();
GenericMessage<String> message = new GenericMessage<String>("foo");
@@ -148,11 +152,12 @@ public class FailoverClientConnectionFactoryTests {
doAnswer(invocation -> {
if (!failedOnce.get()) {
failedOnce.set(true);
throw new IOException("fail");
throw new UncheckedIOException(new IOException("fail"));
}
return null;
}).when(conn1).send(Mockito.any(Message.class));
doThrow(new IOException("fail")).when(conn2).send(Mockito.any(Message.class));
doThrow(new UncheckedIOException(new IOException("fail")))
.when(conn2).send(Mockito.any(Message.class));
FailoverClientConnectionFactory failoverFactory = new FailoverClientConnectionFactory(factories);
failoverFactory.start();
GenericMessage<String> message = new GenericMessage<String>("foo");
@@ -161,15 +166,15 @@ public class FailoverClientConnectionFactoryTests {
Mockito.verify(conn1, times(2)).send(message);
}
@Test(expected = IOException.class)
@Test(expected = UncheckedIOException.class)
public void testFailoverConnectNone() throws Exception {
AbstractClientConnectionFactory factory1 = mock(AbstractClientConnectionFactory.class);
AbstractClientConnectionFactory factory2 = mock(AbstractClientConnectionFactory.class);
List<AbstractClientConnectionFactory> factories = new ArrayList<AbstractClientConnectionFactory>();
factories.add(factory1);
factories.add(factory2);
when(factory1.getConnection()).thenThrow(new IOException("fail"));
when(factory2.getConnection()).thenThrow(new IOException("fail"));
when(factory1.getConnection()).thenThrow(new UncheckedIOException(new IOException("fail")));
when(factory2.getConnection()).thenThrow(new UncheckedIOException(new IOException("fail")));
when(factory1.isActive()).thenReturn(true);
when(factory2.isActive()).thenReturn(true);
FailoverClientConnectionFactory failoverFactory = new FailoverClientConnectionFactory(factories);
@@ -187,8 +192,11 @@ public class FailoverClientConnectionFactoryTests {
factories.add(factory2);
TcpConnectionSupport conn1 = makeMockConnection();
doAnswer(invocation -> null).when(conn1).send(Mockito.any(Message.class));
when(factory1.getConnection()).thenThrow(new IOException("fail")).thenReturn(conn1);
when(factory2.getConnection()).thenThrow(new IOException("fail"));
when(factory1.getConnection())
.thenThrow(new UncheckedIOException(new IOException("fail")))
.thenReturn(conn1);
when(factory2.getConnection())
.thenThrow(new UncheckedIOException(new IOException("fail")));
when(factory1.isActive()).thenReturn(true);
when(factory2.isActive()).thenReturn(true);
FailoverClientConnectionFactory failoverFactory = new FailoverClientConnectionFactory(factories);
@@ -214,20 +222,17 @@ public class FailoverClientConnectionFactoryTests {
final AtomicInteger failCount = new AtomicInteger();
doAnswer(invocation -> {
if (failCount.incrementAndGet() < 3) {
throw new IOException("fail");
throw new UncheckedIOException(new IOException("fail"));
}
return null;
}).when(conn1).send(Mockito.any(Message.class));
doThrow(new IOException("fail")).when(conn2).send(Mockito.any(Message.class));
doThrow(new UncheckedIOException(new IOException("fail")))
.when(conn2).send(Mockito.any(Message.class));
FailoverClientConnectionFactory failoverFactory = new FailoverClientConnectionFactory(factories);
failoverFactory.start();
GenericMessage<String> message = new GenericMessage<String>("foo");
try {
failoverFactory.getConnection().send(message);
fail("ExpectedFailure");
}
catch (IOException e) {
}
assertThatExceptionOfType(UncheckedIOException.class)
.isThrownBy(() -> failoverFactory.getConnection().send(message));
failoverFactory.getConnection().send(message);
Mockito.verify(conn2).send(message);
Mockito.verify(conn1, times(3)).send(message);

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* Copyright 2002-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,9 +19,6 @@ package org.springframework.integration.ip.tcp.connection;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.integration.support.MessageBuilder;
import org.springframework.messaging.Message;
@@ -34,8 +31,6 @@ import org.springframework.messaging.MessagingException;
*/
public class HelloWorldInterceptor extends TcpConnectionInterceptorSupport {
Log logger = LogFactory.getLog(this.getClass());
private volatile boolean negotiated;
private final Semaphore negotiationSemaphore = new Semaphore(0);
@@ -109,14 +104,19 @@ public class HelloWorldInterceptor extends TcpConnectionInterceptorSupport {
}
@Override
public void send(Message<?> message) throws Exception {
public void send(Message<?> message) {
this.pendingSend = true;
try {
if (!this.negotiated) {
if (!this.isServer()) {
logger.debug(this.toString() + " Sending " + hello);
super.send(MessageBuilder.withPayload(hello).build());
this.negotiationSemaphore.tryAcquire(this.timeout, TimeUnit.MILLISECONDS);
try {
this.negotiationSemaphore.tryAcquire(this.timeout, TimeUnit.MILLISECONDS);
}
catch (@SuppressWarnings("unused") InterruptedException e) {
Thread.currentThread().interrupt();
}
if (!this.negotiated) {
throw new MessagingException("Negotiation error");
}

View File

@@ -17,18 +17,15 @@
package org.springframework.integration.ip.tcp.connection;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.fail;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.io.IOException;
import java.io.InputStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.nio.channels.ClosedChannelException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -41,7 +38,6 @@ import java.util.concurrent.atomic.AtomicReference;
import javax.net.ServerSocketFactory;
import javax.net.SocketFactory;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLServerSocket;
import org.junit.Test;
@@ -51,6 +47,7 @@ import org.springframework.integration.ip.tcp.serializer.ByteArrayCrLfSerializer
import org.springframework.integration.ip.util.TestingUtilities;
import org.springframework.integration.test.util.TestUtils;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessagingException;
import org.springframework.messaging.support.GenericMessage;
/**
@@ -366,13 +363,8 @@ public class SocketSupportTests {
@Test
public void testNetClientAndServerSSLDifferentContexts() throws Exception {
testNetClientAndServerSSLDifferentContexts(false);
try {
testNetClientAndServerSSLDifferentContexts(true);
fail("expected Exception");
}
catch (SSLException | SocketException e) {
// NOSONAR
}
assertThatExceptionOfType(MessagingException.class)
.isThrownBy(() -> testNetClientAndServerSSLDifferentContexts(true));
}
private void testNetClientAndServerSSLDifferentContexts(boolean badClient) throws Exception {
@@ -478,19 +470,10 @@ public class SocketSupportTests {
@Test
public void testNioClientAndServerSSLDifferentContexts() throws Exception {
testNioClientAndServerSSLDifferentContexts(false);
try {
testNioClientAndServerSSLDifferentContexts(true);
fail("expected Exception");
}
catch (IOException e) {
if (!(e instanceof ClosedChannelException)) {
assertThat(e.getMessage())
.satisfiesAnyOf(
s -> assertThat(s).contains("Socket closed during SSL Handshake"),
s -> assertThat(s).contains("Broken pipe"),
s -> assertThat(s).contains("Connection reset by peer"));
}
}
assertThatExceptionOfType(MessagingException.class)
.isThrownBy(() -> testNioClientAndServerSSLDifferentContexts(true))
.withMessageMatching(".*(Socket closed during SSL Handshake|Broken pipe"
+ "|Connection reset by peer|AsynchronousCloseException).*");
}
private void testNioClientAndServerSSLDifferentContexts(boolean badClient) throws Exception {

View File

@@ -146,7 +146,7 @@ public class TcpMessageMapperTests {
}
@Test(expected = IllegalArgumentException.class)
public void testToMessageWithBadContentType() throws Exception {
public void testToMessageWithBadContentType() {
TcpMessageMapper mapper = new TcpMessageMapper();
mapper.setAddContentTypeHeader(true);
try {
@@ -169,7 +169,7 @@ public class TcpMessageMapperTests {
}
@Override
public void send(Message<?> message) throws Exception {
public void send(Message<?> message) {
}
@Override
@@ -183,7 +183,7 @@ public class TcpMessageMapperTests {
}
@Override
public Object getPayload() throws Exception {
public Object getPayload() {
return TEST_PAYLOAD.getBytes();
}
@@ -252,7 +252,7 @@ public class TcpMessageMapperTests {
}
@Override
public void send(Message<?> message) throws Exception {
public void send(Message<?> message) {
}
@Override
@@ -266,7 +266,7 @@ public class TcpMessageMapperTests {
}
@Override
public Object getPayload() throws Exception {
public Object getPayload() {
return TEST_PAYLOAD.getBytes();
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2018 the original author or authors.
* Copyright 2018-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -52,13 +52,13 @@ public class TcpNetConnectionSupportTests {
server.setTcpNetConnectionSupport(new DefaultTcpNetConnectionSupport() {
@Override
public TcpNetConnection createNewConnection(Socket socket, boolean server, boolean lookupHost,
ApplicationEventPublisher applicationEventPublisher, String connectionFactoryName)
throws Exception {
public TcpNetConnection createNewConnection(Socket socket, boolean isServer, boolean lookupHost,
ApplicationEventPublisher applicationEventPublisher, String connectionFactoryName) {
if (firstTime.getAndSet(false)) {
throw new RuntimeException("intended");
}
return super.createNewConnection(socket, server, lookupHost, applicationEventPublisher, connectionFactoryName);
return super.createNewConnection(socket, isServer, lookupHost, applicationEventPublisher, connectionFactoryName);
}
});

View File

@@ -17,6 +17,7 @@
package org.springframework.integration.ip.tcp.connection;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@@ -63,6 +64,7 @@ public class TcpNetConnectionTests {
connection.setDeserializer(new ByteArrayStxEtxSerializer());
final AtomicReference<Object> log = new AtomicReference<Object>();
Log logger = mock(Log.class);
given(logger.isErrorEnabled()).willReturn(true);
doAnswer(invocation -> {
log.set(invocation.getArguments()[0]);
return null;

View File

@@ -83,6 +83,7 @@ import org.springframework.integration.test.rule.Log4j2LevelAdjuster;
import org.springframework.integration.test.util.TestUtils;
import org.springframework.integration.util.CompositeExecutor;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessagingException;
import org.springframework.messaging.support.ErrorMessage;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.util.ReflectionUtils;
@@ -143,8 +144,8 @@ public class TcpNioConnectionTests {
TcpConnection connection = factory.getConnection();
connection.send(MessageBuilder.withPayload(new byte[1000000]).build());
}
catch (Exception e) {
assertThat(e instanceof SocketTimeoutException)
catch (MessagingException e) {
assertThat(e.getCause() instanceof SocketTimeoutException)
.as("Expected SocketTimeoutException, got " + e.getClass().getSimpleName() +
":" + e.getMessage()).isTrue();
}

View File

@@ -102,7 +102,7 @@ public class UdpChannelAdapterTests {
}
@Override
protected DatagramPacket receive() throws Exception {
protected DatagramPacket receive() throws IOException {
if (stopping.get()) {
return new DatagramPacket(new byte[0], 0);
}