INT-1145 INT-1146 Add 'close' attribute to tcp gateways and inbound adapters
This commit is contained in:
@@ -42,6 +42,8 @@ public abstract class AbstractInternetProtocolReceivingChannelAdapter
|
|||||||
|
|
||||||
protected volatile boolean active;
|
protected volatile boolean active;
|
||||||
|
|
||||||
|
protected volatile boolean listening;
|
||||||
|
|
||||||
|
|
||||||
public AbstractInternetProtocolReceivingChannelAdapter(int port) {
|
public AbstractInternetProtocolReceivingChannelAdapter(int port) {
|
||||||
this.port = port;
|
this.port = port;
|
||||||
@@ -95,4 +97,8 @@ public abstract class AbstractInternetProtocolReceivingChannelAdapter
|
|||||||
this.active = false;
|
this.active = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isListening() {
|
||||||
|
return listening;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -87,6 +87,8 @@ public abstract class IpAdapterParserUtils {
|
|||||||
|
|
||||||
static final String SO_TRAFFIC_CLASS = "so-traffic-class";
|
static final String SO_TRAFFIC_CLASS = "so-traffic-class";
|
||||||
|
|
||||||
|
static final String CLOSE = "close";
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a constructor-arg to the provided bean definition builder
|
* Adds a constructor-arg to the provided bean definition builder
|
||||||
@@ -172,6 +174,22 @@ public abstract class IpAdapterParserUtils {
|
|||||||
return multicast;
|
return multicast;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the close attribute, if present.
|
||||||
|
* @param element
|
||||||
|
*/
|
||||||
|
static void setClose(Element element, BeanDefinitionBuilder builder) {
|
||||||
|
String close = element.getAttribute(IpAdapterParserUtils.CLOSE);
|
||||||
|
if (!StringUtils.hasText(close)) {
|
||||||
|
close = "false";
|
||||||
|
}
|
||||||
|
if (close.equals("true")) {
|
||||||
|
builder.addPropertyValue(
|
||||||
|
Conventions.attributeNameToPropertyName(IpAdapterParserUtils.CLOSE),
|
||||||
|
close);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the use-nio attribute, if present; if not returns 'false'.
|
* Gets the use-nio attribute, if present; if not returns 'false'.
|
||||||
* @param element
|
* @param element
|
||||||
|
|||||||
@@ -124,6 +124,7 @@ public class IpInboundChannelAdapterParser extends AbstractChannelAdapterParser
|
|||||||
IpAdapterParserUtils.USING_DIRECT_BUFFERS);
|
IpAdapterParserUtils.USING_DIRECT_BUFFERS);
|
||||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element,
|
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element,
|
||||||
IpAdapterParserUtils.SO_KEEP_ALIVE);
|
IpAdapterParserUtils.SO_KEEP_ALIVE);
|
||||||
|
IpAdapterParserUtils.setClose(element, builder);
|
||||||
return builder;
|
return builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import org.w3c.dom.Element;
|
|||||||
* Parser for the <outbound-gateway> element of the integration 'jms' namespace.
|
* Parser for the <outbound-gateway> element of the integration 'jms' namespace.
|
||||||
*
|
*
|
||||||
* @author Gary Russell
|
* @author Gary Russell
|
||||||
|
* @since 2.0
|
||||||
*/
|
*/
|
||||||
public class IpOutboundGatewayParser extends AbstractConsumerEndpointParser {
|
public class IpOutboundGatewayParser extends AbstractConsumerEndpointParser {
|
||||||
|
|
||||||
@@ -44,6 +45,7 @@ public class IpOutboundGatewayParser extends AbstractConsumerEndpointParser {
|
|||||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element,
|
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element,
|
||||||
IpAdapterParserUtils.CUSTOM_SOCKET_READER_CLASS_NAME);
|
IpAdapterParserUtils.CUSTOM_SOCKET_READER_CLASS_NAME);
|
||||||
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "reply-channel");
|
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "reply-channel");
|
||||||
|
IpAdapterParserUtils.setClose(element, builder);
|
||||||
return builder;
|
return builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ import java.io.IOException;
|
|||||||
* when the format is {@link MessageFormats#FORMAT_CUSTOM}.
|
* when the format is {@link MessageFormats#FORMAT_CUSTOM}.
|
||||||
*
|
*
|
||||||
* @author Gary Russell
|
* @author Gary Russell
|
||||||
|
* @since 2.0
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractSocketReader implements SocketReader, MessageFormats {
|
public abstract class AbstractSocketReader implements SocketReader, MessageFormats {
|
||||||
@@ -52,21 +53,21 @@ public abstract class AbstractSocketReader implements SocketReader, MessageForma
|
|||||||
* @return True when a message is completely assembled.
|
* @return True when a message is completely assembled.
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
protected abstract boolean assembleDataLengthFormat() throws IOException;
|
protected abstract int assembleDataLengthFormat() throws IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Assembles data in format {@link #FORMAT_STX_ETX}.
|
* Assembles data in format {@link #FORMAT_STX_ETX}.
|
||||||
* @return True when a message is completely assembled.
|
* @return True when a message is completely assembled.
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
protected abstract boolean assembleDataStxEtxFormat() throws IOException;
|
protected abstract int assembleDataStxEtxFormat() throws IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Assembles data in format {@link #FORMAT_CRLF}.
|
* Assembles data in format {@link #FORMAT_CRLF}.
|
||||||
* @return True when a message is completely assembled.
|
* @return True when a message is completely assembled.
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
protected abstract boolean assembleDataCrLfFormat() throws IOException;
|
protected abstract int assembleDataCrLfFormat() throws IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Assembles data in format {@link #FORMAT_CUSTOM}. Implementations must
|
* Assembles data in format {@link #FORMAT_CUSTOM}. Implementations must
|
||||||
@@ -76,9 +77,9 @@ public abstract class AbstractSocketReader implements SocketReader, MessageForma
|
|||||||
* @return True when a message is completely assembled.
|
* @return True when a message is completely assembled.
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
protected abstract boolean assembleDataCustomFormat() throws IOException;
|
protected abstract int assembleDataCustomFormat() throws IOException;
|
||||||
|
|
||||||
public boolean assembleData() throws IOException {
|
public int assembleData() throws IOException {
|
||||||
try {
|
try {
|
||||||
switch (this.messageFormat) {
|
switch (this.messageFormat) {
|
||||||
case FORMAT_LENGTH_HEADER:
|
case FORMAT_LENGTH_HEADER:
|
||||||
|
|||||||
@@ -17,6 +17,9 @@ package org.springframework.integration.ip.tcp;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Abstract SocketWriter that handles data in 3 standard, and one custom
|
* Abstract SocketWriter that handles data in 3 standard, and one custom
|
||||||
* format. The default format is {@link MessageFormats#FORMAT_LENGTH_HEADER} in which
|
* format. The default format is {@link MessageFormats#FORMAT_LENGTH_HEADER} in which
|
||||||
@@ -31,14 +34,18 @@ import java.io.IOException;
|
|||||||
* appropriate implementation, and provide an implementation for
|
* appropriate implementation, and provide an implementation for
|
||||||
* {@link #writeCustomFormat(byte[])} which is invoked by {@link #write(byte[])}
|
* {@link #writeCustomFormat(byte[])} which is invoked by {@link #write(byte[])}
|
||||||
* when the format is {@link MessageFormats#FORMAT_CUSTOM}.
|
* when the format is {@link MessageFormats#FORMAT_CUSTOM}.
|
||||||
|
*
|
||||||
* @author Gary Russell
|
* @author Gary Russell
|
||||||
|
* @since 2.0
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractSocketWriter implements SocketWriter, MessageFormats {
|
public abstract class AbstractSocketWriter implements SocketWriter, MessageFormats {
|
||||||
|
|
||||||
protected int messageFormat = FORMAT_LENGTH_HEADER;
|
protected int messageFormat = FORMAT_LENGTH_HEADER;
|
||||||
|
|
||||||
/*
|
protected final Log logger = LogFactory.getLog(this.getClass());
|
||||||
|
|
||||||
|
/*
|
||||||
* @see org.springframework.integration.ip.tcp.SocketWriter#write(byte[])
|
* @see org.springframework.integration.ip.tcp.SocketWriter#write(byte[])
|
||||||
*/
|
*/
|
||||||
public synchronized void write(byte[] bytes) throws IOException {
|
public synchronized void write(byte[] bytes) throws IOException {
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
|
|||||||
* are provided.
|
* are provided.
|
||||||
*
|
*
|
||||||
* @author Gary Russell
|
* @author Gary Russell
|
||||||
|
* @since 2.0
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractTcpReceivingChannelAdapter extends
|
public abstract class AbstractTcpReceivingChannelAdapter extends
|
||||||
@@ -42,7 +43,9 @@ public abstract class AbstractTcpReceivingChannelAdapter extends
|
|||||||
|
|
||||||
protected volatile boolean soKeepAlive;
|
protected volatile boolean soKeepAlive;
|
||||||
|
|
||||||
protected int messageFormat = MessageFormats.FORMAT_LENGTH_HEADER;
|
protected volatile int messageFormat = MessageFormats.FORMAT_LENGTH_HEADER;
|
||||||
|
|
||||||
|
protected volatile boolean close;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a receiving channel adapter that listens on the port.
|
* Constructs a receiving channel adapter that listens on the port.
|
||||||
@@ -122,4 +125,11 @@ public abstract class AbstractTcpReceivingChannelAdapter extends
|
|||||||
this.poolSize = poolSize;
|
this.poolSize = poolSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param close the close to set
|
||||||
|
*/
|
||||||
|
public void setClose(boolean close) {
|
||||||
|
this.close = close;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ import org.springframework.integration.message.MessageMappingException;
|
|||||||
* is completely assembled.
|
* is completely assembled.
|
||||||
*
|
*
|
||||||
* @author Gary Russell
|
* @author Gary Russell
|
||||||
|
* @since 2.0
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class NetSocketReader extends AbstractSocketReader {
|
public class NetSocketReader extends AbstractSocketReader {
|
||||||
@@ -52,9 +53,11 @@ public class NetSocketReader extends AbstractSocketReader {
|
|||||||
* @see org.springframework.integration.ip.tcp.SocketReader#read(java.nio.ByteBuffer)
|
* @see org.springframework.integration.ip.tcp.SocketReader#read(java.nio.ByteBuffer)
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected boolean assembleDataLengthFormat() throws IOException {
|
protected int assembleDataLengthFormat() throws IOException {
|
||||||
byte[] lengthPart = new byte[4];
|
byte[] lengthPart = new byte[4];
|
||||||
read(lengthPart);
|
int status = read(lengthPart, true);
|
||||||
|
if (status < 0)
|
||||||
|
return status;
|
||||||
int messageLength = ByteBuffer.wrap(lengthPart).getInt();
|
int messageLength = ByteBuffer.wrap(lengthPart).getInt();
|
||||||
if (logger.isDebugEnabled()) {
|
if (logger.isDebugEnabled()) {
|
||||||
logger.debug("Message length is " + messageLength);
|
logger.debug("Message length is " + messageLength);
|
||||||
@@ -64,27 +67,27 @@ public class NetSocketReader extends AbstractSocketReader {
|
|||||||
" exceeds max message length: " + this.maxMessageSize);
|
" exceeds max message length: " + this.maxMessageSize);
|
||||||
}
|
}
|
||||||
byte[] messagePart = new byte[messageLength];
|
byte[] messagePart = new byte[messageLength];
|
||||||
read(messagePart);
|
read(messagePart, false);
|
||||||
assembledData = messagePart;
|
assembledData = messagePart;
|
||||||
return true;
|
return MESSAGE_COMPLETE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
* @see org.springframework.integration.ip.tcp.AbstractSocketReader#assembleDataStxEtxFormat()
|
* @see org.springframework.integration.ip.tcp.AbstractSocketReader#assembleDataStxEtxFormat()
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected boolean assembleDataStxEtxFormat() throws IOException {
|
protected int assembleDataStxEtxFormat() throws IOException {
|
||||||
InputStream inputStream = socket.getInputStream();
|
InputStream inputStream = socket.getInputStream();
|
||||||
if (inputStream.read() != STX)
|
int bite = inputStream.read();
|
||||||
|
if (bite < 0) {
|
||||||
|
return bite;
|
||||||
|
}
|
||||||
|
if (bite != STX)
|
||||||
throw new MessageMappingException("Expected STX to begin message");
|
throw new MessageMappingException("Expected STX to begin message");
|
||||||
byte[] buffer = new byte[this.maxMessageSize];
|
byte[] buffer = new byte[this.maxMessageSize];
|
||||||
int n = 0;
|
int n = 0;
|
||||||
int bite;
|
|
||||||
while ((bite = inputStream.read()) != ETX) {
|
while ((bite = inputStream.read()) != ETX) {
|
||||||
if (bite < 0) {
|
checkClosure(bite);
|
||||||
logger.debug("Socket closed");
|
|
||||||
throw new IOException("Socket Closed");
|
|
||||||
}
|
|
||||||
buffer[n++] = (byte) bite;
|
buffer[n++] = (byte) bite;
|
||||||
if (n >= this.maxMessageSize) {
|
if (n >= this.maxMessageSize) {
|
||||||
throw new IOException("ETX not found before max message length: "
|
throw new IOException("ETX not found before max message length: "
|
||||||
@@ -93,24 +96,31 @@ public class NetSocketReader extends AbstractSocketReader {
|
|||||||
}
|
}
|
||||||
assembledData = new byte[n];
|
assembledData = new byte[n];
|
||||||
System.arraycopy(buffer, 0, assembledData, 0, n);
|
System.arraycopy(buffer, 0, assembledData, 0, n);
|
||||||
return true;
|
return MESSAGE_COMPLETE;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkClosure(int bite) throws IOException {
|
||||||
|
if (bite < 0) {
|
||||||
|
logger.debug("Socket closed");
|
||||||
|
throw new IOException("Socket closed");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
* @see org.springframework.integration.ip.tcp.AbstractSocketReader#assembleDataCrLfFormat()
|
* @see org.springframework.integration.ip.tcp.AbstractSocketReader#assembleDataCrLfFormat()
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected boolean assembleDataCrLfFormat() throws IOException {
|
protected int assembleDataCrLfFormat() throws IOException {
|
||||||
InputStream inputStream = socket.getInputStream();
|
InputStream inputStream = socket.getInputStream();
|
||||||
byte[] buffer = new byte[this.maxMessageSize];
|
byte[] buffer = new byte[this.maxMessageSize];
|
||||||
int n = 0;
|
int n = 0;
|
||||||
int bite;
|
int bite;
|
||||||
while (true) {
|
while (true) {
|
||||||
bite = inputStream.read();
|
bite = inputStream.read();
|
||||||
if (bite < 0) {
|
if (bite < 0 && n == 0) {
|
||||||
logger.debug("Socket closed");
|
return bite;
|
||||||
throw new IOException("Socket Closed");
|
|
||||||
}
|
}
|
||||||
|
checkClosure(bite);
|
||||||
if (n > 0 && bite == '\n' && buffer[n-1] == '\r')
|
if (n > 0 && bite == '\n' && buffer[n-1] == '\r')
|
||||||
break;
|
break;
|
||||||
buffer[n++] = (byte) bite;
|
buffer[n++] = (byte) bite;
|
||||||
@@ -121,7 +131,7 @@ public class NetSocketReader extends AbstractSocketReader {
|
|||||||
};
|
};
|
||||||
assembledData = new byte[n-1];
|
assembledData = new byte[n-1];
|
||||||
System.arraycopy(buffer, 0, assembledData, 0, n-1);
|
System.arraycopy(buffer, 0, assembledData, 0, n-1);
|
||||||
return true;
|
return MESSAGE_COMPLETE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -132,7 +142,7 @@ public class NetSocketReader extends AbstractSocketReader {
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected boolean assembleDataCustomFormat() throws IOException {
|
protected int assembleDataCustomFormat() throws IOException {
|
||||||
throw new UnsupportedOperationException("Need to subclass for this format");
|
throw new UnsupportedOperationException("Need to subclass for this format");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -149,19 +159,23 @@ public class NetSocketReader extends AbstractSocketReader {
|
|||||||
* Reads data from the socket and puts the data in buffer. Blocks until
|
* Reads data from the socket and puts the data in buffer. Blocks until
|
||||||
* buffer is full or a socket timeout occurs.
|
* buffer is full or a socket timeout occurs.
|
||||||
* @param buffer
|
* @param buffer
|
||||||
|
* @param header true if we are reading the header
|
||||||
|
* @return < 0 if socket closed and not in the middle of a message
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
protected void read(byte[] buffer) throws IOException {
|
protected int read(byte[] buffer, boolean header) throws IOException {
|
||||||
int lengthRead = 0;
|
int lengthRead = 0;
|
||||||
int needed = buffer.length;
|
int needed = buffer.length;
|
||||||
while (lengthRead < needed) {
|
while (lengthRead < needed) {
|
||||||
int len;
|
int len;
|
||||||
len = socket.getInputStream().read(buffer, lengthRead,
|
len = socket.getInputStream().read(buffer, lengthRead,
|
||||||
needed - lengthRead);
|
needed - lengthRead);
|
||||||
if (len < 0) {
|
if (len < 0 && header && lengthRead == 0) {
|
||||||
logger.debug("Socket closed");
|
return len;
|
||||||
throw new IOException("Socket Closed");
|
|
||||||
}
|
}
|
||||||
|
if (len < 0)
|
||||||
|
logger.debug("socket closed after " + lengthRead + " of " + needed);
|
||||||
|
checkClosure(len);
|
||||||
lengthRead += len;
|
lengthRead += len;
|
||||||
if (logger.isDebugEnabled()) {
|
if (logger.isDebugEnabled()) {
|
||||||
logger.debug("Read " + len + " bytes, buffer is now at " +
|
logger.debug("Read " + len + " bytes, buffer is now at " +
|
||||||
@@ -169,7 +183,7 @@ public class NetSocketReader extends AbstractSocketReader {
|
|||||||
needed);
|
needed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import java.nio.ByteBuffer;
|
|||||||
* data is wrapped in a wire protocol based on the messageFormat property.
|
* data is wrapped in a wire protocol based on the messageFormat property.
|
||||||
*
|
*
|
||||||
* @author Gary Russell
|
* @author Gary Russell
|
||||||
|
* @since 2.0
|
||||||
*/
|
*/
|
||||||
public class NetSocketWriter extends AbstractSocketWriter {
|
public class NetSocketWriter extends AbstractSocketWriter {
|
||||||
|
|
||||||
@@ -87,6 +88,8 @@ public class NetSocketWriter extends AbstractSocketWriter {
|
|||||||
protected void doClose() {
|
protected void doClose() {
|
||||||
try {
|
try {
|
||||||
socket.close();
|
socket.close();
|
||||||
} catch (IOException e) {}
|
} catch (IOException e) {
|
||||||
|
logger.error("Error on close", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ import org.springframework.integration.message.MessageMappingException;
|
|||||||
* A non-blocking SocketReader that reads from a {@link java.nio.channels.SocketChannel}.
|
* A non-blocking SocketReader that reads from a {@link java.nio.channels.SocketChannel}.
|
||||||
*
|
*
|
||||||
* @author Gary Russell
|
* @author Gary Russell
|
||||||
|
* @since 2.0
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class NioSocketReader extends AbstractSocketReader {
|
public class NioSocketReader extends AbstractSocketReader {
|
||||||
@@ -71,13 +72,13 @@ public class NioSocketReader extends AbstractSocketReader {
|
|||||||
* @see org.springframework.integration.ip.tcp.SocketReader#assembleData()
|
* @see org.springframework.integration.ip.tcp.SocketReader#assembleData()
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean assembleDataLengthFormat() throws IOException {
|
public int assembleDataLengthFormat() throws IOException {
|
||||||
if (lengthPart == null) {
|
if (lengthPart == null) {
|
||||||
lengthPart = allocate(4);
|
lengthPart = allocate(4);
|
||||||
}
|
}
|
||||||
if (lengthPart.hasRemaining()) {
|
if (lengthPart.hasRemaining()) {
|
||||||
readChannel(lengthPart);
|
readChannel(lengthPart);
|
||||||
return false;
|
return MESSAGE_INCOMPLETE;
|
||||||
}
|
}
|
||||||
if (dataPart == null) {
|
if (dataPart == null) {
|
||||||
lengthPart.flip();
|
lengthPart.flip();
|
||||||
@@ -94,19 +95,19 @@ public class NioSocketReader extends AbstractSocketReader {
|
|||||||
if (dataPart.hasRemaining()) {
|
if (dataPart.hasRemaining()) {
|
||||||
readChannel(dataPart);
|
readChannel(dataPart);
|
||||||
if (dataPart.hasRemaining()) {
|
if (dataPart.hasRemaining()) {
|
||||||
return false;
|
return MESSAGE_INCOMPLETE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assembledData = dataPart.array();
|
assembledData = dataPart.array();
|
||||||
lengthPart = dataPart = null;
|
lengthPart = dataPart = null;
|
||||||
return true;
|
return MESSAGE_COMPLETE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
* @see org.springframework.integration.ip.tcp.AbstractSocketReader#assembleDataStxEtxFormat()
|
* @see org.springframework.integration.ip.tcp.AbstractSocketReader#assembleDataStxEtxFormat()
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected boolean assembleDataStxEtxFormat() throws IOException {
|
protected int assembleDataStxEtxFormat() throws IOException {
|
||||||
if (readChannelNonDeterministic()) {
|
if (readChannelNonDeterministic()) {
|
||||||
byte bite = rawBuffer.get();
|
byte bite = rawBuffer.get();
|
||||||
int count = 0;
|
int count = 0;
|
||||||
@@ -120,12 +121,12 @@ public class NioSocketReader extends AbstractSocketReader {
|
|||||||
if (logger.isDebugEnabled()) {
|
if (logger.isDebugEnabled()) {
|
||||||
logger.debug("Incomplete message, consumed 1 byte");
|
logger.debug("Incomplete message, consumed 1 byte");
|
||||||
}
|
}
|
||||||
return false;
|
return MESSAGE_INCOMPLETE;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (bite == ETX) {
|
if (bite == ETX) {
|
||||||
finishAssembly();
|
finishAssembly();
|
||||||
return true;
|
return MESSAGE_COMPLETE;
|
||||||
}
|
}
|
||||||
buildBuffer.put(bite);
|
buildBuffer.put(bite);
|
||||||
count++;
|
count++;
|
||||||
@@ -139,7 +140,7 @@ public class NioSocketReader extends AbstractSocketReader {
|
|||||||
if (logger.isDebugEnabled()) {
|
if (logger.isDebugEnabled()) {
|
||||||
logger.debug("Incomplete message, consumed " + count + " bytes");
|
logger.debug("Incomplete message, consumed " + count + " bytes");
|
||||||
}
|
}
|
||||||
return false;
|
return MESSAGE_INCOMPLETE;
|
||||||
}
|
}
|
||||||
bite = rawBuffer.get();
|
bite = rawBuffer.get();
|
||||||
if (bite == ETX) {
|
if (bite == ETX) {
|
||||||
@@ -156,13 +157,13 @@ public class NioSocketReader extends AbstractSocketReader {
|
|||||||
logger.debug("Consumed " + count + " bytes");
|
logger.debug("Consumed " + count + " bytes");
|
||||||
}
|
}
|
||||||
finishAssembly();
|
finishAssembly();
|
||||||
return true;
|
return MESSAGE_COMPLETE;
|
||||||
} else {
|
} else {
|
||||||
if (logger.isDebugEnabled()) {
|
if (logger.isDebugEnabled()) {
|
||||||
logger.debug("Incomplete message, consumed 0 bytes");
|
logger.debug("Incomplete message, consumed 0 bytes");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return MESSAGE_INCOMPLETE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -180,7 +181,7 @@ public class NioSocketReader extends AbstractSocketReader {
|
|||||||
* @see org.springframework.integration.ip.tcp.AbstractSocketReader#assembleDataCrLfFormat()
|
* @see org.springframework.integration.ip.tcp.AbstractSocketReader#assembleDataCrLfFormat()
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected boolean assembleDataCrLfFormat() throws IOException {
|
protected int assembleDataCrLfFormat() throws IOException {
|
||||||
if (readChannelNonDeterministic()) {
|
if (readChannelNonDeterministic()) {
|
||||||
int count = 0;
|
int count = 0;
|
||||||
while (true) {
|
while (true) {
|
||||||
@@ -188,7 +189,7 @@ public class NioSocketReader extends AbstractSocketReader {
|
|||||||
if (logger.isDebugEnabled()) {
|
if (logger.isDebugEnabled()) {
|
||||||
logger.debug("Incomplete message, consumed " + count + " bytes");
|
logger.debug("Incomplete message, consumed " + count + " bytes");
|
||||||
}
|
}
|
||||||
return false;
|
return MESSAGE_INCOMPLETE;
|
||||||
}
|
}
|
||||||
byte bite = rawBuffer.get();
|
byte bite = rawBuffer.get();
|
||||||
if (bite == '\n' && buildBuffer.position() > 0) {
|
if (bite == '\n' && buildBuffer.position() > 0) {
|
||||||
@@ -209,13 +210,13 @@ public class NioSocketReader extends AbstractSocketReader {
|
|||||||
logger.debug("Consumed " + count + " bytes");
|
logger.debug("Consumed " + count + " bytes");
|
||||||
}
|
}
|
||||||
finishAssembly();
|
finishAssembly();
|
||||||
return true;
|
return MESSAGE_COMPLETE;
|
||||||
} else {
|
} else {
|
||||||
if (logger.isDebugEnabled()) {
|
if (logger.isDebugEnabled()) {
|
||||||
logger.debug("Incomplete message, consumed 0 bytes");
|
logger.debug("Incomplete message, consumed 0 bytes");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return MESSAGE_INCOMPLETE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -226,7 +227,7 @@ public class NioSocketReader extends AbstractSocketReader {
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected boolean assembleDataCustomFormat() throws IOException {
|
protected int assembleDataCustomFormat() throws IOException {
|
||||||
throw new UnsupportedOperationException("Need to subclass for this format");
|
throw new UnsupportedOperationException("Need to subclass for this format");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import java.util.concurrent.LinkedBlockingQueue;
|
|||||||
* data is wrapped in a wire protocol based on the messageFormat property.
|
* data is wrapped in a wire protocol based on the messageFormat property.
|
||||||
*
|
*
|
||||||
* @author Gary Russell
|
* @author Gary Russell
|
||||||
|
* @since 2.0
|
||||||
*/
|
*/
|
||||||
public class NioSocketWriter extends AbstractSocketWriter {
|
public class NioSocketWriter extends AbstractSocketWriter {
|
||||||
|
|
||||||
@@ -250,7 +251,9 @@ public class NioSocketWriter extends AbstractSocketWriter {
|
|||||||
protected void doClose() {
|
protected void doClose() {
|
||||||
try {
|
try {
|
||||||
channel.close();
|
channel.close();
|
||||||
} catch (IOException e) {}
|
} catch (IOException e) {
|
||||||
|
logger.error("Error on close", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.springframework.integration.ip.tcp;
|
package org.springframework.integration.ip.tcp;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
import java.net.SocketException;
|
import java.net.SocketException;
|
||||||
|
|
||||||
@@ -34,6 +35,7 @@ import org.springframework.integration.message.MessageMappingException;
|
|||||||
* number of concurrent connections expected.
|
* number of concurrent connections expected.
|
||||||
*
|
*
|
||||||
* @author Gary Russell
|
* @author Gary Russell
|
||||||
|
* @since 2.0
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class SimpleTcpNetInboundGateway extends AbstractMessagingGateway {
|
public class SimpleTcpNetInboundGateway extends AbstractMessagingGateway {
|
||||||
@@ -62,6 +64,8 @@ public class SimpleTcpNetInboundGateway extends AbstractMessagingGateway {
|
|||||||
|
|
||||||
protected Class<NetSocketWriter> customSocketWriterClass;
|
protected Class<NetSocketWriter> customSocketWriterClass;
|
||||||
|
|
||||||
|
protected boolean close;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void doStart() {
|
protected void doStart() {
|
||||||
super.doStart();
|
super.doStart();
|
||||||
@@ -86,6 +90,7 @@ public class SimpleTcpNetInboundGateway extends AbstractMessagingGateway {
|
|||||||
this.delegate.setSoTimeout(soTimeout);
|
this.delegate.setSoTimeout(soTimeout);
|
||||||
this.delegate.setTaskScheduler(getTaskScheduler());
|
this.delegate.setTaskScheduler(getTaskScheduler());
|
||||||
this.delegate.setCustomSocketReaderClassName(customSocketReaderClassName);
|
this.delegate.setCustomSocketReaderClassName(customSocketReaderClassName);
|
||||||
|
this.delegate.setClose(close);
|
||||||
super.onInit();
|
super.onInit();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -189,6 +194,17 @@ public class SimpleTcpNetInboundGateway extends AbstractMessagingGateway {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param close the close to set
|
||||||
|
*/
|
||||||
|
public void setClose(boolean close) {
|
||||||
|
this.close = close;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isListening() {
|
||||||
|
return delegate.isListening();
|
||||||
|
}
|
||||||
|
|
||||||
private class WriteCapableTcpNetReceivingChannelAdapter extends TcpNetReceivingChannelAdapter {
|
private class WriteCapableTcpNetReceivingChannelAdapter extends TcpNetReceivingChannelAdapter {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -206,6 +222,13 @@ public class SimpleTcpNetInboundGateway extends AbstractMessagingGateway {
|
|||||||
customSocketWriterClass, socket);
|
customSocketWriterClass, socket);
|
||||||
try {
|
try {
|
||||||
writer.write(this.mapper.fromMessage(message));
|
writer.write(this.mapper.fromMessage(message));
|
||||||
|
if (close) {
|
||||||
|
try {
|
||||||
|
socket.close();
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
logger.error("Error on close", ioe);
|
||||||
|
}
|
||||||
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new MessageMappingException("Failed to map and send response", e);
|
throw new MessageMappingException("Failed to map and send response", e);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,6 +50,8 @@ public class SimpleTcpNetOutboundGateway extends
|
|||||||
|
|
||||||
protected NetSocketReader reader;
|
protected NetSocketReader reader;
|
||||||
|
|
||||||
|
protected boolean close;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a SimpleTcpNetOutboundGateway that sends data to the
|
* Constructs a SimpleTcpNetOutboundGateway that sends data to the
|
||||||
* specified host and port, and waits for a response.
|
* specified host and port, and waits for a response.
|
||||||
@@ -67,9 +69,9 @@ public class SimpleTcpNetOutboundGateway extends
|
|||||||
@Override
|
@Override
|
||||||
protected synchronized Object handleRequestMessage(Message<?> requestMessage) {
|
protected synchronized Object handleRequestMessage(Message<?> requestMessage) {
|
||||||
this.handler.handleMessage(requestMessage);
|
this.handler.handleMessage(requestMessage);
|
||||||
|
Socket socket = this.handler.getSocket();
|
||||||
if (this.reader == null ||
|
if (this.reader == null ||
|
||||||
this.reader.getSocket() != handler.getSocket()) {
|
this.reader.getSocket() != socket) { // might have re-opened on error
|
||||||
Socket socket = this.handler.getSocket();
|
|
||||||
this.reader = SocketIoUtils.createNetReader(this.messageFormat,
|
this.reader = SocketIoUtils.createNetReader(this.messageFormat,
|
||||||
this.customSocketReaderClass, socket, this.maxMessageSize,
|
this.customSocketReaderClass, socket, this.maxMessageSize,
|
||||||
this.soReceiveBufferSize);
|
this.soReceiveBufferSize);
|
||||||
@@ -77,6 +79,10 @@ public class SimpleTcpNetOutboundGateway extends
|
|||||||
try {
|
try {
|
||||||
this.reader.assembleData(); // Net... always returns true
|
this.reader.assembleData(); // Net... always returns true
|
||||||
byte[] bytes = this.reader.getAssembledData();
|
byte[] bytes = this.reader.getAssembledData();
|
||||||
|
if (close) {
|
||||||
|
logger.debug("Closing socket because close=true");
|
||||||
|
this.handler.close();
|
||||||
|
}
|
||||||
return bytes;
|
return bytes;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
this.reader = null;
|
this.reader = null;
|
||||||
@@ -207,4 +213,11 @@ public class SimpleTcpNetOutboundGateway extends
|
|||||||
this.setOutputChannel(replyChannel);
|
this.setOutputChannel(replyChannel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param close the close to set
|
||||||
|
*/
|
||||||
|
public void setClose(boolean close) {
|
||||||
|
this.close = close;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,19 +23,26 @@ import java.net.Socket;
|
|||||||
* General interface for assembling message data from a TCP/IP Socket.
|
* General interface for assembling message data from a TCP/IP Socket.
|
||||||
* Implementations for {@link java.net.Socket} and {@link java.nio.channels.SocketChannel}
|
* Implementations for {@link java.net.Socket} and {@link java.nio.channels.SocketChannel}
|
||||||
* are provided.
|
* are provided.
|
||||||
|
*
|
||||||
* @author Gary Russell
|
* @author Gary Russell
|
||||||
|
* @since 2.0
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public interface SocketReader {
|
public interface SocketReader {
|
||||||
|
|
||||||
|
public static int MESSAGE_INCOMPLETE = 0;
|
||||||
|
|
||||||
|
public static int MESSAGE_COMPLETE = 1;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reads the data the socket and assembles
|
* Reads the data the socket and assembles
|
||||||
* packets of data into a complete message, depending on the format of that
|
* packets of data into a complete message, depending on the format of that
|
||||||
* data.
|
* data.
|
||||||
* @return true when the message is assembled.
|
* @return MESSAGE_COMPLETE when message is assembled, otherwise MESSAGE_IMCOMPLETE, or
|
||||||
|
* < 0 if socket closed before any data for a message is received.
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
public boolean assembleData() throws IOException;
|
public int assembleData() throws IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the assembled tcp data or null if the data is not
|
* Retrieves the assembled tcp data or null if the data is not
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ import org.springframework.integration.ip.util.SocketIoUtils;
|
|||||||
* accordingly.
|
* accordingly.
|
||||||
*
|
*
|
||||||
* @author Gary Russell
|
* @author Gary Russell
|
||||||
|
* @since 2.0
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class TcpNetReceivingChannelAdapter extends
|
public class TcpNetReceivingChannelAdapter extends
|
||||||
@@ -58,6 +59,7 @@ public class TcpNetReceivingChannelAdapter extends
|
|||||||
try {
|
try {
|
||||||
serverSocket = ServerSocketFactory.getDefault()
|
serverSocket = ServerSocketFactory.getDefault()
|
||||||
.createServerSocket(port, Math.abs(poolSize));
|
.createServerSocket(port, Math.abs(poolSize));
|
||||||
|
listening = true;
|
||||||
while (true) {
|
while (true) {
|
||||||
final Socket socket = serverSocket.accept();
|
final Socket socket = serverSocket.accept();
|
||||||
setSocketOptions(socket);
|
setSocketOptions(socket);
|
||||||
@@ -72,6 +74,7 @@ public class TcpNetReceivingChannelAdapter extends
|
|||||||
serverSocket.close();
|
serverSocket.close();
|
||||||
} catch (IOException e1) {}
|
} catch (IOException e1) {}
|
||||||
}
|
}
|
||||||
|
listening = false;
|
||||||
serverSocket = null;
|
serverSocket = null;
|
||||||
if (active) {
|
if (active) {
|
||||||
logger.error("Error on ServerSocket", e);
|
logger.error("Error on ServerSocket", e);
|
||||||
@@ -94,8 +97,21 @@ public class TcpNetReceivingChannelAdapter extends
|
|||||||
this.soReceiveBufferSize);
|
this.soReceiveBufferSize);
|
||||||
while (true) {
|
while (true) {
|
||||||
try {
|
try {
|
||||||
if (reader.assembleData()) {
|
int messageStatus = reader.assembleData();
|
||||||
|
if (messageStatus < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (messageStatus == SocketReader.MESSAGE_COMPLETE) {
|
||||||
processMessage(reader);
|
processMessage(reader);
|
||||||
|
if (close) {
|
||||||
|
logger.debug("Closing socket because close=true");
|
||||||
|
try {
|
||||||
|
reader.getSocket().close();
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
logger.error("Error on close", ioe);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
logger.error("processMessage failed", e);
|
logger.error("processMessage failed", e);
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import org.springframework.integration.ip.util.SocketIoUtils;
|
|||||||
/**
|
/**
|
||||||
* TCP Sending Channel Adapter that that uses a {@link java.net.Socket}.
|
* TCP Sending Channel Adapter that that uses a {@link java.net.Socket}.
|
||||||
* @author Gary Russell
|
* @author Gary Russell
|
||||||
|
* @since 2.0
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class TcpNetSendingMessageHandler extends
|
public class TcpNetSendingMessageHandler extends
|
||||||
@@ -57,6 +58,7 @@ public class TcpNetSendingMessageHandler extends
|
|||||||
protected synchronized SocketWriter getWriter() {
|
protected synchronized SocketWriter getWriter() {
|
||||||
if (this.writer == null) {
|
if (this.writer == null) {
|
||||||
try {
|
try {
|
||||||
|
logger.debug("Opening new socket connection");
|
||||||
this.socket = SocketFactory.getDefault().createSocket(this.host, this.port);
|
this.socket = SocketFactory.getDefault().createSocket(this.host, this.port);
|
||||||
this.setSocketAttributes(socket);
|
this.setSocketAttributes(socket);
|
||||||
NetSocketWriter writer = SocketIoUtils.createNetWriter(messageFormat,
|
NetSocketWriter writer = SocketIoUtils.createNetWriter(messageFormat,
|
||||||
@@ -85,4 +87,12 @@ public class TcpNetSendingMessageHandler extends
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close the underlying socket and prepare to establish a new socket on
|
||||||
|
* the next write.
|
||||||
|
*/
|
||||||
|
protected void close() {
|
||||||
|
this.writer.doClose();
|
||||||
|
this.writer = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ import org.springframework.integration.ip.util.SocketIoUtils;
|
|||||||
* number of threads is controlled by the poolSize property.
|
* number of threads is controlled by the poolSize property.
|
||||||
*
|
*
|
||||||
* @author Gary Russell
|
* @author Gary Russell
|
||||||
|
* @since 2.0
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class TcpNioReceivingChannelAdapter extends
|
public class TcpNioReceivingChannelAdapter extends
|
||||||
@@ -65,6 +66,7 @@ public class TcpNioReceivingChannelAdapter extends
|
|||||||
protected void server() {
|
protected void server() {
|
||||||
try {
|
try {
|
||||||
serverChannel = ServerSocketChannel.open();
|
serverChannel = ServerSocketChannel.open();
|
||||||
|
listening = true;
|
||||||
serverChannel.configureBlocking(false);
|
serverChannel.configureBlocking(false);
|
||||||
serverChannel.socket().bind(new InetSocketAddress(port),
|
serverChannel.socket().bind(new InetSocketAddress(port),
|
||||||
Math.abs(poolSize));
|
Math.abs(poolSize));
|
||||||
@@ -76,6 +78,7 @@ public class TcpNioReceivingChannelAdapter extends
|
|||||||
try {
|
try {
|
||||||
serverChannel.close();
|
serverChannel.close();
|
||||||
} catch (IOException e1) { }
|
} catch (IOException e1) { }
|
||||||
|
listening = false;
|
||||||
serverChannel = null;
|
serverChannel = null;
|
||||||
if (active) {
|
if (active) {
|
||||||
logger.error("Error on ServerSocketChannel", e);
|
logger.error("Error on ServerSocketChannel", e);
|
||||||
@@ -169,11 +172,23 @@ public class TcpNioReceivingChannelAdapter extends
|
|||||||
private void doRead(SelectionKey key) {
|
private void doRead(SelectionKey key) {
|
||||||
NioSocketReader reader = (NioSocketReader) key.attachment();
|
NioSocketReader reader = (NioSocketReader) key.attachment();
|
||||||
try {
|
try {
|
||||||
if (reader.assembleData()) {
|
int messageStatus = reader.assembleData();
|
||||||
|
if (messageStatus < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (messageStatus == SocketReader.MESSAGE_COMPLETE) {
|
||||||
Message<byte[]> message;
|
Message<byte[]> message;
|
||||||
message = mapper.toMessage(reader);
|
message = mapper.toMessage(reader);
|
||||||
if (message != null) {
|
if (message != null) {
|
||||||
sendMessage(message);
|
sendMessage(message);
|
||||||
|
if (close) {
|
||||||
|
logger.debug("Closing channel because close=true");
|
||||||
|
try {
|
||||||
|
key.channel().close();
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
logger.error("Error on close", ioe);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (Exception e) {}
|
} catch (Exception e) {}
|
||||||
|
|||||||
@@ -21,7 +21,10 @@ import org.springframework.integration.ip.util.SocketIoUtils;
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* TCP Sending Channel Adapter that that uses a {@link java.nio.channels.SocketChannel}.
|
||||||
|
*
|
||||||
* @author Gary Russell
|
* @author Gary Russell
|
||||||
|
* @since 2.0
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class TcpNioSendingMessageHandler extends
|
public class TcpNioSendingMessageHandler extends
|
||||||
@@ -49,6 +52,7 @@ public class TcpNioSendingMessageHandler extends
|
|||||||
protected synchronized SocketWriter getWriter() {
|
protected synchronized SocketWriter getWriter() {
|
||||||
if (this.socketChannel == null) {
|
if (this.socketChannel == null) {
|
||||||
try {
|
try {
|
||||||
|
logger.debug("Creating new SocketChannel");
|
||||||
this.socketChannel = SocketChannel.open(this.destinationAddress);
|
this.socketChannel = SocketChannel.open(this.destinationAddress);
|
||||||
this.setSocketAttributes(socketChannel.socket());
|
this.setSocketAttributes(socketChannel.socket());
|
||||||
NioSocketWriter writer = SocketIoUtils.createNioWriter(messageFormat,
|
NioSocketWriter writer = SocketIoUtils.createNioWriter(messageFormat,
|
||||||
|
|||||||
@@ -102,6 +102,8 @@ public class UnicastReceivingChannelAdapter extends AbstractInternetProtocolRece
|
|||||||
this.threadPoolTaskScheduler.initialize();
|
this.threadPoolTaskScheduler.initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
listening = true;
|
||||||
|
|
||||||
// Do as little as possible here so we can loop around and catch the next packet.
|
// Do as little as possible here so we can loop around and catch the next packet.
|
||||||
// Just schedule the packet for processing.
|
// Just schedule the packet for processing.
|
||||||
while (this.active) {
|
while (this.active) {
|
||||||
@@ -121,6 +123,7 @@ public class UnicastReceivingChannelAdapter extends AbstractInternetProtocolRece
|
|||||||
throw new MessagingException("failed to receive DatagramPacket", e);
|
throw new MessagingException("failed to receive DatagramPacket", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
listening = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void sendAck(Message<byte[]> message) {
|
protected void sendAck(Message<byte[]> message) {
|
||||||
|
|||||||
@@ -39,6 +39,15 @@ the custom message format. See java docs for TcpNetReceivingChannelAdapter and T
|
|||||||
</xsd:documentation>
|
</xsd:documentation>
|
||||||
</xsd:annotation>
|
</xsd:annotation>
|
||||||
</xsd:attribute>
|
</xsd:attribute>
|
||||||
|
<xsd:attribute name="close" type="xsd:string" default="false">
|
||||||
|
<xsd:annotation>
|
||||||
|
<xsd:documentation>
|
||||||
|
If true, the socket will be closed after a message is received and sent to the
|
||||||
|
outbound channel. If false, the socket will remain open ready to receive the
|
||||||
|
next message.
|
||||||
|
</xsd:documentation>
|
||||||
|
</xsd:annotation>
|
||||||
|
</xsd:attribute>
|
||||||
</xsd:extension>
|
</xsd:extension>
|
||||||
</xsd:complexContent>
|
</xsd:complexContent>
|
||||||
</xsd:complexType>
|
</xsd:complexType>
|
||||||
@@ -202,6 +211,18 @@ the custom message format. See java docs for TcpNetSendingChannelAdapter and Tcp
|
|||||||
<xsd:attribute name="reply-timeout" type="xsd:string"/>
|
<xsd:attribute name="reply-timeout" type="xsd:string"/>
|
||||||
<xsd:attribute name="auto-startup" type="xsd:string" default="true"/>
|
<xsd:attribute name="auto-startup" type="xsd:string" default="true"/>
|
||||||
<xsd:attribute name="receive-buffer-size" type="xsd:string" />
|
<xsd:attribute name="receive-buffer-size" type="xsd:string" />
|
||||||
|
<xsd:attribute name="close" type="xsd:string" default="false">
|
||||||
|
<xsd:annotation>
|
||||||
|
<xsd:documentation>
|
||||||
|
If true, for an outbound gateway, the socket will be closed after a response
|
||||||
|
is received and sent to the
|
||||||
|
reply channel. If false, the socket will remain open and be used to send the
|
||||||
|
next message. If true, for an inbound gateway, the socket will be closed after
|
||||||
|
the response is sent. If false, the socket will remain open and be used to
|
||||||
|
receive the next message.
|
||||||
|
</xsd:documentation>
|
||||||
|
</xsd:annotation>
|
||||||
|
</xsd:attribute>
|
||||||
</xsd:extension>
|
</xsd:extension>
|
||||||
</xsd:complexContent>
|
</xsd:complexContent>
|
||||||
</xsd:complexType>
|
</xsd:complexType>
|
||||||
|
|||||||
@@ -74,6 +74,7 @@
|
|||||||
so-timeout="32"
|
so-timeout="32"
|
||||||
using-direct-buffers="true"
|
using-direct-buffers="true"
|
||||||
using-nio="true"
|
using-nio="true"
|
||||||
|
close="true"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<ip:inbound-channel-adapter id="testInTcpNet"
|
<ip:inbound-channel-adapter id="testInTcpNet"
|
||||||
@@ -197,13 +198,45 @@
|
|||||||
custom-socket-writer-class-name="org.springframework.integration.ip.tcp.CustomNetSocketWriter"
|
custom-socket-writer-class-name="org.springframework.integration.ip.tcp.CustomNetSocketWriter"
|
||||||
message-format="crlf"
|
message-format="crlf"
|
||||||
host="localhost"
|
host="localhost"
|
||||||
port="#{tcpIpUtils.findAvailableServerSocket(6500)}"
|
port="#{tcpIpUtils.findAvailableServerSocket(6600)}"
|
||||||
receive-buffer-size="223"
|
receive-buffer-size="223"
|
||||||
so-keep-alive="true"
|
so-keep-alive="true"
|
||||||
so-receive-buffer-size="224"
|
so-receive-buffer-size="224"
|
||||||
so-send-buffer-size="225"
|
so-send-buffer-size="225"
|
||||||
so-timeout="226"
|
so-timeout="226"
|
||||||
|
close="false"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<ip:inbound-gateway id="simpleInGatewayClose"
|
||||||
|
request-channel="tcpChannel"
|
||||||
|
reply-channel="replyChannel"
|
||||||
|
custom-socket-reader-class-name="org.springframework.integration.ip.tcp.CustomNetSocketReader"
|
||||||
|
custom-socket-writer-class-name="org.springframework.integration.ip.tcp.CustomNetSocketWriter"
|
||||||
|
message-format="crlf"
|
||||||
|
pool-size="23"
|
||||||
|
port="#{tcpIpUtils.findAvailableServerSocket(6700)}"
|
||||||
|
receive-buffer-size="123"
|
||||||
|
so-keep-alive="true"
|
||||||
|
so-receive-buffer-size="124"
|
||||||
|
so-send-buffer-size="125"
|
||||||
|
so-timeout="126"
|
||||||
|
close="true"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<ip:outbound-gateway id="simpleOutGatewayClose"
|
||||||
|
request-channel="tcpChannel"
|
||||||
|
reply-channel="replyChannel"
|
||||||
|
custom-socket-reader-class-name="org.springframework.integration.ip.tcp.CustomNetSocketReader"
|
||||||
|
custom-socket-writer-class-name="org.springframework.integration.ip.tcp.CustomNetSocketWriter"
|
||||||
|
message-format="crlf"
|
||||||
|
host="localhost"
|
||||||
|
port="#{tcpIpUtils.findAvailableServerSocket(6800)}"
|
||||||
|
receive-buffer-size="223"
|
||||||
|
so-keep-alive="true"
|
||||||
|
so-receive-buffer-size="224"
|
||||||
|
so-send-buffer-size="225"
|
||||||
|
so-timeout="226"
|
||||||
|
close="true"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
</beans>
|
</beans>
|
||||||
|
|||||||
@@ -95,12 +95,21 @@ public class ParserUnitTests {
|
|||||||
TcpNetSendingMessageHandler tcpOutNet;
|
TcpNetSendingMessageHandler tcpOutNet;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
|
@Qualifier(value="simpleInGateway")
|
||||||
SimpleTcpNetInboundGateway simpleTcpNetInboundGateway;
|
SimpleTcpNetInboundGateway simpleTcpNetInboundGateway;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
@Qualifier(value="org.springframework.integration.ip.tcp.SimpleTcpNetOutboundGateway#0")
|
@Qualifier(value="org.springframework.integration.ip.tcp.SimpleTcpNetOutboundGateway#0")
|
||||||
SimpleTcpNetOutboundGateway simpleTcpNetOutboundGateway;
|
SimpleTcpNetOutboundGateway simpleTcpNetOutboundGateway;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
@Qualifier(value="simpleInGatewayClose")
|
||||||
|
SimpleTcpNetInboundGateway simpleTcpNetInboundGatewayClose;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
@Qualifier(value="org.springframework.integration.ip.tcp.SimpleTcpNetOutboundGateway#1")
|
||||||
|
SimpleTcpNetOutboundGateway simpleTcpNetOutboundGatewayClose;
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testInUdp() {
|
public void testInUdp() {
|
||||||
DirectFieldAccessor dfa = new DirectFieldAccessor(udpIn);
|
DirectFieldAccessor dfa = new DirectFieldAccessor(udpIn);
|
||||||
@@ -136,6 +145,7 @@ public class ParserUnitTests {
|
|||||||
assertEquals(29, dfa.getPropertyValue("receiveBufferSize"));
|
assertEquals(29, dfa.getPropertyValue("receiveBufferSize"));
|
||||||
assertEquals(30, dfa.getPropertyValue("soReceiveBufferSize"));
|
assertEquals(30, dfa.getPropertyValue("soReceiveBufferSize"));
|
||||||
assertEquals(32, dfa.getPropertyValue("soTimeout"));
|
assertEquals(32, dfa.getPropertyValue("soTimeout"));
|
||||||
|
assertEquals(false, dfa.getPropertyValue("close"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -150,6 +160,7 @@ public class ParserUnitTests {
|
|||||||
assertEquals(29, dfa.getPropertyValue("receiveBufferSize"));
|
assertEquals(29, dfa.getPropertyValue("receiveBufferSize"));
|
||||||
assertEquals(30, dfa.getPropertyValue("soReceiveBufferSize"));
|
assertEquals(30, dfa.getPropertyValue("soReceiveBufferSize"));
|
||||||
assertEquals(32, dfa.getPropertyValue("soTimeout"));
|
assertEquals(32, dfa.getPropertyValue("soTimeout"));
|
||||||
|
assertEquals(true, dfa.getPropertyValue("close"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -163,6 +174,7 @@ public class ParserUnitTests {
|
|||||||
assertEquals(29, dfa.getPropertyValue("receiveBufferSize"));
|
assertEquals(29, dfa.getPropertyValue("receiveBufferSize"));
|
||||||
assertEquals(30, dfa.getPropertyValue("soReceiveBufferSize"));
|
assertEquals(30, dfa.getPropertyValue("soReceiveBufferSize"));
|
||||||
assertEquals(32, dfa.getPropertyValue("soTimeout"));
|
assertEquals(32, dfa.getPropertyValue("soTimeout"));
|
||||||
|
assertEquals(false, dfa.getPropertyValue("close"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -217,7 +229,6 @@ public class ParserUnitTests {
|
|||||||
assertEquals(53, dfa.getPropertyValue("soSendBufferSize"));
|
assertEquals(53, dfa.getPropertyValue("soSendBufferSize"));
|
||||||
assertEquals(54, dfa.getPropertyValue("soTimeout"));
|
assertEquals(54, dfa.getPropertyValue("soTimeout"));
|
||||||
assertEquals(false, dfa.getPropertyValue("usingDirectBuffers"));
|
assertEquals(false, dfa.getPropertyValue("usingDirectBuffers"));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -233,7 +244,6 @@ public class ParserUnitTests {
|
|||||||
assertEquals(53, dfa.getPropertyValue("soSendBufferSize"));
|
assertEquals(53, dfa.getPropertyValue("soSendBufferSize"));
|
||||||
assertEquals(54, dfa.getPropertyValue("soTimeout"));
|
assertEquals(54, dfa.getPropertyValue("soTimeout"));
|
||||||
assertEquals(true, dfa.getPropertyValue("usingDirectBuffers"));
|
assertEquals(true, dfa.getPropertyValue("usingDirectBuffers"));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -248,7 +258,6 @@ public class ParserUnitTests {
|
|||||||
assertEquals(27, dfa.getPropertyValue("soTrafficClass"));
|
assertEquals(27, dfa.getPropertyValue("soTrafficClass"));
|
||||||
assertEquals(53, dfa.getPropertyValue("soSendBufferSize"));
|
assertEquals(53, dfa.getPropertyValue("soSendBufferSize"));
|
||||||
assertEquals(54, dfa.getPropertyValue("soTimeout"));
|
assertEquals(54, dfa.getPropertyValue("soTimeout"));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -267,13 +276,13 @@ public class ParserUnitTests {
|
|||||||
assertEquals(125, dfa.getPropertyValue("soSendBufferSize"));
|
assertEquals(125, dfa.getPropertyValue("soSendBufferSize"));
|
||||||
assertEquals(126, dfa.getPropertyValue("soTimeout"));
|
assertEquals(126, dfa.getPropertyValue("soTimeout"));
|
||||||
assertEquals(23, dfa.getPropertyValue("poolSize"));
|
assertEquals(23, dfa.getPropertyValue("poolSize"));
|
||||||
|
assertEquals(false, dfa.getPropertyValue("close"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testOutGateway() {
|
public void testOutGateway() {
|
||||||
DirectFieldAccessor dfa = new DirectFieldAccessor(simpleTcpNetOutboundGateway);
|
DirectFieldAccessor dfa = new DirectFieldAccessor(simpleTcpNetOutboundGateway);
|
||||||
assertTrue(simpleTcpNetOutboundGateway.getPort() >= 6500);
|
assertTrue(simpleTcpNetOutboundGateway.getPort() >= 6600);
|
||||||
assertEquals(MessageFormats.FORMAT_CRLF, dfa.getPropertyValue("messageFormat"));
|
assertEquals(MessageFormats.FORMAT_CRLF, dfa.getPropertyValue("messageFormat"));
|
||||||
TcpNetSendingMessageHandler handler = (TcpNetSendingMessageHandler) dfa
|
TcpNetSendingMessageHandler handler = (TcpNetSendingMessageHandler) dfa
|
||||||
.getPropertyValue("handler");
|
.getPropertyValue("handler");
|
||||||
@@ -284,6 +293,42 @@ public class ParserUnitTests {
|
|||||||
assertEquals(224, dfa.getPropertyValue("soReceiveBufferSize"));
|
assertEquals(224, dfa.getPropertyValue("soReceiveBufferSize"));
|
||||||
assertEquals(225, delegateDfa.getPropertyValue("soSendBufferSize"));
|
assertEquals(225, delegateDfa.getPropertyValue("soSendBufferSize"));
|
||||||
assertEquals(226, delegateDfa.getPropertyValue("soTimeout"));
|
assertEquals(226, delegateDfa.getPropertyValue("soTimeout"));
|
||||||
|
assertEquals(false, dfa.getPropertyValue("close"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInGatewayClose() {
|
||||||
|
DirectFieldAccessor dfa = new DirectFieldAccessor(simpleTcpNetInboundGatewayClose);
|
||||||
|
assertTrue(simpleTcpNetInboundGatewayClose.getPort() >= 6700);
|
||||||
|
assertEquals(MessageFormats.FORMAT_CRLF, dfa.getPropertyValue("messageFormat"));
|
||||||
|
TcpNetReceivingChannelAdapter delegate = (TcpNetReceivingChannelAdapter) dfa
|
||||||
|
.getPropertyValue("delegate");
|
||||||
|
DirectFieldAccessor delegateDfa = new DirectFieldAccessor(delegate);
|
||||||
|
assertEquals(CustomNetSocketReader.class, delegateDfa.getPropertyValue("customSocketReaderClass"));
|
||||||
|
assertEquals(CustomNetSocketWriter.class, dfa.getPropertyValue("customSocketWriterClass"));
|
||||||
|
assertEquals(true, dfa.getPropertyValue("soKeepAlive"));
|
||||||
|
assertEquals(123, dfa.getPropertyValue("receiveBufferSize"));
|
||||||
|
assertEquals(124, dfa.getPropertyValue("soReceiveBufferSize"));
|
||||||
|
assertEquals(125, dfa.getPropertyValue("soSendBufferSize"));
|
||||||
|
assertEquals(126, dfa.getPropertyValue("soTimeout"));
|
||||||
|
assertEquals(23, dfa.getPropertyValue("poolSize"));
|
||||||
|
assertEquals(true, dfa.getPropertyValue("close"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOutGatewayClose() {
|
||||||
|
DirectFieldAccessor dfa = new DirectFieldAccessor(simpleTcpNetOutboundGatewayClose);
|
||||||
|
assertTrue(simpleTcpNetOutboundGatewayClose.getPort() >= 6800);
|
||||||
|
assertEquals(MessageFormats.FORMAT_CRLF, dfa.getPropertyValue("messageFormat"));
|
||||||
|
TcpNetSendingMessageHandler handler = (TcpNetSendingMessageHandler) dfa
|
||||||
|
.getPropertyValue("handler");
|
||||||
|
DirectFieldAccessor delegateDfa = new DirectFieldAccessor(handler);
|
||||||
|
assertEquals(CustomNetSocketReader.class, dfa.getPropertyValue("customSocketReaderClass"));
|
||||||
|
assertEquals(CustomNetSocketWriter.class, delegateDfa.getPropertyValue("customSocketWriterClass"));
|
||||||
|
assertEquals(true, delegateDfa.getPropertyValue("soKeepAlive"));
|
||||||
|
assertEquals(224, dfa.getPropertyValue("soReceiveBufferSize"));
|
||||||
|
assertEquals(225, delegateDfa.getPropertyValue("soSendBufferSize"));
|
||||||
|
assertEquals(226, delegateDfa.getPropertyValue("soTimeout"));
|
||||||
|
assertEquals(true, dfa.getPropertyValue("close"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,11 +41,14 @@ public class CustomNetSocketReader extends NetSocketReader {
|
|||||||
* @see org.springframework.integration.ip.tcp.NetSocketReader#assembleDataCustomFormat()
|
* @see org.springframework.integration.ip.tcp.NetSocketReader#assembleDataCustomFormat()
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected boolean assembleDataCustomFormat() throws IOException {
|
protected int assembleDataCustomFormat() throws IOException {
|
||||||
byte[] buff = new byte[24];
|
byte[] buff = new byte[24];
|
||||||
read(buff);
|
int status = read(buff, true);
|
||||||
|
if (status < 0) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
assembledData = buff;
|
assembledData = buff;
|
||||||
return true;
|
return MESSAGE_COMPLETE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -44,17 +44,17 @@ public class CustomNioSocketReader extends NioSocketReader {
|
|||||||
* @see org.springframework.integration.ip.tcp.NetSocketReader#assembleDataCustomFormat()
|
* @see org.springframework.integration.ip.tcp.NetSocketReader#assembleDataCustomFormat()
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected boolean assembleDataCustomFormat() throws IOException {
|
protected int assembleDataCustomFormat() throws IOException {
|
||||||
if (buffer == null) {
|
if (buffer == null) {
|
||||||
buffer = allocate(24);
|
buffer = allocate(24);
|
||||||
}
|
}
|
||||||
readChannel(buffer);
|
readChannel(buffer);
|
||||||
if (buffer.hasRemaining()) {
|
if (buffer.hasRemaining()) {
|
||||||
return false;
|
return MESSAGE_INCOMPLETE;
|
||||||
}
|
}
|
||||||
assembledData = buffer.array();
|
assembledData = buffer.array();
|
||||||
buffer = null;
|
buffer = null;
|
||||||
return true;
|
return MESSAGE_COMPLETE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -45,14 +45,14 @@ public class NetSocketReaderTests {
|
|||||||
Socket socket = server.accept();
|
Socket socket = server.accept();
|
||||||
socket.setSoTimeout(5000);
|
socket.setSoTimeout(5000);
|
||||||
NetSocketReader reader = new NetSocketReader(socket);
|
NetSocketReader reader = new NetSocketReader(socket);
|
||||||
if (reader.assembleData()) {
|
if (reader.assembleData() == SocketReader.MESSAGE_COMPLETE) {
|
||||||
assertEquals("Data", SocketUtils.TEST_STRING + SocketUtils.TEST_STRING,
|
assertEquals("Data", SocketUtils.TEST_STRING + SocketUtils.TEST_STRING,
|
||||||
new String(reader.getAssembledData()));
|
new String(reader.getAssembledData()));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
fail("Failed to assemble first message");
|
fail("Failed to assemble first message");
|
||||||
}
|
}
|
||||||
if (reader.assembleData()) {
|
if (reader.assembleData() == SocketReader.MESSAGE_COMPLETE) {
|
||||||
assertEquals("Data", SocketUtils.TEST_STRING + SocketUtils.TEST_STRING,
|
assertEquals("Data", SocketUtils.TEST_STRING + SocketUtils.TEST_STRING,
|
||||||
new String(reader.getAssembledData()));
|
new String(reader.getAssembledData()));
|
||||||
}
|
}
|
||||||
@@ -75,14 +75,14 @@ public class NetSocketReaderTests {
|
|||||||
socket.setSoTimeout(5000);
|
socket.setSoTimeout(5000);
|
||||||
NetSocketReader reader = new NetSocketReader(socket);
|
NetSocketReader reader = new NetSocketReader(socket);
|
||||||
reader.setMessageFormat(MessageFormats.FORMAT_STX_ETX);
|
reader.setMessageFormat(MessageFormats.FORMAT_STX_ETX);
|
||||||
if (reader.assembleData()) {
|
if (reader.assembleData() == SocketReader.MESSAGE_COMPLETE) {
|
||||||
assertEquals("Data", SocketUtils.TEST_STRING + SocketUtils.TEST_STRING,
|
assertEquals("Data", SocketUtils.TEST_STRING + SocketUtils.TEST_STRING,
|
||||||
new String(reader.getAssembledData()));
|
new String(reader.getAssembledData()));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
fail("Failed to assemble first message");
|
fail("Failed to assemble first message");
|
||||||
}
|
}
|
||||||
if (reader.assembleData()) {
|
if (reader.assembleData() == SocketReader.MESSAGE_COMPLETE) {
|
||||||
assertEquals("Data", SocketUtils.TEST_STRING + SocketUtils.TEST_STRING,
|
assertEquals("Data", SocketUtils.TEST_STRING + SocketUtils.TEST_STRING,
|
||||||
new String(reader.getAssembledData()));
|
new String(reader.getAssembledData()));
|
||||||
}
|
}
|
||||||
@@ -105,14 +105,14 @@ public class NetSocketReaderTests {
|
|||||||
socket.setSoTimeout(5000);
|
socket.setSoTimeout(5000);
|
||||||
NetSocketReader reader = new NetSocketReader(socket);
|
NetSocketReader reader = new NetSocketReader(socket);
|
||||||
reader.setMessageFormat(MessageFormats.FORMAT_CRLF);
|
reader.setMessageFormat(MessageFormats.FORMAT_CRLF);
|
||||||
if (reader.assembleData()) {
|
if (reader.assembleData() == SocketReader.MESSAGE_COMPLETE) {
|
||||||
assertEquals("Data", SocketUtils.TEST_STRING + SocketUtils.TEST_STRING,
|
assertEquals("Data", SocketUtils.TEST_STRING + SocketUtils.TEST_STRING,
|
||||||
new String(reader.getAssembledData()));
|
new String(reader.getAssembledData()));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
fail("Failed to assemble first message");
|
fail("Failed to assemble first message");
|
||||||
}
|
}
|
||||||
if (reader.assembleData()) {
|
if (reader.assembleData() == SocketReader.MESSAGE_COMPLETE) {
|
||||||
assertEquals("Data", SocketUtils.TEST_STRING + SocketUtils.TEST_STRING,
|
assertEquals("Data", SocketUtils.TEST_STRING + SocketUtils.TEST_STRING,
|
||||||
new String(reader.getAssembledData()));
|
new String(reader.getAssembledData()));
|
||||||
}
|
}
|
||||||
@@ -131,7 +131,7 @@ public class NetSocketReaderTests {
|
|||||||
socket.setSoTimeout(5000);
|
socket.setSoTimeout(5000);
|
||||||
NetSocketReader reader = new NetSocketReader(socket);
|
NetSocketReader reader = new NetSocketReader(socket);
|
||||||
try {
|
try {
|
||||||
if (reader.assembleData()) {
|
if (reader.assembleData() == SocketReader.MESSAGE_COMPLETE) {
|
||||||
fail("Expected message length exceeded exception");
|
fail("Expected message length exceeded exception");
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
@@ -153,7 +153,7 @@ public class NetSocketReaderTests {
|
|||||||
NetSocketReader reader = new NetSocketReader(socket);
|
NetSocketReader reader = new NetSocketReader(socket);
|
||||||
reader.setMessageFormat(MessageFormats.FORMAT_STX_ETX);
|
reader.setMessageFormat(MessageFormats.FORMAT_STX_ETX);
|
||||||
try {
|
try {
|
||||||
if (reader.assembleData()) {
|
if (reader.assembleData() == SocketReader.MESSAGE_COMPLETE) {
|
||||||
fail("Expected message length exceeded exception");
|
fail("Expected message length exceeded exception");
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
@@ -176,7 +176,7 @@ public class NetSocketReaderTests {
|
|||||||
reader.setMessageFormat(MessageFormats.FORMAT_STX_ETX);
|
reader.setMessageFormat(MessageFormats.FORMAT_STX_ETX);
|
||||||
reader.setMaxMessageSize(1024);
|
reader.setMaxMessageSize(1024);
|
||||||
try {
|
try {
|
||||||
if (reader.assembleData()) {
|
if (reader.assembleData() == SocketReader.MESSAGE_COMPLETE) {
|
||||||
fail("Expected message length exceeded exception");
|
fail("Expected message length exceeded exception");
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
@@ -198,7 +198,7 @@ public class NetSocketReaderTests {
|
|||||||
NetSocketReader reader = new NetSocketReader(socket);
|
NetSocketReader reader = new NetSocketReader(socket);
|
||||||
reader.setMessageFormat(MessageFormats.FORMAT_CRLF);
|
reader.setMessageFormat(MessageFormats.FORMAT_CRLF);
|
||||||
try {
|
try {
|
||||||
if (reader.assembleData()) {
|
if (reader.assembleData() == SocketReader.MESSAGE_COMPLETE) {
|
||||||
fail("Expected message length exceeded exception");
|
fail("Expected message length exceeded exception");
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
@@ -221,7 +221,7 @@ public class NetSocketReaderTests {
|
|||||||
reader.setMessageFormat(MessageFormats.FORMAT_CRLF);
|
reader.setMessageFormat(MessageFormats.FORMAT_CRLF);
|
||||||
reader.setMaxMessageSize(1024);
|
reader.setMaxMessageSize(1024);
|
||||||
try {
|
try {
|
||||||
if (reader.assembleData()) {
|
if (reader.assembleData() == SocketReader.MESSAGE_COMPLETE) {
|
||||||
fail("Expected message length exceeded exception");
|
fail("Expected message length exceeded exception");
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ public class NioSocketReaderTests {
|
|||||||
iterator.remove();
|
iterator.remove();
|
||||||
if (key.isReadable()) {
|
if (key.isReadable()) {
|
||||||
assertEquals(channel, key.channel());
|
assertEquals(channel, key.channel());
|
||||||
if (reader.assembleData()) {
|
if (reader.assembleData() == SocketReader.MESSAGE_COMPLETE) {
|
||||||
assertEquals("Data", SocketUtils.TEST_STRING + SocketUtils.TEST_STRING,
|
assertEquals("Data", SocketUtils.TEST_STRING + SocketUtils.TEST_STRING,
|
||||||
new String(reader.getAssembledData()));
|
new String(reader.getAssembledData()));
|
||||||
count++;
|
count++;
|
||||||
@@ -138,7 +138,7 @@ public class NioSocketReaderTests {
|
|||||||
iterator.remove();
|
iterator.remove();
|
||||||
if (key.isReadable()) {
|
if (key.isReadable()) {
|
||||||
assertEquals(channel, key.channel());
|
assertEquals(channel, key.channel());
|
||||||
if (reader.assembleData()) {
|
if (reader.assembleData() == SocketReader.MESSAGE_COMPLETE) {
|
||||||
assertEquals("Data", "xx",
|
assertEquals("Data", "xx",
|
||||||
new String(reader.getAssembledData()));
|
new String(reader.getAssembledData()));
|
||||||
done = true;
|
done = true;
|
||||||
@@ -198,7 +198,7 @@ public class NioSocketReaderTests {
|
|||||||
iterator.remove();
|
iterator.remove();
|
||||||
if (key.isReadable()) {
|
if (key.isReadable()) {
|
||||||
assertEquals(channel, key.channel());
|
assertEquals(channel, key.channel());
|
||||||
if (reader.assembleData()) {
|
if (reader.assembleData() == SocketReader.MESSAGE_COMPLETE) {
|
||||||
assertEquals("Data", SocketUtils.TEST_STRING + SocketUtils.TEST_STRING,
|
assertEquals("Data", SocketUtils.TEST_STRING + SocketUtils.TEST_STRING,
|
||||||
new String(reader.getAssembledData()));
|
new String(reader.getAssembledData()));
|
||||||
count++;
|
count++;
|
||||||
@@ -258,7 +258,7 @@ public class NioSocketReaderTests {
|
|||||||
iterator.remove();
|
iterator.remove();
|
||||||
if (key.isReadable()) {
|
if (key.isReadable()) {
|
||||||
assertEquals(channel, key.channel());
|
assertEquals(channel, key.channel());
|
||||||
if (reader.assembleData()) {
|
if (reader.assembleData() == SocketReader.MESSAGE_COMPLETE) {
|
||||||
assertEquals("Data", SocketUtils.TEST_STRING + SocketUtils.TEST_STRING,
|
assertEquals("Data", SocketUtils.TEST_STRING + SocketUtils.TEST_STRING,
|
||||||
new String(reader.getAssembledData()));
|
new String(reader.getAssembledData()));
|
||||||
count++;
|
count++;
|
||||||
@@ -318,7 +318,7 @@ public class NioSocketReaderTests {
|
|||||||
if (key.isReadable()) {
|
if (key.isReadable()) {
|
||||||
assertEquals(channel, key.channel());
|
assertEquals(channel, key.channel());
|
||||||
try {
|
try {
|
||||||
if (reader.assembleData()) {
|
if (reader.assembleData() == SocketReader.MESSAGE_COMPLETE) {
|
||||||
fail("Expected message length exceeded exception");
|
fail("Expected message length exceeded exception");
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
@@ -387,7 +387,7 @@ public class NioSocketReaderTests {
|
|||||||
if (key.isReadable()) {
|
if (key.isReadable()) {
|
||||||
assertEquals(channel, key.channel());
|
assertEquals(channel, key.channel());
|
||||||
try {
|
try {
|
||||||
if (reader.assembleData()) {
|
if (reader.assembleData() == SocketReader.MESSAGE_COMPLETE) {
|
||||||
fail("Expected message length exceeded exception");
|
fail("Expected message length exceeded exception");
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
@@ -456,7 +456,7 @@ public class NioSocketReaderTests {
|
|||||||
if (key.isReadable()) {
|
if (key.isReadable()) {
|
||||||
assertEquals(channel, key.channel());
|
assertEquals(channel, key.channel());
|
||||||
try {
|
try {
|
||||||
if (reader.assembleData()) {
|
if (reader.assembleData() == SocketReader.MESSAGE_COMPLETE) {
|
||||||
fail("Expected message length exceeded exception");
|
fail("Expected message length exceeded exception");
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
|||||||
@@ -134,9 +134,9 @@ public class SimpleTcpNetInboundGatewayTests {
|
|||||||
startup = 0;
|
startup = 0;
|
||||||
Socket socket = SocketFactory.getDefault().createSocket("localhost", gatewayCustom.getPort());
|
Socket socket = SocketFactory.getDefault().createSocket("localhost", gatewayCustom.getPort());
|
||||||
String greetings = "Hello World!";
|
String greetings = "Hello World!";
|
||||||
String pad = " ";
|
String pad = " ";
|
||||||
socket.getOutputStream().write((greetings).getBytes());
|
socket.getOutputStream().write((greetings).getBytes());
|
||||||
socket.getOutputStream().write(pad.getBytes()); // will be truncated
|
socket.getOutputStream().write(pad.getBytes());
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
int c;
|
int c;
|
||||||
int n = 0;
|
int n = 0;
|
||||||
|
|||||||
@@ -15,6 +15,8 @@
|
|||||||
*/
|
*/
|
||||||
package org.springframework.integration.ip.tcp;
|
package org.springframework.integration.ip.tcp;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
import java.net.ServerSocket;
|
import java.net.ServerSocket;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
import java.util.concurrent.CountDownLatch;
|
import java.util.concurrent.CountDownLatch;
|
||||||
@@ -22,7 +24,6 @@ import java.util.concurrent.TimeUnit;
|
|||||||
|
|
||||||
import javax.net.ServerSocketFactory;
|
import javax.net.ServerSocketFactory;
|
||||||
|
|
||||||
import org.junit.Ignore;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
@@ -35,8 +36,6 @@ import org.springframework.integration.message.MessageBuilder;
|
|||||||
import org.springframework.test.context.ContextConfiguration;
|
import org.springframework.test.context.ContextConfiguration;
|
||||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Gary Russell
|
* @author Gary Russell
|
||||||
*
|
*
|
||||||
@@ -74,16 +73,29 @@ public class SimpleTcpNetOutboundGatewayTests {
|
|||||||
SimpleTcpNetOutboundGateway gateway = new SimpleTcpNetOutboundGateway
|
SimpleTcpNetOutboundGateway gateway = new SimpleTcpNetOutboundGateway
|
||||||
("localhost", inboundGatewayCrLf.getPort());
|
("localhost", inboundGatewayCrLf.getPort());
|
||||||
gateway.setMessageFormat(MessageFormats.FORMAT_CRLF);
|
gateway.setMessageFormat(MessageFormats.FORMAT_CRLF);
|
||||||
|
waitListening(inboundGatewayCrLf);
|
||||||
Message<String> message = MessageBuilder.withPayload("test").build();
|
Message<String> message = MessageBuilder.withPayload("test").build();
|
||||||
byte[] bytes = (byte[]) gateway.handleRequestMessage(message);
|
byte[] bytes = (byte[]) gateway.handleRequestMessage(message);
|
||||||
assertEquals("echo:test", new String(bytes));
|
assertEquals("echo:test", new String(bytes));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void waitListening(SimpleTcpNetInboundGateway gateway) throws Exception {
|
||||||
|
int n = 0;
|
||||||
|
while (!gateway.isListening()) {
|
||||||
|
Thread.sleep(100);
|
||||||
|
if (n++ > 100) {
|
||||||
|
throw new Exception("Gateway failed to listen");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testOutboundStxEtx() throws Exception {
|
public void testOutboundStxEtx() throws Exception {
|
||||||
SimpleTcpNetOutboundGateway gateway = new SimpleTcpNetOutboundGateway
|
SimpleTcpNetOutboundGateway gateway = new SimpleTcpNetOutboundGateway
|
||||||
("localhost", inboundGatewayStxEtx.getPort());
|
("localhost", inboundGatewayStxEtx.getPort());
|
||||||
gateway.setMessageFormat(MessageFormats.FORMAT_STX_ETX);
|
gateway.setMessageFormat(MessageFormats.FORMAT_STX_ETX);
|
||||||
|
waitListening(inboundGatewayStxEtx);
|
||||||
Message<String> message = MessageBuilder.withPayload("test").build();
|
Message<String> message = MessageBuilder.withPayload("test").build();
|
||||||
byte[] bytes = (byte[]) gateway.handleRequestMessage(message);
|
byte[] bytes = (byte[]) gateway.handleRequestMessage(message);
|
||||||
assertEquals("echo:test", new String(bytes));
|
assertEquals("echo:test", new String(bytes));
|
||||||
@@ -94,6 +106,7 @@ public class SimpleTcpNetOutboundGatewayTests {
|
|||||||
SimpleTcpNetOutboundGateway gateway = new SimpleTcpNetOutboundGateway
|
SimpleTcpNetOutboundGateway gateway = new SimpleTcpNetOutboundGateway
|
||||||
("localhost", inboundGatewayLength.getPort());
|
("localhost", inboundGatewayLength.getPort());
|
||||||
gateway.setMessageFormat(MessageFormats.FORMAT_LENGTH_HEADER);
|
gateway.setMessageFormat(MessageFormats.FORMAT_LENGTH_HEADER);
|
||||||
|
waitListening(inboundGatewayLength);
|
||||||
Message<String> message = MessageBuilder.withPayload("test").build();
|
Message<String> message = MessageBuilder.withPayload("test").build();
|
||||||
byte[] bytes = (byte[]) gateway.handleRequestMessage(message);
|
byte[] bytes = (byte[]) gateway.handleRequestMessage(message);
|
||||||
assertEquals("echo:test", new String(bytes));
|
assertEquals("echo:test", new String(bytes));
|
||||||
@@ -106,6 +119,7 @@ public class SimpleTcpNetOutboundGatewayTests {
|
|||||||
gateway.setMessageFormat(MessageFormats.FORMAT_CUSTOM);
|
gateway.setMessageFormat(MessageFormats.FORMAT_CUSTOM);
|
||||||
gateway.setCustomSocketReaderClassName("org.springframework.integration.ip.tcp.CustomNetSocketReader");
|
gateway.setCustomSocketReaderClassName("org.springframework.integration.ip.tcp.CustomNetSocketReader");
|
||||||
gateway.setCustomSocketWriterClassName("org.springframework.integration.ip.tcp.CustomNetSocketWriter");
|
gateway.setCustomSocketWriterClassName("org.springframework.integration.ip.tcp.CustomNetSocketWriter");
|
||||||
|
waitListening(inboundGatewayCustom);
|
||||||
Message<String> message = MessageBuilder.withPayload("test").build();
|
Message<String> message = MessageBuilder.withPayload("test").build();
|
||||||
byte[] bytes = (byte[]) gateway.handleRequestMessage(message);
|
byte[] bytes = (byte[]) gateway.handleRequestMessage(message);
|
||||||
assertEquals("echo:test", new String(bytes).trim());
|
assertEquals("echo:test", new String(bytes).trim());
|
||||||
@@ -119,11 +133,12 @@ public class SimpleTcpNetOutboundGatewayTests {
|
|||||||
assertEquals("echo:test", new String(bytes).trim());
|
assertEquals("echo:test", new String(bytes).trim());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Ignore @Test
|
@Test
|
||||||
public void testOutboundClose() throws Exception {
|
public void testOutboundClose() throws Exception {
|
||||||
final int port = SocketUtils.findAvailableServerSocket();
|
final int port = SocketUtils.findAvailableServerSocket();
|
||||||
final CountDownLatch latch1 = new CountDownLatch(1);
|
final CountDownLatch latch1 = new CountDownLatch(1);
|
||||||
final CountDownLatch latch2 = new CountDownLatch(1);
|
final CountDownLatch latch2 = new CountDownLatch(1);
|
||||||
|
final CountDownLatch latch3 = new CountDownLatch(1);
|
||||||
Thread t = new Thread(new Runnable() {
|
Thread t = new Thread(new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
@@ -134,8 +149,9 @@ public class SimpleTcpNetOutboundGatewayTests {
|
|||||||
byte[] b = new byte[1024];
|
byte[] b = new byte[1024];
|
||||||
s.getInputStream().read(b);
|
s.getInputStream().read(b);
|
||||||
s.getOutputStream().write("OK\r\n".getBytes());
|
s.getOutputStream().write("OK\r\n".getBytes());
|
||||||
s.close();
|
|
||||||
latch2.countDown();
|
latch2.countDown();
|
||||||
|
latch3.await();
|
||||||
|
s.close();
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
@@ -146,9 +162,11 @@ public class SimpleTcpNetOutboundGatewayTests {
|
|||||||
SimpleTcpNetOutboundGateway gateway = new SimpleTcpNetOutboundGateway
|
SimpleTcpNetOutboundGateway gateway = new SimpleTcpNetOutboundGateway
|
||||||
("localhost", port);
|
("localhost", port);
|
||||||
gateway.setMessageFormat(MessageFormats.FORMAT_CRLF);
|
gateway.setMessageFormat(MessageFormats.FORMAT_CRLF);
|
||||||
|
gateway.setClose(true);
|
||||||
Message<String> message = MessageBuilder.withPayload("test").build();
|
Message<String> message = MessageBuilder.withPayload("test").build();
|
||||||
byte[] bytes = (byte[]) gateway.handleRequestMessage(message);
|
byte[] bytes = (byte[]) gateway.handleRequestMessage(message);
|
||||||
assertEquals("OK", new String(bytes));
|
assertEquals("OK", new String(bytes));
|
||||||
|
latch3.countDown();
|
||||||
latch2.await(2000, TimeUnit.MILLISECONDS);
|
latch2.await(2000, TimeUnit.MILLISECONDS);
|
||||||
bytes = (byte[]) gateway.handleRequestMessage(message);
|
bytes = (byte[]) gateway.handleRequestMessage(message);
|
||||||
assertEquals("OK", new String(bytes));
|
assertEquals("OK", new String(bytes));
|
||||||
|
|||||||
@@ -91,8 +91,8 @@ public class SocketMessageMapperTests {
|
|||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
* @see org.springframework.integration.ip.tcp.SocketReader#assembleData()
|
* @see org.springframework.integration.ip.tcp.SocketReader#assembleData()
|
||||||
*/
|
*/
|
||||||
public boolean assembleData() {
|
public int assembleData() {
|
||||||
return false;
|
return SocketReader.MESSAGE_INCOMPLETE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
|
|||||||
@@ -18,6 +18,8 @@ package org.springframework.integration.ip.tcp;
|
|||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertNotNull;
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
|
||||||
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.springframework.integration.channel.QueueChannel;
|
import org.springframework.integration.channel.QueueChannel;
|
||||||
import org.springframework.integration.core.Message;
|
import org.springframework.integration.core.Message;
|
||||||
@@ -44,14 +46,13 @@ public class TcpReceivingChannelAdapterTests {
|
|||||||
taskScheduler.initialize();
|
taskScheduler.initialize();
|
||||||
adapter.setTaskScheduler(taskScheduler);
|
adapter.setTaskScheduler(taskScheduler);
|
||||||
adapter.start();
|
adapter.start();
|
||||||
Thread.sleep(2000); // wait for server to start listening
|
waitListening(adapter);
|
||||||
SocketUtils.testSendLength(port, null); //sends 2 copies of TEST_STRING twice
|
SocketUtils.testSendLength(port, null); //sends 2 copies of TEST_STRING twice
|
||||||
Thread.sleep(2000); // wait for asynch processing
|
Message<?> message = channel.receive(2000);
|
||||||
Message<?> message = channel.receive(0);
|
|
||||||
assertNotNull(message);
|
assertNotNull(message);
|
||||||
assertEquals(SocketUtils.TEST_STRING + SocketUtils.TEST_STRING,
|
assertEquals(SocketUtils.TEST_STRING + SocketUtils.TEST_STRING,
|
||||||
new String((byte[])message.getPayload()));
|
new String((byte[])message.getPayload()));
|
||||||
message = channel.receive(0);
|
message = channel.receive(2000);
|
||||||
assertNotNull(message);
|
assertNotNull(message);
|
||||||
assertEquals(SocketUtils.TEST_STRING + SocketUtils.TEST_STRING,
|
assertEquals(SocketUtils.TEST_STRING + SocketUtils.TEST_STRING,
|
||||||
new String((byte[])message.getPayload()));
|
new String((byte[])message.getPayload()));
|
||||||
@@ -74,14 +75,13 @@ public class TcpReceivingChannelAdapterTests {
|
|||||||
taskScheduler.initialize();
|
taskScheduler.initialize();
|
||||||
adapter.setTaskScheduler(taskScheduler);
|
adapter.setTaskScheduler(taskScheduler);
|
||||||
adapter.start();
|
adapter.start();
|
||||||
Thread.sleep(2000); // wait for server to start listening
|
waitListening(adapter);
|
||||||
SocketUtils.testSendStxEtx(port, null); //sends 2 copies of TEST_STRING twice
|
SocketUtils.testSendStxEtx(port, null); //sends 2 copies of TEST_STRING twice
|
||||||
Thread.sleep(4000); // wait for asynch processing
|
Message<?> message = channel.receive(4000);
|
||||||
Message<?> message = channel.receive(0);
|
|
||||||
assertNotNull(message);
|
assertNotNull(message);
|
||||||
assertEquals("\u0002" + SocketUtils.TEST_STRING + SocketUtils.TEST_STRING + "\u0003",
|
assertEquals("\u0002" + SocketUtils.TEST_STRING + SocketUtils.TEST_STRING + "\u0003",
|
||||||
new String((byte[])message.getPayload()));
|
new String((byte[])message.getPayload()));
|
||||||
message = channel.receive(0);
|
message = channel.receive(2000);
|
||||||
assertNotNull(message);
|
assertNotNull(message);
|
||||||
assertEquals("\u0002" + SocketUtils.TEST_STRING + SocketUtils.TEST_STRING + "\u0003",
|
assertEquals("\u0002" + SocketUtils.TEST_STRING + SocketUtils.TEST_STRING + "\u0003",
|
||||||
new String((byte[])message.getPayload()));
|
new String((byte[])message.getPayload()));
|
||||||
@@ -102,14 +102,13 @@ public class TcpReceivingChannelAdapterTests {
|
|||||||
taskScheduler.initialize();
|
taskScheduler.initialize();
|
||||||
adapter.setTaskScheduler(taskScheduler);
|
adapter.setTaskScheduler(taskScheduler);
|
||||||
adapter.start();
|
adapter.start();
|
||||||
Thread.sleep(2000); // wait for server to start listening
|
waitListening(adapter);
|
||||||
SocketUtils.testSendLength(port, null); //sends 2 copies of TEST_STRING twice
|
SocketUtils.testSendLength(port, null); //sends 2 copies of TEST_STRING twice
|
||||||
Thread.sleep(2000); // wait for asynch processing
|
Message<?> message = channel.receive(2000);
|
||||||
Message<?> message = channel.receive(0);
|
|
||||||
assertNotNull(message);
|
assertNotNull(message);
|
||||||
assertEquals(SocketUtils.TEST_STRING + SocketUtils.TEST_STRING,
|
assertEquals(SocketUtils.TEST_STRING + SocketUtils.TEST_STRING,
|
||||||
new String((byte[])message.getPayload()));
|
new String((byte[])message.getPayload()));
|
||||||
message = channel.receive(0);
|
message = channel.receive(2000);
|
||||||
assertNotNull(message);
|
assertNotNull(message);
|
||||||
assertEquals(SocketUtils.TEST_STRING + SocketUtils.TEST_STRING,
|
assertEquals(SocketUtils.TEST_STRING + SocketUtils.TEST_STRING,
|
||||||
new String((byte[])message.getPayload()));
|
new String((byte[])message.getPayload()));
|
||||||
@@ -131,18 +130,98 @@ public class TcpReceivingChannelAdapterTests {
|
|||||||
taskScheduler.initialize();
|
taskScheduler.initialize();
|
||||||
adapter.setTaskScheduler(taskScheduler);
|
adapter.setTaskScheduler(taskScheduler);
|
||||||
adapter.start();
|
adapter.start();
|
||||||
Thread.sleep(2000); // wait for server to start listening
|
waitListening(adapter);
|
||||||
SocketUtils.testSendStxEtx(port, null); //sends 2 copies of TEST_STRING twice
|
SocketUtils.testSendStxEtx(port, null); //sends 2 copies of TEST_STRING twice
|
||||||
Thread.sleep(4000); // wait for asynch processing
|
Message<?> message = channel.receive(2000);
|
||||||
Message<?> message = channel.receive(0);
|
|
||||||
assertNotNull(message);
|
assertNotNull(message);
|
||||||
assertEquals("\u0002" + SocketUtils.TEST_STRING + SocketUtils.TEST_STRING + "\u0003",
|
assertEquals("\u0002" + SocketUtils.TEST_STRING + SocketUtils.TEST_STRING + "\u0003",
|
||||||
new String((byte[])message.getPayload()));
|
new String((byte[])message.getPayload()));
|
||||||
message = channel.receive(0);
|
message = channel.receive(2000);
|
||||||
assertNotNull(message);
|
assertNotNull(message);
|
||||||
assertEquals("\u0002" + SocketUtils.TEST_STRING + SocketUtils.TEST_STRING + "\u0003",
|
assertEquals("\u0002" + SocketUtils.TEST_STRING + SocketUtils.TEST_STRING + "\u0003",
|
||||||
new String((byte[])message.getPayload()));
|
new String((byte[])message.getPayload()));
|
||||||
adapter.stop();
|
adapter.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests close option on inbound adapter.
|
||||||
|
*
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testNetClose() throws Exception {
|
||||||
|
QueueChannel channel = new QueueChannel(2);
|
||||||
|
int port = SocketUtils.findAvailableServerSocket();
|
||||||
|
AbstractTcpReceivingChannelAdapter adapter = new TcpNetReceivingChannelAdapter(port);
|
||||||
|
adapter.setOutputChannel(channel);
|
||||||
|
adapter.setClose(true);
|
||||||
|
adapter.setMessageFormat(MessageFormats.FORMAT_CRLF);
|
||||||
|
ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
|
||||||
|
taskScheduler.initialize();
|
||||||
|
adapter.setTaskScheduler(taskScheduler);
|
||||||
|
adapter.start();
|
||||||
|
waitListening(adapter);
|
||||||
|
CountDownLatch latch = new CountDownLatch(1);
|
||||||
|
SocketUtils.testSendCrLfSingle(port, latch);
|
||||||
|
Message<?> message = channel.receive(5000);
|
||||||
|
latch.countDown();
|
||||||
|
assertNotNull(message);
|
||||||
|
assertEquals(SocketUtils.TEST_STRING + SocketUtils.TEST_STRING,
|
||||||
|
new String((byte[])message.getPayload()));
|
||||||
|
latch = new CountDownLatch(1);
|
||||||
|
SocketUtils.testSendCrLfSingle(port, latch);
|
||||||
|
message = channel.receive(5000);
|
||||||
|
latch.countDown();
|
||||||
|
assertNotNull(message);
|
||||||
|
assertEquals(SocketUtils.TEST_STRING + SocketUtils.TEST_STRING,
|
||||||
|
new String((byte[])message.getPayload()));
|
||||||
|
adapter.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests close option on inbound adapter.
|
||||||
|
*
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testNioClose() throws Exception {
|
||||||
|
QueueChannel channel = new QueueChannel(2);
|
||||||
|
int port = SocketUtils.findAvailableServerSocket();
|
||||||
|
AbstractTcpReceivingChannelAdapter adapter = new TcpNioReceivingChannelAdapter(port);
|
||||||
|
adapter.setOutputChannel(channel);
|
||||||
|
adapter.setClose(true);
|
||||||
|
adapter.setMessageFormat(MessageFormats.FORMAT_CRLF);
|
||||||
|
ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
|
||||||
|
taskScheduler.initialize();
|
||||||
|
adapter.setTaskScheduler(taskScheduler);
|
||||||
|
adapter.start();
|
||||||
|
waitListening(adapter);
|
||||||
|
CountDownLatch latch = new CountDownLatch(1);
|
||||||
|
SocketUtils.testSendCrLfSingle(port, latch);
|
||||||
|
Message<?> message = channel.receive(2000);
|
||||||
|
assertNotNull(message);
|
||||||
|
assertEquals(SocketUtils.TEST_STRING + SocketUtils.TEST_STRING,
|
||||||
|
new String((byte[])message.getPayload()));
|
||||||
|
latch = new CountDownLatch(1);
|
||||||
|
SocketUtils.testSendCrLfSingle(port, latch);
|
||||||
|
message = channel.receive(2000);
|
||||||
|
assertNotNull(message);
|
||||||
|
assertEquals(SocketUtils.TEST_STRING + SocketUtils.TEST_STRING,
|
||||||
|
new String((byte[])message.getPayload()));
|
||||||
|
adapter.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void waitListening(AbstractInternetProtocolReceivingChannelAdapter adapter) throws Exception {
|
||||||
|
int n = 0;
|
||||||
|
while (!adapter.isListening()) {
|
||||||
|
Thread.sleep(100);
|
||||||
|
if (n++ > 100) {
|
||||||
|
throw new Exception("Gateway failed to listen");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -222,7 +222,34 @@ public class SocketUtils {
|
|||||||
thread.setDaemon(true);
|
thread.setDaemon(true);
|
||||||
thread.start();
|
thread.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends a single message +CRLF.
|
||||||
|
* @param latch Waits for latch to count down before closing the socket.
|
||||||
|
*/
|
||||||
|
public static void testSendCrLfSingle(final int port, final CountDownLatch latch) {
|
||||||
|
Thread thread = new Thread(new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
Socket socket = new Socket(InetAddress.getByName("localhost"), port);
|
||||||
|
OutputStream outputStream = socket.getOutputStream();
|
||||||
|
outputStream.write(TEST_STRING.getBytes());
|
||||||
|
outputStream.write(TEST_STRING.getBytes());
|
||||||
|
writeByte(outputStream, '\r', true);
|
||||||
|
writeByte(outputStream, '\n', true);
|
||||||
|
if (latch != null) {
|
||||||
|
latch.await();
|
||||||
|
}
|
||||||
|
socket.close();
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
thread.setDaemon(true);
|
||||||
|
thread.start();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sends a large CRLF message with no CRLF.
|
* Sends a large CRLF message with no CRLF.
|
||||||
*/
|
*/
|
||||||
|
|||||||
Reference in New Issue
Block a user